Refactor material shaders generator to use modular features as extensions
This commit is contained in:
@@ -108,6 +108,8 @@ float4 GetVertexColor(MaterialInput input)
|
||||
return 1;
|
||||
}
|
||||
|
||||
@8
|
||||
|
||||
// Get material properties function (for pixel shader)
|
||||
Material GetMaterialPS(MaterialInput input)
|
||||
{
|
||||
@@ -211,3 +213,5 @@ void PS_Decal(
|
||||
#error "Invalid decal blending mode"
|
||||
#endif
|
||||
}
|
||||
|
||||
@9
|
||||
|
||||
53
Content/Editor/MaterialTemplates/Features/Lightmap.hlsl
Normal file
53
Content/Editor/MaterialTemplates/Features/Lightmap.hlsl
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Lightmap: Defines
|
||||
@1// Lightmap: Includes
|
||||
@2// Lightmap: Constants
|
||||
float4 LightmapArea;
|
||||
@3// Lightmap: Resources
|
||||
#if USE_LIGHTMAP
|
||||
// Irradiance and directionality prebaked lightmaps
|
||||
Texture2D Lightmap0 : register(t__SRV__);
|
||||
Texture2D Lightmap1 : register(t__SRV__);
|
||||
Texture2D Lightmap2 : register(t__SRV__);
|
||||
#endif
|
||||
@4// Lightmap: Utilities
|
||||
#if USE_LIGHTMAP
|
||||
|
||||
// Evaluates the H-Basis coefficients in the tangent space normal direction
|
||||
float3 GetHBasisIrradiance(float3 n, float3 h0, float3 h1, float3 h2, float3 h3)
|
||||
{
|
||||
// Band 0
|
||||
float3 color = h0 * (1.0f / sqrt(2.0f * PI));
|
||||
|
||||
// Band 1
|
||||
color += h1 * -sqrt(1.5f / PI) * n.y;
|
||||
color += h2 * sqrt(1.5f / PI) * (2 * n.z - 1.0f);
|
||||
color += h3 * -sqrt(1.5f / PI) * n.x;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
float3 SampleLightmap(Material material, MaterialInput materialInput)
|
||||
{
|
||||
// Sample lightmaps
|
||||
float4 lightmap0 = Lightmap0.Sample(SamplerLinearClamp, materialInput.LightmapUV);
|
||||
float4 lightmap1 = Lightmap1.Sample(SamplerLinearClamp, materialInput.LightmapUV);
|
||||
float4 lightmap2 = Lightmap2.Sample(SamplerLinearClamp, materialInput.LightmapUV);
|
||||
|
||||
// Unpack H-basis
|
||||
float3 h0 = float3(lightmap0.x, lightmap1.x, lightmap2.x);
|
||||
float3 h1 = float3(lightmap0.y, lightmap1.y, lightmap2.y);
|
||||
float3 h2 = float3(lightmap0.z, lightmap1.z, lightmap2.z);
|
||||
float3 h3 = float3(lightmap0.w, lightmap1.w, lightmap2.w);
|
||||
|
||||
// Sample baked diffuse irradiance from the H-basis coefficients
|
||||
float3 normal = material.TangentNormal;
|
||||
#if MATERIAL_SHADING_MODEL == SHADING_MODEL_FOLIAGE
|
||||
normal *= material.TangentNormal;
|
||||
#endif
|
||||
return GetHBasisIrradiance(normal, h0, h1, h2, h3) / PI;
|
||||
}
|
||||
|
||||
#endif
|
||||
@5// Lightmap: Shaders
|
||||
294
Content/Editor/MaterialTemplates/Features/Tessellation.hlsl
Normal file
294
Content/Editor/MaterialTemplates/Features/Tessellation.hlsl
Normal file
@@ -0,0 +1,294 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Tessellation: Defines
|
||||
@1// Tessellation: Includes
|
||||
@2// Tessellation: Constants
|
||||
@3// Tessellation: Resources
|
||||
@4// Tessellation: Utilities
|
||||
@5// Tessellation: Shaders
|
||||
#if USE_TESSELLATION
|
||||
|
||||
// Interpolants passed from the hull shader to the domain shader
|
||||
struct TessalationHSToDS
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float3 WorldPosition : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD1;
|
||||
float2 LightmapUV : TEXCOORD2;
|
||||
#if USE_VERTEX_COLOR
|
||||
half4 VertexColor : COLOR;
|
||||
#endif
|
||||
float3 WorldNormal : TEXCOORD3;
|
||||
float4 WorldTangent : TEXCOORD4;
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
|
||||
#endif
|
||||
float3 InstanceOrigin : TEXCOORD6;
|
||||
float2 InstanceParams : TEXCOORD7;
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
float3 PrevWorldPosition : TEXCOORD8;
|
||||
#endif
|
||||
float TessellationMultiplier : TESS;
|
||||
};
|
||||
|
||||
// Interpolants passed from the domain shader and to the pixel shader
|
||||
struct TessalationDSToPS
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float3 WorldPosition : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD1;
|
||||
float2 LightmapUV : TEXCOORD2;
|
||||
#if USE_VERTEX_COLOR
|
||||
half4 VertexColor : COLOR;
|
||||
#endif
|
||||
float3 WorldNormal : TEXCOORD3;
|
||||
float4 WorldTangent : TEXCOORD4;
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
|
||||
#endif
|
||||
float3 InstanceOrigin : TEXCOORD6;
|
||||
float2 InstanceParams : TEXCOORD7;
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
float3 PrevWorldPosition : TEXCOORD8;
|
||||
#endif
|
||||
};
|
||||
|
||||
MaterialInput GetMaterialInput(TessalationDSToPS input)
|
||||
{
|
||||
MaterialInput result = (MaterialInput)0;
|
||||
result.WorldPosition = input.WorldPosition;
|
||||
result.TexCoord = input.TexCoord;
|
||||
#if USE_LIGHTMAP
|
||||
result.LightmapUV = input.LightmapUV;
|
||||
#endif
|
||||
#if USE_VERTEX_COLOR
|
||||
result.VertexColor = input.VertexColor;
|
||||
#endif
|
||||
result.TBN = CalcTangentBasis(input.WorldNormal, input.WorldTangent);
|
||||
result.TwoSidedSign = WorldDeterminantSign;
|
||||
result.InstanceOrigin = input.InstanceOrigin;
|
||||
result.InstanceParams = input.InstanceParams;
|
||||
result.SvPosition = input.Position;
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
result.CustomVSToPS = input.CustomVSToPS;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
struct TessalationPatch
|
||||
{
|
||||
float EdgeTessFactor[3] : SV_TessFactor;
|
||||
float InsideTessFactor : SV_InsideTessFactor;
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
|
||||
float3 B210 : POSITION4;
|
||||
float3 B120 : POSITION5;
|
||||
float3 B021 : POSITION6;
|
||||
float3 B012 : POSITION7;
|
||||
float3 B102 : POSITION8;
|
||||
float3 B201 : POSITION9;
|
||||
float3 B111 : CENTER;
|
||||
#endif
|
||||
};
|
||||
|
||||
TessalationPatch HS_PatchConstant(InputPatch<VertexOutput, 3> input)
|
||||
{
|
||||
TessalationPatch output;
|
||||
|
||||
// Average tess factors along edges, and pick an edge tess factor for the interior tessellation
|
||||
float4 tessellationMultipliers;
|
||||
tessellationMultipliers.x = 0.5f * (input[1].TessellationMultiplier + input[2].TessellationMultiplier);
|
||||
tessellationMultipliers.y = 0.5f * (input[2].TessellationMultiplier + input[0].TessellationMultiplier);
|
||||
tessellationMultipliers.z = 0.5f * (input[0].TessellationMultiplier + input[1].TessellationMultiplier);
|
||||
tessellationMultipliers.w = 0.333f * (input[0].TessellationMultiplier + input[1].TessellationMultiplier + input[2].TessellationMultiplier);
|
||||
tessellationMultipliers = clamp(tessellationMultipliers, 1, MAX_TESSELLATION_FACTOR);
|
||||
|
||||
output.EdgeTessFactor[0] = tessellationMultipliers.x; // 1->2 edge
|
||||
output.EdgeTessFactor[1] = tessellationMultipliers.y; // 2->0 edge
|
||||
output.EdgeTessFactor[2] = tessellationMultipliers.z; // 0->1 edge
|
||||
output.InsideTessFactor = tessellationMultipliers.w;
|
||||
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
|
||||
// Calculate PN Triangle control points
|
||||
// Reference: [Vlachos 2001]
|
||||
float3 p1 = input[0].WorldPosition;
|
||||
float3 p2 = input[1].WorldPosition;
|
||||
float3 p3 = input[2].WorldPosition;
|
||||
float3 n1 = input[0].WorldNormal;
|
||||
float3 n2 = input[1].WorldNormal;
|
||||
float3 n3 = input[2].WorldNormal;
|
||||
output.B210 = (2.0f * p1 + p2 - dot((p2 - p1), n1) * n1) / 3.0f;
|
||||
output.B120 = (2.0f * p2 + p1 - dot((p1 - p2), n2) * n2) / 3.0f;
|
||||
output.B021 = (2.0f * p2 + p3 - dot((p3 - p2), n2) * n2) / 3.0f;
|
||||
output.B012 = (2.0f * p3 + p2 - dot((p2 - p3), n3) * n3) / 3.0f;
|
||||
output.B102 = (2.0f * p3 + p1 - dot((p1 - p3), n3) * n3) / 3.0f;
|
||||
output.B201 = (2.0f * p1 + p3 - dot((p3 - p1), n1) * n1) / 3.0f;
|
||||
float3 e = (output.B210 + output.B120 + output.B021 +
|
||||
output.B012 + output.B102 + output.B201) / 6.0f;
|
||||
float3 v = (p1 + p2 + p3) / 3.0f;
|
||||
output.B111 = e + ((e - v) / 2.0f);
|
||||
#endif
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
META_HS(USE_TESSELLATION, FEATURE_LEVEL_SM5)
|
||||
META_PERMUTATION_1(IS_MOTION_VECTORS_PASS=0)
|
||||
META_PERMUTATION_1(IS_MOTION_VECTORS_PASS=1)
|
||||
META_HS_PATCH(TESSELLATION_IN_CONTROL_POINTS)
|
||||
[domain("tri")]
|
||||
[partitioning("fractional_odd")]
|
||||
[outputtopology("triangle_cw")]
|
||||
[maxtessfactor(MAX_TESSELLATION_FACTOR)]
|
||||
[outputcontrolpoints(3)]
|
||||
[patchconstantfunc("HS_PatchConstant")]
|
||||
TessalationHSToDS HS(InputPatch<VertexOutput, TESSELLATION_IN_CONTROL_POINTS> input, uint ControlPointID : SV_OutputControlPointID)
|
||||
{
|
||||
TessalationHSToDS output;
|
||||
|
||||
// Pass through shader
|
||||
#define COPY(thing) output.thing = input[ControlPointID].thing;
|
||||
COPY(Position);
|
||||
COPY(WorldPosition);
|
||||
COPY(TexCoord);
|
||||
COPY(LightmapUV);
|
||||
#if USE_VERTEX_COLOR
|
||||
COPY(VertexColor);
|
||||
#endif
|
||||
COPY(WorldNormal);
|
||||
COPY(WorldTangent);
|
||||
COPY(InstanceOrigin);
|
||||
COPY(InstanceParams);
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
COPY(PrevWorldPosition);
|
||||
#endif
|
||||
COPY(TessellationMultiplier);
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
COPY(CustomVSToPS);
|
||||
#endif
|
||||
#undef COPY
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PHONG
|
||||
|
||||
// Orthogonal projection on to plane
|
||||
float3 ProjectOntoPlane(float3 planeNormal, float3 planePosition, float3 pointToProject)
|
||||
{
|
||||
return pointToProject - dot(pointToProject - planePosition, planeNormal) * planeNormal;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
META_DS(USE_TESSELLATION, FEATURE_LEVEL_SM5)
|
||||
META_PERMUTATION_1(IS_MOTION_VECTORS_PASS=0)
|
||||
META_PERMUTATION_1(IS_MOTION_VECTORS_PASS=1)
|
||||
[domain("tri")]
|
||||
TessalationDSToPS DS(TessalationPatch constantData, float3 barycentricCoords : SV_DomainLocation, const OutputPatch<TessalationHSToDS, 3> input)
|
||||
{
|
||||
TessalationDSToPS output;
|
||||
|
||||
// Get the barycentric coords
|
||||
float U = barycentricCoords.x;
|
||||
float V = barycentricCoords.y;
|
||||
float W = barycentricCoords.z;
|
||||
|
||||
// Interpolate patch attributes to generated vertices
|
||||
#define INTERPOLATE(thing) output.thing = U * input[0].thing + V * input[1].thing + W * input[2].thing
|
||||
#define COPY(thing) output.thing = input[0].thing
|
||||
INTERPOLATE(Position);
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
|
||||
float UU = U * U;
|
||||
float VV = V * V;
|
||||
float WW = W * W;
|
||||
float UU3 = UU * 3.0f;
|
||||
float VV3 = VV * 3.0f;
|
||||
float WW3 = WW * 3.0f;
|
||||
|
||||
// Interpolate using barycentric coordinates and PN Triangle control points
|
||||
output.WorldPosition =
|
||||
input[0].WorldPosition * UU * U +
|
||||
input[1].WorldPosition * VV * V +
|
||||
input[2].WorldPosition * WW * W +
|
||||
constantData.B210 * UU3 * V +
|
||||
constantData.B120 * VV3 * U +
|
||||
constantData.B021 * VV3 * W +
|
||||
constantData.B012 * WW3 * V +
|
||||
constantData.B102 * WW3 * U +
|
||||
constantData.B201 * UU3 * W +
|
||||
constantData.B111 * 6.0f * W * U * V;
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
output.PrevWorldPosition =
|
||||
input[0].PrevWorldPosition * UU * U +
|
||||
input[1].PrevWorldPosition * VV * V +
|
||||
input[2].PrevWorldPosition * WW * W +
|
||||
constantData.B210 * UU3 * V +
|
||||
constantData.B120 * VV3 * U +
|
||||
constantData.B021 * VV3 * W +
|
||||
constantData.B012 * WW3 * V +
|
||||
constantData.B102 * WW3 * U +
|
||||
constantData.B201 * UU3 * W +
|
||||
constantData.B111 * 6.0f * W * U * V;
|
||||
#endif
|
||||
#else
|
||||
INTERPOLATE(WorldPosition);
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
INTERPOLATE(PrevWorldPosition);
|
||||
#endif
|
||||
#endif
|
||||
INTERPOLATE(TexCoord);
|
||||
INTERPOLATE(LightmapUV);
|
||||
#if USE_VERTEX_COLOR
|
||||
INTERPOLATE(VertexColor);
|
||||
#endif
|
||||
INTERPOLATE(WorldNormal);
|
||||
INTERPOLATE(WorldTangent);
|
||||
COPY(InstanceOrigin);
|
||||
COPY(InstanceParams);
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
UNROLL
|
||||
for (int i = 0; i < CUSTOM_VERTEX_INTERPOLATORS_COUNT; i++)
|
||||
{
|
||||
INTERPOLATE(CustomVSToPS[i]);
|
||||
}
|
||||
#endif
|
||||
#undef INTERPOLATE
|
||||
#undef COPY
|
||||
|
||||
// Interpolating tangents can unnormalize it, so normalize it
|
||||
output.WorldNormal = normalize(output.WorldNormal);
|
||||
output.WorldTangent.xyz = normalize(output.WorldTangent.xyz);
|
||||
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PHONG
|
||||
// Orthogonal projection in the tangent planes
|
||||
float3 posProjectedU = ProjectOntoPlane(input[0].WorldNormal, input[0].WorldPosition, output.WorldPosition);
|
||||
float3 posProjectedV = ProjectOntoPlane(input[1].WorldNormal, input[1].WorldPosition, output.WorldPosition);
|
||||
float3 posProjectedW = ProjectOntoPlane(input[2].WorldNormal, input[2].WorldPosition, output.WorldPosition);
|
||||
|
||||
// Interpolate the projected points
|
||||
output.WorldPosition = U * posProjectedU + V * posProjectedV + W * posProjectedW;
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
posProjectedU = ProjectOntoPlane(input[0].WorldNormal, input[0].PrevWorldPosition, output.PrevWorldPosition);
|
||||
posProjectedV = ProjectOntoPlane(input[1].WorldNormal, input[1].PrevWorldPosition, output.PrevWorldPosition);
|
||||
posProjectedW = ProjectOntoPlane(input[2].WorldNormal, input[2].PrevWorldPosition, output.PrevWorldPosition);
|
||||
output.PrevWorldPosition = U * posProjectedU + V * posProjectedV + W * posProjectedW;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Perform displacement mapping
|
||||
#if USE_DISPLACEMENT
|
||||
MaterialInput materialInput = GetMaterialInput(output);
|
||||
Material material = GetMaterialDS(materialInput);
|
||||
output.WorldPosition += material.WorldDisplacement;
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
output.PrevWorldPosition += material.WorldDisplacement;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Recalculate the clip space position
|
||||
output.Position = mul(float4(output.WorldPosition, 1), ViewProjectionMatrix);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -185,6 +185,8 @@ float4 GetVertexColor(MaterialInput input)
|
||||
#endif
|
||||
}
|
||||
|
||||
@8
|
||||
|
||||
// Get material properties function (for vertex shader)
|
||||
Material GetMaterialVS(MaterialInput input)
|
||||
{
|
||||
@@ -257,3 +259,5 @@ float4 PS_GUI(PixelInput input) : SV_Target0
|
||||
|
||||
return float4(material.Emissive, material.Opacity);
|
||||
}
|
||||
|
||||
@9
|
||||
|
||||
@@ -312,6 +312,8 @@ float3 TransformParticleVector(float3 input)
|
||||
return mul(float4(input, 0.0f), WorldMatrixInverseTransposed).xyz;
|
||||
}
|
||||
|
||||
@8
|
||||
|
||||
// Get material properties function (for vertex shader)
|
||||
Material GetMaterialVS(MaterialInput input)
|
||||
{
|
||||
@@ -865,3 +867,5 @@ void PS_Depth(PixelInput input
|
||||
OutColor = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@9
|
||||
|
||||
@@ -128,6 +128,8 @@ float4 GetVertexColor(MaterialInput input)
|
||||
return 1;
|
||||
}
|
||||
|
||||
@8
|
||||
|
||||
// Get material properties function (for pixel shader)
|
||||
Material GetMaterialPS(MaterialInput input)
|
||||
{
|
||||
@@ -147,3 +149,5 @@ float4 PS_PostFx(PixelInput input) : SV_Target0
|
||||
|
||||
return float4(material.Emissive, material.Opacity);
|
||||
}
|
||||
|
||||
@9
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#define MATERIAL 1
|
||||
@3
|
||||
|
||||
#include "./Flax/Common.hlsl"
|
||||
#include "./Flax/MaterialCommon.hlsl"
|
||||
#include "./Flax/GBufferCommon.hlsl"
|
||||
@@ -21,7 +20,6 @@ float3 ViewDir;
|
||||
float TimeParam;
|
||||
float4 ViewInfo;
|
||||
float4 ScreenSize;
|
||||
float4 LightmapArea;
|
||||
float3 WorldInvScale;
|
||||
float WorldDeterminantSign;
|
||||
float2 Dummy0;
|
||||
@@ -32,18 +30,8 @@ float3 GeometrySize;
|
||||
float Dummy1;
|
||||
@1META_CB_END
|
||||
|
||||
#if CAN_USE_LIGHTMAP
|
||||
|
||||
// Irradiance and directionality prebaked lightmaps
|
||||
Texture2D Lightmap0 : register(t0);
|
||||
Texture2D Lightmap1 : register(t1);
|
||||
Texture2D Lightmap2 : register(t2);
|
||||
|
||||
#endif
|
||||
|
||||
// Material shader resources
|
||||
@2
|
||||
|
||||
// Interpolants passed from the vertex shader
|
||||
struct VertexOutput
|
||||
{
|
||||
@@ -322,6 +310,8 @@ float4 GetVertexColor(MaterialInput input)
|
||||
#endif
|
||||
}
|
||||
|
||||
@8
|
||||
|
||||
// Get material properties function (for vertex shader)
|
||||
Material GetMaterialVS(MaterialInput input)
|
||||
{
|
||||
@@ -613,320 +603,6 @@ VertexOutput VS_Skinned(ModelInput_Skinned input)
|
||||
|
||||
#endif
|
||||
|
||||
#if USE_TESSELLATION
|
||||
|
||||
// Interpolants passed from the hull shader to the domain shader
|
||||
struct TessalationHSToDS
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float3 WorldPosition : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD1;
|
||||
float2 LightmapUV : TEXCOORD2;
|
||||
#if USE_VERTEX_COLOR
|
||||
half4 VertexColor : COLOR;
|
||||
#endif
|
||||
float3 WorldNormal : TEXCOORD3;
|
||||
float4 WorldTangent : TEXCOORD4;
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
|
||||
#endif
|
||||
float3 InstanceOrigin : TEXCOORD6;
|
||||
float2 InstanceParams : TEXCOORD7;
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
float3 PrevWorldPosition : TEXCOORD8;
|
||||
#endif
|
||||
float TessellationMultiplier : TESS;
|
||||
};
|
||||
|
||||
// Interpolants passed from the domain shader and to the pixel shader
|
||||
struct TessalationDSToPS
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float3 WorldPosition : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD1;
|
||||
float2 LightmapUV : TEXCOORD2;
|
||||
#if USE_VERTEX_COLOR
|
||||
half4 VertexColor : COLOR;
|
||||
#endif
|
||||
float3 WorldNormal : TEXCOORD3;
|
||||
float4 WorldTangent : TEXCOORD4;
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
|
||||
#endif
|
||||
float3 InstanceOrigin : TEXCOORD6;
|
||||
float2 InstanceParams : TEXCOORD7;
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
float3 PrevWorldPosition : TEXCOORD8;
|
||||
#endif
|
||||
};
|
||||
|
||||
MaterialInput GetMaterialInput(TessalationDSToPS input)
|
||||
{
|
||||
MaterialInput result = (MaterialInput)0;
|
||||
result.WorldPosition = input.WorldPosition;
|
||||
result.TexCoord = input.TexCoord;
|
||||
#if USE_LIGHTMAP
|
||||
result.LightmapUV = input.LightmapUV;
|
||||
#endif
|
||||
#if USE_VERTEX_COLOR
|
||||
result.VertexColor = input.VertexColor;
|
||||
#endif
|
||||
result.TBN = CalcTangentBasis(input.WorldNormal, input.WorldTangent);
|
||||
result.TwoSidedSign = WorldDeterminantSign;
|
||||
result.InstanceOrigin = input.InstanceOrigin;
|
||||
result.InstanceParams = input.InstanceParams;
|
||||
result.SvPosition = input.Position;
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
result.CustomVSToPS = input.CustomVSToPS;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
struct TessalationPatch
|
||||
{
|
||||
float EdgeTessFactor[3] : SV_TessFactor;
|
||||
float InsideTessFactor : SV_InsideTessFactor;
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
|
||||
float3 B210 : POSITION4;
|
||||
float3 B120 : POSITION5;
|
||||
float3 B021 : POSITION6;
|
||||
float3 B012 : POSITION7;
|
||||
float3 B102 : POSITION8;
|
||||
float3 B201 : POSITION9;
|
||||
float3 B111 : CENTER;
|
||||
#endif
|
||||
};
|
||||
|
||||
TessalationPatch HS_PatchConstant(InputPatch<VertexOutput, 3> input)
|
||||
{
|
||||
TessalationPatch output;
|
||||
|
||||
// Average tess factors along edges, and pick an edge tess factor for the interior tessellation
|
||||
float4 tessellationMultipliers;
|
||||
tessellationMultipliers.x = 0.5f * (input[1].TessellationMultiplier + input[2].TessellationMultiplier);
|
||||
tessellationMultipliers.y = 0.5f * (input[2].TessellationMultiplier + input[0].TessellationMultiplier);
|
||||
tessellationMultipliers.z = 0.5f * (input[0].TessellationMultiplier + input[1].TessellationMultiplier);
|
||||
tessellationMultipliers.w = 0.333f * (input[0].TessellationMultiplier + input[1].TessellationMultiplier + input[2].TessellationMultiplier);
|
||||
tessellationMultipliers = clamp(tessellationMultipliers, 1, MAX_TESSELLATION_FACTOR);
|
||||
|
||||
output.EdgeTessFactor[0] = tessellationMultipliers.x; // 1->2 edge
|
||||
output.EdgeTessFactor[1] = tessellationMultipliers.y; // 2->0 edge
|
||||
output.EdgeTessFactor[2] = tessellationMultipliers.z; // 0->1 edge
|
||||
output.InsideTessFactor = tessellationMultipliers.w;
|
||||
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
|
||||
// Calculate PN-Triangle coefficients
|
||||
// Refer to Vlachos 2001 for the original formula
|
||||
float3 p1 = input[0].WorldPosition;
|
||||
float3 p2 = input[1].WorldPosition;
|
||||
float3 p3 = input[2].WorldPosition;
|
||||
float3 n1 = input[0].WorldNormal;
|
||||
float3 n2 = input[1].WorldNormal;
|
||||
float3 n3 = input[2].WorldNormal;
|
||||
|
||||
// Calculate control points
|
||||
output.B210 = (2.0f * p1 + p2 - dot((p2 - p1), n1) * n1) / 3.0f;
|
||||
output.B120 = (2.0f * p2 + p1 - dot((p1 - p2), n2) * n2) / 3.0f;
|
||||
output.B021 = (2.0f * p2 + p3 - dot((p3 - p2), n2) * n2) / 3.0f;
|
||||
output.B012 = (2.0f * p3 + p2 - dot((p2 - p3), n3) * n3) / 3.0f;
|
||||
output.B102 = (2.0f * p3 + p1 - dot((p1 - p3), n3) * n3) / 3.0f;
|
||||
output.B201 = (2.0f * p1 + p3 - dot((p3 - p1), n1) * n1) / 3.0f;
|
||||
float3 e = (output.B210 + output.B120 + output.B021 +
|
||||
output.B012 + output.B102 + output.B201) / 6.0f;
|
||||
float3 v = (p1 + p2 + p3) / 3.0f;
|
||||
output.B111 = e + ((e - v) / 2.0f);
|
||||
#endif
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
META_HS(USE_TESSELLATION, FEATURE_LEVEL_SM5)
|
||||
META_PERMUTATION_1(IS_MOTION_VECTORS_PASS=0)
|
||||
META_PERMUTATION_1(IS_MOTION_VECTORS_PASS=1)
|
||||
META_HS_PATCH(TESSELLATION_IN_CONTROL_POINTS)
|
||||
[domain("tri")]
|
||||
[partitioning("fractional_odd")]
|
||||
[outputtopology("triangle_cw")]
|
||||
[maxtessfactor(MAX_TESSELLATION_FACTOR)]
|
||||
[outputcontrolpoints(3)]
|
||||
[patchconstantfunc("HS_PatchConstant")]
|
||||
TessalationHSToDS HS(InputPatch<VertexOutput, TESSELLATION_IN_CONTROL_POINTS> input, uint ControlPointID : SV_OutputControlPointID)
|
||||
{
|
||||
TessalationHSToDS output;
|
||||
|
||||
// Pass through shader
|
||||
#define COPY(thing) output.thing = input[ControlPointID].thing;
|
||||
COPY(Position);
|
||||
COPY(WorldPosition);
|
||||
COPY(TexCoord);
|
||||
COPY(LightmapUV);
|
||||
#if USE_VERTEX_COLOR
|
||||
COPY(VertexColor);
|
||||
#endif
|
||||
COPY(WorldNormal);
|
||||
COPY(WorldTangent);
|
||||
COPY(InstanceOrigin);
|
||||
COPY(InstanceParams);
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
COPY(PrevWorldPosition);
|
||||
#endif
|
||||
COPY(TessellationMultiplier);
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
COPY(CustomVSToPS);
|
||||
#endif
|
||||
#undef COPY
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PHONG
|
||||
|
||||
// Orthogonal projection on to plane
|
||||
float3 ProjectOntoPlane(float3 planeNormal, float3 planePoint, float3 pointToProject)
|
||||
{
|
||||
return pointToProject - dot(pointToProject-planePoint, planeNormal) * planeNormal;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
META_DS(USE_TESSELLATION, FEATURE_LEVEL_SM5)
|
||||
META_PERMUTATION_1(IS_MOTION_VECTORS_PASS=0)
|
||||
META_PERMUTATION_1(IS_MOTION_VECTORS_PASS=1)
|
||||
[domain("tri")]
|
||||
TessalationDSToPS DS(TessalationPatch constantData, float3 barycentricCoords : SV_DomainLocation, const OutputPatch<TessalationHSToDS, 3> input)
|
||||
{
|
||||
TessalationDSToPS output;
|
||||
|
||||
// Get the barycentric coords
|
||||
float U = barycentricCoords.x;
|
||||
float V = barycentricCoords.y;
|
||||
float W = barycentricCoords.z;
|
||||
|
||||
// Interpolate patch attributes to generated vertices
|
||||
#define INTERPOLATE(thing) output.thing = U * input[0].thing + V * input[1].thing + W * input[2].thing
|
||||
#define COPY(thing) output.thing = input[0].thing
|
||||
INTERPOLATE(Position);
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
|
||||
float UU = U * U;
|
||||
float VV = V * V;
|
||||
float WW = W * W;
|
||||
float UU3 = UU * 3.0f;
|
||||
float VV3 = VV * 3.0f;
|
||||
float WW3 = WW * 3.0f;
|
||||
|
||||
// Interpolate using barycentric coordinates and PN Triangle control points
|
||||
output.WorldPosition =
|
||||
input[0].WorldPosition * UU * U +
|
||||
input[1].WorldPosition * VV * V +
|
||||
input[2].WorldPosition * WW * W +
|
||||
constantData.B210 * UU3 * V +
|
||||
constantData.B120 * VV3 * U +
|
||||
constantData.B021 * VV3 * W +
|
||||
constantData.B012 * WW3 * V +
|
||||
constantData.B102 * WW3 * U +
|
||||
constantData.B201 * UU3 * W +
|
||||
constantData.B111 * 6.0f * W * U * V;
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
output.PrevWorldPosition =
|
||||
input[0].PrevWorldPosition * UU * U +
|
||||
input[1].PrevWorldPosition * VV * V +
|
||||
input[2].PrevWorldPosition * WW * W +
|
||||
constantData.B210 * UU3 * V +
|
||||
constantData.B120 * VV3 * U +
|
||||
constantData.B021 * VV3 * W +
|
||||
constantData.B012 * WW3 * V +
|
||||
constantData.B102 * WW3 * U +
|
||||
constantData.B201 * UU3 * W +
|
||||
constantData.B111 * 6.0f * W * U * V;
|
||||
#endif
|
||||
#else
|
||||
INTERPOLATE(WorldPosition);
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
INTERPOLATE(PrevWorldPosition);
|
||||
#endif
|
||||
#endif
|
||||
INTERPOLATE(TexCoord);
|
||||
INTERPOLATE(LightmapUV);
|
||||
#if USE_VERTEX_COLOR
|
||||
INTERPOLATE(VertexColor);
|
||||
#endif
|
||||
INTERPOLATE(WorldNormal);
|
||||
INTERPOLATE(WorldTangent);
|
||||
COPY(InstanceOrigin);
|
||||
COPY(InstanceParams);
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
UNROLL
|
||||
for (int i = 0; i < CUSTOM_VERTEX_INTERPOLATORS_COUNT; i++)
|
||||
{
|
||||
INTERPOLATE(CustomVSToPS[i]);
|
||||
}
|
||||
#endif
|
||||
#undef INTERPOLATE
|
||||
#undef COPY
|
||||
|
||||
// Interpolating tangents can unnormalize it, so normalize it
|
||||
output.WorldNormal = normalize(output.WorldNormal);
|
||||
output.WorldTangent.xyz = normalize(output.WorldTangent.xyz);
|
||||
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PHONG
|
||||
// Orthogonal projection in the tangent planes
|
||||
float3 posProjectedU = ProjectOntoPlane(input[0].WorldNormal, input[0].WorldPosition, output.WorldPosition);
|
||||
float3 posProjectedV = ProjectOntoPlane(input[1].WorldNormal, input[1].WorldPosition, output.WorldPosition);
|
||||
float3 posProjectedW = ProjectOntoPlane(input[2].WorldNormal, input[2].WorldPosition, output.WorldPosition);
|
||||
|
||||
// Interpolate the projected points
|
||||
output.WorldPosition = U * posProjectedU + V * posProjectedV + W * posProjectedW;
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
posProjectedU = ProjectOntoPlane(input[0].WorldNormal, input[0].PrevWorldPosition, output.PrevWorldPosition);
|
||||
posProjectedV = ProjectOntoPlane(input[1].WorldNormal, input[1].PrevWorldPosition, output.PrevWorldPosition);
|
||||
posProjectedW = ProjectOntoPlane(input[2].WorldNormal, input[2].PrevWorldPosition, output.PrevWorldPosition);
|
||||
output.PrevWorldPosition = U * posProjectedU + V * posProjectedV + W * posProjectedW;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Perform displacement mapping
|
||||
#if USE_DISPLACEMENT
|
||||
MaterialInput materialInput = GetMaterialInput(output);
|
||||
Material material = GetMaterialDS(materialInput);
|
||||
output.WorldPosition += material.WorldDisplacement;
|
||||
#if IS_MOTION_VECTORS_PASS
|
||||
output.PrevWorldPosition += material.WorldDisplacement;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Recalculate the clip space position
|
||||
output.Position = mul(float4(output.WorldPosition, 1), ViewProjectionMatrix);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if USE_LIGHTMAP
|
||||
|
||||
float3 SampleLightmap(Material material, MaterialInput materialInput)
|
||||
{
|
||||
// Sample lightmaps
|
||||
float4 lightmap0 = Lightmap0.Sample(SamplerLinearClamp, materialInput.LightmapUV);
|
||||
float4 lightmap1 = Lightmap1.Sample(SamplerLinearClamp, materialInput.LightmapUV);
|
||||
float4 lightmap2 = Lightmap2.Sample(SamplerLinearClamp, materialInput.LightmapUV);
|
||||
|
||||
// Unpack H-basis
|
||||
float3 h0 = float3(lightmap0.x, lightmap1.x, lightmap2.x);
|
||||
float3 h1 = float3(lightmap0.y, lightmap1.y, lightmap2.y);
|
||||
float3 h2 = float3(lightmap0.z, lightmap1.z, lightmap2.z);
|
||||
float3 h3 = float3(lightmap0.w, lightmap1.w, lightmap2.w);
|
||||
|
||||
// Sample baked diffuse irradiance from the H-basis coefficients
|
||||
float3 normal = material.TangentNormal;
|
||||
#if MATERIAL_SHADING_MODEL == SHADING_MODEL_FOLIAGE
|
||||
normal *= material.TangentNormal;
|
||||
#endif
|
||||
return GetHBasisIrradiance(normal, h0, h1, h2, h3) / PI;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if USE_DITHERED_LOD_TRANSITION
|
||||
|
||||
void ClipLODTransition(PixelInput input)
|
||||
@@ -1081,3 +757,5 @@ float4 PS_MotionVectors(PixelInput input) : SV_Target0
|
||||
return float4(0, 0, 0, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
@9
|
||||
|
||||
@@ -29,7 +29,6 @@ float3 ViewDir;
|
||||
float TimeParam;
|
||||
float4 ViewInfo;
|
||||
float4 ScreenSize;
|
||||
float4 LightmapArea;
|
||||
float3 WorldInvScale;
|
||||
float WorldDeterminantSign;
|
||||
float2 Dummy0;
|
||||
@@ -319,6 +318,8 @@ float4 GetVertexColor(MaterialInput input)
|
||||
#endif
|
||||
}
|
||||
|
||||
@8
|
||||
|
||||
// Get material properties function (for vertex shader)
|
||||
Material GetMaterialVS(MaterialInput input)
|
||||
{
|
||||
@@ -387,12 +388,11 @@ VertexOutput VS(ModelInput input)
|
||||
#if USE_VERTEX_COLOR
|
||||
output.VertexColor = input.Color;
|
||||
#endif
|
||||
output.LightmapUV = input.LightmapUV;
|
||||
#if USE_INSTANCING
|
||||
output.LightmapUV = input.LightmapUV * input.InstanceLightmapArea.zw + input.InstanceLightmapArea.xy;
|
||||
output.InstanceOrigin = world[3].xyz;
|
||||
output.InstanceParams = float2(input.InstanceOrigin.w, input.InstanceTransform1.w);
|
||||
#else
|
||||
output.LightmapUV = input.LightmapUV * LightmapArea.zw + LightmapArea.xy;
|
||||
output.InstanceOrigin = WorldMatrix[3].xyz;
|
||||
output.InstanceParams = float2(PerInstanceRandom, LODDitherFactor);
|
||||
#endif
|
||||
@@ -576,256 +576,6 @@ VertexOutput VS_Skinned(ModelInput_Skinned input)
|
||||
|
||||
#endif
|
||||
|
||||
#if USE_TESSELLATION
|
||||
|
||||
// Interpolants passed from the hull shader to the domain shader
|
||||
struct TessalationHSToDS
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float3 WorldPosition : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD1;
|
||||
float2 LightmapUV : TEXCOORD2;
|
||||
#if USE_VERTEX_COLOR
|
||||
half4 VertexColor : COLOR;
|
||||
#endif
|
||||
float3x3 TBN : TEXCOORD3;
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
|
||||
#endif
|
||||
float3 InstanceOrigin : TEXCOORD6;
|
||||
float2 InstanceParams : TEXCOORD7;
|
||||
float TessellationMultiplier : TESS;
|
||||
};
|
||||
|
||||
// Interpolants passed from the domain shader and to the pixel shader
|
||||
struct TessalationDSToPS
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float3 WorldPosition : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD1;
|
||||
float2 LightmapUV : TEXCOORD2;
|
||||
#if USE_VERTEX_COLOR
|
||||
half4 VertexColor : COLOR;
|
||||
#endif
|
||||
float3x3 TBN : TEXCOORD3;
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
|
||||
#endif
|
||||
float3 InstanceOrigin : TEXCOORD6;
|
||||
float2 InstanceParams : TEXCOORD7;
|
||||
};
|
||||
|
||||
MaterialInput GetMaterialInput(TessalationDSToPS input)
|
||||
{
|
||||
MaterialInput result = (MaterialInput)0;
|
||||
result.WorldPosition = input.WorldPosition;
|
||||
result.TexCoord = input.TexCoord;
|
||||
#if USE_LIGHTMAP
|
||||
result.LightmapUV = input.LightmapUV;
|
||||
#endif
|
||||
#if USE_VERTEX_COLOR
|
||||
result.VertexColor = input.VertexColor;
|
||||
#endif
|
||||
result.TBN = input.TBN;
|
||||
result.TwoSidedSign = WorldDeterminantSign;
|
||||
result.InstanceOrigin = input.InstanceOrigin;
|
||||
result.InstanceParams = input.InstanceParams;
|
||||
result.SvPosition = input.Position;
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
result.CustomVSToPS = input.CustomVSToPS;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
struct TessalationPatch
|
||||
{
|
||||
float EdgeTessFactor[3] : SV_TessFactor;
|
||||
float InsideTessFactor : SV_InsideTessFactor;
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
|
||||
float3 B210 : POSITION4;
|
||||
float3 B120 : POSITION5;
|
||||
float3 B021 : POSITION6;
|
||||
float3 B012 : POSITION7;
|
||||
float3 B102 : POSITION8;
|
||||
float3 B201 : POSITION9;
|
||||
float3 B111 : CENTER;
|
||||
#endif
|
||||
};
|
||||
|
||||
TessalationPatch HS_PatchConstant(InputPatch<VertexOutput, 3> input)
|
||||
{
|
||||
TessalationPatch output;
|
||||
|
||||
// Average tess factors along edges, and pick an edge tess factor for the interior tessellation
|
||||
float4 tessellationMultipliers;
|
||||
tessellationMultipliers.x = 0.5f * (input[1].TessellationMultiplier + input[2].TessellationMultiplier);
|
||||
tessellationMultipliers.y = 0.5f * (input[2].TessellationMultiplier + input[0].TessellationMultiplier);
|
||||
tessellationMultipliers.z = 0.5f * (input[0].TessellationMultiplier + input[1].TessellationMultiplier);
|
||||
tessellationMultipliers.w = 0.333f * (input[0].TessellationMultiplier + input[1].TessellationMultiplier + input[2].TessellationMultiplier);
|
||||
tessellationMultipliers = clamp(tessellationMultipliers, 1, MAX_TESSELLATION_FACTOR);
|
||||
|
||||
output.EdgeTessFactor[0] = tessellationMultipliers.x; // 1->2 edge
|
||||
output.EdgeTessFactor[1] = tessellationMultipliers.y; // 2->0 edge
|
||||
output.EdgeTessFactor[2] = tessellationMultipliers.z; // 0->1 edge
|
||||
output.InsideTessFactor = tessellationMultipliers.w;
|
||||
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
|
||||
// Calculate PN-Triangle coefficients
|
||||
// Refer to Vlachos 2001 for the original formula
|
||||
float3 p1 = input[0].WorldPosition;
|
||||
float3 p2 = input[1].WorldPosition;
|
||||
float3 p3 = input[2].WorldPosition;
|
||||
float3 n1 = input[0].TBN[2];
|
||||
float3 n2 = input[1].TBN[2];
|
||||
float3 n3 = input[2].TBN[2];
|
||||
|
||||
// Calculate control points
|
||||
output.B210 = (2.0f * p1 + p2 - dot((p2 - p1), n1) * n1) / 3.0f;
|
||||
output.B120 = (2.0f * p2 + p1 - dot((p1 - p2), n2) * n2) / 3.0f;
|
||||
output.B021 = (2.0f * p2 + p3 - dot((p3 - p2), n2) * n2) / 3.0f;
|
||||
output.B012 = (2.0f * p3 + p2 - dot((p2 - p3), n3) * n3) / 3.0f;
|
||||
output.B102 = (2.0f * p3 + p1 - dot((p1 - p3), n3) * n3) / 3.0f;
|
||||
output.B201 = (2.0f * p1 + p3 - dot((p3 - p1), n1) * n1) / 3.0f;
|
||||
float3 e = (output.B210 + output.B120 + output.B021 +
|
||||
output.B012 + output.B102 + output.B201) / 6.0f;
|
||||
float3 v = (p1 + p2 + p3) / 3.0f;
|
||||
output.B111 = e + ((e - v) / 2.0f);
|
||||
#endif
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
META_HS(USE_TESSELLATION, FEATURE_LEVEL_SM5)
|
||||
META_HS_PATCH(TESSELLATION_IN_CONTROL_POINTS)
|
||||
[domain("tri")]
|
||||
[partitioning("fractional_odd")]
|
||||
[outputtopology("triangle_cw")]
|
||||
[maxtessfactor(MAX_TESSELLATION_FACTOR)]
|
||||
[outputcontrolpoints(3)]
|
||||
[patchconstantfunc("HS_PatchConstant")]
|
||||
TessalationHSToDS HS(InputPatch<VertexOutput, TESSELLATION_IN_CONTROL_POINTS> input, uint ControlPointID : SV_OutputControlPointID)
|
||||
{
|
||||
TessalationHSToDS output;
|
||||
|
||||
// Pass through shader
|
||||
#define COPY(thing) output.thing = input[ControlPointID].thing;
|
||||
COPY(Position);
|
||||
COPY(WorldPosition);
|
||||
COPY(TexCoord);
|
||||
COPY(LightmapUV);
|
||||
#if USE_VERTEX_COLOR
|
||||
COPY(VertexColor);
|
||||
#endif
|
||||
COPY(TBN);
|
||||
COPY(InstanceOrigin);
|
||||
COPY(InstanceParams);
|
||||
COPY(TessellationMultiplier);
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
COPY(CustomVSToPS);
|
||||
#endif
|
||||
#undef COPY
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PHONG
|
||||
|
||||
// Orthogonal projection on to plane
|
||||
float3 ProjectOntoPlane(float3 planeNormal, float3 planePoint, float3 pointToProject)
|
||||
{
|
||||
return pointToProject - dot(pointToProject-planePoint, planeNormal) * planeNormal;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
META_DS(USE_TESSELLATION, FEATURE_LEVEL_SM5)
|
||||
[domain("tri")]
|
||||
TessalationDSToPS DS(TessalationPatch constantData, float3 barycentricCoords : SV_DomainLocation, const OutputPatch<TessalationHSToDS, 3> input)
|
||||
{
|
||||
TessalationDSToPS output;
|
||||
|
||||
// Get the barycentric coords
|
||||
float U = barycentricCoords.x;
|
||||
float V = barycentricCoords.y;
|
||||
float W = barycentricCoords.z;
|
||||
|
||||
// Interpolate patch attributes to generated vertices
|
||||
#define INTERPOLATE(thing) output.thing = U * input[0].thing + V * input[1].thing + W * input[2].thing
|
||||
#define COPY(thing) output.thing = input[0].thing
|
||||
INTERPOLATE(Position);
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
|
||||
float UU = U * U;
|
||||
float VV = V * V;
|
||||
float WW = W * W;
|
||||
float UU3 = UU * 3.0f;
|
||||
float VV3 = VV * 3.0f;
|
||||
float WW3 = WW * 3.0f;
|
||||
|
||||
// Interpolate using barycentric coordinates and PN Triangle control points
|
||||
output.WorldPosition =
|
||||
input[0].WorldPosition * UU * U +
|
||||
input[1].WorldPosition * VV * V +
|
||||
input[2].WorldPosition * WW * W +
|
||||
constantData.B210 * UU3 * V +
|
||||
constantData.B120 * VV3 * U +
|
||||
constantData.B021 * VV3 * W +
|
||||
constantData.B012 * WW3 * V +
|
||||
constantData.B102 * WW3 * U +
|
||||
constantData.B201 * UU3 * W +
|
||||
constantData.B111 * 6.0f * W * U * V;
|
||||
#else
|
||||
INTERPOLATE(WorldPosition);
|
||||
#endif
|
||||
INTERPOLATE(TexCoord);
|
||||
INTERPOLATE(LightmapUV);
|
||||
#if USE_VERTEX_COLOR
|
||||
INTERPOLATE(VertexColor);
|
||||
#endif
|
||||
INTERPOLATE(TBN[0]);
|
||||
INTERPOLATE(TBN[1]);
|
||||
INTERPOLATE(TBN[2]);
|
||||
COPY(InstanceOrigin);
|
||||
COPY(InstanceParams);
|
||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||
UNROLL
|
||||
for (int i = 0; i < CUSTOM_VERTEX_INTERPOLATORS_COUNT; i++)
|
||||
{
|
||||
INTERPOLATE(CustomVSToPS[i]);
|
||||
}
|
||||
#endif
|
||||
#undef INTERPOLATE
|
||||
#undef COPY
|
||||
|
||||
// Interpolating normal can unnormalize it, so normalize it
|
||||
output.TBN[0] = normalize(output.TBN[0]);
|
||||
output.TBN[1] = normalize(output.TBN[1]);
|
||||
output.TBN[2] = normalize(output.TBN[2]);
|
||||
|
||||
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PHONG
|
||||
// Orthogonal projection in the tangent planes
|
||||
float3 posProjectedU = ProjectOntoPlane(input[0].TBN[2], input[0].WorldPosition, output.WorldPosition);
|
||||
float3 posProjectedV = ProjectOntoPlane(input[1].TBN[2], input[1].WorldPosition, output.WorldPosition);
|
||||
float3 posProjectedW = ProjectOntoPlane(input[2].TBN[2], input[2].WorldPosition, output.WorldPosition);
|
||||
|
||||
// Interpolate the projected points
|
||||
output.WorldPosition = U * posProjectedU + V * posProjectedV + W * posProjectedW;
|
||||
#endif
|
||||
|
||||
// Perform displacement mapping
|
||||
#if USE_DISPLACEMENT
|
||||
MaterialInput materialInput = GetMaterialInput(output);
|
||||
Material material = GetMaterialDS(materialInput);
|
||||
output.WorldPosition += material.WorldDisplacement;
|
||||
#endif
|
||||
|
||||
// Recalculate the clip space position
|
||||
output.Position = mul(float4(output.WorldPosition, 1), ViewProjectionMatrix);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if USE_DITHERED_LOD_TRANSITION
|
||||
|
||||
void ClipLODTransition(PixelInput input)
|
||||
@@ -1009,3 +759,5 @@ void PS_Depth(PixelInput input
|
||||
OutColor = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@9
|
||||
|
||||
@@ -39,15 +39,11 @@ float2 OffsetUV;
|
||||
float2 Dummy0;
|
||||
@1META_CB_END
|
||||
|
||||
#if CAN_USE_LIGHTMAP
|
||||
|
||||
// Irradiance and directionality prebaked lightmaps
|
||||
Texture2D Lightmap0 : register(t0);
|
||||
Texture2D Lightmap1 : register(t1);
|
||||
Texture2D Lightmap2 : register(t2);
|
||||
|
||||
#endif
|
||||
|
||||
// Terrain data
|
||||
Texture2D Heightmap : register(t3);
|
||||
Texture2D Splatmap0 : register(t4);
|
||||
@@ -216,6 +212,22 @@ float4 GetVertexColor(MaterialInput input)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Evaluates the H-Basis coefficients in the tangent space normal direction
|
||||
float3 GetHBasisIrradiance(float3 n, float3 h0, float3 h1, float3 h2, float3 h3)
|
||||
{
|
||||
// Band 0
|
||||
float3 color = h0 * (1.0f / sqrt(2.0f * PI));
|
||||
|
||||
// Band 1
|
||||
color += h1 * -sqrt(1.5f / PI) * n.y;
|
||||
color += h2 * sqrt(1.5f / PI) * (2 * n.z - 1.0f);
|
||||
color += h3 * -sqrt(1.5f / PI) * n.x;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
@8
|
||||
|
||||
// Get material properties function (for vertex shader)
|
||||
Material GetMaterialVS(MaterialInput input)
|
||||
{
|
||||
@@ -781,3 +793,5 @@ void PS_Depth(PixelInput input
|
||||
OutColor = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@9
|
||||
|
||||
@@ -458,7 +458,6 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options)
|
||||
options.Macros.Add({ "USE_FORWARD", Numbers[useForward ? 1 : 0] });
|
||||
options.Macros.Add({ "USE_DEFERRED", Numbers[isSurfaceOrTerrain && info.BlendMode == MaterialBlendMode::Opaque ? 1 : 0] });
|
||||
options.Macros.Add({ "USE_DISTORTION", Numbers[useDistortion ? 1 : 0] });
|
||||
options.Macros.Add({ "CAN_USE_LIGHTMAP", Numbers[isSurfaceOrTerrain ? 1 : 0] });
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ void DecalMaterialShader::Bind(BindParameters& params)
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(DecalMaterialShaderData) : nullptr;
|
||||
bindMeta.Constants = hasCb0 ? _cb0Data.Get() + sizeof(DecalMaterialShaderData) : nullptr;
|
||||
bindMeta.Input = nullptr;
|
||||
bindMeta.Buffers = nullptr;
|
||||
bindMeta.CanSampleDepth = true;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "DeferredMaterialShader.h"
|
||||
#include "MaterialShaderFeatures.h"
|
||||
#include "MaterialParams.h"
|
||||
#include "Engine/Graphics/RenderBuffers.h"
|
||||
#include "Engine/Graphics/RenderView.h"
|
||||
@@ -28,7 +29,6 @@ PACK_STRUCT(struct DeferredMaterialShaderData {
|
||||
float TimeParam;
|
||||
Vector4 ViewInfo;
|
||||
Vector4 ScreenSize;
|
||||
Rectangle LightmapArea;
|
||||
Vector3 WorldInvScale;
|
||||
float WorldDeterminantSign;
|
||||
Vector2 Dummy0;
|
||||
@@ -63,11 +63,21 @@ void DeferredMaterialShader::Bind(BindParameters& params)
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
const auto cb0 = _shader->GetCB(0);
|
||||
const bool hasCb0 = cb0 && cb0->GetSize() != 0;
|
||||
ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing
|
||||
byte* cb = _cb0Data.Get();
|
||||
auto materialData = reinterpret_cast<DeferredMaterialShaderData*>(cb);
|
||||
cb += sizeof(DeferredMaterialShaderData);
|
||||
int32 srv = 0;
|
||||
|
||||
// Setup features
|
||||
if (_info.TessellationMode != TessellationMethod::None)
|
||||
TessellationFeature::Bind(params, cb, srv);
|
||||
const bool useLightmap = _info.BlendMode == MaterialBlendMode::Opaque && LightmapFeature::Bind(params, cb, srv);
|
||||
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(DeferredMaterialShaderData) : nullptr;
|
||||
bindMeta.Constants = cb;
|
||||
bindMeta.Input = nullptr;
|
||||
bindMeta.Buffers = nullptr;
|
||||
bindMeta.CanSampleDepth = false;
|
||||
@@ -75,7 +85,6 @@ void DeferredMaterialShader::Bind(BindParameters& params)
|
||||
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);
|
||||
@@ -107,23 +116,6 @@ void DeferredMaterialShader::Bind(BindParameters& params)
|
||||
materialData->TemporalAAJitter = view.TemporalAAJitter;
|
||||
materialData->GeometrySize = drawCall.Surface.GeometrySize;
|
||||
}
|
||||
const bool useLightmap = view.Flags & ViewFlags::GI
|
||||
#if USE_EDITOR
|
||||
&& EnableLightmapsUsage
|
||||
#endif
|
||||
&& drawCall.Surface.Lightmap != nullptr;
|
||||
if (useLightmap)
|
||||
{
|
||||
// Bind lightmap textures
|
||||
GPUTexture *lightmap0, *lightmap1, *lightmap2;
|
||||
drawCall.Surface.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2);
|
||||
context->BindSR(0, lightmap0);
|
||||
context->BindSR(1, lightmap1);
|
||||
context->BindSR(2, lightmap2);
|
||||
|
||||
// Set lightmap data
|
||||
materialData->LightmapArea = drawCall.Surface.LightmapUVsArea;
|
||||
}
|
||||
|
||||
// Check if is using mesh skinning
|
||||
const bool useSkinning = drawCall.Surface.Skinning != nullptr;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ForwardMaterialShader.h"
|
||||
#include "MaterialShaderFeatures.h"
|
||||
#include "MaterialParams.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Graphics/GPULimits.h"
|
||||
@@ -29,7 +30,6 @@ PACK_STRUCT(struct ForwardMaterialShaderData {
|
||||
float TimeParam;
|
||||
Vector4 ViewInfo;
|
||||
Vector4 ScreenSize;
|
||||
Rectangle LightmapArea;
|
||||
Vector3 WorldInvScale;
|
||||
float WorldDeterminantSign;
|
||||
Vector2 Dummy0;
|
||||
@@ -70,13 +70,22 @@ void ForwardMaterialShader::Bind(BindParameters& params)
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
const auto cb0 = _shader->GetCB(0);
|
||||
const bool hasCb0 = cb0 && cb0->GetSize() != 0;
|
||||
ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing
|
||||
const auto cb1 = _shader->GetCB(1);
|
||||
const bool hasCb1 = cb1 && cb1->GetSize() != 0;
|
||||
byte* cb = _cb0Data.Get();
|
||||
auto materialData = reinterpret_cast<ForwardMaterialShaderData*>(cb);
|
||||
cb += sizeof(ForwardMaterialShaderData);
|
||||
int32 srv = 0;
|
||||
|
||||
// Setup features
|
||||
if (_info.TessellationMode != TessellationMethod::None)
|
||||
TessellationFeature::Bind(params, cb, srv);
|
||||
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(ForwardMaterialShaderData) : nullptr;
|
||||
bindMeta.Constants = cb;
|
||||
bindMeta.Input = nullptr; // forward pass materials cannot sample scene color for now
|
||||
bindMeta.Buffers = params.RenderContext.Buffers;
|
||||
bindMeta.CanSampleDepth = GPUDevice::Instance->Limits.HasReadOnlyDepth;
|
||||
@@ -93,7 +102,6 @@ void ForwardMaterialShader::Bind(BindParameters& params)
|
||||
}
|
||||
|
||||
// Setup material constants data
|
||||
const auto materialData = reinterpret_cast<ForwardMaterialShaderData*>(_cb0Data.Get());
|
||||
if (hasCb0)
|
||||
{
|
||||
Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix);
|
||||
|
||||
@@ -36,7 +36,7 @@ void GUIMaterialShader::Bind(BindParameters& params)
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(GUIMaterialShaderData) : nullptr;
|
||||
bindMeta.Constants = hasCb0 ? _cb0Data.Get() + sizeof(GUIMaterialShaderData) : nullptr;
|
||||
bindMeta.Input = nullptr;
|
||||
bindMeta.Buffers = nullptr;
|
||||
bindMeta.CanSampleDepth = false;
|
||||
|
||||
@@ -29,7 +29,6 @@ public:
|
||||
/// <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;
|
||||
@@ -38,7 +37,6 @@ public:
|
||||
/// <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;
|
||||
@@ -47,7 +45,6 @@ public:
|
||||
/// <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;
|
||||
@@ -56,7 +53,6 @@ public:
|
||||
/// <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;
|
||||
@@ -65,7 +61,6 @@ public:
|
||||
/// <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;
|
||||
@@ -74,7 +69,6 @@ public:
|
||||
/// <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;
|
||||
|
||||
@@ -230,36 +230,28 @@ void MaterialParameter::Bind(BindMeta& meta) const
|
||||
switch (_type)
|
||||
{
|
||||
case MaterialParameterType::Bool:
|
||||
if (meta.Buffer0)
|
||||
*((int32*)(meta.Buffer0 + _offset)) = _asBool;
|
||||
*((int32*)(meta.Constants + _offset)) = _asBool;
|
||||
break;
|
||||
case MaterialParameterType::Integer:
|
||||
if (meta.Buffer0)
|
||||
*((int32*)(meta.Buffer0 + _offset)) = _asInteger;
|
||||
*((int32*)(meta.Constants + _offset)) = _asInteger;
|
||||
break;
|
||||
case MaterialParameterType::Float:
|
||||
if (meta.Buffer0)
|
||||
*((float*)(meta.Buffer0 + _offset)) = _asFloat;
|
||||
*((float*)(meta.Constants + _offset)) = _asFloat;
|
||||
break;
|
||||
case MaterialParameterType::Vector2:
|
||||
if (meta.Buffer0)
|
||||
*((Vector2*)(meta.Buffer0 + _offset)) = _asVector2;
|
||||
*((Vector2*)(meta.Constants + _offset)) = _asVector2;
|
||||
break;
|
||||
case MaterialParameterType::Vector3:
|
||||
if (meta.Buffer0)
|
||||
*((Vector3*)(meta.Buffer0 + _offset)) = _asVector3;
|
||||
*((Vector3*)(meta.Constants + _offset)) = _asVector3;
|
||||
break;
|
||||
case MaterialParameterType::Vector4:
|
||||
if (meta.Buffer0)
|
||||
*((Vector4*)(meta.Buffer0 + _offset)) = _asVector4;
|
||||
*((Vector4*)(meta.Constants + _offset)) = _asVector4;
|
||||
break;
|
||||
case MaterialParameterType::Color:
|
||||
if (meta.Buffer0)
|
||||
*((Color*)(meta.Buffer0 + _offset)) = _asColor;
|
||||
*((Color*)(meta.Constants + _offset)) = _asColor;
|
||||
break;
|
||||
case MaterialParameterType::Matrix:
|
||||
if (meta.Buffer0)
|
||||
Matrix::Transpose(_asMatrix, *(Matrix*)(meta.Buffer0 + _offset));
|
||||
Matrix::Transpose(_asMatrix, *(Matrix*)(meta.Constants + _offset));
|
||||
break;
|
||||
case MaterialParameterType::NormalMap:
|
||||
{
|
||||
@@ -336,11 +328,10 @@ void MaterialParameter::Bind(BindMeta& meta) const
|
||||
break;
|
||||
}
|
||||
case MaterialParameterType::ChannelMask:
|
||||
if (meta.Buffer0)
|
||||
*((Vector4*)(meta.Buffer0 + _offset)) = Vector4(_asInteger == 0, _asInteger == 1, _asInteger == 2, _asInteger == 3);
|
||||
*((Vector4*)(meta.Constants + _offset)) = Vector4(_asInteger == 0, _asInteger == 1, _asInteger == 2, _asInteger == 3);
|
||||
break;
|
||||
case MaterialParameterType::GameplayGlobal:
|
||||
if (meta.Buffer0 && _asAsset)
|
||||
if (_asAsset)
|
||||
{
|
||||
const auto e = _asAsset.As<GameplayGlobals>()->Variables.TryGet(_name);
|
||||
if (e)
|
||||
@@ -348,26 +339,26 @@ void MaterialParameter::Bind(BindMeta& meta) const
|
||||
switch (e->Value.Type.Type)
|
||||
{
|
||||
case VariantType::Bool:
|
||||
*((bool*)(meta.Buffer0 + _offset)) = e->Value.AsBool;
|
||||
*((bool*)(meta.Constants + _offset)) = e->Value.AsBool;
|
||||
break;
|
||||
case VariantType::Int:
|
||||
*((int32*)(meta.Buffer0 + _offset)) = e->Value.AsInt;
|
||||
*((int32*)(meta.Constants + _offset)) = e->Value.AsInt;
|
||||
break;
|
||||
case VariantType::Uint:
|
||||
*((uint32*)(meta.Buffer0 + _offset)) = e->Value.AsUint;
|
||||
*((uint32*)(meta.Constants + _offset)) = e->Value.AsUint;
|
||||
break;
|
||||
case VariantType::Float:
|
||||
*((float*)(meta.Buffer0 + _offset)) = e->Value.AsFloat;
|
||||
*((float*)(meta.Constants + _offset)) = e->Value.AsFloat;
|
||||
break;
|
||||
case VariantType::Vector2:
|
||||
*((Vector2*)(meta.Buffer0 + _offset)) = e->Value.AsVector2();
|
||||
*((Vector2*)(meta.Constants + _offset)) = e->Value.AsVector2();
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
*((Vector3*)(meta.Buffer0 + _offset)) = e->Value.AsVector3();
|
||||
*((Vector3*)(meta.Constants + _offset)) = e->Value.AsVector3();
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
*((Vector4*)(meta.Buffer0 + _offset)) = e->Value.AsVector4();
|
||||
*((Vector4*)(meta.Constants + _offset)) = e->Value.AsVector4();
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
|
||||
@@ -309,9 +309,9 @@ public:
|
||||
GPUContext* Context;
|
||||
|
||||
/// <summary>
|
||||
/// The pointer to the first constants buffer in memory.
|
||||
/// The pointer to the constants buffer in the memory.
|
||||
/// </summary>
|
||||
byte* Buffer0;
|
||||
byte* Constants;
|
||||
|
||||
/// <summary>
|
||||
/// The input scene color. It's optional and used in forward/postFx rendering.
|
||||
|
||||
172
Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp
Normal file
172
Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "MaterialShaderFeatures.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Renderer/RenderList.h"
|
||||
#include "Engine/Renderer/ShadowsPass.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Renderer/Lightmaps.h"
|
||||
#endif
|
||||
#include "Engine/Level/Scene/Lightmap.h"
|
||||
#include "Engine/Level/Actors/EnvironmentProbe.h"
|
||||
|
||||
void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv)
|
||||
{
|
||||
auto context = params.GPUContext;
|
||||
auto cache = params.RenderContext.List;
|
||||
auto& view = params.RenderContext.View;
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
auto& data = *(Data*)cb;
|
||||
const int32 envProbeShaderRegisterIndex = srv + 0;
|
||||
const int32 skyLightShaderRegisterIndex = srv + 1;
|
||||
const int32 dirLightShaderRegisterIndex = srv + 2;
|
||||
|
||||
// Set fog input
|
||||
if (cache->Fog)
|
||||
{
|
||||
cache->Fog->GetExponentialHeightFogData(view, data.ExponentialHeightFog);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.ExponentialHeightFog.FogMinOpacity = 1.0f;
|
||||
data.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)
|
||||
{
|
||||
data.DirectionalLightShadow = shadowPass->LastDirLight;
|
||||
context->BindSR(dirLightShaderRegisterIndex, shadowPass->LastDirLightShadowMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
context->UnBindSR(dirLightShaderRegisterIndex);
|
||||
}
|
||||
dirLight.SetupLightData(&data.DirectionalLight, view, useShadow);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.DirectionalLight.Color = Vector3::Zero;
|
||||
data.DirectionalLight.CastShadows = 0.0f;
|
||||
context->UnBindSR(dirLightShaderRegisterIndex);
|
||||
}
|
||||
|
||||
// Set sky light
|
||||
if (cache->SkyLights.HasItems())
|
||||
{
|
||||
auto& skyLight = cache->SkyLights.First();
|
||||
skyLight.SetupLightData(&data.SkyLight, view, false);
|
||||
const auto texture = skyLight.Image ? skyLight.Image->GetTexture() : nullptr;
|
||||
context->BindSR(skyLightShaderRegisterIndex, GET_TEXTURE_VIEW_SAFE(texture));
|
||||
}
|
||||
else
|
||||
{
|
||||
Platform::MemoryClear(&data.SkyLight, sizeof(data.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(&data.EnvironmentProbe);
|
||||
const auto texture = probe->GetProbe()->GetTexture();
|
||||
context->BindSR(envProbeShaderRegisterIndex, GET_TEXTURE_VIEW_SAFE(texture));
|
||||
}
|
||||
else
|
||||
{
|
||||
data.EnvironmentProbe.Data1 = Vector4::Zero;
|
||||
context->UnBindSR(envProbeShaderRegisterIndex);
|
||||
}
|
||||
|
||||
// Set local lights
|
||||
data.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(&data.LocalLights[data.LocalLightsCount], view, false);
|
||||
data.LocalLightsCount++;
|
||||
if (data.LocalLightsCount == MaxLocalLights)
|
||||
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(&data.LocalLights[data.LocalLightsCount], view, false);
|
||||
data.LocalLightsCount++;
|
||||
if (data.LocalLightsCount == MaxLocalLights)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cb += sizeof(Data);
|
||||
srv += SRVs;
|
||||
}
|
||||
|
||||
bool LightmapFeature::Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv)
|
||||
{
|
||||
auto context = params.GPUContext;
|
||||
auto& view = params.RenderContext.View;
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
auto& data = *(Data*)cb;
|
||||
|
||||
const bool useLightmap = view.Flags & ViewFlags::GI
|
||||
#if USE_EDITOR
|
||||
&& EnableLightmapsUsage
|
||||
#endif
|
||||
&& drawCall.Surface.Lightmap != nullptr;
|
||||
if (useLightmap)
|
||||
{
|
||||
// Bind lightmap textures
|
||||
GPUTexture *lightmap0, *lightmap1, *lightmap2;
|
||||
drawCall.Surface.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2);
|
||||
context->BindSR(0, lightmap0);
|
||||
context->BindSR(1, lightmap1);
|
||||
context->BindSR(2, lightmap2);
|
||||
|
||||
// Set lightmap data
|
||||
data.LightmapArea = drawCall.Surface.LightmapUVsArea;
|
||||
}
|
||||
|
||||
srv += SRVs;
|
||||
cb += sizeof(Data);
|
||||
return useLightmap;
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void TessellationFeature::Generate(GeneratorData& data)
|
||||
{
|
||||
data.Template = TEXT("Tessellation.hlsl");
|
||||
data.ConstantsSize = 0;
|
||||
data.ResourcesCount = SRVs;
|
||||
}
|
||||
|
||||
void LightmapFeature::Generate(GeneratorData& data)
|
||||
{
|
||||
data.Template = TEXT("Lightmap.hlsl");
|
||||
data.ConstantsSize = sizeof(Data);
|
||||
data.ResourcesCount = SRVs;
|
||||
}
|
||||
|
||||
#endif
|
||||
70
Source/Engine/Graphics/Materials/MaterialShaderFeatures.h
Normal file
70
Source/Engine/Graphics/Materials/MaterialShaderFeatures.h
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MaterialShader.h"
|
||||
#include "Engine/Core/Math/Rectangle.h"
|
||||
|
||||
// Material shader features are plugin-based functionalities that are reusable between different material domains.
|
||||
struct MaterialShaderFeature
|
||||
{
|
||||
#if USE_EDITOR
|
||||
struct GeneratorData
|
||||
{
|
||||
const Char* Template;
|
||||
int32 ConstantsSize;
|
||||
int32 ResourcesCount;
|
||||
};
|
||||
#endif;
|
||||
};
|
||||
|
||||
// Material shader feature that add support for Forward shading inside the material shader.
|
||||
struct ForwardShadingFeature : MaterialShaderFeature
|
||||
{
|
||||
enum { MaxLocalLights = 4 };
|
||||
|
||||
enum { SRVs = 3 };
|
||||
|
||||
PACK_STRUCT(struct Data
|
||||
{
|
||||
LightData DirectionalLight;
|
||||
LightShadowData DirectionalLightShadow;
|
||||
LightData SkyLight;
|
||||
ProbeData EnvironmentProbe;
|
||||
ExponentialHeightFogData ExponentialHeightFog;
|
||||
Vector3 Dummy2;
|
||||
uint32 LocalLightsCount;
|
||||
LightData LocalLights[MaxLocalLights];
|
||||
});
|
||||
|
||||
static void Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv);
|
||||
};
|
||||
|
||||
// Material shader feature that adds geometry hardware tessellation (using Hull and Domain shaders).
|
||||
struct TessellationFeature : MaterialShaderFeature
|
||||
{
|
||||
enum { SRVs = 0 };
|
||||
|
||||
static void Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv)
|
||||
{
|
||||
}
|
||||
#if USE_EDITOR
|
||||
static void Generate(GeneratorData& data);
|
||||
#endif
|
||||
};
|
||||
|
||||
// Material shader feature that adds lightmap sampling feature.
|
||||
struct LightmapFeature : MaterialShaderFeature
|
||||
{
|
||||
enum { SRVs = 3 };
|
||||
|
||||
PACK_STRUCT(struct Data
|
||||
{
|
||||
Rectangle LightmapArea;
|
||||
});
|
||||
|
||||
static bool Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv);
|
||||
#if USE_EDITOR
|
||||
static void Generate(GeneratorData& data);
|
||||
#endif
|
||||
};
|
||||
@@ -81,7 +81,7 @@ void ParticleMaterialShader::Bind(BindParameters& params)
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(ParticleMaterialShaderData) : nullptr;
|
||||
bindMeta.Constants = hasCb0 ? _cb0Data.Get() + sizeof(ParticleMaterialShaderData) : nullptr;
|
||||
bindMeta.Input = nullptr;
|
||||
bindMeta.Buffers = params.RenderContext.Buffers;
|
||||
bindMeta.CanSampleDepth = GPUDevice::Instance->Limits.HasReadOnlyDepth;
|
||||
@@ -105,7 +105,7 @@ void ParticleMaterialShader::Bind(BindParameters& params)
|
||||
auto name = StringView(param.GetName().Get() + 9);
|
||||
|
||||
const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name);
|
||||
*((int32*)(bindMeta.Buffer0 + param.GetBindOffset())) = offset;
|
||||
*((int32*)(bindMeta.Constants + param.GetBindOffset())) = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ void PostFxMaterialShader::Bind(BindParameters& params)
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(PostFxMaterialShaderData) : nullptr;
|
||||
bindMeta.Constants = hasCb0 ? _cb0Data.Get() + sizeof(PostFxMaterialShaderData) : nullptr;
|
||||
bindMeta.Input = params.Input;
|
||||
bindMeta.Buffers = params.RenderContext.Buffers;
|
||||
bindMeta.CanSampleDepth = true;
|
||||
|
||||
@@ -60,7 +60,7 @@ void TerrainMaterialShader::Bind(BindParameters& params)
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCb0 ? _cb0Data.Get() + sizeof(TerrainMaterialShaderData) : nullptr;
|
||||
bindMeta.Constants = hasCb0 ? _cb0Data.Get() + sizeof(TerrainMaterialShaderData) : nullptr;
|
||||
bindMeta.Input = nullptr;
|
||||
bindMeta.Buffers = nullptr;
|
||||
bindMeta.CanSampleDepth = false;
|
||||
|
||||
@@ -155,7 +155,7 @@ void GPUParticles::Execute(GPUContext* context, ParticleEmitter* emitter, Partic
|
||||
// Setup parameters
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Buffer0 = hasCB ? _cbData.Get() + sizeof(GPUParticlesData) : nullptr;
|
||||
bindMeta.Constants = hasCB ? _cbData.Get() + sizeof(GPUParticlesData) : nullptr;
|
||||
bindMeta.Input = nullptr;
|
||||
if (viewTask)
|
||||
{
|
||||
|
||||
@@ -163,27 +163,4 @@ void MaterialGenerator::linearizeSceneDepth(Node* caller, const Value& depth, Va
|
||||
value = writeLocal(VariantType::Float, String::Format(TEXT("ViewInfo.w / ({0}.x - ViewInfo.z)"), depth.Value), caller);
|
||||
}
|
||||
|
||||
byte MaterialGenerator::getStartSrvRegister(MaterialLayer* baseLayer)
|
||||
{
|
||||
// Note: this must match material templates
|
||||
switch (baseLayer->Domain)
|
||||
{
|
||||
case MaterialDomain::Surface:
|
||||
return baseLayer->BlendMode == MaterialBlendMode::Transparent ? 3 : 3;
|
||||
case MaterialDomain::PostProcess:
|
||||
return 0;
|
||||
case MaterialDomain::Decal:
|
||||
return 1;
|
||||
case MaterialDomain::GUI:
|
||||
return 0;
|
||||
case MaterialDomain::Terrain:
|
||||
return 6;
|
||||
case MaterialDomain::Particle:
|
||||
return 5;
|
||||
default:
|
||||
CRASH;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
#include "MaterialGenerator.h"
|
||||
#include "Engine/Visject/ShaderGraphUtilities.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Graphics/Materials/MaterialShader.h"
|
||||
#include "Engine/Graphics/Materials/MaterialShaderFeatures.h"
|
||||
|
||||
/// <summary>
|
||||
/// Material shader source code template has special marks for generated code.
|
||||
@@ -20,10 +22,86 @@ enum MaterialTemplateInputsMapping
|
||||
In_GetMaterialVS = 5,
|
||||
In_GetMaterialDS = 6,
|
||||
In_Includes = 7,
|
||||
In_Utilities = 8,
|
||||
In_Shaders = 9,
|
||||
|
||||
In_MAX
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Material shader feature source code template has special marks for generated code. Each starts with '@' char and index of the mapped string.
|
||||
/// </summary>
|
||||
enum class FeatureTemplateInputsMapping
|
||||
{
|
||||
Defines = 0,
|
||||
Includes = 1,
|
||||
Constants = 2,
|
||||
Resources = 3,
|
||||
Utilities = 4,
|
||||
Shaders = 5,
|
||||
MAX
|
||||
};
|
||||
|
||||
struct FeatureData
|
||||
{
|
||||
MaterialShaderFeature::GeneratorData Data;
|
||||
String Inputs[(int32)FeatureTemplateInputsMapping::MAX];
|
||||
|
||||
bool Init();
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
// Loaded and parsed features data cache
|
||||
Dictionary<StringAnsi, FeatureData> Features;
|
||||
}
|
||||
|
||||
bool FeatureData::Init()
|
||||
{
|
||||
// Load template file
|
||||
const String path = Globals::EngineContentFolder / TEXT("Editor/MaterialTemplates/Features/") + Data.Template;
|
||||
String contents;
|
||||
if (File::ReadAllText(path, contents))
|
||||
{
|
||||
LOG(Error, "Cannot open file {0}", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
int32 i = 0;
|
||||
const int32 length = contents.Length();
|
||||
|
||||
// Skip until input start
|
||||
for (; i < length; i++)
|
||||
{
|
||||
if (contents[i] == '@')
|
||||
break;
|
||||
}
|
||||
|
||||
// Load all inputs
|
||||
do
|
||||
{
|
||||
// Parse input type
|
||||
i++;
|
||||
const int32 inIndex = contents[i++] - '0';
|
||||
ASSERT_LOW_LAYER(Math::IsInRange(inIndex, 0, (int32)FeatureTemplateInputsMapping::MAX - 1));
|
||||
|
||||
// Read until next input start
|
||||
const Char* start = &contents[i];
|
||||
for (; i < length; i++)
|
||||
{
|
||||
const auto c = contents[i];
|
||||
if (c == '@')
|
||||
break;
|
||||
}
|
||||
const Char* end = &contents[i];
|
||||
|
||||
// Set input
|
||||
Inputs[inIndex].Set(start, (int32)(end - start));
|
||||
} while (i < length);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
MaterialValue MaterialGenerator::getUVs(VariantType::Vector2, TEXT("input.TexCoord"));
|
||||
MaterialValue MaterialGenerator::getTime(VariantType::Float, TEXT("TimeParam"));
|
||||
MaterialValue MaterialGenerator::getNormal(VariantType::Vector3, TEXT("input.TBN[2]"));
|
||||
@@ -53,6 +131,7 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
|
||||
ASSERT_LOW_LAYER(_layers.Count() > 0);
|
||||
|
||||
String inputs[In_MAX];
|
||||
Array<StringAnsiView, FixedAllocation<8>> features;
|
||||
|
||||
// Setup and prepare layers
|
||||
_writer.Clear();
|
||||
@@ -87,6 +166,32 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
|
||||
const MaterialGraphBox* layerInputBox = baseLayer->Root->GetBox(0);
|
||||
const bool isLayered = layerInputBox->HasConnection();
|
||||
|
||||
// Initialize features
|
||||
#define ADD_FEATURE(type) \
|
||||
{ \
|
||||
StringAnsiView typeName(#type, ARRAY_COUNT(#type) - 1); \
|
||||
features.Add(typeName); \
|
||||
if (!Features.ContainsKey(typeName)) \
|
||||
{ \
|
||||
auto& feature = Features[typeName]; \
|
||||
type::Generate(feature.Data); \
|
||||
if (feature.Init()) \
|
||||
return true; \
|
||||
} \
|
||||
}
|
||||
switch (baseLayer->Domain)
|
||||
{
|
||||
case MaterialDomain::Surface:
|
||||
if (materialInfo.TessellationMode != TessellationMethod::None)
|
||||
ADD_FEATURE(TessellationFeature);
|
||||
if (materialInfo.BlendMode == MaterialBlendMode::Opaque)
|
||||
ADD_FEATURE(LightmapFeature);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#undef ADD_FEATURE
|
||||
|
||||
// Check if material is using special features and update the metadata flags
|
||||
if (!isLayered)
|
||||
{
|
||||
@@ -240,11 +345,13 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
|
||||
// Update material usage based on material generator outputs
|
||||
materialInfo.UsageFlags = baseLayer->UsageFlags;
|
||||
|
||||
#define WRITE_FEATURES(input) for (auto f : features) _writer.Write(Features[f].Inputs[(int32)FeatureTemplateInputsMapping::input]);
|
||||
// Defines
|
||||
{
|
||||
_writer.Write(TEXT("#define MATERIAL_MASK_THRESHOLD ({0})\n"), baseLayer->MaskThreshold);
|
||||
_writer.Write(TEXT("#define CUSTOM_VERTEX_INTERPOLATORS_COUNT ({0})\n"), _vsToPsInterpolants.Count());
|
||||
_writer.Write(TEXT("#define MATERIAL_OPACITY_THRESHOLD ({0})"), baseLayer->OpacityThreshold);
|
||||
_writer.Write(TEXT("#define MATERIAL_OPACITY_THRESHOLD ({0})\n"), baseLayer->OpacityThreshold);
|
||||
WRITE_FEATURES(Defines);
|
||||
inputs[In_Defines] = _writer.ToString();
|
||||
_writer.Clear();
|
||||
}
|
||||
@@ -252,31 +359,87 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
|
||||
// Includes
|
||||
{
|
||||
for (auto& include : _includes)
|
||||
{
|
||||
_writer.Write(TEXT("#include \"{0}\"\n"), include.Item);
|
||||
}
|
||||
WRITE_FEATURES(Includes);
|
||||
inputs[In_Includes] = _writer.ToString();
|
||||
_writer.Clear();
|
||||
}
|
||||
|
||||
// Check if material is using any parameters
|
||||
if (_parameters.HasItems())
|
||||
// Constants
|
||||
{
|
||||
ShaderGraphUtilities::GenerateShaderConstantBuffer(_writer, _parameters);
|
||||
WRITE_FEATURES(Constants);
|
||||
if (_parameters.HasItems())
|
||||
ShaderGraphUtilities::GenerateShaderConstantBuffer(_writer, _parameters);
|
||||
inputs[In_Constants] = _writer.ToString();
|
||||
_writer.Clear();
|
||||
}
|
||||
|
||||
const int32 startRegister = getStartSrvRegister(baseLayer);
|
||||
const auto error = ShaderGraphUtilities::GenerateShaderResources(_writer, _parameters, startRegister);
|
||||
if (error)
|
||||
// Resources
|
||||
{
|
||||
int32 srv = 0;
|
||||
switch (baseLayer->Domain)
|
||||
{
|
||||
OnError(nullptr, nullptr, error);
|
||||
return true;
|
||||
case MaterialDomain::Surface:
|
||||
if (materialInfo.BlendMode != MaterialBlendMode::Opaque)
|
||||
srv = 3; // Forward shading resources
|
||||
break;
|
||||
case MaterialDomain::Decal:
|
||||
srv = 1;
|
||||
break;
|
||||
case MaterialDomain::Terrain:
|
||||
srv = 6;
|
||||
break;
|
||||
case MaterialDomain::Particle:
|
||||
srv = 5;
|
||||
break;
|
||||
}
|
||||
for (auto f : features)
|
||||
{
|
||||
const auto& text = Features[f].Inputs[(int32)FeatureTemplateInputsMapping::Resources];
|
||||
const Char* str = text.Get();
|
||||
int32 prevIdx = 0, idx = 0;
|
||||
while (true)
|
||||
{
|
||||
idx = text.Find(TEXT("__SRV__"), StringSearchCase::CaseSensitive, prevIdx);
|
||||
if (idx == -1)
|
||||
break;
|
||||
int32 len = idx - prevIdx;
|
||||
_writer.Write(StringView(str, len));
|
||||
str += len;
|
||||
_writer.Write(StringUtils::ToString(srv));
|
||||
srv++;
|
||||
str += ARRAY_COUNT("__SRV__") - 1;
|
||||
prevIdx = idx + ARRAY_COUNT("__SRV__") - 1;
|
||||
}
|
||||
_writer.Write(StringView(str));
|
||||
}
|
||||
if (_parameters.HasItems())
|
||||
{
|
||||
const auto error = ShaderGraphUtilities::GenerateShaderResources(_writer, _parameters, srv);
|
||||
if (error)
|
||||
{
|
||||
OnError(nullptr, nullptr, error);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
inputs[In_ShaderResources] = _writer.ToString();
|
||||
_writer.Clear();
|
||||
}
|
||||
|
||||
// Utilities
|
||||
{
|
||||
WRITE_FEATURES(Utilities);
|
||||
inputs[In_Utilities] = _writer.ToString();
|
||||
_writer.Clear();
|
||||
}
|
||||
|
||||
// Shaders
|
||||
{
|
||||
WRITE_FEATURES(Shaders);
|
||||
inputs[In_Shaders] = _writer.ToString();
|
||||
_writer.Clear();
|
||||
}
|
||||
|
||||
// Save material parameters data
|
||||
if (_parameters.HasItems())
|
||||
MaterialParams::Save(parametersData, &_parameters);
|
||||
@@ -315,16 +478,15 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
|
||||
LOG(Warning, "Unknown material domain.");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto file = FileReadStream::Open(path);
|
||||
if (file == nullptr)
|
||||
{
|
||||
LOG(Warning, "Cannot load material base source code.");
|
||||
LOG(Error, "Cannot open file {0}", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Format template
|
||||
uint32 length = file->GetLength();
|
||||
const uint32 length = file->GetLength();
|
||||
Array<char> tmp;
|
||||
for (uint32 i = 0; i < length; i++)
|
||||
{
|
||||
|
||||
@@ -209,8 +209,6 @@ public:
|
||||
static MaterialGraphBoxesMapping MaterialGraphBoxesMappings[];
|
||||
|
||||
static const MaterialGraphBoxesMapping& GetMaterialRootNodeBox(MaterialGraphBoxes box);
|
||||
|
||||
static byte getStartSrvRegister(MaterialLayer* baseLayer);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "Engine/Core/NonCopyable.h"
|
||||
#include "Engine/Core/Formatting.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Types/StringView.h"
|
||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||
|
||||
/// <summary>
|
||||
@@ -97,6 +99,24 @@ public:
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write text to the buffer
|
||||
/// </summary>
|
||||
/// <param name="text">Data</param>
|
||||
void Write(const StringViewBase<CharType>& text)
|
||||
{
|
||||
_buffer.WriteBytes((void*)text.Get(), text.Length() * sizeof(CharType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write text to the buffer
|
||||
/// </summary>
|
||||
/// <param name="text">Data</param>
|
||||
void Write(const StringBase<CharType>& text)
|
||||
{
|
||||
_buffer.WriteBytes((void*)text.Get(), text.Length() * sizeof(CharType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write text to the buffer
|
||||
/// </summary>
|
||||
|
||||
@@ -177,10 +177,6 @@ const Char* ShaderGraphUtilities::GenerateShaderResources(TextWriterUnicode& wri
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (startRegister != registerIndex)
|
||||
writer.WriteLine();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -173,24 +173,4 @@ float3 AOMultiBounce(float visibility, float3 albedo)
|
||||
return max(visibility, ((visibility * a + b) * visibility + c) * visibility);
|
||||
}
|
||||
|
||||
#if CAN_USE_LIGHTMAP
|
||||
|
||||
// Evaluates the H-Basis coefficients in the tangent space normal direction
|
||||
float3 GetHBasisIrradiance(in float3 n, in float3 h0, in float3 h1, in float3 h2, in float3 h3)
|
||||
{
|
||||
float3 color = 0.0f;
|
||||
|
||||
// Band 0
|
||||
color += h0 * (1.0f / sqrt(2.0f * PI));
|
||||
|
||||
// Band 1
|
||||
color += h1 * -sqrt(1.5f / PI) * n.y;
|
||||
color += h2 * sqrt(1.5f / PI) * (2 * n.z - 1.0f);
|
||||
color += h3 * -sqrt(1.5f / PI) * n.x;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user