You're breathtaking!
This commit is contained in:
168
Source/Engine/Graphics/Materials/DecalMaterialShader.cpp
Normal file
168
Source/Engine/Graphics/Materials/DecalMaterialShader.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "DecalMaterialShader.h"
|
||||
#include "MaterialParams.h"
|
||||
#include "Engine/Core/Math/OrientedBoundingBox.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||
#include "Engine/Graphics/RenderBuffers.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Graphics/RenderView.h"
|
||||
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
|
||||
PACK_STRUCT(struct DecalMaterialShaderData {
|
||||
Matrix ViewProjectionMatrix;
|
||||
Matrix WorldMatrix;
|
||||
Matrix ViewMatrix;
|
||||
Matrix InvWorld;
|
||||
Matrix SVPositionToWorld;
|
||||
Vector3 ViewPos;
|
||||
float ViewFar;
|
||||
Vector3 ViewDir;
|
||||
float TimeParam;
|
||||
Vector4 ViewInfo;
|
||||
Vector4 ScreenSize;
|
||||
});
|
||||
|
||||
DrawPass DecalMaterialShader::GetDrawModes() const
|
||||
{
|
||||
return DrawPass::GBuffer;
|
||||
}
|
||||
|
||||
void DecalMaterialShader::Bind(BindParameters& params)
|
||||
{
|
||||
// Prepare
|
||||
auto context = params.GPUContext;
|
||||
auto& view = params.RenderContext.View;
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
const auto cb0 = _shader->GetCB(0);
|
||||
const bool hasCb0 = cb0->GetSize() != 0;
|
||||
const bool isCameraInside = OrientedBoundingBox(Vector3::Half, params.FirstDrawCall->World).Contains(view.Position) == ContainmentType::Contains;
|
||||
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(DecalMaterialShaderData) : nullptr;
|
||||
bindMeta.Input = nullptr;
|
||||
bindMeta.Buffers = nullptr;
|
||||
bindMeta.CanSampleDepth = true;
|
||||
bindMeta.CanSampleGBuffer = false;
|
||||
MaterialParams::Bind(params.ParamsLink, bindMeta);
|
||||
|
||||
// Decals use depth buffer to draw on top of the objects
|
||||
context->BindSR(0, GET_TEXTURE_VIEW_SAFE(params.RenderContext.Buffers->DepthBuffer));
|
||||
|
||||
// Setup material constants data
|
||||
if (hasCb0)
|
||||
{
|
||||
const auto materialData = reinterpret_cast<DecalMaterialShaderData*>(_cb0Data.Get());
|
||||
|
||||
Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix);
|
||||
Matrix::Transpose(drawCall.World, materialData->WorldMatrix);
|
||||
Matrix::Transpose(view.View, materialData->ViewMatrix);
|
||||
materialData->ViewPos = view.Position;
|
||||
materialData->ViewFar = view.Far;
|
||||
materialData->ViewDir = view.Direction;
|
||||
materialData->TimeParam = Time::Draw.UnscaledTime.GetTotalSeconds();
|
||||
materialData->ViewInfo = view.ViewInfo;
|
||||
materialData->ScreenSize = view.ScreenSize;
|
||||
|
||||
// Matrix for transformation from world space to decal object space
|
||||
Matrix invWorld;
|
||||
Matrix::Invert(drawCall.World, invWorld);
|
||||
Matrix::Transpose(invWorld, materialData->InvWorld);
|
||||
|
||||
// Matrix for transformation from SV Position space to world space
|
||||
const Matrix offsetMatrix(
|
||||
2.0f * view.ScreenSize.Z, 0, 0, 0,
|
||||
0, -2.0f * view.ScreenSize.W, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
-1.0f, 1.0f, 0, 1);
|
||||
const Matrix svPositionToWorld = offsetMatrix * view.IVP;
|
||||
Matrix::Transpose(svPositionToWorld, materialData->SVPositionToWorld);
|
||||
}
|
||||
|
||||
// Bind constants
|
||||
if (hasCb0)
|
||||
{
|
||||
context->UpdateCB(cb0, _cb0Data.Get());
|
||||
context->BindCB(0, cb0);
|
||||
}
|
||||
|
||||
// Bind pipeline
|
||||
context->SetState(isCameraInside ? _cache.Inside : _cache.Outside);
|
||||
}
|
||||
|
||||
void DecalMaterialShader::Unload()
|
||||
{
|
||||
// Base
|
||||
MaterialShader::Unload();
|
||||
|
||||
_cache.Release();
|
||||
}
|
||||
|
||||
bool DecalMaterialShader::Load()
|
||||
{
|
||||
GPUPipelineState::Description psDesc0 = GPUPipelineState::Description::DefaultNoDepth;
|
||||
psDesc0.VS = _shader->GetVS("VS_Decal");
|
||||
psDesc0.PS = _shader->GetPS("PS_Decal");
|
||||
psDesc0.CullMode = CullMode::Normal;
|
||||
|
||||
switch (_info.DecalBlendingMode)
|
||||
{
|
||||
case MaterialDecalBlendingMode::Translucent:
|
||||
{
|
||||
psDesc0.BlendMode.BlendEnable = true;
|
||||
psDesc0.BlendMode.SrcBlend = BlendingMode::Blend::SrcAlpha;
|
||||
psDesc0.BlendMode.DestBlend = BlendingMode::Blend::InvSrcAlpha;
|
||||
psDesc0.BlendMode.SrcBlendAlpha = BlendingMode::Blend::Zero;
|
||||
psDesc0.BlendMode.DestBlendAlpha = BlendingMode::Blend::One;
|
||||
psDesc0.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::RGB;
|
||||
break;
|
||||
}
|
||||
case MaterialDecalBlendingMode::Stain:
|
||||
{
|
||||
psDesc0.BlendMode.BlendEnable = true;
|
||||
psDesc0.BlendMode.SrcBlend = BlendingMode::Blend::DestColor;
|
||||
psDesc0.BlendMode.DestBlend = BlendingMode::Blend::InvSrcAlpha;
|
||||
psDesc0.BlendMode.SrcBlendAlpha = BlendingMode::Blend::Zero;
|
||||
psDesc0.BlendMode.DestBlendAlpha = BlendingMode::Blend::One;
|
||||
psDesc0.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::RGB;
|
||||
break;
|
||||
}
|
||||
case MaterialDecalBlendingMode::Normal:
|
||||
{
|
||||
psDesc0.BlendMode.BlendEnable = true;
|
||||
psDesc0.BlendMode.SrcBlend = BlendingMode::Blend::SrcAlpha;
|
||||
psDesc0.BlendMode.DestBlend = BlendingMode::Blend::InvSrcAlpha;
|
||||
psDesc0.BlendMode.SrcBlendAlpha = BlendingMode::Blend::One;
|
||||
psDesc0.BlendMode.DestBlendAlpha = BlendingMode::Blend::One;
|
||||
psDesc0.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::RGB;
|
||||
break;
|
||||
}
|
||||
case MaterialDecalBlendingMode::Emissive:
|
||||
{
|
||||
psDesc0.BlendMode = BlendingMode::Additive;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_cache.Outside = GPUDevice::Instance->CreatePipelineState();
|
||||
if (_cache.Outside->Init(psDesc0))
|
||||
{
|
||||
LOG(Warning, "Failed to create decal material pipeline state.");
|
||||
return true;
|
||||
}
|
||||
|
||||
psDesc0.CullMode = CullMode::Inverted;
|
||||
_cache.Inside = GPUDevice::Instance->CreatePipelineState();
|
||||
if (_cache.Inside->Init(psDesc0))
|
||||
{
|
||||
LOG(Warning, "Failed to create decal material pipeline state.");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
52
Source/Engine/Graphics/Materials/DecalMaterialShader.h
Normal file
52
Source/Engine/Graphics/Materials/DecalMaterialShader.h
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MaterialShader.h"
|
||||
|
||||
/// <summary>
|
||||
/// Represents material that can be used to render decals.
|
||||
/// </summary>
|
||||
class DecalMaterialShader : public MaterialShader
|
||||
{
|
||||
private:
|
||||
|
||||
struct Cache
|
||||
{
|
||||
GPUPipelineState* Inside = nullptr;
|
||||
GPUPipelineState* Outside = nullptr;
|
||||
|
||||
FORCE_INLINE void Release()
|
||||
{
|
||||
SAFE_DELETE_GPU_RESOURCE(Inside);
|
||||
SAFE_DELETE_GPU_RESOURCE(Outside);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Cache _cache;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="name">Material resource name</param>
|
||||
DecalMaterialShader(const String& name)
|
||||
: MaterialShader(name)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [MaterialShader]
|
||||
DrawPass GetDrawModes() const override;
|
||||
void Bind(BindParameters& params) override;
|
||||
void Unload() override;
|
||||
|
||||
protected:
|
||||
|
||||
// [MaterialShader]
|
||||
bool Load() override;
|
||||
};
|
||||
268
Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp
Normal file
268
Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "DeferredMaterialShader.h"
|
||||
#include "MaterialParams.h"
|
||||
#include "Engine/Graphics/RenderBuffers.h"
|
||||
#include "Engine/Graphics/RenderView.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
#include "Engine/Level/Scene/Lightmap.h"
|
||||
#include "Engine/Graphics/GPUContext.h"
|
||||
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
|
||||
#include "Engine/Graphics/Models/SkinnedMeshDrawData.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||
#include "Engine/Graphics/GPULimits.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
|
||||
PACK_STRUCT(struct DeferredMaterialShaderData {
|
||||
Matrix ViewProjectionMatrix;
|
||||
Matrix WorldMatrix;
|
||||
Matrix ViewMatrix;
|
||||
Matrix PrevViewProjectionMatrix;
|
||||
Matrix PrevWorldMatrix;
|
||||
Vector3 ViewPos;
|
||||
float ViewFar;
|
||||
Vector3 ViewDir;
|
||||
float TimeParam;
|
||||
Vector4 ViewInfo;
|
||||
Vector4 ScreenSize;
|
||||
Rectangle LightmapArea;
|
||||
Vector3 WorldInvScale;
|
||||
float WorldDeterminantSign;
|
||||
Vector2 Dummy0;
|
||||
float LODDitherFactor;
|
||||
float PerInstanceRandom;
|
||||
Vector4 TemporalAAJitter;
|
||||
Vector3 GeometrySize;
|
||||
float Dummy1;
|
||||
});
|
||||
|
||||
DrawPass DeferredMaterialShader::GetDrawModes() const
|
||||
{
|
||||
return DrawPass::Depth | DrawPass::GBuffer | DrawPass::MotionVectors;
|
||||
}
|
||||
|
||||
bool DeferredMaterialShader::CanUseLightmap() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeferredMaterialShader::CanUseInstancing() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeferredMaterialShader::Bind(BindParameters& params)
|
||||
{
|
||||
// Prepare
|
||||
auto context = params.GPUContext;
|
||||
auto& view = params.RenderContext.View;
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
const auto cb0 = _shader->GetCB(0);
|
||||
const bool hasCb0 = cb0 && cb0->GetSize() != 0;
|
||||
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(DeferredMaterialShaderData) : nullptr;
|
||||
bindMeta.Input = nullptr;
|
||||
bindMeta.Buffers = nullptr;
|
||||
bindMeta.CanSampleDepth = false;
|
||||
bindMeta.CanSampleGBuffer = false;
|
||||
MaterialParams::Bind(params.ParamsLink, bindMeta);
|
||||
|
||||
// Setup material constants data
|
||||
auto materialData = reinterpret_cast<DeferredMaterialShaderData*>(_cb0Data.Get());
|
||||
if (hasCb0)
|
||||
{
|
||||
Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix);
|
||||
Matrix::Transpose(drawCall.World, materialData->WorldMatrix);
|
||||
Matrix::Transpose(view.View, materialData->ViewMatrix);
|
||||
Matrix::Transpose(drawCall.PrevWorld, materialData->PrevWorldMatrix);
|
||||
Matrix::Transpose(view.PrevViewProjection, materialData->PrevViewProjectionMatrix);
|
||||
|
||||
materialData->ViewPos = view.Position;
|
||||
materialData->ViewFar = view.Far;
|
||||
materialData->ViewDir = view.Direction;
|
||||
materialData->TimeParam = Time::Draw.UnscaledTime.GetTotalSeconds();
|
||||
materialData->ViewInfo = view.ViewInfo;
|
||||
materialData->ScreenSize = view.ScreenSize;
|
||||
|
||||
// Extract per axis scales from LocalToWorld transform
|
||||
const float scaleX = Vector3(drawCall.World.M11, drawCall.World.M12, drawCall.World.M13).Length();
|
||||
const float scaleY = Vector3(drawCall.World.M21, drawCall.World.M22, drawCall.World.M23).Length();
|
||||
const float scaleZ = Vector3(drawCall.World.M31, drawCall.World.M32, drawCall.World.M33).Length();
|
||||
const Vector3 worldInvScale = Vector3(
|
||||
scaleX > 0.00001f ? 1.0f / scaleX : 0.0f,
|
||||
scaleY > 0.00001f ? 1.0f / scaleY : 0.0f,
|
||||
scaleZ > 0.00001f ? 1.0f / scaleZ : 0.0f);
|
||||
|
||||
materialData->WorldInvScale = worldInvScale;
|
||||
materialData->WorldDeterminantSign = drawCall.WorldDeterminantSign;
|
||||
materialData->LODDitherFactor = drawCall.LODDitherFactor;
|
||||
materialData->PerInstanceRandom = drawCall.PerInstanceRandom;
|
||||
materialData->TemporalAAJitter = view.TemporalAAJitter;
|
||||
materialData->GeometrySize = drawCall.GeometrySize;
|
||||
}
|
||||
const bool useLightmap = view.Flags & ViewFlags::GI
|
||||
#if USE_EDITOR
|
||||
&& EnableLightmapsUsage
|
||||
#endif
|
||||
&& drawCall.Lightmap != nullptr;
|
||||
if (useLightmap)
|
||||
{
|
||||
// Bind lightmap textures
|
||||
GPUTexture *lightmap0, *lightmap1, *lightmap2;
|
||||
drawCall.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2);
|
||||
context->BindSR(0, lightmap0);
|
||||
context->BindSR(1, lightmap1);
|
||||
context->BindSR(2, lightmap2);
|
||||
|
||||
// Set lightmap data
|
||||
materialData->LightmapArea = drawCall.LightmapUVsArea;
|
||||
}
|
||||
|
||||
// Check if is using mesh skinning
|
||||
const bool useSkinning = drawCall.Skinning != nullptr;
|
||||
bool perBoneMotionBlur = false;
|
||||
if (useSkinning)
|
||||
{
|
||||
// Bind skinning buffer
|
||||
ASSERT(drawCall.Skinning->IsReady());
|
||||
context->BindSR(0, drawCall.Skinning->BoneMatrices->View());
|
||||
if (drawCall.Skinning->PrevBoneMatrices && drawCall.Skinning->PrevBoneMatrices->IsAllocated())
|
||||
{
|
||||
context->BindSR(1, drawCall.Skinning->PrevBoneMatrices->View());
|
||||
perBoneMotionBlur = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Bind constants
|
||||
if (hasCb0)
|
||||
{
|
||||
context->UpdateCB(cb0, _cb0Data.Get());
|
||||
context->BindCB(0, cb0);
|
||||
}
|
||||
|
||||
// Select pipeline state based on current pass and render mode
|
||||
const bool wireframe = (_info.FeaturesFlags & MaterialFeaturesFlags::Wireframe) != 0 || view.Mode == ViewMode::Wireframe;
|
||||
CullMode cullMode = view.Pass == DrawPass::Depth ? CullMode::TwoSided : _info.CullMode;
|
||||
#if USE_EDITOR
|
||||
if (IsRunningRadiancePass)
|
||||
cullMode = CullMode::TwoSided;
|
||||
#endif
|
||||
if (cullMode != CullMode::TwoSided && drawCall.IsNegativeScale())
|
||||
{
|
||||
// Invert culling when scale is negative
|
||||
if (cullMode == CullMode::Normal)
|
||||
cullMode = CullMode::Inverted;
|
||||
else
|
||||
cullMode = CullMode::Normal;
|
||||
}
|
||||
ASSERT_LOW_LAYER(!(useSkinning && params.DrawCallsCount > 1)); // No support for instancing skinned meshes
|
||||
const auto cache = params.DrawCallsCount == 1 ? &_cache : &_cacheInstanced;
|
||||
PipelineStateCache* psCache = cache->GetPS(view.Pass, useLightmap, useSkinning, perBoneMotionBlur);
|
||||
ASSERT(psCache);
|
||||
GPUPipelineState* state = psCache->GetPS(cullMode, wireframe);
|
||||
|
||||
// Bind pipeline
|
||||
context->SetState(state);
|
||||
}
|
||||
|
||||
void DeferredMaterialShader::Unload()
|
||||
{
|
||||
// Base
|
||||
MaterialShader::Unload();
|
||||
|
||||
_cache.Release();
|
||||
_cacheInstanced.Release();
|
||||
}
|
||||
|
||||
bool DeferredMaterialShader::Load()
|
||||
{
|
||||
auto psDesc = GPUPipelineState::Description::Default;
|
||||
psDesc.DepthTestEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == 0;
|
||||
psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == 0;
|
||||
|
||||
// Check if use tessellation (both material and runtime supports it)
|
||||
const bool useTess = _info.TessellationMode != TessellationMethod::None && GPUDevice::Instance->Limits.HasTessellation;
|
||||
if (useTess)
|
||||
{
|
||||
psDesc.HS = _shader->GetHS("HS");
|
||||
psDesc.DS = _shader->GetDS("DS");
|
||||
}
|
||||
|
||||
// GBuffer Pass
|
||||
psDesc.VS = _shader->GetVS("VS");
|
||||
psDesc.PS = _shader->GetPS("PS_GBuffer");
|
||||
_cache.Default.Init(psDesc);
|
||||
psDesc.VS = _shader->GetVS("VS", 1);
|
||||
_cacheInstanced.Default.Init(psDesc);
|
||||
|
||||
// GBuffer Pass with lightmap (use pixel shader permutation for USE_LIGHTMAP=1)
|
||||
psDesc.VS = _shader->GetVS("VS");
|
||||
psDesc.PS = _shader->GetPS("PS_GBuffer", 1);
|
||||
_cache.DefaultLightmap.Init(psDesc);
|
||||
psDesc.VS = _shader->GetVS("VS", 1);
|
||||
_cacheInstanced.DefaultLightmap.Init(psDesc);
|
||||
|
||||
// GBuffer Pass with skinning
|
||||
psDesc.VS = _shader->GetVS("VS_Skinned");
|
||||
psDesc.PS = _shader->GetPS("PS_GBuffer");
|
||||
_cache.DefaultSkinned.Init(psDesc);
|
||||
|
||||
// Motion Vectors pass
|
||||
psDesc.DepthWriteEnable = false;
|
||||
psDesc.DepthTestEnable = true;
|
||||
psDesc.DepthFunc = ComparisonFunc::LessEqual;
|
||||
if (useTess)
|
||||
{
|
||||
psDesc.HS = _shader->GetHS("HS", 1);
|
||||
psDesc.DS = _shader->GetDS("DS", 1);
|
||||
}
|
||||
psDesc.VS = _shader->GetVS("VS", 2);
|
||||
psDesc.PS = _shader->GetPS("PS_MotionVectors");
|
||||
_cache.MotionVectors.Init(psDesc);
|
||||
|
||||
// Motion Vectors pass with skinning
|
||||
psDesc.VS = _shader->GetVS("VS_Skinned", 1);
|
||||
_cache.MotionVectorsSkinned.Init(psDesc);
|
||||
|
||||
// Motion Vectors pass with skinning (with per-bone motion blur)
|
||||
psDesc.VS = _shader->GetVS("VS_Skinned", 2);
|
||||
_cache.MotionVectorsSkinnedPerBone.Init(psDesc);
|
||||
|
||||
// Depth Pass
|
||||
psDesc.CullMode = CullMode::TwoSided;
|
||||
psDesc.DepthClipEnable = false;
|
||||
psDesc.DepthWriteEnable = true;
|
||||
psDesc.DepthTestEnable = true;
|
||||
psDesc.DepthFunc = ComparisonFunc::Less;
|
||||
psDesc.HS = nullptr;
|
||||
psDesc.DS = nullptr;
|
||||
GPUShaderProgramVS* instancedDepthPassVS;
|
||||
if ((_info.UsageFlags & (MaterialUsageFlags::UseMask | MaterialUsageFlags::UsePositionOffset)) != 0)
|
||||
{
|
||||
// Materials with masking need full vertex buffer to get texcoord used to sample textures for per pixel masking.
|
||||
// Materials with world pos offset need full VB to apply offset using texcoord etc.
|
||||
psDesc.VS = _shader->GetVS("VS");
|
||||
instancedDepthPassVS = _shader->GetVS("VS", 1);
|
||||
psDesc.PS = _shader->GetPS("PS_Depth");
|
||||
}
|
||||
else
|
||||
{
|
||||
psDesc.VS = _shader->GetVS("VS_Depth");
|
||||
instancedDepthPassVS = _shader->GetVS("VS_Depth", 1);
|
||||
psDesc.PS = nullptr;
|
||||
}
|
||||
_cache.Depth.Init(psDesc);
|
||||
psDesc.VS = instancedDepthPassVS;
|
||||
_cacheInstanced.Depth.Init(psDesc);
|
||||
|
||||
// Depth Pass with skinning
|
||||
psDesc.VS = _shader->GetVS("VS_Skinned");
|
||||
_cache.DepthSkinned.Init(psDesc);
|
||||
|
||||
return false;
|
||||
}
|
||||
77
Source/Engine/Graphics/Materials/DeferredMaterialShader.h
Normal file
77
Source/Engine/Graphics/Materials/DeferredMaterialShader.h
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MaterialShader.h"
|
||||
|
||||
/// <summary>
|
||||
/// Represents material that can be used to render objects to GBuffer.
|
||||
/// </summary>
|
||||
class DeferredMaterialShader : public MaterialShader
|
||||
{
|
||||
private:
|
||||
|
||||
struct Cache
|
||||
{
|
||||
PipelineStateCache Default;
|
||||
PipelineStateCache DefaultSkinned;
|
||||
PipelineStateCache DefaultLightmap;
|
||||
PipelineStateCache Depth;
|
||||
PipelineStateCache DepthSkinned;
|
||||
PipelineStateCache MotionVectors;
|
||||
PipelineStateCache MotionVectorsSkinned;
|
||||
PipelineStateCache MotionVectorsSkinnedPerBone;
|
||||
|
||||
FORCE_INLINE PipelineStateCache* GetPS(const DrawPass pass, const bool useLightmap, const bool useSkinning, const bool perBoneMotionBlur)
|
||||
{
|
||||
switch (pass)
|
||||
{
|
||||
case DrawPass::Depth:
|
||||
return useSkinning ? &DepthSkinned : &Depth;
|
||||
case DrawPass::GBuffer:
|
||||
return useLightmap ? &DefaultLightmap : (useSkinning ? &DefaultSkinned : &Default);
|
||||
case DrawPass::MotionVectors:
|
||||
return useSkinning ? (perBoneMotionBlur ? &MotionVectorsSkinnedPerBone : &MotionVectorsSkinned) : &MotionVectors;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE void Release()
|
||||
{
|
||||
Default.Release();
|
||||
DefaultSkinned.Release();
|
||||
DefaultLightmap.Release();
|
||||
Depth.Release();
|
||||
DepthSkinned.Release();
|
||||
MotionVectors.Release();
|
||||
MotionVectorsSkinned.Release();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Cache _cache;
|
||||
Cache _cacheInstanced;
|
||||
|
||||
public:
|
||||
|
||||
DeferredMaterialShader(const String& name)
|
||||
: MaterialShader(name)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [MaterialShader]
|
||||
DrawPass GetDrawModes() const override;
|
||||
bool CanUseLightmap() const override;
|
||||
bool CanUseInstancing() const override;
|
||||
void Bind(BindParameters& params) override;
|
||||
void Unload() override;
|
||||
|
||||
protected:
|
||||
|
||||
// [MaterialShader]
|
||||
bool Load() override;
|
||||
};
|
||||
353
Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp
Normal file
353
Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp
Normal file
@@ -0,0 +1,353 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ForwardMaterialShader.h"
|
||||
#include "MaterialParams.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Graphics/GPULimits.h"
|
||||
#include "Engine/Graphics/Models/SkinnedMeshDrawData.h"
|
||||
#include "Engine/Graphics/RenderView.h"
|
||||
#include "Engine/Level/Actors/EnvironmentProbe.h"
|
||||
#include "Engine/Renderer/DepthOfFieldPass.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
#include "Engine/Renderer/ShadowsPass.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Renderer/Lightmaps.h"
|
||||
#endif
|
||||
|
||||
#define MAX_LOCAL_LIGHTS 4
|
||||
|
||||
PACK_STRUCT(struct ForwardMaterialShaderData {
|
||||
Matrix ViewProjectionMatrix;
|
||||
Matrix WorldMatrix;
|
||||
Matrix ViewMatrix;
|
||||
Matrix PrevViewProjectionMatrix;
|
||||
Matrix PrevWorldMatrix;
|
||||
Vector3 ViewPos;
|
||||
float ViewFar;
|
||||
Vector3 ViewDir;
|
||||
float TimeParam;
|
||||
Vector4 ViewInfo;
|
||||
Vector4 ScreenSize;
|
||||
Rectangle LightmapArea;
|
||||
Vector3 WorldInvScale;
|
||||
float WorldDeterminantSign;
|
||||
Vector2 Dummy0;
|
||||
float LODDitherFactor;
|
||||
float PerInstanceRandom;
|
||||
Vector3 GeometrySize;
|
||||
float Dummy1;
|
||||
});
|
||||
|
||||
PACK_STRUCT(struct ForwardMaterialShaderLightingData {
|
||||
LightData DirectionalLight;
|
||||
LightShadowData DirectionalLightShadow;
|
||||
LightData SkyLight;
|
||||
ProbeData EnvironmentProbe;
|
||||
ExponentialHeightFogData ExponentialHeightFog;
|
||||
Vector3 Dummy2;
|
||||
uint32 LocalLightsCount;
|
||||
LightData LocalLights[MAX_LOCAL_LIGHTS];
|
||||
});
|
||||
|
||||
DrawPass ForwardMaterialShader::GetDrawModes() const
|
||||
{
|
||||
return _drawModes;
|
||||
}
|
||||
|
||||
bool ForwardMaterialShader::CanUseInstancing() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void ForwardMaterialShader::Bind(BindParameters& params)
|
||||
{
|
||||
// Prepare
|
||||
auto context = params.GPUContext;
|
||||
auto& view = params.RenderContext.View;
|
||||
auto cache = params.RenderContext.List;
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
const auto cb0 = _shader->GetCB(0);
|
||||
const bool hasCb0 = cb0 && cb0->GetSize() != 0;
|
||||
const auto cb1 = _shader->GetCB(1);
|
||||
const bool hasCb1 = cb1 && cb1->GetSize() != 0;
|
||||
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(ForwardMaterialShaderData) : nullptr;
|
||||
bindMeta.Input = nullptr; // forward pass materials cannot sample scene color for now
|
||||
bindMeta.Buffers = params.RenderContext.Buffers;
|
||||
bindMeta.CanSampleDepth = GPUDevice::Instance->Limits.HasReadOnlyDepth;
|
||||
bindMeta.CanSampleGBuffer = true;
|
||||
MaterialParams::Bind(params.ParamsLink, bindMeta);
|
||||
|
||||
// Check if is using mesh skinning
|
||||
const bool useSkinning = drawCall.Skinning != nullptr;
|
||||
if (useSkinning)
|
||||
{
|
||||
// Bind skinning buffer
|
||||
ASSERT(drawCall.Skinning->IsReady());
|
||||
context->BindSR(0, drawCall.Skinning->BoneMatrices->View());
|
||||
}
|
||||
|
||||
// Setup material constants data
|
||||
const auto materialData = reinterpret_cast<ForwardMaterialShaderData*>(_cb0Data.Get());
|
||||
if (hasCb0)
|
||||
{
|
||||
Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix);
|
||||
Matrix::Transpose(drawCall.World, materialData->WorldMatrix);
|
||||
Matrix::Transpose(view.View, materialData->ViewMatrix);
|
||||
Matrix::Transpose(drawCall.PrevWorld, materialData->PrevWorldMatrix);
|
||||
Matrix::Transpose(view.PrevViewProjection, materialData->PrevViewProjectionMatrix);
|
||||
|
||||
materialData->ViewPos = view.Position;
|
||||
materialData->ViewFar = view.Far;
|
||||
materialData->ViewDir = view.Direction;
|
||||
materialData->TimeParam = Time::Draw.UnscaledTime.GetTotalSeconds();
|
||||
materialData->ViewInfo = view.ViewInfo;
|
||||
materialData->ScreenSize = view.ScreenSize;
|
||||
|
||||
// Extract per axis scales from LocalToWorld transform
|
||||
const float scaleX = Vector3(drawCall.World.M11, drawCall.World.M12, drawCall.World.M13).Length();
|
||||
const float scaleY = Vector3(drawCall.World.M21, drawCall.World.M22, drawCall.World.M23).Length();
|
||||
const float scaleZ = Vector3(drawCall.World.M31, drawCall.World.M32, drawCall.World.M33).Length();
|
||||
const Vector3 worldInvScale = Vector3(
|
||||
scaleX > 0.00001f ? 1.0f / scaleX : 0.0f,
|
||||
scaleY > 0.00001f ? 1.0f / scaleY : 0.0f,
|
||||
scaleZ > 0.00001f ? 1.0f / scaleZ : 0.0f);
|
||||
|
||||
materialData->WorldInvScale = worldInvScale;
|
||||
materialData->WorldDeterminantSign = drawCall.WorldDeterminantSign;
|
||||
materialData->LODDitherFactor = drawCall.LODDitherFactor;
|
||||
materialData->PerInstanceRandom = drawCall.PerInstanceRandom;
|
||||
materialData->GeometrySize = drawCall.GeometrySize;
|
||||
}
|
||||
|
||||
// Setup lighting constants data
|
||||
if (hasCb1)
|
||||
{
|
||||
auto& lightingData = *reinterpret_cast<ForwardMaterialShaderLightingData*>(_cb1Data.Get());
|
||||
const int32 envProbeShaderRegisterIndex = 0;
|
||||
const int32 skyLightShaderRegisterIndex = 1;
|
||||
const int32 dirLightShaderRegisterIndex = 2;
|
||||
|
||||
// Set fog input
|
||||
if (cache->Fog)
|
||||
{
|
||||
cache->Fog->GetExponentialHeightFogData(view, lightingData.ExponentialHeightFog);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightingData.ExponentialHeightFog.FogMinOpacity = 1.0f;
|
||||
lightingData.ExponentialHeightFog.ApplyDirectionalInscattering = 0.0f;
|
||||
}
|
||||
|
||||
// Set directional light input
|
||||
if (cache->DirectionalLights.HasItems())
|
||||
{
|
||||
const auto& dirLight = cache->DirectionalLights.First();
|
||||
const auto shadowPass = ShadowsPass::Instance();
|
||||
const bool useShadow = shadowPass->LastDirLightIndex == 0;
|
||||
if (useShadow)
|
||||
{
|
||||
lightingData.DirectionalLightShadow = shadowPass->LastDirLight;
|
||||
context->BindSR(dirLightShaderRegisterIndex, shadowPass->LastDirLightShadowMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
context->UnBindSR(dirLightShaderRegisterIndex);
|
||||
}
|
||||
dirLight.SetupLightData(&lightingData.DirectionalLight, view, useShadow);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightingData.DirectionalLight.Color = Vector3::Zero;
|
||||
lightingData.DirectionalLight.CastShadows = 0.0f;
|
||||
context->UnBindSR(dirLightShaderRegisterIndex);
|
||||
}
|
||||
|
||||
// Set sky light
|
||||
if (cache->SkyLights.HasItems())
|
||||
{
|
||||
auto& skyLight = cache->SkyLights.First();
|
||||
skyLight.SetupLightData(&lightingData.SkyLight, view, false);
|
||||
const auto texture = skyLight.Image ? skyLight.Image->GetTexture() : nullptr;
|
||||
context->BindSR(skyLightShaderRegisterIndex, GET_TEXTURE_VIEW_SAFE(texture));
|
||||
}
|
||||
else
|
||||
{
|
||||
Platform::MemoryClear(&lightingData.SkyLight, sizeof(lightingData.SkyLight));
|
||||
context->UnBindSR(skyLightShaderRegisterIndex);
|
||||
}
|
||||
|
||||
// Set reflection probe data
|
||||
EnvironmentProbe* probe = nullptr;
|
||||
// TODO: optimize env probe searching for a transparent material - use spatial cache for renderer to find it
|
||||
for (int32 i = 0; i < cache->EnvironmentProbes.Count(); i++)
|
||||
{
|
||||
const auto p = cache->EnvironmentProbes[i];
|
||||
if (p->GetSphere().Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
|
||||
{
|
||||
probe = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (probe && probe->GetProbe())
|
||||
{
|
||||
probe->SetupProbeData(&lightingData.EnvironmentProbe);
|
||||
const auto texture = probe->GetProbe()->GetTexture();
|
||||
context->BindSR(envProbeShaderRegisterIndex, GET_TEXTURE_VIEW_SAFE(texture));
|
||||
}
|
||||
else
|
||||
{
|
||||
lightingData.EnvironmentProbe.Data1 = Vector4::Zero;
|
||||
context->UnBindSR(envProbeShaderRegisterIndex);
|
||||
}
|
||||
|
||||
// Set local lights
|
||||
lightingData.LocalLightsCount = 0;
|
||||
for (int32 i = 0; i < cache->PointLights.Count(); i++)
|
||||
{
|
||||
const auto& light = cache->PointLights[i];
|
||||
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
|
||||
{
|
||||
light.SetupLightData(&lightingData.LocalLights[lightingData.LocalLightsCount], view, false);
|
||||
lightingData.LocalLightsCount++;
|
||||
if (lightingData.LocalLightsCount == MAX_LOCAL_LIGHTS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int32 i = 0; i < cache->SpotLights.Count(); i++)
|
||||
{
|
||||
const auto& light = cache->SpotLights[i];
|
||||
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
|
||||
{
|
||||
light.SetupLightData(&lightingData.LocalLights[lightingData.LocalLightsCount], view, false);
|
||||
lightingData.LocalLightsCount++;
|
||||
if (lightingData.LocalLightsCount == MAX_LOCAL_LIGHTS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bind constants
|
||||
if (hasCb0)
|
||||
{
|
||||
context->UpdateCB(cb0, _cb0Data.Get());
|
||||
context->BindCB(0, cb0);
|
||||
}
|
||||
if (hasCb1)
|
||||
{
|
||||
context->UpdateCB(cb1, _cb1Data.Get());
|
||||
context->BindCB(1, cb1);
|
||||
}
|
||||
|
||||
// Select pipeline state based on current pass and render mode
|
||||
const bool wireframe = (_info.FeaturesFlags & MaterialFeaturesFlags::Wireframe) != 0 || view.Mode == ViewMode::Wireframe;
|
||||
CullMode cullMode = view.Pass == DrawPass::Depth ? CullMode::TwoSided : _info.CullMode;
|
||||
#if USE_EDITOR
|
||||
if (IsRunningRadiancePass)
|
||||
cullMode = CullMode::TwoSided;
|
||||
#endif
|
||||
if (cullMode != CullMode::TwoSided && drawCall.IsNegativeScale())
|
||||
{
|
||||
// Invert culling when scale is negative
|
||||
if (cullMode == CullMode::Normal)
|
||||
cullMode = CullMode::Inverted;
|
||||
else
|
||||
cullMode = CullMode::Normal;
|
||||
}
|
||||
ASSERT_LOW_LAYER(!(useSkinning && params.DrawCallsCount > 1)); // No support for instancing skinned meshes
|
||||
const auto cacheObj = params.DrawCallsCount == 1 ? &_cache : &_cacheInstanced;
|
||||
PipelineStateCache* psCache = cacheObj->GetPS(view.Pass, useSkinning);
|
||||
ASSERT(psCache);
|
||||
GPUPipelineState* state = psCache->GetPS(cullMode, wireframe);
|
||||
|
||||
// Bind pipeline
|
||||
context->SetState(state);
|
||||
}
|
||||
|
||||
void ForwardMaterialShader::Unload()
|
||||
{
|
||||
// Base
|
||||
MaterialShader::Unload();
|
||||
|
||||
_cache.Release();
|
||||
_cacheInstanced.Release();
|
||||
}
|
||||
|
||||
bool ForwardMaterialShader::Load()
|
||||
{
|
||||
_drawModes = DrawPass::Depth | DrawPass::Forward;
|
||||
|
||||
auto psDesc = GPUPipelineState::Description::Default;
|
||||
psDesc.DepthTestEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == 0;
|
||||
psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == 0;
|
||||
|
||||
// Check if use tessellation (both material and runtime supports it)
|
||||
const bool useTess = _info.TessellationMode != TessellationMethod::None && GPUDevice::Instance->Limits.HasTessellation;
|
||||
if (useTess)
|
||||
{
|
||||
psDesc.HS = _shader->GetHS("HS");
|
||||
psDesc.DS = _shader->GetDS("DS");
|
||||
}
|
||||
|
||||
// Check if use transparent distortion pass
|
||||
if (_shader->HasShader("PS_Distortion"))
|
||||
{
|
||||
_drawModes |= DrawPass::Distortion;
|
||||
|
||||
// Accumulate Distortion Pass
|
||||
psDesc.VS = _shader->GetVS("VS");
|
||||
psDesc.PS = _shader->GetPS("PS_Distortion");
|
||||
psDesc.BlendMode = BlendingMode::Add;
|
||||
psDesc.DepthWriteEnable = false;
|
||||
_cache.Distortion.Init(psDesc);
|
||||
//psDesc.VS = _shader->GetVS("VS", 1);
|
||||
//_cacheInstanced.Distortion.Init(psDesc);
|
||||
psDesc.VS = _shader->GetVS("VS_Skinned");
|
||||
_cache.DistortionSkinned.Init(psDesc);
|
||||
}
|
||||
|
||||
// Forward Pass
|
||||
psDesc.VS = _shader->GetVS("VS");
|
||||
psDesc.PS = _shader->GetPS("PS_Forward");
|
||||
psDesc.DepthWriteEnable = false;
|
||||
psDesc.BlendMode = BlendingMode::AlphaBlend;
|
||||
switch (_info.BlendMode)
|
||||
{
|
||||
case MaterialBlendMode::Transparent:
|
||||
psDesc.BlendMode = BlendingMode::AlphaBlend;
|
||||
break;
|
||||
case MaterialBlendMode::Additive:
|
||||
psDesc.BlendMode = BlendingMode::Additive;
|
||||
break;
|
||||
case MaterialBlendMode::Multiply:
|
||||
psDesc.BlendMode = BlendingMode::Multiply;
|
||||
break;
|
||||
}
|
||||
_cache.Default.Init(psDesc);
|
||||
//psDesc.VS = _shader->GetVS("VS", 1);
|
||||
//_cacheInstanced.Default.Init(psDesc);
|
||||
psDesc.VS = _shader->GetVS("VS_Skinned");
|
||||
_cache.DefaultSkinned.Init(psDesc);
|
||||
|
||||
// Depth Pass
|
||||
psDesc = GPUPipelineState::Description::Default;
|
||||
psDesc.CullMode = CullMode::TwoSided;
|
||||
psDesc.DepthClipEnable = false;
|
||||
psDesc.DepthWriteEnable = true;
|
||||
psDesc.DepthTestEnable = true;
|
||||
psDesc.DepthFunc = ComparisonFunc::Less;
|
||||
psDesc.HS = nullptr;
|
||||
psDesc.DS = nullptr;
|
||||
psDesc.VS = _shader->GetVS("VS");
|
||||
psDesc.PS = _shader->GetPS("PS_Depth");
|
||||
_cache.Depth.Init(psDesc);
|
||||
psDesc.VS = _shader->GetVS("VS", 1);
|
||||
_cacheInstanced.Depth.Init(psDesc);
|
||||
psDesc.VS = _shader->GetVS("VS_Skinned");
|
||||
_cache.DepthSkinned.Init(psDesc);
|
||||
|
||||
return false;
|
||||
}
|
||||
78
Source/Engine/Graphics/Materials/ForwardMaterialShader.h
Normal file
78
Source/Engine/Graphics/Materials/ForwardMaterialShader.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MaterialShader.h"
|
||||
|
||||
/// <summary>
|
||||
/// Represents material that can be used to render objects with Forward Rendering.
|
||||
/// </summary>
|
||||
class ForwardMaterialShader : public MaterialShader
|
||||
{
|
||||
private:
|
||||
|
||||
struct Cache
|
||||
{
|
||||
PipelineStateCache Default;
|
||||
PipelineStateCache DefaultSkinned;
|
||||
PipelineStateCache Depth;
|
||||
PipelineStateCache DepthSkinned;
|
||||
PipelineStateCache Distortion;
|
||||
PipelineStateCache DistortionSkinned;
|
||||
|
||||
FORCE_INLINE PipelineStateCache* GetPS(const DrawPass pass, const bool useSkinning)
|
||||
{
|
||||
switch (pass)
|
||||
{
|
||||
case DrawPass::Depth:
|
||||
return useSkinning ? &DepthSkinned : &Depth;
|
||||
case DrawPass::Distortion:
|
||||
return useSkinning ? &DistortionSkinned : &Distortion;
|
||||
case DrawPass::Forward:
|
||||
return useSkinning ? &DefaultSkinned : &Default;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE void Release()
|
||||
{
|
||||
Default.Release();
|
||||
DefaultSkinned.Release();
|
||||
Depth.Release();
|
||||
DepthSkinned.Release();
|
||||
Distortion.Release();
|
||||
DistortionSkinned.Release();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Cache _cache;
|
||||
Cache _cacheInstanced;
|
||||
DrawPass _drawModes = DrawPass::None;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="name">Material resource name</param>
|
||||
ForwardMaterialShader(const String& name)
|
||||
: MaterialShader(name)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [MaterialShader]
|
||||
DrawPass GetDrawModes() const override;
|
||||
bool CanUseInstancing() const override;
|
||||
void Bind(BindParameters& params) override;
|
||||
void Unload() override;
|
||||
|
||||
protected:
|
||||
|
||||
// [MaterialShader]
|
||||
bool Load() override;
|
||||
};
|
||||
107
Source/Engine/Graphics/Materials/GUIMaterialShader.cpp
Normal file
107
Source/Engine/Graphics/Materials/GUIMaterialShader.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "GUIMaterialShader.h"
|
||||
#include "MaterialParams.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Core/Math/Viewport.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||
#include "Engine/Graphics/RenderView.h"
|
||||
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
|
||||
#include "Engine/Render2D/Render2D.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
|
||||
PACK_STRUCT(struct GUIMaterialShaderData {
|
||||
Matrix ViewProjectionMatrix;
|
||||
Matrix WorldMatrix;
|
||||
Matrix ViewMatrix;
|
||||
Vector3 ViewPos;
|
||||
float ViewFar;
|
||||
Vector3 ViewDir;
|
||||
float TimeParam;
|
||||
Vector4 ViewInfo;
|
||||
Vector4 ScreenSize;
|
||||
});
|
||||
|
||||
void GUIMaterialShader::Bind(BindParameters& params)
|
||||
{
|
||||
// Prepare
|
||||
auto context = params.GPUContext;
|
||||
auto& view = params.RenderContext.View;
|
||||
const auto cb0 = _shader->GetCB(0);
|
||||
const bool hasCb0 = cb0->GetSize() != 0;
|
||||
const auto ps = context->IsDepthBufferBinded() ? _cache.Depth : _cache.NoDepth;
|
||||
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(GUIMaterialShaderData) : nullptr;
|
||||
bindMeta.Input = nullptr;
|
||||
bindMeta.Buffers = nullptr;
|
||||
bindMeta.CanSampleDepth = false;
|
||||
bindMeta.CanSampleGBuffer = false;
|
||||
MaterialParams::Bind(params.ParamsLink, bindMeta);
|
||||
|
||||
// Setup material constants data
|
||||
if (hasCb0)
|
||||
{
|
||||
auto materialData = reinterpret_cast<GUIMaterialShaderData*>(_cb0Data.Get());
|
||||
|
||||
const auto viewProjectionMatrix = (Matrix*)params.CustomData;
|
||||
Matrix::Transpose(*viewProjectionMatrix, materialData->ViewProjectionMatrix);
|
||||
Matrix::Transpose(Matrix::Identity, materialData->WorldMatrix);
|
||||
Matrix::Transpose(Matrix::Identity, materialData->ViewMatrix);
|
||||
materialData->ViewPos = Vector3::Zero;
|
||||
materialData->ViewFar = 0.0f;
|
||||
materialData->ViewDir = Vector3::Forward;
|
||||
materialData->TimeParam = Time::Draw.UnscaledTime.GetTotalSeconds();
|
||||
materialData->ViewInfo = Vector4::Zero;
|
||||
auto& viewport = Render2D::GetViewport();
|
||||
materialData->ScreenSize = Vector4(viewport.Width, viewport.Height, 1.0f / viewport.Width, 1.0f / viewport.Height);
|
||||
}
|
||||
|
||||
// Bind constants
|
||||
if (hasCb0)
|
||||
{
|
||||
context->UpdateCB(cb0, _cb0Data.Get());
|
||||
context->BindCB(0, cb0);
|
||||
}
|
||||
|
||||
// Bind pipeline
|
||||
context->SetState(ps);
|
||||
}
|
||||
|
||||
void GUIMaterialShader::Unload()
|
||||
{
|
||||
// Base
|
||||
MaterialShader::Unload();
|
||||
|
||||
_cache.Release();
|
||||
}
|
||||
|
||||
bool GUIMaterialShader::Load()
|
||||
{
|
||||
GPUPipelineState::Description psDesc0 = GPUPipelineState::Description::DefaultFullscreenTriangle;
|
||||
psDesc0.Wireframe = (_info.FeaturesFlags & MaterialFeaturesFlags::Wireframe) != 0;
|
||||
psDesc0.VS = _shader->GetVS("VS_GUI");
|
||||
psDesc0.PS = _shader->GetPS("PS_GUI");
|
||||
psDesc0.BlendMode = BlendingMode::AlphaBlend;
|
||||
|
||||
psDesc0.DepthTestEnable = psDesc0.DepthWriteEnable = true;
|
||||
_cache.Depth = GPUDevice::Instance->CreatePipelineState();
|
||||
_cache.NoDepth = GPUDevice::Instance->CreatePipelineState();
|
||||
|
||||
bool failed = _cache.Depth->Init(psDesc0);
|
||||
|
||||
psDesc0.DepthTestEnable = psDesc0.DepthWriteEnable = false;
|
||||
failed |= _cache.NoDepth->Init(psDesc0);
|
||||
|
||||
if (failed)
|
||||
{
|
||||
LOG(Warning, "Failed to create GUI material pipeline state.");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
51
Source/Engine/Graphics/Materials/GUIMaterialShader.h
Normal file
51
Source/Engine/Graphics/Materials/GUIMaterialShader.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MaterialShader.h"
|
||||
|
||||
/// <summary>
|
||||
/// Represents material that can be used to render GUI.
|
||||
/// </summary>
|
||||
class GUIMaterialShader : public MaterialShader
|
||||
{
|
||||
private:
|
||||
|
||||
struct Cache
|
||||
{
|
||||
GPUPipelineState* Depth = nullptr;
|
||||
GPUPipelineState* NoDepth = nullptr;
|
||||
|
||||
FORCE_INLINE void Release()
|
||||
{
|
||||
SAFE_DELETE_GPU_RESOURCE(Depth);
|
||||
SAFE_DELETE_GPU_RESOURCE(NoDepth);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Cache _cache;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="name">Material resource name</param>
|
||||
GUIMaterialShader(const String& name)
|
||||
: MaterialShader(name)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [MaterialShader]
|
||||
void Bind(BindParameters& params) override;
|
||||
void Unload() override;
|
||||
|
||||
protected:
|
||||
|
||||
// [MaterialShader]
|
||||
bool Load() override;
|
||||
};
|
||||
184
Source/Engine/Graphics/Materials/IMaterial.h
Normal file
184
Source/Engine/Graphics/Materials/IMaterial.h
Normal file
@@ -0,0 +1,184 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Threading/Task.h"
|
||||
#include "MaterialInfo.h"
|
||||
|
||||
struct MaterialParamsLink;
|
||||
class GPUContext;
|
||||
class GPUTextureView;
|
||||
class RenderBuffers;
|
||||
class SceneRenderTask;
|
||||
struct RenderView;
|
||||
struct RenderContext;
|
||||
struct DrawCall;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for material objects.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API IMaterial
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the material info, structure which describes material surface.
|
||||
/// </summary>
|
||||
/// <returns>The constant reference to the material descriptor.</returns>
|
||||
virtual const MaterialInfo& GetInfo() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether material is a surface shader.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if material is surface shader; otherwise, <c>false</c>.</returns>
|
||||
FORCE_INLINE bool IsSurface() const
|
||||
{
|
||||
return GetInfo().Domain == MaterialDomain::Surface;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether material is a post fx.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if material is post fx; otherwise, <c>false</c>.</returns>
|
||||
FORCE_INLINE bool IsPostFx() const
|
||||
{
|
||||
return GetInfo().Domain == MaterialDomain::PostProcess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether material is a decal.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if material is decal; otherwise, <c>false</c>.</returns>
|
||||
FORCE_INLINE bool IsDecal() const
|
||||
{
|
||||
return GetInfo().Domain == MaterialDomain::Decal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether material is a GUI shader.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if material is GUI shader; otherwise, <c>false</c>.</returns>
|
||||
FORCE_INLINE bool IsGUI() const
|
||||
{
|
||||
return GetInfo().Domain == MaterialDomain::GUI;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether material is a terrain shader.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if material is terrain shader; otherwise, <c>false</c>.</returns>
|
||||
FORCE_INLINE bool IsTerrain() const
|
||||
{
|
||||
return GetInfo().Domain == MaterialDomain::Terrain;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether material is a particle shader.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if material is particle shader; otherwise, <c>false</c>.</returns>
|
||||
FORCE_INLINE bool IsParticle() const
|
||||
{
|
||||
return GetInfo().Domain == MaterialDomain::Particle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if material needs vertex color vertex buffer data for rendering.
|
||||
/// </summary>
|
||||
/// <returns>True if mesh renderer have to provide vertex color buffer to render that material</returns>
|
||||
FORCE_INLINE bool RequireVertexColor() const
|
||||
{
|
||||
return (GetInfo().UsageFlags & MaterialUsageFlags::UseVertexColor) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if material supports dithered LOD transitions.
|
||||
/// </summary>
|
||||
/// <returns>True if material supports dithered LOD transitions, otherwise false.</returns>
|
||||
FORCE_INLINE bool IsDitheredLODTransition() const
|
||||
{
|
||||
return (GetInfo().FeaturesFlags & MaterialFeaturesFlags::DitheredLODTransition) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if material is ready for rendering.
|
||||
/// </summary>
|
||||
/// <returns>True if can render that material</returns>
|
||||
virtual bool IsReady() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mask of render passes supported by this material.
|
||||
/// </summary>
|
||||
/// <returns>The drw passes supported by this material.</returns>
|
||||
virtual DrawPass GetDrawModes() const
|
||||
{
|
||||
return DrawPass::None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if material can use lightmaps (this includes lightmaps offline baking and sampling at runtime).
|
||||
/// </summary>
|
||||
/// <returns>True if can use lightmaps, otherwise false</returns>
|
||||
virtual bool CanUseLightmap() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if material can use draw calls instancing.
|
||||
/// </summary>
|
||||
/// <returns>True if can use instancing, otherwise false.</returns>
|
||||
virtual bool CanUseInstancing() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Settings for the material binding to the graphics pipeline.
|
||||
/// </summary>
|
||||
struct BindParameters
|
||||
{
|
||||
GPUContext* GPUContext;
|
||||
const RenderContext& RenderContext;
|
||||
const DrawCall* FirstDrawCall;
|
||||
int32 DrawCallsCount;
|
||||
MaterialParamsLink* ParamsLink = nullptr;
|
||||
void* CustomData = nullptr;
|
||||
|
||||
/// <summary>
|
||||
/// The input scene color. It's optional and used in forward/postFx rendering.
|
||||
/// </summary>
|
||||
GPUTextureView* Input = nullptr;
|
||||
|
||||
BindParameters(::GPUContext* context, const ::RenderContext& renderContext)
|
||||
: GPUContext(context)
|
||||
, RenderContext(renderContext)
|
||||
, FirstDrawCall(nullptr)
|
||||
, DrawCallsCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
BindParameters(::GPUContext* context, const ::RenderContext& renderContext, const DrawCall& drawCall)
|
||||
: GPUContext(context)
|
||||
, RenderContext(renderContext)
|
||||
, FirstDrawCall(&drawCall)
|
||||
, DrawCallsCount(1)
|
||||
{
|
||||
}
|
||||
|
||||
BindParameters(::GPUContext* context, const ::RenderContext& renderContext, const DrawCall* firstDrawCall, int32 drawCallsCount)
|
||||
: GPUContext(context)
|
||||
, RenderContext(renderContext)
|
||||
, FirstDrawCall(firstDrawCall)
|
||||
, DrawCallsCount(drawCallsCount)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Binds the material state to the GPU pipeline. Should be called before the draw command.
|
||||
/// </summary>
|
||||
/// <param name="params">The material bind settings.</param>
|
||||
virtual void Bind(BindParameters& params) = 0;
|
||||
};
|
||||
856
Source/Engine/Graphics/Materials/MaterialInfo.h
Normal file
856
Source/Engine/Graphics/Materials/MaterialInfo.h
Normal file
@@ -0,0 +1,856 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Enums.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
|
||||
/// <summary>
|
||||
/// Material domain type. Material domain defines the target usage of the material shader.
|
||||
/// </summary>
|
||||
API_ENUM() enum class MaterialDomain : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// The surface material. Can be used to render the scene geometry including models and skinned models.
|
||||
/// </summary>
|
||||
Surface = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The post process material. Can be used to perform custom post-processing of the rendered frame.
|
||||
/// </summary>
|
||||
PostProcess = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The deferred decal material. Can be used to apply custom overlay or surface modifications to the object surfaces in the world.
|
||||
/// </summary>
|
||||
Decal = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The GUI shader. Can be used to draw custom control interface elements or to add custom effects to the GUI.
|
||||
/// </summary>
|
||||
GUI = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The terrain shader. Can be used only with landscape chunks geometry that use optimized vertex data and support multi-layered blending.
|
||||
/// </summary>
|
||||
Terrain = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The particle shader. Can be used only with particles geometry (sprites, trails and ribbons). Supports reading particle data on a GPU.
|
||||
/// </summary>
|
||||
Particle = 5,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material blending modes.
|
||||
/// </summary>
|
||||
API_ENUM() enum class MaterialBlendMode : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// The opaque material. Used during GBuffer pass rendering.
|
||||
/// </summary>
|
||||
Opaque = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The transparent material. Used during Forward pass rendering.
|
||||
/// </summary>
|
||||
Transparent = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The additive blend. Material color is used to add to color of the objects behind the surface. Used during Forward pass rendering.
|
||||
/// </summary>
|
||||
Additive = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The multiply blend. Material color is used to multiply color of the objects behind the surface. Used during Forward pass rendering.
|
||||
/// </summary>
|
||||
Multiply = 3,
|
||||
};
|
||||
|
||||
// Old material blending mode used before introducing MaterialShadingModel
|
||||
// [Deprecated on 10.09.2018, expires on 10.05.2019]
|
||||
enum class OldMaterialBlendMode : byte
|
||||
{
|
||||
Opaque = 0,
|
||||
Transparent = 1,
|
||||
Unlit = 2,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material shading modes. Defines how material inputs and properties are combined to result the final surface color.
|
||||
/// </summary>
|
||||
API_ENUM() enum class MaterialShadingModel : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// The unlit material. Emissive channel is used as an output color. Can perform custom lighting operations or just glow. Won't be affected by the lighting pipeline.
|
||||
/// </summary>
|
||||
Unlit = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The default lit material. The most common choice for the material surfaces.
|
||||
/// </summary>
|
||||
Lit = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The subsurface material. Intended for materials like vax or skin that need light scattering to transport simulation through the object.
|
||||
/// </summary>
|
||||
Subsurface = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The foliage material. Intended for foliage materials like leaves and grass that need light scattering to transport simulation through the thin object.
|
||||
/// </summary>
|
||||
Foliage = 3,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material transparent lighting modes.
|
||||
/// [Deprecated on 24.07.2019, expires on 10.05.2021]
|
||||
/// </summary>
|
||||
enum class MaterialTransparentLighting_Deprecated : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Shading is disabled.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Shading is performed per pixel for single directional light.
|
||||
/// </summary>
|
||||
SingleDirectionalPerPixel = 1
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material usage flags (deprecated).
|
||||
/// [Deprecated on 24.07.2019, expires on 10.05.2021]
|
||||
/// </summary>
|
||||
enum class MaterialFlags_Deprecated : uint32
|
||||
{
|
||||
/// <summary>
|
||||
/// The none.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Material is using mask to discard some pixels.
|
||||
/// Masked materials are using full vertex buffer during shadow maps and depth pass rendering (need UVs).
|
||||
/// </summary>
|
||||
UseMask = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// The two sided material. No triangle normal culling is performed.
|
||||
/// </summary>
|
||||
TwoSided = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// The wireframe material.
|
||||
/// </summary>
|
||||
Wireframe = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// The material is using emissive light.
|
||||
/// </summary>
|
||||
UseEmissive = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// The transparent materials option. Disable depth test (material ignores depth).
|
||||
/// </summary>
|
||||
TransparentDisableDepthTest = 1 << 4,
|
||||
|
||||
/// <summary>
|
||||
/// The transparent materials option. Disable fog.
|
||||
/// </summary>
|
||||
TransparentDisableFog = 1 << 5,
|
||||
|
||||
/// <summary>
|
||||
/// The transparent materials option. Disable reflections.
|
||||
/// </summary>
|
||||
TransparentDisableReflections = 1 << 6,
|
||||
|
||||
/// <summary>
|
||||
/// The transparent materials option. Disable depth buffer write (won't modify depth buffer value after rendering).
|
||||
/// </summary>
|
||||
DisableDepthWrite = 1 << 7,
|
||||
|
||||
/// <summary>
|
||||
/// The transparent materials option. Disable distortion.
|
||||
/// </summary>
|
||||
TransparentDisableDistortion = 1 << 8,
|
||||
|
||||
/// <summary>
|
||||
/// The material is using world position offset (it may be animated inside a shader).
|
||||
/// </summary>
|
||||
UsePositionOffset = 1 << 9,
|
||||
|
||||
/// <summary>
|
||||
/// The material is using vertex colors. The render will try to feed the pipeline with a proper buffer so material can gather valid data.
|
||||
/// </summary>
|
||||
UseVertexColor = 1 << 10,
|
||||
|
||||
/// <summary>
|
||||
/// The material is using per-pixel normal mapping.
|
||||
/// </summary>
|
||||
UseNormal = 1 << 11,
|
||||
|
||||
/// <summary>
|
||||
/// The material is using position displacement (in domain shader).
|
||||
/// </summary>
|
||||
UseDisplacement = 1 << 12,
|
||||
|
||||
/// <summary>
|
||||
/// The flag used to indicate that material input normal vector is defined in the world space rather than tangent space.
|
||||
/// </summary>
|
||||
InputWorldSpaceNormal = 1 << 13,
|
||||
|
||||
/// <summary>
|
||||
/// The flag used to indicate that material uses dithered model LOD transition for smoother LODs switching.
|
||||
/// </summary>
|
||||
UseDitheredLODTransition = 1 << 14,
|
||||
|
||||
/// <summary>
|
||||
/// The flag used to indicate that material uses refraction feature.
|
||||
/// </summary>
|
||||
UseRefraction = 1 << 15,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_OPERATORS(MaterialFlags_Deprecated);
|
||||
|
||||
/// <summary>
|
||||
/// Material features flags.
|
||||
/// </summary>
|
||||
API_ENUM(Attributes="Flags") enum class MaterialFeaturesFlags : uint32
|
||||
{
|
||||
/// <summary>
|
||||
/// No flags.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The wireframe material.
|
||||
/// </summary>
|
||||
Wireframe = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// The depth test is disabled (material ignores depth).
|
||||
/// </summary>
|
||||
DisableDepthTest = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// Disable depth buffer write (won't modify depth buffer value during rendering).
|
||||
/// </summary>
|
||||
DisableDepthWrite = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// The flag used to indicate that material input normal vector is defined in the world space rather than tangent space.
|
||||
/// </summary>
|
||||
InputWorldSpaceNormal = 1 << 4,
|
||||
|
||||
/// <summary>
|
||||
/// The flag used to indicate that material uses dithered model LOD transition for smoother LODs switching.
|
||||
/// </summary>
|
||||
DitheredLODTransition = 1 << 5,
|
||||
|
||||
/// <summary>
|
||||
/// The flag used to disable fog. The Forward Pass materials option.
|
||||
/// </summary>
|
||||
DisableFog = 1 << 6,
|
||||
|
||||
/// <summary>
|
||||
/// The flag used to disable reflections. The Forward Pass materials option.
|
||||
/// </summary>
|
||||
DisableReflections = 1 << 7,
|
||||
|
||||
/// <summary>
|
||||
/// The flag used to disable distortion effect (light refraction). The Forward Pass materials option.
|
||||
/// </summary>
|
||||
DisableDistortion = 1 << 8,
|
||||
|
||||
/// <summary>
|
||||
/// The flag used to enable refraction offset based on the difference between the per-pixel normal and the per-vertex normal. Useful for large water-like surfaces.
|
||||
/// </summary>
|
||||
PixelNormalOffsetRefraction = 1 << 9,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_OPERATORS(MaterialFeaturesFlags);
|
||||
|
||||
/// <summary>
|
||||
/// Material features usage flags. Detected by the material generator to help graphics pipeline optimize rendering of material shaders.
|
||||
/// </summary>
|
||||
API_ENUM(Attributes="Flags") enum class MaterialUsageFlags : uint32
|
||||
{
|
||||
/// <summary>
|
||||
/// No flags.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Material is using mask to discard some pixels. Masked materials are using full vertex buffer during shadow maps and depth pass rendering (need UVs).
|
||||
/// </summary>
|
||||
UseMask = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// The material is using emissive light.
|
||||
/// </summary>
|
||||
UseEmissive = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// The material is using world position offset (it may be animated inside a shader).
|
||||
/// </summary>
|
||||
UsePositionOffset = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// The material is using vertex colors. The render will try to feed the pipeline with a proper buffer so material can gather valid data.
|
||||
/// </summary>
|
||||
UseVertexColor = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// The material is using per-pixel normal mapping.
|
||||
/// </summary>
|
||||
UseNormal = 1 << 4,
|
||||
|
||||
/// <summary>
|
||||
/// The material is using position displacement (in domain shader).
|
||||
/// </summary>
|
||||
UseDisplacement = 1 << 5,
|
||||
|
||||
/// <summary>
|
||||
/// The flag used to indicate that material uses refraction feature.
|
||||
/// </summary>
|
||||
UseRefraction = 1 << 6,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_OPERATORS(MaterialUsageFlags);
|
||||
|
||||
/// <summary>
|
||||
/// Decal material blending modes.
|
||||
/// </summary>
|
||||
API_ENUM() enum class MaterialDecalBlendingMode : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Decal will be fully blended with the material surface.
|
||||
/// </summary>
|
||||
Translucent = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Decal color will be blended with the material surface color (using multiplication).
|
||||
/// </summary>
|
||||
Stain = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Decal will blend the normal vector only.
|
||||
/// </summary>
|
||||
Normal = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Decal will apply the emissive light only.
|
||||
/// </summary>
|
||||
Emissive = 3,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material input scene textures. Special inputs from the graphics pipeline.
|
||||
/// </summary>
|
||||
API_ENUM() enum class MaterialSceneTextures
|
||||
{
|
||||
/// <summary>
|
||||
/// The scene color.
|
||||
/// </summary>
|
||||
SceneColor = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The scene depth.
|
||||
/// </summary>
|
||||
SceneDepth = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The material diffuse color.
|
||||
/// </summary>
|
||||
DiffuseColor = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The material specular color.
|
||||
/// </summary>
|
||||
SpecularColor = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The material world space normal.
|
||||
/// </summary>
|
||||
WorldNormal = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The ambient occlusion.
|
||||
/// </summary>
|
||||
AmbientOcclusion = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The material metalness value.
|
||||
/// </summary>
|
||||
Metalness = 6,
|
||||
|
||||
/// <summary>
|
||||
/// The material roughness value.
|
||||
/// </summary>
|
||||
Roughness = 7,
|
||||
|
||||
/// <summary>
|
||||
/// The material specular value.
|
||||
/// </summary>
|
||||
Specular = 8,
|
||||
|
||||
/// <summary>
|
||||
/// The material color.
|
||||
/// </summary>
|
||||
BaseColor = 9,
|
||||
|
||||
/// <summary>
|
||||
/// The material shading mode.
|
||||
/// </summary>
|
||||
ShadingModel = 10,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material info structure - version 1
|
||||
/// [Deprecated on 10.09.2018, expires on 10.05.2019]
|
||||
/// </summary>
|
||||
struct MaterialInfo1
|
||||
{
|
||||
int32 Version;
|
||||
MaterialDomain Domain;
|
||||
OldMaterialBlendMode BlendMode;
|
||||
MaterialFlags_Deprecated Flags;
|
||||
|
||||
/// <summary>
|
||||
/// Compare structure with other one
|
||||
/// </summary>
|
||||
/// <param name="other">Other structure to compare</param>
|
||||
/// <returns>True if both structures are equal</returns>
|
||||
bool operator==(const MaterialInfo1& other) const
|
||||
{
|
||||
return Domain == other.Domain
|
||||
&& BlendMode == other.BlendMode
|
||||
&& Flags == other.Flags;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material info structure - version 2
|
||||
/// [Deprecated on 10.09.2018, expires on 10.05.2019]
|
||||
/// </summary>
|
||||
struct MaterialInfo2
|
||||
{
|
||||
int32 Version;
|
||||
MaterialDomain Domain;
|
||||
OldMaterialBlendMode BlendMode;
|
||||
MaterialFlags_Deprecated Flags;
|
||||
MaterialTransparentLighting_Deprecated TransparentLighting;
|
||||
|
||||
/// <summary>
|
||||
/// Compare structure with other one
|
||||
/// </summary>
|
||||
/// <param name="other">Other structure to compare</param>
|
||||
/// <returns>True if both structures are equal</returns>
|
||||
bool operator==(const MaterialInfo2& other) const
|
||||
{
|
||||
return Domain == other.Domain
|
||||
&& BlendMode == other.BlendMode
|
||||
&& TransparentLighting == other.TransparentLighting
|
||||
&& Flags == other.Flags;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material info structure - version 3
|
||||
/// [Deprecated on 10.09.2018, expires on 10.05.2019]
|
||||
/// </summary>
|
||||
struct MaterialInfo3
|
||||
{
|
||||
MaterialDomain Domain;
|
||||
OldMaterialBlendMode BlendMode;
|
||||
MaterialFlags_Deprecated Flags;
|
||||
MaterialTransparentLighting_Deprecated TransparentLighting;
|
||||
|
||||
/// <summary>
|
||||
/// Compare structure with other one
|
||||
/// </summary>
|
||||
/// <param name="other">Other structure to compare</param>
|
||||
/// <returns>True if both structures are equal</returns>
|
||||
bool operator==(const MaterialInfo3& other) const
|
||||
{
|
||||
return Domain == other.Domain
|
||||
&& BlendMode == other.BlendMode
|
||||
&& TransparentLighting == other.TransparentLighting
|
||||
&& Flags == other.Flags;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material info structure - version 4
|
||||
/// [Deprecated on 10.09.2018, expires on 10.05.2019]
|
||||
/// </summary>
|
||||
struct MaterialInfo4
|
||||
{
|
||||
MaterialDomain Domain;
|
||||
OldMaterialBlendMode BlendMode;
|
||||
MaterialFlags_Deprecated Flags;
|
||||
MaterialTransparentLighting_Deprecated TransparentLighting;
|
||||
MaterialPostFxLocation PostFxLocation;
|
||||
|
||||
/// <summary>
|
||||
/// Compare structure with other one
|
||||
/// </summary>
|
||||
/// <param name="other">Other structure to compare</param>
|
||||
/// <returns>True if both structures are equal</returns>
|
||||
bool operator==(const MaterialInfo4& other) const
|
||||
{
|
||||
return Domain == other.Domain
|
||||
&& BlendMode == other.BlendMode
|
||||
&& TransparentLighting == other.TransparentLighting
|
||||
&& PostFxLocation == other.PostFxLocation
|
||||
&& Flags == other.Flags;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material info structure - version 5
|
||||
/// [Deprecated on 10.09.2018, expires on 10.05.2019]
|
||||
/// </summary>
|
||||
struct MaterialInfo5
|
||||
{
|
||||
MaterialDomain Domain;
|
||||
OldMaterialBlendMode BlendMode;
|
||||
MaterialFlags_Deprecated Flags;
|
||||
MaterialTransparentLighting_Deprecated TransparentLighting;
|
||||
MaterialPostFxLocation PostFxLocation;
|
||||
float MaskThreshold;
|
||||
float OpacityThreshold;
|
||||
|
||||
/// <summary>
|
||||
/// Compare structure with other one
|
||||
/// </summary>
|
||||
/// <param name="other">Other structure to compare</param>
|
||||
/// <returns>True if both structures are equal</returns>
|
||||
bool operator==(const MaterialInfo5& other) const
|
||||
{
|
||||
return Domain == other.Domain
|
||||
&& BlendMode == other.BlendMode
|
||||
&& TransparentLighting == other.TransparentLighting
|
||||
&& PostFxLocation == other.PostFxLocation
|
||||
&& Math::NearEqual(MaskThreshold, other.MaskThreshold)
|
||||
&& Math::NearEqual(OpacityThreshold, other.OpacityThreshold)
|
||||
&& Flags == other.Flags;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material info structure - version 6
|
||||
/// [Deprecated on 10.09.2018, expires on 10.05.2019]
|
||||
/// </summary>
|
||||
struct MaterialInfo6
|
||||
{
|
||||
MaterialDomain Domain;
|
||||
OldMaterialBlendMode BlendMode;
|
||||
MaterialFlags_Deprecated Flags;
|
||||
MaterialTransparentLighting_Deprecated TransparentLighting;
|
||||
MaterialDecalBlendingMode DecalBlendingMode;
|
||||
MaterialPostFxLocation PostFxLocation;
|
||||
float MaskThreshold;
|
||||
float OpacityThreshold;
|
||||
|
||||
MaterialInfo6()
|
||||
{
|
||||
}
|
||||
|
||||
MaterialInfo6(const MaterialInfo5& other)
|
||||
{
|
||||
Domain = other.Domain;
|
||||
BlendMode = other.BlendMode;
|
||||
Flags = other.Flags;
|
||||
TransparentLighting = other.TransparentLighting;
|
||||
DecalBlendingMode = MaterialDecalBlendingMode::Translucent;
|
||||
PostFxLocation = other.PostFxLocation;
|
||||
MaskThreshold = other.MaskThreshold;
|
||||
OpacityThreshold = other.OpacityThreshold;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare structure with other one
|
||||
/// </summary>
|
||||
/// <param name="other">Other structure to compare</param>
|
||||
/// <returns>True if both structures are equal</returns>
|
||||
bool operator==(const MaterialInfo6& other) const
|
||||
{
|
||||
return Domain == other.Domain
|
||||
&& BlendMode == other.BlendMode
|
||||
&& TransparentLighting == other.TransparentLighting
|
||||
&& DecalBlendingMode == other.DecalBlendingMode
|
||||
&& PostFxLocation == other.PostFxLocation
|
||||
&& Math::NearEqual(MaskThreshold, other.MaskThreshold)
|
||||
&& Math::NearEqual(OpacityThreshold, other.OpacityThreshold)
|
||||
&& Flags == other.Flags;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material info structure - version 7
|
||||
/// [Deprecated on 13.09.2018, expires on 13.12.2018]
|
||||
/// </summary>
|
||||
struct MaterialInfo7
|
||||
{
|
||||
MaterialDomain Domain;
|
||||
OldMaterialBlendMode BlendMode;
|
||||
MaterialFlags_Deprecated Flags;
|
||||
MaterialTransparentLighting_Deprecated TransparentLighting;
|
||||
MaterialDecalBlendingMode DecalBlendingMode;
|
||||
MaterialPostFxLocation PostFxLocation;
|
||||
float MaskThreshold;
|
||||
float OpacityThreshold;
|
||||
TessellationMethod TessellationMode;
|
||||
int32 MaxTessellationFactor;
|
||||
|
||||
MaterialInfo7()
|
||||
{
|
||||
}
|
||||
|
||||
MaterialInfo7(const MaterialInfo6& other)
|
||||
{
|
||||
Domain = other.Domain;
|
||||
BlendMode = other.BlendMode;
|
||||
Flags = other.Flags;
|
||||
TransparentLighting = other.TransparentLighting;
|
||||
DecalBlendingMode = other.DecalBlendingMode;
|
||||
PostFxLocation = other.PostFxLocation;
|
||||
MaskThreshold = other.MaskThreshold;
|
||||
OpacityThreshold = other.OpacityThreshold;
|
||||
TessellationMode = TessellationMethod::None;
|
||||
MaxTessellationFactor = 15;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare structure with other one
|
||||
/// </summary>
|
||||
/// <param name="other">Other structure to compare</param>
|
||||
/// <returns>True if both structures are equal</returns>
|
||||
bool operator==(const MaterialInfo7& other) const
|
||||
{
|
||||
return Domain == other.Domain
|
||||
&& BlendMode == other.BlendMode
|
||||
&& TransparentLighting == other.TransparentLighting
|
||||
&& DecalBlendingMode == other.DecalBlendingMode
|
||||
&& PostFxLocation == other.PostFxLocation
|
||||
&& Math::NearEqual(MaskThreshold, other.MaskThreshold)
|
||||
&& Math::NearEqual(OpacityThreshold, other.OpacityThreshold)
|
||||
&& Flags == other.Flags
|
||||
&& TessellationMode == other.TessellationMode
|
||||
&& MaxTessellationFactor == other.MaxTessellationFactor;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material info structure - version 8
|
||||
/// [Deprecated on 24.07.2019, expires on 10.05.2021]
|
||||
/// </summary>
|
||||
struct MaterialInfo8
|
||||
{
|
||||
MaterialDomain Domain;
|
||||
MaterialBlendMode BlendMode;
|
||||
MaterialShadingModel ShadingModel;
|
||||
MaterialFlags_Deprecated Flags;
|
||||
MaterialTransparentLighting_Deprecated TransparentLighting;
|
||||
MaterialDecalBlendingMode DecalBlendingMode;
|
||||
MaterialPostFxLocation PostFxLocation;
|
||||
float MaskThreshold;
|
||||
float OpacityThreshold;
|
||||
TessellationMethod TessellationMode;
|
||||
int32 MaxTessellationFactor;
|
||||
|
||||
MaterialInfo8()
|
||||
{
|
||||
}
|
||||
|
||||
MaterialInfo8(const MaterialInfo7& other)
|
||||
{
|
||||
Domain = other.Domain;
|
||||
switch (other.BlendMode)
|
||||
{
|
||||
case OldMaterialBlendMode::Opaque:
|
||||
BlendMode = MaterialBlendMode::Opaque;
|
||||
ShadingModel = MaterialShadingModel::Lit;
|
||||
break;
|
||||
case OldMaterialBlendMode::Transparent:
|
||||
BlendMode = MaterialBlendMode::Transparent;
|
||||
ShadingModel = MaterialShadingModel::Lit;
|
||||
break;
|
||||
case OldMaterialBlendMode::Unlit:
|
||||
BlendMode = MaterialBlendMode::Opaque;
|
||||
ShadingModel = MaterialShadingModel::Unlit;
|
||||
break;
|
||||
}
|
||||
Flags = other.Flags;
|
||||
TransparentLighting = other.TransparentLighting;
|
||||
DecalBlendingMode = other.DecalBlendingMode;
|
||||
PostFxLocation = other.PostFxLocation;
|
||||
MaskThreshold = other.MaskThreshold;
|
||||
OpacityThreshold = other.OpacityThreshold;
|
||||
TessellationMode = other.TessellationMode;
|
||||
MaxTessellationFactor = other.MaxTessellationFactor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare structure with other one
|
||||
/// </summary>
|
||||
/// <param name="other">Other structure to compare</param>
|
||||
/// <returns>True if both structures are equal</returns>
|
||||
bool operator==(const MaterialInfo8& other) const
|
||||
{
|
||||
return Domain == other.Domain
|
||||
&& BlendMode == other.BlendMode
|
||||
&& ShadingModel == other.ShadingModel
|
||||
&& TransparentLighting == other.TransparentLighting
|
||||
&& DecalBlendingMode == other.DecalBlendingMode
|
||||
&& PostFxLocation == other.PostFxLocation
|
||||
&& Math::NearEqual(MaskThreshold, other.MaskThreshold)
|
||||
&& Math::NearEqual(OpacityThreshold, other.OpacityThreshold)
|
||||
&& Flags == other.Flags
|
||||
&& TessellationMode == other.TessellationMode
|
||||
&& MaxTessellationFactor == other.MaxTessellationFactor;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Structure with basic information about the material surface. It describes how material is reacting on light and which graphical features of it requires to render.
|
||||
/// </summary>
|
||||
API_STRUCT() struct FLAXENGINE_API MaterialInfo
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(MaterialInfo);
|
||||
|
||||
/// <summary>
|
||||
/// The material shader domain.
|
||||
/// </summary>
|
||||
API_FIELD() MaterialDomain Domain;
|
||||
|
||||
/// <summary>
|
||||
/// The blending mode for rendering.
|
||||
/// </summary>
|
||||
API_FIELD() MaterialBlendMode BlendMode;
|
||||
|
||||
/// <summary>
|
||||
/// The shading mode for lighting.
|
||||
/// </summary>
|
||||
API_FIELD() MaterialShadingModel ShadingModel;
|
||||
|
||||
/// <summary>
|
||||
/// The usage flags.
|
||||
/// </summary>
|
||||
API_FIELD() MaterialUsageFlags UsageFlags;
|
||||
|
||||
/// <summary>
|
||||
/// The features usage flags.
|
||||
/// </summary>
|
||||
API_FIELD() MaterialFeaturesFlags FeaturesFlags;
|
||||
|
||||
/// <summary>
|
||||
/// The decal material blending mode.
|
||||
/// </summary>
|
||||
API_FIELD() MaterialDecalBlendingMode DecalBlendingMode;
|
||||
|
||||
/// <summary>
|
||||
/// The post fx material rendering location.
|
||||
/// </summary>
|
||||
API_FIELD() MaterialPostFxLocation PostFxLocation;
|
||||
|
||||
/// <summary>
|
||||
/// The primitives culling mode.
|
||||
/// </summary>
|
||||
API_FIELD() CullMode CullMode;
|
||||
|
||||
/// <summary>
|
||||
/// The mask threshold.
|
||||
/// </summary>
|
||||
API_FIELD() float MaskThreshold;
|
||||
|
||||
/// <summary>
|
||||
/// The opacity threshold.
|
||||
/// </summary>
|
||||
API_FIELD() float OpacityThreshold;
|
||||
|
||||
/// <summary>
|
||||
/// The tessellation mode.
|
||||
/// </summary>
|
||||
API_FIELD() TessellationMethod TessellationMode;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum tessellation factor (used only if material uses tessellation).
|
||||
/// </summary>
|
||||
API_FIELD() int32 MaxTessellationFactor;
|
||||
|
||||
MaterialInfo()
|
||||
{
|
||||
}
|
||||
|
||||
MaterialInfo(const MaterialInfo8& other)
|
||||
{
|
||||
Domain = other.Domain;
|
||||
BlendMode = other.BlendMode;
|
||||
ShadingModel = other.ShadingModel;
|
||||
UsageFlags = MaterialUsageFlags::None;
|
||||
if (other.Flags & MaterialFlags_Deprecated::UseMask)
|
||||
UsageFlags |= MaterialUsageFlags::UseMask;
|
||||
if (other.Flags & MaterialFlags_Deprecated::UseEmissive)
|
||||
UsageFlags |= MaterialUsageFlags::UseEmissive;
|
||||
if (other.Flags & MaterialFlags_Deprecated::UsePositionOffset)
|
||||
UsageFlags |= MaterialUsageFlags::UsePositionOffset;
|
||||
if (other.Flags & MaterialFlags_Deprecated::UseVertexColor)
|
||||
UsageFlags |= MaterialUsageFlags::UseVertexColor;
|
||||
if (other.Flags & MaterialFlags_Deprecated::UseNormal)
|
||||
UsageFlags |= MaterialUsageFlags::UseNormal;
|
||||
if (other.Flags & MaterialFlags_Deprecated::UseDisplacement)
|
||||
UsageFlags |= MaterialUsageFlags::UseDisplacement;
|
||||
if (other.Flags & MaterialFlags_Deprecated::UseRefraction)
|
||||
UsageFlags |= MaterialUsageFlags::UseRefraction;
|
||||
FeaturesFlags = MaterialFeaturesFlags::None;
|
||||
if (other.Flags & MaterialFlags_Deprecated::Wireframe)
|
||||
FeaturesFlags |= MaterialFeaturesFlags::Wireframe;
|
||||
if (other.Flags & MaterialFlags_Deprecated::TransparentDisableDepthTest && BlendMode != MaterialBlendMode::Opaque)
|
||||
FeaturesFlags |= MaterialFeaturesFlags::DisableDepthTest;
|
||||
if (other.Flags & MaterialFlags_Deprecated::TransparentDisableFog && BlendMode != MaterialBlendMode::Opaque)
|
||||
FeaturesFlags |= MaterialFeaturesFlags::DisableFog;
|
||||
if (other.Flags & MaterialFlags_Deprecated::TransparentDisableReflections && BlendMode != MaterialBlendMode::Opaque)
|
||||
FeaturesFlags |= MaterialFeaturesFlags::DisableReflections;
|
||||
if (other.Flags & MaterialFlags_Deprecated::DisableDepthWrite)
|
||||
FeaturesFlags |= MaterialFeaturesFlags::DisableDepthWrite;
|
||||
if (other.Flags & MaterialFlags_Deprecated::TransparentDisableDistortion && BlendMode != MaterialBlendMode::Opaque)
|
||||
FeaturesFlags |= MaterialFeaturesFlags::DisableDistortion;
|
||||
if (other.Flags & MaterialFlags_Deprecated::InputWorldSpaceNormal)
|
||||
FeaturesFlags |= MaterialFeaturesFlags::InputWorldSpaceNormal;
|
||||
if (other.Flags & MaterialFlags_Deprecated::UseDitheredLODTransition)
|
||||
FeaturesFlags |= MaterialFeaturesFlags::DitheredLODTransition;
|
||||
if (other.BlendMode != MaterialBlendMode::Opaque && other.TransparentLighting == MaterialTransparentLighting_Deprecated::None)
|
||||
ShadingModel = MaterialShadingModel::Unlit;
|
||||
DecalBlendingMode = other.DecalBlendingMode;
|
||||
PostFxLocation = other.PostFxLocation;
|
||||
CullMode = other.Flags & MaterialFlags_Deprecated::TwoSided ? ::CullMode::TwoSided : ::CullMode::Normal;
|
||||
MaskThreshold = other.MaskThreshold;
|
||||
OpacityThreshold = other.OpacityThreshold;
|
||||
TessellationMode = other.TessellationMode;
|
||||
MaxTessellationFactor = other.MaxTessellationFactor;
|
||||
}
|
||||
|
||||
bool operator==(const MaterialInfo& other) const
|
||||
{
|
||||
return Domain == other.Domain
|
||||
&& BlendMode == other.BlendMode
|
||||
&& ShadingModel == other.ShadingModel
|
||||
&& UsageFlags == other.UsageFlags
|
||||
&& FeaturesFlags == other.FeaturesFlags
|
||||
&& DecalBlendingMode == other.DecalBlendingMode
|
||||
&& PostFxLocation == other.PostFxLocation
|
||||
&& CullMode == other.CullMode
|
||||
&& Math::NearEqual(MaskThreshold, other.MaskThreshold)
|
||||
&& Math::NearEqual(OpacityThreshold, other.OpacityThreshold)
|
||||
&& TessellationMode == other.TessellationMode
|
||||
&& MaxTessellationFactor == other.MaxTessellationFactor;
|
||||
}
|
||||
};
|
||||
|
||||
// The current material info descriptor version used by the material pipeline
|
||||
typedef MaterialInfo MaterialInfo9;
|
||||
#define MaterialInfo_Version 9
|
||||
916
Source/Engine/Graphics/Materials/MaterialParams.cpp
Normal file
916
Source/Engine/Graphics/Materials/MaterialParams.cpp
Normal file
@@ -0,0 +1,916 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "MaterialParams.h"
|
||||
#include "MaterialInfo.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Graphics/GPUContext.h"
|
||||
#include "Engine/Engine/GameplayGlobals.h"
|
||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||
#include "Engine/Graphics/RenderBuffers.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/GPULimits.h"
|
||||
|
||||
const Char* ToString(MaterialParameterType value)
|
||||
{
|
||||
const Char* result;
|
||||
switch (value)
|
||||
{
|
||||
case MaterialParameterType::Invalid:
|
||||
result = TEXT("Invalid");
|
||||
break;
|
||||
case MaterialParameterType::Bool:
|
||||
result = TEXT("Bool");
|
||||
break;
|
||||
case MaterialParameterType::Integer:
|
||||
result = TEXT("Integer");
|
||||
break;
|
||||
case MaterialParameterType::Float:
|
||||
result = TEXT("Float");
|
||||
break;
|
||||
case MaterialParameterType::Vector2:
|
||||
result = TEXT("Vector2");
|
||||
break;
|
||||
case MaterialParameterType::Vector3:
|
||||
result = TEXT("Vector3");
|
||||
break;
|
||||
case MaterialParameterType::Vector4:
|
||||
result = TEXT("Vector4");
|
||||
break;
|
||||
case MaterialParameterType::Color:
|
||||
result = TEXT("Color");
|
||||
break;
|
||||
case MaterialParameterType::Texture:
|
||||
result = TEXT("Texture");
|
||||
break;
|
||||
case MaterialParameterType::CubeTexture:
|
||||
result = TEXT("CubeTexture");
|
||||
break;
|
||||
case MaterialParameterType::NormalMap:
|
||||
result = TEXT("NormalMap");
|
||||
break;
|
||||
case MaterialParameterType::SceneTexture:
|
||||
result = TEXT("SceneTexture");
|
||||
break;
|
||||
case MaterialParameterType::GPUTexture:
|
||||
result = TEXT("GPUTexture");
|
||||
break;
|
||||
case MaterialParameterType::Matrix:
|
||||
result = TEXT("Matrix");
|
||||
break;
|
||||
case MaterialParameterType::GPUTextureArray:
|
||||
result = TEXT("GPUTextureArray");
|
||||
break;
|
||||
case MaterialParameterType::GPUTextureVolume:
|
||||
result = TEXT("GPUTextureVolume");
|
||||
break;
|
||||
case MaterialParameterType::GPUTextureCube:
|
||||
result = TEXT("GPUTextureCube");
|
||||
break;
|
||||
case MaterialParameterType::ChannelMask:
|
||||
result = TEXT("ChannelMask");
|
||||
break;
|
||||
case MaterialParameterType::GameplayGlobal:
|
||||
result = TEXT("GameplayGlobal");
|
||||
break;
|
||||
default:
|
||||
result = TEXT("");
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant MaterialParameter::GetValue() const
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case MaterialParameterType::Bool:
|
||||
return _asBool;
|
||||
case MaterialParameterType::Integer:
|
||||
case MaterialParameterType::SceneTexture:
|
||||
case MaterialParameterType::ChannelMask:
|
||||
return _asInteger;
|
||||
case MaterialParameterType::Float:
|
||||
return _asFloat;
|
||||
case MaterialParameterType::Vector2:
|
||||
return _asVector2;
|
||||
case MaterialParameterType::Vector3:
|
||||
return _asVector3;
|
||||
case MaterialParameterType::Vector4:
|
||||
return _asVector4;
|
||||
case MaterialParameterType::Color:
|
||||
return _asColor;
|
||||
case MaterialParameterType::Matrix:
|
||||
return Variant(_asMatrix);
|
||||
case MaterialParameterType::NormalMap:
|
||||
case MaterialParameterType::Texture:
|
||||
case MaterialParameterType::CubeTexture:
|
||||
case MaterialParameterType::GameplayGlobal:
|
||||
return _asAsset.Get();
|
||||
case MaterialParameterType::GPUTextureVolume:
|
||||
case MaterialParameterType::GPUTextureArray:
|
||||
case MaterialParameterType::GPUTextureCube:
|
||||
case MaterialParameterType::GPUTexture:
|
||||
return _asGPUTexture.Get();
|
||||
default:
|
||||
CRASH;
|
||||
return Variant::Zero;
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialParameter::SetValue(const Variant& value)
|
||||
{
|
||||
bool invalidType = false;
|
||||
switch (_type)
|
||||
{
|
||||
case MaterialParameterType::Bool:
|
||||
_asBool = (bool)value;
|
||||
break;
|
||||
case MaterialParameterType::Integer:
|
||||
case MaterialParameterType::SceneTexture:
|
||||
case MaterialParameterType::ChannelMask:
|
||||
_asInteger = (int32)value;
|
||||
break;
|
||||
case MaterialParameterType::Float:
|
||||
_asFloat = (float)value;
|
||||
break;
|
||||
case MaterialParameterType::Vector2:
|
||||
_asVector2 = (Vector2)value;
|
||||
break;
|
||||
case MaterialParameterType::Vector3:
|
||||
_asVector3 = (Vector3)value;
|
||||
break;
|
||||
case MaterialParameterType::Vector4:
|
||||
_asVector4 = (Vector4)value;
|
||||
break;
|
||||
case MaterialParameterType::Color:
|
||||
_asColor = (Color)value;
|
||||
break;
|
||||
case MaterialParameterType::Matrix:
|
||||
_asMatrix = (Matrix)value;
|
||||
break;
|
||||
case MaterialParameterType::NormalMap:
|
||||
case MaterialParameterType::Texture:
|
||||
case MaterialParameterType::CubeTexture:
|
||||
switch (value.Type.Type)
|
||||
{
|
||||
case VariantType::Null:
|
||||
_asAsset = nullptr;
|
||||
break;
|
||||
case VariantType::Guid:
|
||||
_asAsset = Content::LoadAsync<TextureBase>(*(Guid*)value.AsData);
|
||||
break;
|
||||
case VariantType::Pointer:
|
||||
_asAsset = (TextureBase*)value.AsPointer;
|
||||
break;
|
||||
case VariantType::Object:
|
||||
_asAsset = Cast<TextureBase>(value.AsObject);
|
||||
break;
|
||||
case VariantType::Asset:
|
||||
_asAsset = Cast<TextureBase>(value.AsAsset);
|
||||
break;
|
||||
default:
|
||||
invalidType = true;
|
||||
}
|
||||
break;
|
||||
case MaterialParameterType::GPUTextureVolume:
|
||||
case MaterialParameterType::GPUTextureCube:
|
||||
case MaterialParameterType::GPUTextureArray:
|
||||
case MaterialParameterType::GPUTexture:
|
||||
switch (value.Type.Type)
|
||||
{
|
||||
case VariantType::Null:
|
||||
_asGPUTexture = nullptr;
|
||||
break;
|
||||
case VariantType::Guid:
|
||||
_asGPUTexture = *(Guid*)value.AsData;
|
||||
break;
|
||||
case VariantType::Pointer:
|
||||
_asGPUTexture = (GPUTexture*)value.AsPointer;
|
||||
break;
|
||||
case VariantType::Object:
|
||||
_asGPUTexture = Cast<GPUTexture>(value.AsObject);
|
||||
break;
|
||||
default:
|
||||
invalidType = true;
|
||||
}
|
||||
break;
|
||||
case MaterialParameterType::GameplayGlobal:
|
||||
switch (value.Type.Type)
|
||||
{
|
||||
case VariantType::Null:
|
||||
_asAsset = nullptr;
|
||||
break;
|
||||
case VariantType::Guid:
|
||||
_asAsset = Content::LoadAsync<GameplayGlobals>(*(Guid*)value.AsData);
|
||||
break;
|
||||
case VariantType::Pointer:
|
||||
_asAsset = (GameplayGlobals*)value.AsPointer;
|
||||
break;
|
||||
case VariantType::Object:
|
||||
_asAsset = Cast<GameplayGlobals>(value.AsObject);
|
||||
break;
|
||||
case VariantType::Asset:
|
||||
_asAsset = Cast<GameplayGlobals>(value.AsAsset);
|
||||
break;
|
||||
default:
|
||||
invalidType = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
invalidType = true;
|
||||
}
|
||||
if (invalidType)
|
||||
{
|
||||
LOG(Error, "Invalid material parameter value type {0} to set (param type: {1})", value.Type, ::ToString(_type));
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialParameter::Bind(BindMeta& meta) const
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case MaterialParameterType::Bool:
|
||||
if (meta.Buffer0)
|
||||
*((int32*)(meta.Buffer0 + _offset)) = _asBool;
|
||||
break;
|
||||
case MaterialParameterType::Integer:
|
||||
if (meta.Buffer0)
|
||||
*((int32*)(meta.Buffer0 + _offset)) = _asInteger;
|
||||
break;
|
||||
case MaterialParameterType::Float:
|
||||
if (meta.Buffer0)
|
||||
*((float*)(meta.Buffer0 + _offset)) = _asFloat;
|
||||
break;
|
||||
case MaterialParameterType::Vector2:
|
||||
if (meta.Buffer0)
|
||||
*((Vector2*)(meta.Buffer0 + _offset)) = _asVector2;
|
||||
break;
|
||||
case MaterialParameterType::Vector3:
|
||||
if (meta.Buffer0)
|
||||
*((Vector3*)(meta.Buffer0 + _offset)) = _asVector3;
|
||||
break;
|
||||
case MaterialParameterType::Vector4:
|
||||
if (meta.Buffer0)
|
||||
*((Vector4*)(meta.Buffer0 + _offset)) = _asVector4;
|
||||
break;
|
||||
case MaterialParameterType::Color:
|
||||
if (meta.Buffer0)
|
||||
*((Color*)(meta.Buffer0 + _offset)) = _asColor;
|
||||
break;
|
||||
case MaterialParameterType::Matrix:
|
||||
if (meta.Buffer0)
|
||||
Matrix::Transpose(_asMatrix, *(Matrix*)(meta.Buffer0 + _offset));
|
||||
break;
|
||||
case MaterialParameterType::NormalMap:
|
||||
{
|
||||
// If normal map texture is set but not loaded yet, use default engine normal map (reduces loading artifacts)
|
||||
auto texture = _asAsset ? ((TextureBase*)_asAsset.Get())->GetTexture() : nullptr;
|
||||
if (texture && texture->ResidentMipLevels() == 0)
|
||||
texture = GPUDevice::Instance->GetDefaultNormalMap();
|
||||
const auto view = GET_TEXTURE_VIEW_SAFE(texture);
|
||||
meta.Context->BindSR(_registerIndex, view);
|
||||
break;
|
||||
}
|
||||
case MaterialParameterType::Texture:
|
||||
case MaterialParameterType::CubeTexture:
|
||||
{
|
||||
const auto texture = _asAsset ? ((TextureBase*)_asAsset.Get())->GetTexture() : nullptr;
|
||||
const auto view = GET_TEXTURE_VIEW_SAFE(texture);
|
||||
meta.Context->BindSR(_registerIndex, view);
|
||||
break;
|
||||
}
|
||||
case MaterialParameterType::GPUTexture:
|
||||
{
|
||||
const auto texture = _asGPUTexture.Get();
|
||||
const auto view = GET_TEXTURE_VIEW_SAFE(texture);
|
||||
meta.Context->BindSR(_registerIndex, view);
|
||||
break;
|
||||
}
|
||||
case MaterialParameterType::GPUTextureArray:
|
||||
case MaterialParameterType::GPUTextureCube:
|
||||
{
|
||||
const auto view = _asGPUTexture ? _asGPUTexture->ViewArray() : nullptr;
|
||||
meta.Context->BindSR(_registerIndex, view);
|
||||
break;
|
||||
}
|
||||
case MaterialParameterType::GPUTextureVolume:
|
||||
{
|
||||
const auto view = _asGPUTexture ? _asGPUTexture->ViewVolume() : nullptr;
|
||||
meta.Context->BindSR(_registerIndex, view);
|
||||
break;
|
||||
}
|
||||
case MaterialParameterType::SceneTexture:
|
||||
{
|
||||
GPUTextureView* view = nullptr;
|
||||
const auto type = (MaterialSceneTextures)_asInteger;
|
||||
if (type == MaterialSceneTextures::SceneColor)
|
||||
{
|
||||
view = meta.Input;
|
||||
}
|
||||
else if (meta.Buffers)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MaterialSceneTextures::SceneDepth:
|
||||
view = meta.CanSampleDepth
|
||||
? (GPUDevice::Instance->Limits.HasReadOnlyDepth ? meta.Buffers->DepthBuffer->ViewReadOnlyDepth() : meta.Buffers->DepthBuffer->View())
|
||||
: GPUDevice::Instance->GetDefaultWhiteTexture()->View();
|
||||
break;
|
||||
case MaterialSceneTextures::AmbientOcclusion:
|
||||
case MaterialSceneTextures::BaseColor:
|
||||
view = meta.CanSampleGBuffer ? meta.Buffers->GBuffer0->View() : nullptr;
|
||||
break;
|
||||
case MaterialSceneTextures::WorldNormal:
|
||||
case MaterialSceneTextures::ShadingModel:
|
||||
view = meta.CanSampleGBuffer ? meta.Buffers->GBuffer1->View() : nullptr;
|
||||
break;
|
||||
case MaterialSceneTextures::Roughness:
|
||||
case MaterialSceneTextures::Metalness:
|
||||
case MaterialSceneTextures::Specular:
|
||||
view = meta.CanSampleGBuffer ? meta.Buffers->GBuffer2->View() : nullptr;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
meta.Context->BindSR(_registerIndex, view);
|
||||
break;
|
||||
}
|
||||
case MaterialParameterType::ChannelMask:
|
||||
if (meta.Buffer0)
|
||||
*((Vector4*)(meta.Buffer0 + _offset)) = Vector4(_asInteger == 0, _asInteger == 1, _asInteger == 2, _asInteger == 3);
|
||||
break;
|
||||
case MaterialParameterType::GameplayGlobal:
|
||||
if (meta.Buffer0 && _asAsset)
|
||||
{
|
||||
const auto e = _asAsset.As<GameplayGlobals>()->Variables.TryGet(_name);
|
||||
if (e)
|
||||
{
|
||||
switch (e->Value.Type.Type)
|
||||
{
|
||||
case VariantType::Bool:
|
||||
*((bool*)(meta.Buffer0 + _offset)) = e->Value.AsBool;
|
||||
break;
|
||||
case VariantType::Int:
|
||||
*((int32*)(meta.Buffer0 + _offset)) = e->Value.AsInt;
|
||||
break;
|
||||
case VariantType::Uint:
|
||||
*((uint32*)(meta.Buffer0 + _offset)) = e->Value.AsUint;
|
||||
break;
|
||||
case VariantType::Float:
|
||||
*((float*)(meta.Buffer0 + _offset)) = e->Value.AsFloat;
|
||||
break;
|
||||
case VariantType::Vector2:
|
||||
*((Vector2*)(meta.Buffer0 + _offset)) = e->Value.AsVector2();
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
*((Vector3*)(meta.Buffer0 + _offset)) = e->Value.AsVector3();
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
*((Vector4*)(meta.Buffer0 + _offset)) = e->Value.AsVector4();
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MaterialParameter::HasContentLoaded() const
|
||||
{
|
||||
return _asAsset == nullptr || _asAsset->IsLoaded();
|
||||
}
|
||||
|
||||
void MaterialParameter::clone(const MaterialParameter* param)
|
||||
{
|
||||
// Clone data
|
||||
_type = param->_type;
|
||||
_isPublic = param->_isPublic;
|
||||
_override = param->_override;
|
||||
_registerIndex = param->_registerIndex;
|
||||
_offset = param->_offset;
|
||||
_name = param->_name;
|
||||
_paramId = param->_paramId;
|
||||
|
||||
// Clone value
|
||||
switch (_type)
|
||||
{
|
||||
case MaterialParameterType::Bool:
|
||||
_asBool = param->_asBool;
|
||||
break;
|
||||
case MaterialParameterType::Integer:
|
||||
case MaterialParameterType::SceneTexture:
|
||||
_asInteger = param->_asInteger;
|
||||
break;
|
||||
case MaterialParameterType::Float:
|
||||
_asFloat = param->_asFloat;
|
||||
break;
|
||||
case MaterialParameterType::Vector2:
|
||||
_asVector2 = param->_asVector2;
|
||||
break;
|
||||
case MaterialParameterType::Vector3:
|
||||
_asVector3 = param->_asVector3;
|
||||
break;
|
||||
case MaterialParameterType::Vector4:
|
||||
_asVector4 = param->_asVector4;
|
||||
break;
|
||||
case MaterialParameterType::Color:
|
||||
_asColor = param->_asColor;
|
||||
break;
|
||||
case MaterialParameterType::Matrix:
|
||||
_asMatrix = param->_asMatrix;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_asAsset = param->_asAsset;
|
||||
_asGPUTexture = param->_asGPUTexture;
|
||||
}
|
||||
|
||||
bool MaterialParameter::operator==(const MaterialParameter& other) const
|
||||
{
|
||||
return _paramId == other._paramId;
|
||||
}
|
||||
|
||||
String MaterialParameter::ToString() const
|
||||
{
|
||||
return String::Format(TEXT("\'{0}\' ({1}:{2}:{3})"), _name, ::ToString(_type), _paramId, _isPublic);
|
||||
}
|
||||
|
||||
void MaterialParams::Bind(MaterialParamsLink* link, MaterialParameter::BindMeta& meta)
|
||||
{
|
||||
ASSERT(link && link->This);
|
||||
for (int32 i = 0; i < link->This->Count(); i++)
|
||||
{
|
||||
MaterialParamsLink* l = link;
|
||||
while (l->Down && !l->This->At(i).IsOverride())
|
||||
{
|
||||
l = l->Down;
|
||||
}
|
||||
|
||||
l->This->At(i).Bind(meta);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialParams::Clone(MaterialParams& result)
|
||||
{
|
||||
ASSERT(this != &result);
|
||||
|
||||
// Clone all parameters
|
||||
result.Resize(Count(), false);
|
||||
for (int32 i = 0; i < Count(); i++)
|
||||
{
|
||||
result.At(i).clone(&At(i));
|
||||
}
|
||||
|
||||
result._versionHash = _versionHash;
|
||||
}
|
||||
|
||||
void MaterialParams::Dispose()
|
||||
{
|
||||
Resize(0);
|
||||
_versionHash = 0;
|
||||
}
|
||||
|
||||
bool MaterialParams::Load(ReadStream* stream)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// Release
|
||||
Resize(0);
|
||||
|
||||
// Check for not empty params
|
||||
if (stream != nullptr && stream->CanRead())
|
||||
{
|
||||
// Version
|
||||
uint16 version;
|
||||
stream->ReadUint16(&version);
|
||||
switch (version)
|
||||
{
|
||||
case 1: // [Deprecated on 15.11.2019, expires on 15.11.2021]
|
||||
{
|
||||
// Size of the collection
|
||||
uint16 paramsCount;
|
||||
stream->ReadUint16(¶msCount);
|
||||
Resize(paramsCount, false);
|
||||
|
||||
// Read all parameters
|
||||
Guid id;
|
||||
for (int32 i = 0; i < paramsCount; i++)
|
||||
{
|
||||
auto param = &At(i);
|
||||
|
||||
// Read properties
|
||||
param->_paramId = Guid::New();
|
||||
param->_type = static_cast<MaterialParameterType>(stream->ReadByte());
|
||||
param->_isPublic = stream->ReadBool();
|
||||
param->_override = param->_isPublic;
|
||||
stream->ReadString(¶m->_name, 10421);
|
||||
param->_registerIndex = stream->ReadByte();
|
||||
stream->ReadUint16(¶m->_offset);
|
||||
|
||||
// Read value
|
||||
switch (param->_type)
|
||||
{
|
||||
case MaterialParameterType::Bool:
|
||||
param->_asBool = stream->ReadBool();
|
||||
break;
|
||||
case MaterialParameterType::Integer:
|
||||
case MaterialParameterType::SceneTexture:
|
||||
case MaterialParameterType::ChannelMask:
|
||||
stream->ReadInt32(¶m->_asInteger);
|
||||
break;
|
||||
case MaterialParameterType::Float:
|
||||
stream->ReadFloat(¶m->_asFloat);
|
||||
break;
|
||||
case MaterialParameterType::Vector2:
|
||||
stream->Read(¶m->_asVector2);
|
||||
break;
|
||||
case MaterialParameterType::Vector3:
|
||||
stream->Read(¶m->_asVector3);
|
||||
break;
|
||||
case MaterialParameterType::Vector4:
|
||||
stream->Read(¶m->_asVector4);
|
||||
break;
|
||||
case MaterialParameterType::Color:
|
||||
stream->Read(¶m->_asColor);
|
||||
break;
|
||||
case MaterialParameterType::Matrix:
|
||||
stream->Read(¶m->_asMatrix);
|
||||
break;
|
||||
case MaterialParameterType::NormalMap:
|
||||
case MaterialParameterType::Texture:
|
||||
case MaterialParameterType::CubeTexture:
|
||||
stream->Read(&id);
|
||||
param->_asAsset = Content::LoadAsync<TextureBase>(id);
|
||||
break;
|
||||
case MaterialParameterType::GPUTextureVolume:
|
||||
case MaterialParameterType::GPUTextureCube:
|
||||
case MaterialParameterType::GPUTextureArray:
|
||||
case MaterialParameterType::GPUTexture:
|
||||
stream->Read(&id);
|
||||
param->_asGPUTexture = id;
|
||||
break;
|
||||
case MaterialParameterType::GameplayGlobal:
|
||||
stream->Read(&id);
|
||||
param->_asAsset = Content::LoadAsync<GameplayGlobals>(id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: // [Deprecated on 15.11.2019, expires on 15.11.2021]
|
||||
{
|
||||
// Size of the collection
|
||||
uint16 paramsCount;
|
||||
stream->ReadUint16(¶msCount);
|
||||
Resize(paramsCount, false);
|
||||
|
||||
// Read all parameters
|
||||
Guid id;
|
||||
for (int32 i = 0; i < paramsCount; i++)
|
||||
{
|
||||
auto param = &At(i);
|
||||
|
||||
// Read properties
|
||||
param->_type = static_cast<MaterialParameterType>(stream->ReadByte());
|
||||
stream->Read(¶m->_paramId);
|
||||
param->_isPublic = stream->ReadBool();
|
||||
param->_override = param->_isPublic;
|
||||
stream->ReadString(¶m->_name, 10421);
|
||||
param->_registerIndex = stream->ReadByte();
|
||||
stream->ReadUint16(¶m->_offset);
|
||||
|
||||
// Read value
|
||||
switch (param->_type)
|
||||
{
|
||||
case MaterialParameterType::Bool:
|
||||
param->_asBool = stream->ReadBool();
|
||||
break;
|
||||
case MaterialParameterType::Integer:
|
||||
case MaterialParameterType::SceneTexture:
|
||||
stream->ReadInt32(¶m->_asInteger);
|
||||
break;
|
||||
case MaterialParameterType::Float:
|
||||
stream->ReadFloat(¶m->_asFloat);
|
||||
break;
|
||||
case MaterialParameterType::Vector2:
|
||||
stream->Read(¶m->_asVector2);
|
||||
break;
|
||||
case MaterialParameterType::Vector3:
|
||||
stream->Read(¶m->_asVector3);
|
||||
break;
|
||||
case MaterialParameterType::Vector4:
|
||||
stream->Read(¶m->_asVector4);
|
||||
break;
|
||||
case MaterialParameterType::Color:
|
||||
stream->Read(¶m->_asColor);
|
||||
break;
|
||||
case MaterialParameterType::Matrix:
|
||||
stream->Read(¶m->_asMatrix);
|
||||
break;
|
||||
case MaterialParameterType::NormalMap:
|
||||
case MaterialParameterType::Texture:
|
||||
case MaterialParameterType::CubeTexture:
|
||||
stream->Read(&id);
|
||||
param->_asAsset = Content::LoadAsync<TextureBase>(id);
|
||||
break;
|
||||
case MaterialParameterType::GPUTextureVolume:
|
||||
case MaterialParameterType::GPUTextureCube:
|
||||
case MaterialParameterType::GPUTextureArray:
|
||||
case MaterialParameterType::GPUTexture:
|
||||
stream->Read(&id);
|
||||
param->_asGPUTexture = id;
|
||||
break;
|
||||
case MaterialParameterType::GameplayGlobal:
|
||||
stream->Read(&id);
|
||||
param->_asAsset = Content::LoadAsync<GameplayGlobals>(id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
// Size of the collection
|
||||
uint16 paramsCount;
|
||||
stream->ReadUint16(¶msCount);
|
||||
Resize(paramsCount, false);
|
||||
|
||||
// Read all parameters
|
||||
Guid id;
|
||||
for (int32 i = 0; i < paramsCount; i++)
|
||||
{
|
||||
auto param = &At(i);
|
||||
|
||||
// Read properties
|
||||
param->_type = static_cast<MaterialParameterType>(stream->ReadByte());
|
||||
stream->Read(¶m->_paramId);
|
||||
param->_isPublic = stream->ReadBool();
|
||||
param->_override = stream->ReadBool();
|
||||
stream->ReadString(¶m->_name, 10421);
|
||||
param->_registerIndex = stream->ReadByte();
|
||||
stream->ReadUint16(¶m->_offset);
|
||||
|
||||
// Read value
|
||||
switch (param->_type)
|
||||
{
|
||||
case MaterialParameterType::Bool:
|
||||
param->_asBool = stream->ReadBool();
|
||||
break;
|
||||
case MaterialParameterType::Integer:
|
||||
case MaterialParameterType::SceneTexture:
|
||||
case MaterialParameterType::ChannelMask:
|
||||
stream->ReadInt32(¶m->_asInteger);
|
||||
break;
|
||||
case MaterialParameterType::Float:
|
||||
stream->ReadFloat(¶m->_asFloat);
|
||||
break;
|
||||
case MaterialParameterType::Vector2:
|
||||
stream->Read(¶m->_asVector2);
|
||||
break;
|
||||
case MaterialParameterType::Vector3:
|
||||
stream->Read(¶m->_asVector3);
|
||||
break;
|
||||
case MaterialParameterType::Vector4:
|
||||
stream->Read(¶m->_asVector4);
|
||||
break;
|
||||
case MaterialParameterType::Color:
|
||||
stream->Read(¶m->_asColor);
|
||||
break;
|
||||
case MaterialParameterType::Matrix:
|
||||
stream->Read(¶m->_asMatrix);
|
||||
break;
|
||||
case MaterialParameterType::NormalMap:
|
||||
case MaterialParameterType::Texture:
|
||||
case MaterialParameterType::CubeTexture:
|
||||
stream->Read(&id);
|
||||
param->_asAsset = Content::LoadAsync<TextureBase>(id);
|
||||
break;
|
||||
case MaterialParameterType::GPUTextureVolume:
|
||||
case MaterialParameterType::GPUTextureCube:
|
||||
case MaterialParameterType::GPUTextureArray:
|
||||
case MaterialParameterType::GPUTexture:
|
||||
stream->Read(&id);
|
||||
param->_asGPUTexture = id;
|
||||
break;
|
||||
case MaterialParameterType::GameplayGlobal:
|
||||
stream->Read(&id);
|
||||
param->_asAsset = Content::LoadAsync<GameplayGlobals>(id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateHash();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MaterialParams::Save(WriteStream* stream)
|
||||
{
|
||||
// Skip serialization if no parameters to save
|
||||
if (IsEmpty())
|
||||
return;
|
||||
|
||||
// Version
|
||||
stream->WriteUint16(3);
|
||||
|
||||
// Size of the collection
|
||||
stream->WriteUint16(Count());
|
||||
|
||||
// Write all parameters
|
||||
for (int32 i = 0; i < Count(); i++)
|
||||
{
|
||||
// Cache
|
||||
auto param = &At(i);
|
||||
|
||||
// Write properties
|
||||
stream->WriteByte(static_cast<byte>(param->_type));
|
||||
stream->Write(¶m->_paramId);
|
||||
stream->WriteBool(param->_isPublic);
|
||||
stream->WriteBool(param->_override);
|
||||
stream->WriteString(param->_name, 10421);
|
||||
stream->WriteByte(param->_registerIndex);
|
||||
stream->WriteUint16(param->_offset);
|
||||
|
||||
// Write value
|
||||
Guid id;
|
||||
switch (param->_type)
|
||||
{
|
||||
case MaterialParameterType::Bool:
|
||||
stream->WriteBool(param->_asBool);
|
||||
break;
|
||||
case MaterialParameterType::Integer:
|
||||
case MaterialParameterType::SceneTexture:
|
||||
case MaterialParameterType::ChannelMask:
|
||||
stream->WriteInt32(param->_asInteger);
|
||||
break;
|
||||
case MaterialParameterType::Float:
|
||||
stream->WriteFloat(param->_asFloat);
|
||||
break;
|
||||
case MaterialParameterType::Vector2:
|
||||
stream->Write(¶m->_asVector2);
|
||||
break;
|
||||
case MaterialParameterType::Vector3:
|
||||
stream->Write(¶m->_asVector3);
|
||||
break;
|
||||
case MaterialParameterType::Vector4:
|
||||
stream->Write(¶m->_asVector4);
|
||||
break;
|
||||
case MaterialParameterType::Color:
|
||||
stream->Write(¶m->_asColor);
|
||||
break;
|
||||
case MaterialParameterType::Matrix:
|
||||
stream->Write(¶m->_asMatrix);
|
||||
break;
|
||||
case MaterialParameterType::NormalMap:
|
||||
case MaterialParameterType::Texture:
|
||||
case MaterialParameterType::CubeTexture:
|
||||
case MaterialParameterType::GameplayGlobal:
|
||||
id = param->_asAsset.GetID();
|
||||
stream->Write(&id);
|
||||
break;
|
||||
case MaterialParameterType::GPUTextureVolume:
|
||||
case MaterialParameterType::GPUTextureArray:
|
||||
case MaterialParameterType::GPUTextureCube:
|
||||
case MaterialParameterType::GPUTexture:
|
||||
id = param->_asGPUTexture.GetID();
|
||||
stream->Write(&id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialParams::Save(WriteStream* stream, const Array<SerializedMaterialParam>* params)
|
||||
{
|
||||
// Version
|
||||
stream->WriteUint16(3);
|
||||
|
||||
// Size of the collection
|
||||
stream->WriteUint16(params ? params->Count() : 0);
|
||||
|
||||
// Write all parameters
|
||||
if (params)
|
||||
{
|
||||
for (int32 i = 0; i < params->Count(); i++)
|
||||
{
|
||||
// Cache
|
||||
const SerializedMaterialParam& param = params->At(i);
|
||||
|
||||
// Write properties
|
||||
stream->WriteByte(static_cast<byte>(param.Type));
|
||||
stream->Write(¶m.ID);
|
||||
stream->WriteBool(param.IsPublic);
|
||||
stream->WriteBool(param.Override);
|
||||
stream->WriteString(param.Name, 10421);
|
||||
stream->WriteByte(param.RegisterIndex);
|
||||
stream->WriteUint16(param.Offset);
|
||||
|
||||
// Write value
|
||||
switch (param.Type)
|
||||
{
|
||||
case MaterialParameterType::Bool:
|
||||
stream->WriteBool(param.AsBool);
|
||||
break;
|
||||
case MaterialParameterType::SceneTexture:
|
||||
case MaterialParameterType::ChannelMask:
|
||||
case MaterialParameterType::Integer:
|
||||
stream->WriteInt32(param.AsInteger);
|
||||
break;
|
||||
case MaterialParameterType::Float:
|
||||
stream->WriteFloat(param.AsFloat);
|
||||
break;
|
||||
case MaterialParameterType::Vector2:
|
||||
stream->Write(¶m.AsVector2);
|
||||
break;
|
||||
case MaterialParameterType::Vector3:
|
||||
stream->Write(¶m.AsVector3);
|
||||
break;
|
||||
case MaterialParameterType::Vector4:
|
||||
stream->Write(¶m.AsVector4);
|
||||
break;
|
||||
case MaterialParameterType::Color:
|
||||
stream->Write(¶m.AsColor);
|
||||
break;
|
||||
case MaterialParameterType::Matrix:
|
||||
stream->Write(¶m.AsMatrix);
|
||||
break;
|
||||
case MaterialParameterType::NormalMap:
|
||||
case MaterialParameterType::Texture:
|
||||
case MaterialParameterType::CubeTexture:
|
||||
case MaterialParameterType::GameplayGlobal:
|
||||
case MaterialParameterType::GPUTextureVolume:
|
||||
case MaterialParameterType::GPUTextureCube:
|
||||
case MaterialParameterType::GPUTextureArray:
|
||||
case MaterialParameterType::GPUTexture:
|
||||
stream->Write(¶m.AsGuid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialParams::Save(BytesContainer& data, const Array<SerializedMaterialParam>* params)
|
||||
{
|
||||
MemoryWriteStream stream(1024);
|
||||
Save(&stream, params);
|
||||
if (stream.GetPosition() > 0)
|
||||
data.Copy(stream.GetHandle(), stream.GetPosition());
|
||||
else
|
||||
data.Release();
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void MaterialParams::GetReferences(Array<Guid>& output) const
|
||||
{
|
||||
for (int32 i = 0; i < Count(); i++)
|
||||
{
|
||||
if (At(i)._asAsset)
|
||||
output.Add(At(i)._asAsset->GetID());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool MaterialParams::HasContentLoaded() const
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
for (int32 i = 0; i < Count(); i++)
|
||||
{
|
||||
if (!At(i).HasContentLoaded())
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MaterialParams::UpdateHash()
|
||||
{
|
||||
_versionHash = rand();
|
||||
}
|
||||
500
Source/Engine/Graphics/Materials/MaterialParams.h
Normal file
500
Source/Engine/Graphics/Materials/MaterialParams.h
Normal file
@@ -0,0 +1,500 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Math/Matrix.h"
|
||||
#include "Engine/Core/Types/StringView.h"
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Scripting/ScriptingObjectReference.h"
|
||||
#include "Engine/Content/Assets/Texture.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
|
||||
class MaterialInstance;
|
||||
class MaterialParams;
|
||||
class GPUContext;
|
||||
class RenderBuffers;
|
||||
|
||||
struct MaterialParamsLink
|
||||
{
|
||||
MaterialParams* This;
|
||||
MaterialParamsLink* Up;
|
||||
MaterialParamsLink* Down;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The material parameter types.
|
||||
/// </summary>
|
||||
enum class MaterialParameterType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// The invalid type.
|
||||
/// </summary>
|
||||
Invalid = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The bool.
|
||||
/// </summary>
|
||||
Bool = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The integer.
|
||||
/// </summary>
|
||||
Integer = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The float.
|
||||
/// </summary>
|
||||
Float = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The vector2
|
||||
/// </summary>
|
||||
Vector2 = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The vector3.
|
||||
/// </summary>
|
||||
Vector3 = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The vector4.
|
||||
/// </summary>
|
||||
Vector4 = 6,
|
||||
|
||||
/// <summary>
|
||||
/// The color.
|
||||
/// </summary>
|
||||
Color = 7,
|
||||
|
||||
/// <summary>
|
||||
/// The texture.
|
||||
/// </summary>
|
||||
Texture = 8,
|
||||
|
||||
/// <summary>
|
||||
/// The cube texture.
|
||||
/// </summary>
|
||||
CubeTexture = 9,
|
||||
|
||||
/// <summary>
|
||||
/// The normal map texture.
|
||||
/// </summary>
|
||||
NormalMap = 10,
|
||||
|
||||
/// <summary>
|
||||
/// The scene texture.
|
||||
/// </summary>
|
||||
SceneTexture = 11,
|
||||
|
||||
/// <summary>
|
||||
/// The GPU texture (created from code).
|
||||
/// </summary>
|
||||
GPUTexture = 12,
|
||||
|
||||
/// <summary>
|
||||
/// The matrix.
|
||||
/// </summary>
|
||||
Matrix = 13,
|
||||
|
||||
/// <summary>
|
||||
/// The GPU texture array (created from code).
|
||||
/// </summary>
|
||||
GPUTextureArray = 14,
|
||||
|
||||
/// <summary>
|
||||
/// The GPU volume texture (created from code).
|
||||
/// </summary>
|
||||
GPUTextureVolume = 15,
|
||||
|
||||
/// <summary>
|
||||
/// The GPU cube texture (created from code).
|
||||
/// </summary>
|
||||
GPUTextureCube = 16,
|
||||
|
||||
/// <summary>
|
||||
/// The RGBA channel selection mask.
|
||||
/// </summary>
|
||||
ChannelMask = 17,
|
||||
|
||||
/// <summary>
|
||||
/// The gameplay global.
|
||||
/// </summary>
|
||||
GameplayGlobal = 18,
|
||||
};
|
||||
|
||||
const Char* ToString(MaterialParameterType value);
|
||||
|
||||
/// <summary>
|
||||
/// Structure of serialized material parameter data.
|
||||
/// </summary>
|
||||
struct SerializedMaterialParam
|
||||
{
|
||||
MaterialParameterType Type;
|
||||
Guid ID;
|
||||
bool IsPublic;
|
||||
bool Override;
|
||||
String Name;
|
||||
String ShaderName;
|
||||
|
||||
union
|
||||
{
|
||||
bool AsBool;
|
||||
int32 AsInteger;
|
||||
float AsFloat;
|
||||
Vector2 AsVector2;
|
||||
Vector3 AsVector3;
|
||||
Vector4 AsVector4;
|
||||
Color AsColor;
|
||||
Guid AsGuid;
|
||||
Matrix AsMatrix;
|
||||
};
|
||||
|
||||
byte RegisterIndex;
|
||||
uint16 Offset;
|
||||
|
||||
SerializedMaterialParam()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material variable object. Allows to modify material parameter value at runtime.
|
||||
/// </summary>
|
||||
API_CLASS(NoSpawn) class FLAXENGINE_API MaterialParameter : public PersistentScriptingObject
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(MaterialParameter, PersistentScriptingObject);
|
||||
friend MaterialParams;
|
||||
friend MaterialInstance;
|
||||
private:
|
||||
|
||||
Guid _paramId;
|
||||
MaterialParameterType _type = MaterialParameterType::Invalid;
|
||||
bool _isPublic;
|
||||
bool _override;
|
||||
byte _registerIndex;
|
||||
uint16 _offset;
|
||||
|
||||
union
|
||||
{
|
||||
bool _asBool;
|
||||
int32 _asInteger;
|
||||
float _asFloat;
|
||||
Vector2 _asVector2;
|
||||
Vector3 _asVector3;
|
||||
Vector4 _asVector4;
|
||||
Color _asColor;
|
||||
Matrix _asMatrix;
|
||||
};
|
||||
|
||||
AssetReference<Asset> _asAsset;
|
||||
ScriptingObjectReference<GPUTexture> _asGPUTexture;
|
||||
String _name;
|
||||
|
||||
public:
|
||||
|
||||
MaterialParameter(const MaterialParameter& other)
|
||||
: MaterialParameter()
|
||||
{
|
||||
#if !BUILD_RELEASE
|
||||
CRASH; // Not used
|
||||
#endif
|
||||
}
|
||||
|
||||
MaterialParameter& operator=(const MaterialParameter& other)
|
||||
{
|
||||
#if !BUILD_RELEASE
|
||||
CRASH; // Not used
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameter ID (not the parameter instance Id but the original parameter ID).
|
||||
/// </summary>
|
||||
/// <returns>The ID.</returns>
|
||||
API_PROPERTY() FORCE_INLINE Guid GetParameterID() const
|
||||
{
|
||||
return _paramId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameter type.
|
||||
/// </summary>
|
||||
/// <returns>The type.</returns>
|
||||
API_PROPERTY() FORCE_INLINE MaterialParameterType GetParameterType() const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameter name.
|
||||
/// </summary>
|
||||
/// <returns>The name.</returns>
|
||||
API_PROPERTY() FORCE_INLINE const String& GetName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true is parameter is public visible.
|
||||
/// </summary>
|
||||
/// <returns>True if parameter has public access, otherwise false.</returns>
|
||||
API_PROPERTY() FORCE_INLINE bool IsPublic() const
|
||||
{
|
||||
return _isPublic;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true is parameter is overriding the value.
|
||||
/// </summary>
|
||||
/// <returns>True if parameter is overriding the value, otherwise false.</returns>
|
||||
API_PROPERTY() FORCE_INLINE bool IsOverride() const
|
||||
{
|
||||
return _override;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value override mode.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
API_PROPERTY() void SetIsOverride(bool value)
|
||||
{
|
||||
_override = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameter resource graphics pipeline binding register index.
|
||||
/// </summary>
|
||||
/// <returns>The binding register.</returns>
|
||||
FORCE_INLINE byte GetRegister() const
|
||||
{
|
||||
return _registerIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameter binding offset since the start of the constant buffer.
|
||||
/// </summary>
|
||||
/// <returns>The binding data offset (in bytes).</returns>
|
||||
FORCE_INLINE uint16 GetBindOffset() const
|
||||
{
|
||||
return _offset;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the parameter.
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY() Variant GetValue() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of the parameter.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
API_PROPERTY() void SetValue(const Variant& value);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// The material parameter binding metadata.
|
||||
/// </summary>
|
||||
struct BindMeta
|
||||
{
|
||||
/// <summary>
|
||||
/// The GPU commands context.
|
||||
/// </summary>
|
||||
GPUContext* Context;
|
||||
|
||||
/// <summary>
|
||||
/// The pointer to the first constants buffer in memory.
|
||||
/// </summary>
|
||||
byte* Buffer0;
|
||||
|
||||
/// <summary>
|
||||
/// The input scene color. It's optional and used in forward/postFx rendering.
|
||||
/// </summary>
|
||||
GPUTextureView* Input;
|
||||
|
||||
/// <summary>
|
||||
/// The scene buffers. It's optional and used in forward/postFx rendering.
|
||||
/// </summary>
|
||||
const RenderBuffers* Buffers;
|
||||
|
||||
/// <summary>
|
||||
/// True if parameters can sample depth buffer.
|
||||
/// </summary>
|
||||
bool CanSampleDepth;
|
||||
|
||||
/// <summary>
|
||||
/// True if parameters can sample GBuffer.
|
||||
/// </summary>
|
||||
bool CanSampleGBuffer;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Binds the parameter to the pipeline.
|
||||
/// </summary>
|
||||
/// <param name="meta">The bind meta.</param>
|
||||
void Bind(BindMeta& meta) const;
|
||||
|
||||
bool HasContentLoaded() const;
|
||||
|
||||
private:
|
||||
|
||||
void clone(const MaterialParameter* param);
|
||||
|
||||
public:
|
||||
|
||||
bool operator==(const MaterialParameter& other) const;
|
||||
|
||||
// [Object]
|
||||
String ToString() const override;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The collection of material parameters.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API MaterialParams : public Array<MaterialParameter>
|
||||
{
|
||||
friend MaterialInstance;
|
||||
private:
|
||||
|
||||
int32 _versionHash = 0;
|
||||
|
||||
public:
|
||||
|
||||
MaterialParameter* Get(const Guid& id)
|
||||
{
|
||||
MaterialParameter* result = nullptr;
|
||||
for (int32 i = 0; i < Count(); i++)
|
||||
{
|
||||
if (At(i).GetParameterID() == id)
|
||||
{
|
||||
result = &At(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
MaterialParameter* Get(const StringView& name)
|
||||
{
|
||||
MaterialParameter* result = nullptr;
|
||||
for (int32 i = 0; i < Count(); i++)
|
||||
{
|
||||
if (At(i).GetName() == name)
|
||||
{
|
||||
result = &At(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int32 Find(const Guid& id)
|
||||
{
|
||||
int32 result = -1;
|
||||
for (int32 i = 0; i < Count(); i++)
|
||||
{
|
||||
if (At(i).GetParameterID() == id)
|
||||
{
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int32 Find(const StringView& name)
|
||||
{
|
||||
int32 result = -1;
|
||||
for (int32 i = 0; i < Count(); i++)
|
||||
{
|
||||
if (At(i).GetName() == name)
|
||||
{
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameters version hash. Every time the parameters are modified (loaded, edited, etc.) the hash changes. Can be used to sync instanced parameters collection.
|
||||
/// </summary>
|
||||
/// <returns>The hash.</returns>
|
||||
FORCE_INLINE int32 GetVersionHash() const
|
||||
{
|
||||
return _versionHash;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Binds the parameters to the pipeline.
|
||||
/// </summary>
|
||||
/// <param name="link">The parameters binding link. Used to support per-parameter override.</param>
|
||||
/// <param name="meta">The bind meta.</param>
|
||||
static void Bind(MaterialParamsLink* link, MaterialParameter::BindMeta& meta);
|
||||
|
||||
/// <summary>
|
||||
/// Clones the parameters list.
|
||||
/// </summary>
|
||||
/// <param name="result">The result container.</param>
|
||||
void Clone(MaterialParams& result);
|
||||
|
||||
/// <summary>
|
||||
/// Releases the whole data.
|
||||
/// </summary>
|
||||
void Dispose();
|
||||
|
||||
/// <summary>
|
||||
/// Loads material parameters from the stream.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream with data.</param>
|
||||
/// <returns>True if cannot load parameters for the file.</returns>
|
||||
bool Load(ReadStream* stream);
|
||||
|
||||
/// <summary>
|
||||
/// Saves material parameters to the stream.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream with data.</param>
|
||||
void Save(WriteStream* stream);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the material parameters to the stream.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream with data.</param>
|
||||
/// <param name="params">The array of parameters.</param>
|
||||
static void Save(WriteStream* stream, const Array<SerializedMaterialParam>* params);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the material parameters to the bytes container.
|
||||
/// </summary>
|
||||
/// <param name="data">The output data.</param>
|
||||
/// <param name="params">The array of parameters.</param>
|
||||
static void Save(BytesContainer& data, const Array<SerializedMaterialParam>* params);
|
||||
|
||||
public:
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
/// <summary>
|
||||
/// Gets the asset references (see Asset.GetReferences for more info).
|
||||
/// </summary>
|
||||
/// <param name="output">The output.</param>
|
||||
void GetReferences(Array<Guid>& output) const;
|
||||
|
||||
#endif
|
||||
|
||||
bool HasContentLoaded() const;
|
||||
|
||||
private:
|
||||
|
||||
void UpdateHash();
|
||||
};
|
||||
168
Source/Engine/Graphics/Materials/MaterialShader.cpp
Normal file
168
Source/Engine/Graphics/Materials/MaterialShader.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "MaterialShader.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Renderer/RenderList.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
|
||||
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||
#include "DecalMaterialShader.h"
|
||||
#include "PostFxMaterialShader.h"
|
||||
#include "ForwardMaterialShader.h"
|
||||
#include "DeferredMaterialShader.h"
|
||||
#include "GUIMaterialShader.h"
|
||||
#include "TerrainMaterialShader.h"
|
||||
#include "ParticleMaterialShader.h"
|
||||
|
||||
GPUPipelineState* MaterialShader::PipelineStateCache::GetPS(CullMode mode, bool wireframe)
|
||||
{
|
||||
const int32 index = static_cast<int32>(mode) + (wireframe ? 3 : 0);
|
||||
if (PS[index])
|
||||
return PS[index];
|
||||
|
||||
Desc.CullMode = mode;
|
||||
Desc.Wireframe = wireframe;
|
||||
PS[index] = GPUDevice::Instance->CreatePipelineState();
|
||||
PS[index]->Init(Desc);
|
||||
return PS[index];
|
||||
}
|
||||
|
||||
MaterialShader::MaterialShader(const String& name)
|
||||
: _isLoaded(false)
|
||||
, _shader(nullptr)
|
||||
{
|
||||
ASSERT(GPUDevice::Instance);
|
||||
_shader = GPUDevice::Instance->CreateShader(name);
|
||||
}
|
||||
|
||||
MaterialShader::~MaterialShader()
|
||||
{
|
||||
ASSERT(!_isLoaded);
|
||||
SAFE_DELETE_GPU_RESOURCE(_shader);
|
||||
}
|
||||
|
||||
MaterialShader* MaterialShader::Create(const String& name, MemoryReadStream& shaderCacheStream, const MaterialInfo& info)
|
||||
{
|
||||
MaterialShader* material;
|
||||
switch (info.Domain)
|
||||
{
|
||||
case MaterialDomain::Surface:
|
||||
material = info.BlendMode == MaterialBlendMode::Opaque ? (MaterialShader*)New<DeferredMaterialShader>(name) : (MaterialShader*)New<ForwardMaterialShader>(name);
|
||||
break;
|
||||
case MaterialDomain::PostProcess:
|
||||
material = New<PostFxMaterialShader>(name);
|
||||
break;
|
||||
case MaterialDomain::Decal:
|
||||
material = New<DecalMaterialShader>(name);
|
||||
break;
|
||||
case MaterialDomain::GUI:
|
||||
material = New<GUIMaterialShader>(name);
|
||||
break;
|
||||
case MaterialDomain::Terrain:
|
||||
material = New<TerrainMaterialShader>(name);
|
||||
break;
|
||||
case MaterialDomain::Particle:
|
||||
material = New<ParticleMaterialShader>(name);
|
||||
break;
|
||||
default:
|
||||
LOG(Fatal, "Unknown material type.");
|
||||
return nullptr;
|
||||
}
|
||||
if (material->Load(shaderCacheStream, info))
|
||||
{
|
||||
Delete(material);
|
||||
return nullptr;
|
||||
}
|
||||
return material;
|
||||
}
|
||||
|
||||
class DummyMaterial : public MaterialShader
|
||||
{
|
||||
public:
|
||||
|
||||
DummyMaterial()
|
||||
: MaterialShader(String::Empty)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [Material]
|
||||
void Bind(BindParameters& params) override
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// [Material]
|
||||
bool Load() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
MaterialShader* MaterialShader::CreateDummy(MemoryReadStream& shaderCacheStream, const MaterialInfo& info)
|
||||
{
|
||||
MaterialShader* material = New<DummyMaterial>();
|
||||
if (material->Load(shaderCacheStream, info))
|
||||
{
|
||||
Delete(material);
|
||||
return nullptr;
|
||||
}
|
||||
return material;
|
||||
}
|
||||
|
||||
const MaterialInfo& MaterialShader::GetInfo() const
|
||||
{
|
||||
return _info;
|
||||
}
|
||||
|
||||
bool MaterialShader::IsReady() const
|
||||
{
|
||||
return _isLoaded;
|
||||
}
|
||||
|
||||
bool MaterialShader::Load(MemoryReadStream& shaderCacheStream, const MaterialInfo& info)
|
||||
{
|
||||
ASSERT(!_isLoaded);
|
||||
|
||||
// Cache material info
|
||||
_info = info;
|
||||
|
||||
// Create shader
|
||||
if (_shader->Create(shaderCacheStream))
|
||||
{
|
||||
LOG(Warning, "Cannot load shader.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Init memory for a constant buffer
|
||||
const auto cb0 = _shader->GetCB(0);
|
||||
if (cb0)
|
||||
{
|
||||
_cb0Data.Resize(cb0->GetSize(), false);
|
||||
}
|
||||
const auto cb1 = _shader->GetCB(1);
|
||||
if (cb1)
|
||||
{
|
||||
_cb1Data.Resize(cb1->GetSize(), false);
|
||||
}
|
||||
|
||||
// Initialize the material based on type (create pipeline states and setup)
|
||||
if (Load())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
_isLoaded = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void MaterialShader::Unload()
|
||||
{
|
||||
_isLoaded = false;
|
||||
_cb0Data.Resize(0, false);
|
||||
_cb1Data.Resize(0, false);
|
||||
_shader->ReleaseGPU();
|
||||
}
|
||||
110
Source/Engine/Graphics/Materials/MaterialShader.h
Normal file
110
Source/Engine/Graphics/Materials/MaterialShader.h
Normal file
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IMaterial.h"
|
||||
#include "Engine/Graphics/GPUPipelineState.h"
|
||||
#include "Engine/Renderer/Config.h"
|
||||
|
||||
/// <summary>
|
||||
/// Current materials shader version.
|
||||
/// </summary>
|
||||
#define MATERIAL_GRAPH_VERSION 146
|
||||
|
||||
class Material;
|
||||
class GPUShader;
|
||||
class MemoryReadStream;
|
||||
|
||||
/// <summary>
|
||||
/// Represents material shader that can be used to render objects, visuals or effects. Contains a dedicated shader.
|
||||
/// </summary>
|
||||
class MaterialShader : public IMaterial
|
||||
{
|
||||
protected:
|
||||
|
||||
struct PipelineStateCache
|
||||
{
|
||||
GPUPipelineState* PS[6];
|
||||
GPUPipelineState::Description Desc;
|
||||
|
||||
PipelineStateCache()
|
||||
{
|
||||
Platform::MemoryClear(PS, sizeof(PS));
|
||||
}
|
||||
|
||||
void Init(GPUPipelineState::Description& desc)
|
||||
{
|
||||
Desc = desc;
|
||||
}
|
||||
|
||||
GPUPipelineState* GetPS(CullMode mode, bool wireframe);
|
||||
|
||||
void Release()
|
||||
{
|
||||
for (int32 i = 0; i < ARRAY_COUNT(PS); i++)
|
||||
{
|
||||
SAFE_DELETE_GPU_RESOURCE(PS[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
bool _isLoaded;
|
||||
GPUShader* _shader;
|
||||
Array<byte> _cb0Data;
|
||||
Array<byte> _cb1Data;
|
||||
MaterialInfo _info;
|
||||
|
||||
protected:
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="name">Material resource name</param>
|
||||
MaterialShader(const String& name);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="MaterialShader"/> class.
|
||||
/// </summary>
|
||||
virtual ~MaterialShader();
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Creates and loads the material from the data.
|
||||
/// </summary>
|
||||
/// <param name="name">Material resource name</param>
|
||||
/// <param name="shaderCacheStream">Stream with compiled shader data</param>
|
||||
/// <param name="info">Loaded material info structure</param>
|
||||
/// <returns>The created and loaded material or null if failed.</returns>
|
||||
static MaterialShader* Create(const String& name, MemoryReadStream& shaderCacheStream, const MaterialInfo& info);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the dummy material used by the Null rendering backend to mock object but not perform any rendering.
|
||||
/// </summary>
|
||||
/// <param name="shaderCacheStream">The shader cache stream.</param>
|
||||
/// <param name="info">The material information.</param>
|
||||
/// <returns>The created and loaded material or null if failed.</returns>
|
||||
static MaterialShader* CreateDummy(MemoryReadStream& shaderCacheStream, const MaterialInfo& info);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Clear loaded data
|
||||
/// </summary>
|
||||
virtual void Unload();
|
||||
|
||||
protected:
|
||||
|
||||
bool Load(MemoryReadStream& shaderCacheStream, const MaterialInfo& info);
|
||||
virtual bool Load() = 0;
|
||||
|
||||
public:
|
||||
|
||||
// [IMaterial]
|
||||
const MaterialInfo& GetInfo() const override;
|
||||
bool IsReady() const override;
|
||||
};
|
||||
400
Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp
Normal file
400
Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp
Normal file
@@ -0,0 +1,400 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ParticleMaterialShader.h"
|
||||
#include "MaterialParams.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
#include "Engine/Renderer/ShadowsPass.h"
|
||||
#include "Engine/Graphics/RenderView.h"
|
||||
#include "Engine/Renderer/RenderList.h"
|
||||
#include "Engine/Graphics/GPUContext.h"
|
||||
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||
#include "Engine/Graphics/GPULimits.h"
|
||||
#include "Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.h"
|
||||
#include "Engine/Content/Assets/CubeTexture.h"
|
||||
#include "Engine/Level/Actors/EnvironmentProbe.h"
|
||||
|
||||
#define MAX_LOCAL_LIGHTS 4
|
||||
|
||||
PACK_STRUCT(struct ParticleMaterialShaderData {
|
||||
Matrix ViewProjectionMatrix;
|
||||
Matrix WorldMatrix;
|
||||
Matrix ViewMatrix;
|
||||
Vector3 ViewPos;
|
||||
float ViewFar;
|
||||
Vector3 ViewDir;
|
||||
float TimeParam;
|
||||
Vector4 ViewInfo;
|
||||
Vector4 ScreenSize;
|
||||
uint32 SortedIndicesOffset;
|
||||
float PerInstanceRandom;
|
||||
int32 ParticleStride;
|
||||
int32 PositionOffset;
|
||||
int32 SpriteSizeOffset;
|
||||
int32 SpriteFacingModeOffset;
|
||||
int32 SpriteFacingVectorOffset;
|
||||
int32 VelocityOffset;
|
||||
int32 RotationOffset;
|
||||
int32 ScaleOffset;
|
||||
int32 ModelFacingModeOffset;
|
||||
float RibbonUVTilingDistance;
|
||||
Vector2 RibbonUVScale;
|
||||
Vector2 RibbonUVOffset;
|
||||
int32 RibbonWidthOffset;
|
||||
int32 RibbonTwistOffset;
|
||||
int32 RibbonFacingVectorOffset;
|
||||
uint32 RibbonSegmentCount;
|
||||
Matrix WorldMatrixInverseTransposed;
|
||||
});
|
||||
|
||||
PACK_STRUCT(struct ParticleMaterialShaderLightingData {
|
||||
LightData DirectionalLight;
|
||||
LightShadowData DirectionalLightShadow;
|
||||
LightData SkyLight;
|
||||
ProbeData EnvironmentProbe;
|
||||
ExponentialHeightFogData ExponentialHeightFog;
|
||||
Vector3 Dummy1;
|
||||
uint32 LocalLightsCount;
|
||||
LightData LocalLights[MAX_LOCAL_LIGHTS];
|
||||
});
|
||||
|
||||
DrawPass ParticleMaterialShader::GetDrawModes() const
|
||||
{
|
||||
return _drawModes;
|
||||
}
|
||||
|
||||
void ParticleMaterialShader::Bind(BindParameters& params)
|
||||
{
|
||||
// Prepare
|
||||
auto context = params.GPUContext;
|
||||
auto& view = params.RenderContext.View;
|
||||
auto cache = params.RenderContext.List;
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
const auto cb0 = _shader->GetCB(0);
|
||||
const bool hasCb0 = cb0->GetSize() != 0;
|
||||
const auto cb1 = _shader->GetCB(1);
|
||||
const bool hasCb1 = cb1->GetSize() != 0;
|
||||
const uint32 sortedIndicesOffset = drawCall.Module->SortedIndicesOffset;
|
||||
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(ParticleMaterialShaderData) : nullptr;
|
||||
bindMeta.Input = nullptr;
|
||||
bindMeta.Buffers = params.RenderContext.Buffers;
|
||||
bindMeta.CanSampleDepth = GPUDevice::Instance->Limits.HasReadOnlyDepth;
|
||||
bindMeta.CanSampleGBuffer = true;
|
||||
MaterialParams::Bind(params.ParamsLink, bindMeta);
|
||||
|
||||
// Setup particles data and attributes binding info
|
||||
{
|
||||
context->BindSR(0, drawCall.Particles->GPU.Buffer->View());
|
||||
if (drawCall.Particles->GPU.SortedIndices)
|
||||
context->BindSR(1, drawCall.Particles->GPU.SortedIndices->View());
|
||||
|
||||
if (hasCb0)
|
||||
{
|
||||
const auto& p = *params.ParamsLink->This;
|
||||
for (int32 i = 0; i < p.Count(); i++)
|
||||
{
|
||||
const auto& param = p.At(i);
|
||||
if (param.GetParameterType() == MaterialParameterType::Integer && param.GetName().StartsWith(TEXT("Particle.")))
|
||||
{
|
||||
auto name = StringView(param.GetName().Get() + 9);
|
||||
|
||||
const int32 offset = drawCall.Particles->Layout->FindAttributeOffset(name);
|
||||
*((int32*)(bindMeta.Buffer0 + param.GetBindOffset())) = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Select pipeline state based on current pass and render mode
|
||||
const bool wireframe = (_info.FeaturesFlags & MaterialFeaturesFlags::Wireframe) != 0 || view.Mode == ViewMode::Wireframe;
|
||||
CullMode cullMode = view.Pass == DrawPass::Depth ? CullMode::TwoSided : _info.CullMode;
|
||||
PipelineStateCache* psCache = nullptr;
|
||||
switch (drawCall.Module->TypeID)
|
||||
{
|
||||
// Sprite Rendering
|
||||
case 400:
|
||||
{
|
||||
psCache = (PipelineStateCache*)_cacheSprite.GetPS(view.Pass);
|
||||
break;
|
||||
}
|
||||
// Model Rendering
|
||||
case 403:
|
||||
{
|
||||
psCache = (PipelineStateCache*)_cacheModel.GetPS(view.Pass);
|
||||
break;
|
||||
}
|
||||
// Ribbon Rendering
|
||||
case 404:
|
||||
{
|
||||
psCache = (PipelineStateCache*)_cacheRibbon.GetPS(view.Pass);
|
||||
|
||||
static StringView ParticleRibbonWidth(TEXT("RibbonWidth"));
|
||||
static StringView ParticleRibbonTwist(TEXT("RibbonTwist"));
|
||||
static StringView ParticleRibbonFacingVector(TEXT("RibbonFacingVector"));
|
||||
|
||||
if (hasCb0)
|
||||
{
|
||||
const auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(_cb0Data.Get());
|
||||
|
||||
materialData->RibbonWidthOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleRibbonWidth, ParticleAttribute::ValueTypes::Float, -1);
|
||||
materialData->RibbonTwistOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleRibbonTwist, ParticleAttribute::ValueTypes::Float, -1);
|
||||
materialData->RibbonFacingVectorOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleRibbonFacingVector, ParticleAttribute::ValueTypes::Vector3, -1);
|
||||
|
||||
materialData->RibbonUVTilingDistance = drawCall.Ribbon.UVTilingDistance;
|
||||
materialData->RibbonUVScale.X = drawCall.Ribbon.UVScaleX;
|
||||
materialData->RibbonUVScale.Y = drawCall.Ribbon.UVScaleY;
|
||||
materialData->RibbonUVOffset.X = drawCall.Ribbon.UVOffsetX;
|
||||
materialData->RibbonUVOffset.Y = drawCall.Ribbon.UVOffsetY;
|
||||
materialData->RibbonSegmentCount = drawCall.Ribbon.SegmentCount;
|
||||
}
|
||||
|
||||
if (drawCall.Ribbon.SegmentDistances)
|
||||
context->BindSR(1, drawCall.Ribbon.SegmentDistances->View());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(psCache);
|
||||
GPUPipelineState* state = psCache->GetPS(cullMode, wireframe);
|
||||
|
||||
// Setup material constants data
|
||||
if (hasCb0)
|
||||
{
|
||||
const auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(_cb0Data.Get());
|
||||
|
||||
static StringView ParticlePosition(TEXT("Position"));
|
||||
static StringView ParticleSpriteSize(TEXT("SpriteSize"));
|
||||
static StringView ParticleSpriteFacingMode(TEXT("SpriteFacingMode"));
|
||||
static StringView ParticleSpriteFacingVector(TEXT("SpriteFacingVector"));
|
||||
static StringView ParticleVelocityOffset(TEXT("Velocity"));
|
||||
static StringView ParticleRotationOffset(TEXT("Rotation"));
|
||||
static StringView ParticleScaleOffset(TEXT("Scale"));
|
||||
static StringView ParticleModelFacingModeOffset(TEXT("ModelFacingMode"));
|
||||
|
||||
Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix);
|
||||
Matrix::Transpose(drawCall.World, materialData->WorldMatrix);
|
||||
Matrix::Transpose(view.View, materialData->ViewMatrix);
|
||||
materialData->ViewPos = view.Position;
|
||||
materialData->ViewFar = view.Far;
|
||||
materialData->ViewDir = view.Direction;
|
||||
materialData->TimeParam = Time::Draw.UnscaledTime.GetTotalSeconds();
|
||||
materialData->ViewInfo = view.ViewInfo;
|
||||
materialData->ScreenSize = view.ScreenSize;
|
||||
materialData->SortedIndicesOffset = drawCall.Particles->GPU.SortedIndices && params.RenderContext.View.Pass != DrawPass::Depth ? sortedIndicesOffset : 0xFFFFFFFF;
|
||||
materialData->PerInstanceRandom = drawCall.PerInstanceRandom;
|
||||
materialData->ParticleStride = drawCall.Particles->Stride;
|
||||
materialData->PositionOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticlePosition, ParticleAttribute::ValueTypes::Vector3);
|
||||
materialData->SpriteSizeOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleSpriteSize, ParticleAttribute::ValueTypes::Vector2);
|
||||
materialData->SpriteFacingModeOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleSpriteFacingMode, ParticleAttribute::ValueTypes::Int, -1);
|
||||
materialData->SpriteFacingVectorOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleSpriteFacingVector, ParticleAttribute::ValueTypes::Vector3);
|
||||
materialData->VelocityOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleVelocityOffset, ParticleAttribute::ValueTypes::Vector3);
|
||||
materialData->RotationOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleRotationOffset, ParticleAttribute::ValueTypes::Vector3, -1);
|
||||
materialData->ScaleOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleScaleOffset, ParticleAttribute::ValueTypes::Vector3, -1);
|
||||
materialData->ModelFacingModeOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleModelFacingModeOffset, ParticleAttribute::ValueTypes::Int, -1);
|
||||
Matrix::Invert(drawCall.World, materialData->WorldMatrixInverseTransposed);
|
||||
}
|
||||
|
||||
// Setup lighting constants data
|
||||
if (hasCb1)
|
||||
{
|
||||
auto& lightingData = *reinterpret_cast<ParticleMaterialShaderLightingData*>(_cb1Data.Get());
|
||||
const int32 envProbeShaderRegisterIndex = 2;
|
||||
const int32 skyLightShaderRegisterIndex = 3;
|
||||
const int32 dirLightShaderRegisterIndex = 4;
|
||||
|
||||
// Set fog input
|
||||
if (cache->Fog)
|
||||
{
|
||||
cache->Fog->GetExponentialHeightFogData(view, lightingData.ExponentialHeightFog);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightingData.ExponentialHeightFog.FogMinOpacity = 1.0f;
|
||||
lightingData.ExponentialHeightFog.ApplyDirectionalInscattering = 0.0f;
|
||||
}
|
||||
|
||||
// Set directional light input
|
||||
if (cache->DirectionalLights.HasItems())
|
||||
{
|
||||
const auto& dirLight = cache->DirectionalLights.First();
|
||||
const auto shadowPass = ShadowsPass::Instance();
|
||||
const bool useShadow = shadowPass->LastDirLightIndex == 0;
|
||||
if (useShadow)
|
||||
{
|
||||
lightingData.DirectionalLightShadow = shadowPass->LastDirLight;
|
||||
context->BindSR(dirLightShaderRegisterIndex, shadowPass->LastDirLightShadowMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
context->UnBindSR(dirLightShaderRegisterIndex);
|
||||
}
|
||||
dirLight.SetupLightData(&lightingData.DirectionalLight, view, useShadow);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightingData.DirectionalLight.Color = Vector3::Zero;
|
||||
lightingData.DirectionalLight.CastShadows = 0.0f;
|
||||
context->UnBindSR(dirLightShaderRegisterIndex);
|
||||
}
|
||||
|
||||
// Set sky light
|
||||
if (cache->SkyLights.HasItems())
|
||||
{
|
||||
auto& skyLight = cache->SkyLights.Last();
|
||||
skyLight.SetupLightData(&lightingData.SkyLight, view, false);
|
||||
const auto texture = skyLight.Image ? skyLight.Image->GetTexture() : nullptr;
|
||||
context->BindSR(skyLightShaderRegisterIndex, texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
Platform::MemoryClear(&lightingData.SkyLight, sizeof(lightingData.SkyLight));
|
||||
context->UnBindSR(skyLightShaderRegisterIndex);
|
||||
}
|
||||
|
||||
// Set reflection probe data
|
||||
EnvironmentProbe* probe = nullptr;
|
||||
// TODO: optimize env probe searching for a transparent material - use spatial cache for renderer to find it
|
||||
for (int32 i = 0; i < cache->EnvironmentProbes.Count(); i++)
|
||||
{
|
||||
const auto p = cache->EnvironmentProbes[i];
|
||||
if (p->GetSphere().Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
|
||||
{
|
||||
probe = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (probe && probe->GetProbe())
|
||||
{
|
||||
probe->SetupProbeData(&lightingData.EnvironmentProbe);
|
||||
const auto texture = probe->GetProbe()->GetTexture();
|
||||
context->BindSR(envProbeShaderRegisterIndex, texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightingData.EnvironmentProbe.Data1 = Vector4::Zero;
|
||||
context->UnBindSR(envProbeShaderRegisterIndex);
|
||||
}
|
||||
|
||||
// Set local lights
|
||||
lightingData.LocalLightsCount = 0;
|
||||
for (int32 i = 0; i < cache->PointLights.Count(); i++)
|
||||
{
|
||||
const auto& light = cache->PointLights[i];
|
||||
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
|
||||
{
|
||||
light.SetupLightData(&lightingData.LocalLights[lightingData.LocalLightsCount], view, false);
|
||||
lightingData.LocalLightsCount++;
|
||||
if (lightingData.LocalLightsCount == MAX_LOCAL_LIGHTS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int32 i = 0; i < cache->SpotLights.Count(); i++)
|
||||
{
|
||||
const auto& light = cache->SpotLights[i];
|
||||
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
|
||||
{
|
||||
light.SetupLightData(&lightingData.LocalLights[lightingData.LocalLightsCount], view, false);
|
||||
lightingData.LocalLightsCount++;
|
||||
if (lightingData.LocalLightsCount == MAX_LOCAL_LIGHTS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bind constants
|
||||
if (hasCb0)
|
||||
{
|
||||
context->UpdateCB(cb0, _cb0Data.Get());
|
||||
context->BindCB(0, cb0);
|
||||
}
|
||||
if (hasCb1)
|
||||
{
|
||||
context->UpdateCB(cb1, _cb1Data.Get());
|
||||
context->BindCB(1, cb1);
|
||||
}
|
||||
|
||||
// Bind pipeline
|
||||
context->SetState(state);
|
||||
}
|
||||
|
||||
void ParticleMaterialShader::Unload()
|
||||
{
|
||||
// Base
|
||||
MaterialShader::Unload();
|
||||
|
||||
_cacheSprite.Release();
|
||||
_cacheModel.Release();
|
||||
_cacheRibbon.Release();
|
||||
}
|
||||
|
||||
bool ParticleMaterialShader::Load()
|
||||
{
|
||||
_drawModes = DrawPass::Depth | DrawPass::Forward;
|
||||
GPUPipelineState::Description psDesc = GPUPipelineState::Description::Default;
|
||||
psDesc.DepthTestEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == 0;
|
||||
psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == 0;
|
||||
|
||||
auto vsSprite = _shader->GetVS("VS_Sprite");
|
||||
auto vsMesh = _shader->GetVS("VS_Model");
|
||||
auto vsRibbon = _shader->GetVS("VS_Ribbon");
|
||||
|
||||
// Check if use transparent distortion pass
|
||||
if (_shader->HasShader("PS_Distortion"))
|
||||
{
|
||||
_drawModes |= DrawPass::Distortion;
|
||||
|
||||
// Accumulate Distortion Pass
|
||||
psDesc.PS = _shader->GetPS("PS_Distortion");
|
||||
psDesc.BlendMode = BlendingMode::Add;
|
||||
psDesc.DepthWriteEnable = false;
|
||||
psDesc.VS = vsSprite;
|
||||
_cacheSprite.Distortion.Init(psDesc);
|
||||
psDesc.VS = vsMesh;
|
||||
_cacheModel.Distortion.Init(psDesc);
|
||||
psDesc.VS = vsRibbon;
|
||||
_cacheRibbon.Distortion.Init(psDesc);
|
||||
}
|
||||
|
||||
// Forward Pass
|
||||
psDesc.PS = _shader->GetPS("PS_Forward");
|
||||
psDesc.DepthWriteEnable = false;
|
||||
psDesc.BlendMode = BlendingMode::AlphaBlend;
|
||||
switch (_info.BlendMode)
|
||||
{
|
||||
case MaterialBlendMode::Transparent:
|
||||
psDesc.BlendMode = BlendingMode::AlphaBlend;
|
||||
break;
|
||||
case MaterialBlendMode::Additive:
|
||||
psDesc.BlendMode = BlendingMode::Additive;
|
||||
break;
|
||||
case MaterialBlendMode::Multiply:
|
||||
psDesc.BlendMode = BlendingMode::Multiply;
|
||||
break;
|
||||
}
|
||||
psDesc.VS = vsSprite;
|
||||
_cacheSprite.Default.Init(psDesc);
|
||||
psDesc.VS = vsMesh;
|
||||
_cacheModel.Default.Init(psDesc);
|
||||
psDesc.VS = vsRibbon;
|
||||
_cacheRibbon.Default.Init(psDesc);
|
||||
|
||||
// Depth Pass
|
||||
psDesc = GPUPipelineState::Description::Default;
|
||||
psDesc.CullMode = CullMode::TwoSided;
|
||||
psDesc.DepthClipEnable = false;
|
||||
psDesc.PS = _shader->GetPS("PS_Depth");
|
||||
psDesc.VS = vsSprite;
|
||||
_cacheSprite.Depth.Init(psDesc);
|
||||
psDesc.VS = vsMesh;
|
||||
_cacheModel.Depth.Init(psDesc);
|
||||
psDesc.VS = vsRibbon;
|
||||
_cacheRibbon.Depth.Init(psDesc);
|
||||
|
||||
return false;
|
||||
}
|
||||
72
Source/Engine/Graphics/Materials/ParticleMaterialShader.h
Normal file
72
Source/Engine/Graphics/Materials/ParticleMaterialShader.h
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MaterialShader.h"
|
||||
|
||||
/// <summary>
|
||||
/// Represents material that can be used to render particles.
|
||||
/// </summary>
|
||||
class ParticleMaterialShader : public MaterialShader
|
||||
{
|
||||
private:
|
||||
|
||||
struct Cache
|
||||
{
|
||||
PipelineStateCache Default;
|
||||
PipelineStateCache Depth;
|
||||
PipelineStateCache Distortion;
|
||||
|
||||
FORCE_INLINE PipelineStateCache* GetPS(const DrawPass pass)
|
||||
{
|
||||
switch (pass)
|
||||
{
|
||||
case DrawPass::Depth:
|
||||
return &Depth;
|
||||
case DrawPass::Distortion:
|
||||
return &Distortion;
|
||||
case DrawPass::Forward:
|
||||
return &Default;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE void Release()
|
||||
{
|
||||
Default.Release();
|
||||
Depth.Release();
|
||||
Distortion.Release();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Cache _cacheSprite;
|
||||
Cache _cacheModel;
|
||||
Cache _cacheRibbon;
|
||||
DrawPass _drawModes = DrawPass::None;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="name">Material resource name</param>
|
||||
ParticleMaterialShader(const String& name)
|
||||
: MaterialShader(name)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [MaterialShader]
|
||||
DrawPass GetDrawModes() const override;
|
||||
void Bind(BindParameters& params) override;
|
||||
void Unload() override;
|
||||
|
||||
protected:
|
||||
|
||||
// [MaterialShader]
|
||||
bool Load() override;
|
||||
};
|
||||
91
Source/Engine/Graphics/Materials/PostFxMaterialShader.cpp
Normal file
91
Source/Engine/Graphics/Materials/PostFxMaterialShader.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "PostFxMaterialShader.h"
|
||||
#include "MaterialParams.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||
#include "Engine/Graphics/RenderView.h"
|
||||
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
|
||||
PACK_STRUCT(struct PostFxMaterialShaderData {
|
||||
Matrix ViewMatrix;
|
||||
Vector3 ViewPos;
|
||||
float ViewFar;
|
||||
Vector3 ViewDir;
|
||||
float TimeParam;
|
||||
Vector4 ViewInfo;
|
||||
Vector4 ScreenSize;
|
||||
Vector4 TemporalAAJitter;
|
||||
});
|
||||
|
||||
void PostFxMaterialShader::Bind(BindParameters& params)
|
||||
{
|
||||
// Prepare
|
||||
auto context = params.GPUContext;
|
||||
auto& view = params.RenderContext.View;
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
const auto cb0 = _shader->GetCB(0);
|
||||
const bool hasCb0 = cb0->GetSize() != 0;
|
||||
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(PostFxMaterialShaderData) : nullptr;
|
||||
bindMeta.Input = params.Input;
|
||||
bindMeta.Buffers = params.RenderContext.Buffers;
|
||||
bindMeta.CanSampleDepth = true;
|
||||
bindMeta.CanSampleGBuffer = true;
|
||||
MaterialParams::Bind(params.ParamsLink, bindMeta);
|
||||
|
||||
// Setup material constants data
|
||||
if (hasCb0)
|
||||
{
|
||||
const auto materialData = reinterpret_cast<PostFxMaterialShaderData*>(_cb0Data.Get());
|
||||
|
||||
Matrix::Transpose(view.View, materialData->ViewMatrix);
|
||||
materialData->ViewPos = view.Position;
|
||||
materialData->ViewFar = view.Far;
|
||||
materialData->ViewDir = view.Direction;
|
||||
materialData->TimeParam = Time::Draw.UnscaledTime.GetTotalSeconds();
|
||||
materialData->ViewInfo = view.ViewInfo;
|
||||
materialData->ScreenSize = view.ScreenSize;
|
||||
materialData->TemporalAAJitter = view.TemporalAAJitter;
|
||||
}
|
||||
|
||||
// Bind constants
|
||||
if (hasCb0)
|
||||
{
|
||||
context->UpdateCB(cb0, _cb0Data.Get());
|
||||
context->BindCB(0, cb0);
|
||||
}
|
||||
|
||||
// Bind pipeline
|
||||
context->SetState(_cache.Default);
|
||||
}
|
||||
|
||||
void PostFxMaterialShader::Unload()
|
||||
{
|
||||
// Base
|
||||
MaterialShader::Unload();
|
||||
|
||||
_cache.Release();
|
||||
}
|
||||
|
||||
bool PostFxMaterialShader::Load()
|
||||
{
|
||||
// PostFx material uses 'PS_PostFx' pixel shader and default simple shared quad vertex shader
|
||||
GPUPipelineState::Description psDesc0 = GPUPipelineState::Description::DefaultFullscreenTriangle;
|
||||
psDesc0.VS = GPUDevice::Instance->QuadShader->GetVS("VS_PostFx");
|
||||
psDesc0.PS = _shader->GetPS("PS_PostFx");
|
||||
_cache.Default = GPUDevice::Instance->CreatePipelineState();
|
||||
if (_cache.Default->Init(psDesc0))
|
||||
{
|
||||
LOG(Warning, "Failed to create postFx material pipeline state.");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
49
Source/Engine/Graphics/Materials/PostFxMaterialShader.h
Normal file
49
Source/Engine/Graphics/Materials/PostFxMaterialShader.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MaterialShader.h"
|
||||
|
||||
/// <summary>
|
||||
/// Represents material that can be used to render post-process effects.
|
||||
/// </summary>
|
||||
class PostFxMaterialShader : public MaterialShader
|
||||
{
|
||||
private:
|
||||
|
||||
struct Cache
|
||||
{
|
||||
GPUPipelineState* Default = nullptr;
|
||||
|
||||
FORCE_INLINE void Release()
|
||||
{
|
||||
SAFE_DELETE_GPU_RESOURCE(Default);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Cache _cache;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="name">Material resource name</param>
|
||||
PostFxMaterialShader(const String& name)
|
||||
: MaterialShader(name)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [MaterialShader]
|
||||
void Bind(BindParameters& params) override;
|
||||
void Unload() override;
|
||||
|
||||
protected:
|
||||
|
||||
// [MaterialShader]
|
||||
bool Load() override;
|
||||
};
|
||||
220
Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp
Normal file
220
Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "TerrainMaterialShader.h"
|
||||
#include "MaterialParams.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Graphics/GPUContext.h"
|
||||
#include "Engine/Graphics/GPULimits.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||
#include "Engine/Graphics/RenderBuffers.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Graphics/RenderView.h"
|
||||
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
|
||||
#include "Engine/Level/Scene/Lightmap.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
#include "Engine/Terrain/TerrainPatch.h"
|
||||
|
||||
PACK_STRUCT(struct TerrainMaterialShaderData {
|
||||
Matrix ViewProjectionMatrix;
|
||||
Matrix WorldMatrix;
|
||||
Matrix ViewMatrix;
|
||||
Vector3 ViewPos;
|
||||
float ViewFar;
|
||||
Vector3 ViewDir;
|
||||
float TimeParam;
|
||||
Vector4 ViewInfo;
|
||||
Vector4 ScreenSize;
|
||||
Rectangle LightmapArea;
|
||||
Vector3 WorldInvScale;
|
||||
float WorldDeterminantSign;
|
||||
float PerInstanceRandom;
|
||||
float CurrentLOD; // Index of the current LOD
|
||||
float ChunkSizeNextLOD; // ChunkSize for the next current LOD (after applying LOD down-scaling)
|
||||
float TerrainChunkSizeLOD0; // Size of the terrain chunk in world units of the top-most LOD0
|
||||
Vector4 HeightmapUVScaleBias; // xy-scale, zw-offset for chunk geometry UVs into heightmap UVs (as single MAD instruction)
|
||||
Vector4 NeighborLOD; // Per component LOD index for chunk neighbors ordered: top, left, right, bottom
|
||||
Vector2 OffsetUV; // Offset applied to the texture coordinates (used to implement seamless UVs based on chunk location relative to terrain root)
|
||||
Vector2 Dummy0;
|
||||
});
|
||||
|
||||
DrawPass TerrainMaterialShader::GetDrawModes() const
|
||||
{
|
||||
return DrawPass::Depth | DrawPass::GBuffer;
|
||||
}
|
||||
|
||||
bool TerrainMaterialShader::CanUseLightmap() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void TerrainMaterialShader::Bind(BindParameters& params)
|
||||
{
|
||||
// Prepare
|
||||
auto context = params.GPUContext;
|
||||
auto& view = params.RenderContext.View;
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
const auto cb0 = _shader->GetCB(0);
|
||||
const bool hasCb0 = cb0->GetSize() != 0;
|
||||
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(TerrainMaterialShaderData) : nullptr;
|
||||
bindMeta.Input = nullptr;
|
||||
bindMeta.Buffers = nullptr;
|
||||
bindMeta.CanSampleDepth = false;
|
||||
bindMeta.CanSampleGBuffer = false;
|
||||
MaterialParams::Bind(params.ParamsLink, bindMeta);
|
||||
|
||||
// Setup material constants data
|
||||
auto data = reinterpret_cast<TerrainMaterialShaderData*>(_cb0Data.Get());
|
||||
if (hasCb0)
|
||||
{
|
||||
Matrix::Transpose(view.Frustum.GetMatrix(), data->ViewProjectionMatrix);
|
||||
Matrix::Transpose(drawCall.World, data->WorldMatrix);
|
||||
Matrix::Transpose(view.View, data->ViewMatrix);
|
||||
|
||||
data->ViewPos = view.Position;
|
||||
data->ViewFar = view.Far;
|
||||
data->ViewDir = view.Direction;
|
||||
data->TimeParam = Time::Draw.UnscaledTime.GetTotalSeconds();
|
||||
data->ViewInfo = view.ViewInfo;
|
||||
data->ScreenSize = view.ScreenSize;
|
||||
|
||||
// Extract per axis scales from LocalToWorld transform
|
||||
const float scaleX = Vector3(drawCall.World.M11, drawCall.World.M12, drawCall.World.M13).Length();
|
||||
const float scaleY = Vector3(drawCall.World.M21, drawCall.World.M22, drawCall.World.M23).Length();
|
||||
const float scaleZ = Vector3(drawCall.World.M31, drawCall.World.M32, drawCall.World.M33).Length();
|
||||
data->WorldInvScale = Vector3(
|
||||
scaleX > 0.00001f ? 1.0f / scaleX : 0.0f,
|
||||
scaleY > 0.00001f ? 1.0f / scaleY : 0.0f,
|
||||
scaleZ > 0.00001f ? 1.0f / scaleZ : 0.0f);
|
||||
|
||||
data->WorldDeterminantSign = drawCall.WorldDeterminantSign;
|
||||
data->PerInstanceRandom = drawCall.PerInstanceRandom;
|
||||
data->CurrentLOD = drawCall.TerrainData.CurrentLOD;
|
||||
data->ChunkSizeNextLOD = drawCall.TerrainData.ChunkSizeNextLOD;
|
||||
data->TerrainChunkSizeLOD0 = drawCall.TerrainData.TerrainChunkSizeLOD0;
|
||||
data->HeightmapUVScaleBias = drawCall.TerrainData.HeightmapUVScaleBias;
|
||||
data->NeighborLOD = drawCall.TerrainData.NeighborLOD;
|
||||
data->OffsetUV = drawCall.TerrainData.OffsetUV;
|
||||
}
|
||||
const bool useLightmap = view.Flags & ViewFlags::GI
|
||||
#if USE_EDITOR
|
||||
&& EnableLightmapsUsage
|
||||
#endif
|
||||
&& view.Pass == DrawPass::GBuffer
|
||||
&& drawCall.Lightmap != nullptr;
|
||||
if (useLightmap)
|
||||
{
|
||||
// Bind lightmap textures
|
||||
GPUTexture *lightmap0, *lightmap1, *lightmap2;
|
||||
drawCall.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2);
|
||||
context->BindSR(0, lightmap0);
|
||||
context->BindSR(1, lightmap1);
|
||||
context->BindSR(2, lightmap2);
|
||||
|
||||
// Set lightmap data
|
||||
data->LightmapArea = drawCall.LightmapUVsArea;
|
||||
}
|
||||
|
||||
// Bind terrain textures
|
||||
const auto heightmap = drawCall.TerrainData.Patch->Heightmap.Get()->GetTexture();
|
||||
const auto splatmap0 = drawCall.TerrainData.Patch->Splatmap[0] ? drawCall.TerrainData.Patch->Splatmap[0]->GetTexture() : nullptr;
|
||||
const auto splatmap1 = drawCall.TerrainData.Patch->Splatmap[1] ? drawCall.TerrainData.Patch->Splatmap[1]->GetTexture() : nullptr;
|
||||
context->BindSR(3, heightmap);
|
||||
context->BindSR(4, splatmap0);
|
||||
context->BindSR(5, splatmap1);
|
||||
|
||||
// Bind constants
|
||||
if (hasCb0)
|
||||
{
|
||||
context->UpdateCB(cb0, _cb0Data.Get());
|
||||
context->BindCB(0, cb0);
|
||||
}
|
||||
|
||||
// Select pipeline state based on current pass and render mode
|
||||
const bool wireframe = (_info.FeaturesFlags & MaterialFeaturesFlags::Wireframe) != 0 || view.Mode == ViewMode::Wireframe;
|
||||
CullMode cullMode = view.Pass == DrawPass::Depth ? CullMode::TwoSided : _info.CullMode;
|
||||
#if USE_EDITOR
|
||||
if (IsRunningRadiancePass)
|
||||
cullMode = CullMode::TwoSided;
|
||||
#endif
|
||||
if (cullMode != CullMode::TwoSided && drawCall.IsNegativeScale())
|
||||
{
|
||||
// Invert culling when scale is negative
|
||||
if (cullMode == CullMode::Normal)
|
||||
cullMode = CullMode::Inverted;
|
||||
else
|
||||
cullMode = CullMode::Normal;
|
||||
}
|
||||
const PipelineStateCache* psCache = _cache.GetPS(view.Pass, useLightmap);
|
||||
ASSERT(psCache);
|
||||
GPUPipelineState* state = ((PipelineStateCache*)psCache)->GetPS(cullMode, wireframe);
|
||||
|
||||
// Bind pipeline
|
||||
context->SetState(state);
|
||||
}
|
||||
|
||||
void TerrainMaterialShader::Unload()
|
||||
{
|
||||
// Base
|
||||
MaterialShader::Unload();
|
||||
|
||||
_cache.Release();
|
||||
}
|
||||
|
||||
bool TerrainMaterialShader::Load()
|
||||
{
|
||||
GPUPipelineState::Description psDesc = GPUPipelineState::Description::Default;
|
||||
psDesc.DepthTestEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == 0;
|
||||
psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == 0;
|
||||
|
||||
// Check if use tessellation (both material and runtime supports it)
|
||||
const bool useTess = _info.TessellationMode != TessellationMethod::None && GPUDevice::Instance->Limits.HasTessellation;
|
||||
if (useTess)
|
||||
{
|
||||
psDesc.HS = _shader->GetHS("HS");
|
||||
psDesc.DS = _shader->GetDS("DS");
|
||||
}
|
||||
|
||||
// Support blending but then use only emissive channel
|
||||
switch (_info.BlendMode)
|
||||
{
|
||||
case MaterialBlendMode::Transparent:
|
||||
psDesc.BlendMode = BlendingMode::AlphaBlend;
|
||||
break;
|
||||
case MaterialBlendMode::Additive:
|
||||
psDesc.BlendMode = BlendingMode::Additive;
|
||||
break;
|
||||
case MaterialBlendMode::Multiply:
|
||||
psDesc.BlendMode = BlendingMode::Multiply;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
|
||||
// GBuffer Pass
|
||||
psDesc.VS = _shader->GetVS("VS");
|
||||
psDesc.PS = _shader->GetPS("PS_GBuffer");
|
||||
_cache.Default.Init(psDesc);
|
||||
|
||||
// GBuffer Pass with lightmap (use pixel shader permutation for USE_LIGHTMAP=1)
|
||||
psDesc.PS = _shader->GetPS("PS_GBuffer", 1);
|
||||
_cache.DefaultLightmap.Init(psDesc);
|
||||
|
||||
// Depth Pass
|
||||
psDesc.CullMode = CullMode::TwoSided;
|
||||
psDesc.BlendMode = BlendingMode::Opaque;
|
||||
psDesc.DepthClipEnable = false;
|
||||
psDesc.DepthWriteEnable = true;
|
||||
psDesc.DepthTestEnable = true;
|
||||
psDesc.DepthFunc = ComparisonFunc::Less;
|
||||
psDesc.HS = nullptr;
|
||||
psDesc.DS = nullptr;
|
||||
// TODO: masked terrain materials (depth pass should clip holes)
|
||||
psDesc.PS = nullptr;
|
||||
_cache.Depth.Init(psDesc);
|
||||
|
||||
return false;
|
||||
}
|
||||
68
Source/Engine/Graphics/Materials/TerrainMaterialShader.h
Normal file
68
Source/Engine/Graphics/Materials/TerrainMaterialShader.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MaterialShader.h"
|
||||
|
||||
/// <summary>
|
||||
/// Represents material that can be used to render terrain.
|
||||
/// </summary>
|
||||
class TerrainMaterialShader : public MaterialShader
|
||||
{
|
||||
private:
|
||||
|
||||
struct Cache
|
||||
{
|
||||
PipelineStateCache Default;
|
||||
PipelineStateCache DefaultLightmap;
|
||||
PipelineStateCache Depth;
|
||||
|
||||
FORCE_INLINE PipelineStateCache* GetPS(const DrawPass pass, const bool useLightmap)
|
||||
{
|
||||
switch (pass)
|
||||
{
|
||||
case DrawPass::Depth:
|
||||
return &Depth;
|
||||
case DrawPass::GBuffer:
|
||||
return useLightmap ? &DefaultLightmap : &Default;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE void Release()
|
||||
{
|
||||
Default.Release();
|
||||
DefaultLightmap.Release();
|
||||
Depth.Release();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Cache _cache;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="name">Material resource name</param>
|
||||
TerrainMaterialShader(const String& name)
|
||||
: MaterialShader(name)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [MaterialShader]
|
||||
DrawPass GetDrawModes() const override;
|
||||
bool CanUseLightmap() const override;
|
||||
void Bind(BindParameters& params) override;
|
||||
void Unload() override;
|
||||
|
||||
protected:
|
||||
|
||||
// [MaterialShader]
|
||||
bool Load() override;
|
||||
};
|
||||
Reference in New Issue
Block a user