diff --git a/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl b/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl index 09b628e54..12f7fa81a 100644 --- a/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl +++ b/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl @@ -26,14 +26,12 @@ void PS_GBuffer( ) { Light = float4(0, 0, 0, 1); - + MaterialInput materialInput = GetMaterialInput(input); #if USE_DITHERED_LOD_TRANSITION - // LOD masking - ClipLODTransition(input); + ClipLODTransition(materialInput); #endif // Get material parameters - MaterialInput materialInput = GetMaterialInput(input); Material material = GetMaterialPS(materialInput); // Masking diff --git a/Content/Editor/MaterialTemplates/Features/Distortion.hlsl b/Content/Editor/MaterialTemplates/Features/Distortion.hlsl index 16ed80522..c3a56b2e8 100644 --- a/Content/Editor/MaterialTemplates/Features/Distortion.hlsl +++ b/Content/Editor/MaterialTemplates/Features/Distortion.hlsl @@ -12,13 +12,12 @@ META_PS(USE_DISTORTION, FEATURE_LEVEL_ES2) float4 PS_Distortion(PixelInput input) : SV_Target0 { + MaterialInput materialInput = GetMaterialInput(input); #if USE_DITHERED_LOD_TRANSITION - // LOD masking - ClipLODTransition(input); + ClipLODTransition(materialInput); #endif // Get material parameters - MaterialInput materialInput = GetMaterialInput(input); Material material = GetMaterialPS(materialInput); // Masking diff --git a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl index 7f7d16545..a9a757d87 100644 --- a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl +++ b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl @@ -38,14 +38,12 @@ void PS_Forward( ) { output = 0; - + MaterialInput materialInput = GetMaterialInput(input); #if USE_DITHERED_LOD_TRANSITION - // LOD masking - ClipLODTransition(input); + ClipLODTransition(materialInput); #endif // Get material parameters - MaterialInput materialInput = GetMaterialInput(input); Material material = GetMaterialPS(materialInput); // Masking diff --git a/Content/Editor/MaterialTemplates/Features/Lightmap.hlsl b/Content/Editor/MaterialTemplates/Features/Lightmap.hlsl index 46d021711..b47d65a72 100644 --- a/Content/Editor/MaterialTemplates/Features/Lightmap.hlsl +++ b/Content/Editor/MaterialTemplates/Features/Lightmap.hlsl @@ -4,7 +4,6 @@ #define CAN_USE_LIGHTMAP 1 @1// Lightmap: Includes @2// Lightmap: Constants -float4 LightmapArea; @3// Lightmap: Resources #if USE_LIGHTMAP // Irradiance and directionality prebaked lightmaps diff --git a/Content/Editor/MaterialTemplates/Features/MotionVectors.hlsl b/Content/Editor/MaterialTemplates/Features/MotionVectors.hlsl index 587902ae7..8531853f4 100644 --- a/Content/Editor/MaterialTemplates/Features/MotionVectors.hlsl +++ b/Content/Editor/MaterialTemplates/Features/MotionVectors.hlsl @@ -11,14 +11,15 @@ META_PS(true, FEATURE_LEVEL_ES2) float4 PS_MotionVectors(PixelInput input) : SV_Target0 { +#if USE_DITHERED_LOD_TRANSITION || MATERIAL_MASKED + MaterialInput materialInput = GetMaterialInput(input); #if USE_DITHERED_LOD_TRANSITION - // LOD masking - ClipLODTransition(input); + ClipLODTransition(materialInput); +#endif #endif #if MATERIAL_MASKED // Perform per pixel clipping if material requries it - MaterialInput materialInput = GetMaterialInput(input); Material material = GetMaterialPS(materialInput); clip(material.Mask - MATERIAL_MASK_THRESHOLD); #endif diff --git a/Content/Editor/MaterialTemplates/Features/Tessellation.hlsl b/Content/Editor/MaterialTemplates/Features/Tessellation.hlsl index f26fbd515..bc9e50834 100644 --- a/Content/Editor/MaterialTemplates/Features/Tessellation.hlsl +++ b/Content/Editor/MaterialTemplates/Features/Tessellation.hlsl @@ -33,8 +33,13 @@ struct TessalationDSToPS MaterialInput GetMaterialInput(TessalationDSToPS input) { MaterialInput output = GetGeometryMaterialInput(input.Geometry); +#if USE_PER_DRAW_CONSTANTS + output.Object = LoadObject(ObjectsBuffer, input.Geometry.ObjectIndex); +#else + LoadObjectFromCB(output.Object); +#endif output.SvPosition = input.Position; - output.TwoSidedSign = WorldDeterminantSign; + output.TwoSidedSign = output.Object.WorldDeterminantSign; #if USE_CUSTOM_VERTEX_INTERPOLATORS output.CustomVSToPS = input.CustomVSToPS; #endif diff --git a/Content/Editor/MaterialTemplates/Surface.shader b/Content/Editor/MaterialTemplates/Surface.shader index 4b3581cee..fd6cb31fa 100644 --- a/Content/Editor/MaterialTemplates/Surface.shader +++ b/Content/Editor/MaterialTemplates/Surface.shader @@ -3,6 +3,7 @@ #define MATERIAL 1 #define USE_PER_VIEW_CONSTANTS 1 +#define USE_PER_DRAW_CONSTANTS 1 @3 #include "./Flax/Common.hlsl" #include "./Flax/MaterialCommon.hlsl" @@ -10,17 +11,19 @@ @7 // Primary constant buffer (with additional material parameters) META_CB_BEGIN(0, Data) -float4x3 WorldMatrix; -float4x3 PrevWorldMatrix; -float2 Dummy0; -float LODDitherFactor; -float PerInstanceRandom; -float3 GeometrySize; -float WorldDeterminantSign; @1META_CB_END // Shader resources @2 +Buffer ObjectsBuffer : register(t0); +#if USE_SKINNING +// The skeletal bones matrix buffer (stored as 4x3, 3 float4 behind each other) +Buffer BoneMatrices : register(t1); +#if PER_BONE_MOTION_BLUR +// The skeletal bones matrix buffer from the previous frame +Buffer PrevBoneMatrices : register(t2); +#endif +#endif // Geometry data passed though the graphics rendering stages up to the pixel shader struct GeometryData { @@ -32,12 +35,8 @@ struct GeometryData #endif float3 WorldNormal : TEXCOORD3; float4 WorldTangent : TEXCOORD4; - nointerpolation float3 InstanceOrigin : TEXCOORD5; - nointerpolation float2 InstanceParams : TEXCOORD6; // x-PerInstanceRandom, y-LODDitherFactor float3 PrevWorldPosition : TEXCOORD7; - nointerpolation float3 InstanceTransform1 : TEXCOORD8; - nointerpolation float3 InstanceTransform2 : TEXCOORD9; - nointerpolation float3 InstanceTransform3 : TEXCOORD10; + nointerpolation uint ObjectIndex : TEXCOORD8; }; // Interpolants passed from the vertex shader @@ -80,11 +79,8 @@ struct MaterialInput float4 SvPosition; float3 PreSkinnedPosition; float3 PreSkinnedNormal; - float3 InstanceOrigin; - float2 InstanceParams; - float3 InstanceTransform1; - float3 InstanceTransform2; - float3 InstanceTransform3; + uint ObjectIndex; + ObjectData Object; #if USE_CUSTOM_VERTEX_INTERPOLATORS float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT]; #endif @@ -103,11 +99,7 @@ MaterialInput GetGeometryMaterialInput(GeometryData geometry) output.VertexColor = geometry.VertexColor; #endif output.TBN = CalcTangentBasis(geometry.WorldNormal, geometry.WorldTangent); - output.InstanceOrigin = geometry.InstanceOrigin; - output.InstanceParams = geometry.InstanceParams; - output.InstanceTransform1 = geometry.InstanceTransform1; - output.InstanceTransform2 = geometry.InstanceTransform2; - output.InstanceTransform3 = geometry.InstanceTransform3; + output.ObjectIndex = geometry.ObjectIndex; return output; } @@ -143,11 +135,7 @@ GeometryData InterpolateGeometry(GeometryData p0, float w0, GeometryData p1, flo output.WorldNormal = normalize(output.WorldNormal); output.WorldTangent = p0.WorldTangent * w0 + p1.WorldTangent * w1 + p2.WorldTangent * w2; output.WorldTangent.xyz = normalize(output.WorldTangent.xyz); - output.InstanceOrigin = p0.InstanceOrigin; - output.InstanceParams = p0.InstanceParams; - output.InstanceTransform1 = p0.InstanceTransform1; - output.InstanceTransform2 = p0.InstanceTransform2; - output.InstanceTransform3 = p0.InstanceTransform3; + output.ObjectIndex = p0.ObjectIndex; return output; } @@ -156,7 +144,8 @@ GeometryData InterpolateGeometry(GeometryData p0, float w0, GeometryData p1, flo MaterialInput GetMaterialInput(PixelInput input) { MaterialInput output = GetGeometryMaterialInput(input.Geometry); - output.TwoSidedSign = WorldDeterminantSign * (input.IsFrontFace ? 1.0 : -1.0); + output.Object = LoadObject(ObjectsBuffer, input.Geometry.ObjectIndex); + output.TwoSidedSign = output.Object.WorldDeterminantSign * (input.IsFrontFace ? 1.0 : -1.0); output.SvPosition = input.Position; #if USE_CUSTOM_VERTEX_INTERPOLATORS output.CustomVSToPS = input.CustomVSToPS; @@ -164,16 +153,6 @@ MaterialInput GetMaterialInput(PixelInput input) return output; } -// Gets the local to world transform matrix -#define GetInstanceTransform(input) float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f)) - -// Extarcts the world matrix and instancce transform vector -#if USE_INSTANCING -#define CalculateInstanceTransform(input) float4x4 world = GetInstanceTransform(input); output.Geometry.InstanceTransform1 = input.InstanceTransform1.xyz; output.Geometry.InstanceTransform2 = input.InstanceTransform2.xyz; output.Geometry.InstanceTransform3 = input.InstanceTransform3.xyz; -#else -#define CalculateInstanceTransform(input) float4x4 world = ToMatrix4x4(WorldMatrix); output.Geometry.InstanceTransform1 = world[0].xyz; output.Geometry.InstanceTransform2 = world[1].xyz; output.Geometry.InstanceTransform3 = world[2].xyz; -#endif - // Removes the scale vector from the local to world transformation matrix (supports instancing) float3x3 RemoveScaleFromLocalToWorld(float3x3 localToWorld) { @@ -218,7 +197,7 @@ float3 TransformViewVectorToWorld(MaterialInput input, float3 viewVector) // Transforms a vector from local space to world space float3 TransformLocalVectorToWorld(MaterialInput input, float3 localVector) { - float3x3 localToWorld = (float3x3)GetInstanceTransform(input); + float3x3 localToWorld = (float3x3)input.Object.WorldMatrix; //localToWorld = RemoveScaleFromLocalToWorld(localToWorld); return mul(localVector, localToWorld); } @@ -226,7 +205,7 @@ float3 TransformLocalVectorToWorld(MaterialInput input, float3 localVector) // Transforms a vector from local space to world space float3 TransformWorldVectorToLocal(MaterialInput input, float3 worldVector) { - float3x3 localToWorld = (float3x3)GetInstanceTransform(input); + float3x3 localToWorld = (float3x3)input.Object.WorldMatrix; //localToWorld = RemoveScaleFromLocalToWorld(localToWorld); return mul(localToWorld, worldVector); } @@ -234,30 +213,26 @@ float3 TransformWorldVectorToLocal(MaterialInput input, float3 worldVector) // Gets the current object position (supports instancing) float3 GetObjectPosition(MaterialInput input) { - return input.InstanceOrigin.xyz; + return input.Object.WorldMatrix[3].xyz; } // Gets the current object size (supports instancing) float3 GetObjectSize(MaterialInput input) { - float4x4 world = GetInstanceTransform(input); - return GeometrySize * float3(world._m00, world._m11, world._m22); + float4x4 world = input.Object.WorldMatrix; + return input.Object.GeometrySize * float3(world._m00, world._m11, world._m22); } // Get the current object random value (supports instancing) float GetPerInstanceRandom(MaterialInput input) { - return input.InstanceParams.x; + return input.Object.PerInstanceRandom; } // Get the current object LOD transition dither factor (supports instancing) float GetLODDitherFactor(MaterialInput input) { -#if USE_DITHERED_LOD_TRANSITION - return input.InstanceParams.y; -#else - return 0; -#endif + return input.Object.LODDitherFactor; } // Gets the interpolated vertex color (in linear space) @@ -316,19 +291,22 @@ META_VS_IN_ELEMENT(NORMAL, 0, R10G10B10A2_UNORM, 1, ALIGN, PER_VERTEX, 0, true META_VS_IN_ELEMENT(TANGENT, 0, R10G10B10A2_UNORM, 1, ALIGN, PER_VERTEX, 0, true) META_VS_IN_ELEMENT(TEXCOORD, 1, R16G16_FLOAT, 1, ALIGN, PER_VERTEX, 0, true) META_VS_IN_ELEMENT(COLOR, 0, R8G8B8A8_UNORM, 2, 0, PER_VERTEX, 0, USE_VERTEX_COLOR) -META_VS_IN_ELEMENT(ATTRIBUTE,0, R32G32B32A32_FLOAT,3, 0, PER_INSTANCE, 1, USE_INSTANCING) -META_VS_IN_ELEMENT(ATTRIBUTE,1, R32G32B32A32_FLOAT,3, ALIGN, PER_INSTANCE, 1, USE_INSTANCING) -META_VS_IN_ELEMENT(ATTRIBUTE,2, R32G32B32_FLOAT, 3, ALIGN, PER_INSTANCE, 1, USE_INSTANCING) -META_VS_IN_ELEMENT(ATTRIBUTE,3, R32G32B32_FLOAT, 3, ALIGN, PER_INSTANCE, 1, USE_INSTANCING) -META_VS_IN_ELEMENT(ATTRIBUTE,4, R16G16B16A16_FLOAT,3, ALIGN, PER_INSTANCE, 1, USE_INSTANCING) +META_VS_IN_ELEMENT(ATTRIBUTE,0, R32_UINT, 3, 0, PER_INSTANCE, 1, USE_INSTANCING) VertexOutput VS(ModelInput input) { VertexOutput output; + // Load object data +#if USE_INSTANCING + output.Geometry.ObjectIndex = input.ObjectIndex; +#else + output.Geometry.ObjectIndex = DrawObjectIndex; +#endif + ObjectData object = LoadObject(ObjectsBuffer, output.Geometry.ObjectIndex); + // Compute world space vertex position - CalculateInstanceTransform(input); - output.Geometry.WorldPosition = mul(float4(input.Position.xyz, 1), world).xyz; - output.Geometry.PrevWorldPosition = mul(float4(input.Position.xyz, 1), ToMatrix4x4(PrevWorldMatrix)).xyz; + output.Geometry.WorldPosition = mul(float4(input.Position.xyz, 1), object.WorldMatrix).xyz; + output.Geometry.PrevWorldPosition = mul(float4(input.Position.xyz, 1), object.PrevWorldMatrix).xyz; // Compute clip space position output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix); @@ -338,22 +316,15 @@ VertexOutput VS(ModelInput input) #if USE_VERTEX_COLOR output.Geometry.VertexColor = input.Color; #endif - output.Geometry.InstanceOrigin = world[3].xyz; -#if USE_INSTANCING - output.Geometry.LightmapUV = input.LightmapUV * input.InstanceLightmapArea.zw + input.InstanceLightmapArea.xy; - output.Geometry.InstanceParams = float2(input.InstanceOrigin.w, input.InstanceTransform1.w); -#else #if CAN_USE_LIGHTMAP - output.Geometry.LightmapUV = input.LightmapUV * LightmapArea.zw + LightmapArea.xy; + output.Geometry.LightmapUV = input.LightmapUV * object.LightmapArea.zw + object.LightmapArea.xy; #else output.Geometry.LightmapUV = input.LightmapUV; #endif - output.Geometry.InstanceParams = float2(PerInstanceRandom, LODDitherFactor); -#endif // Calculate tanget space to world space transformation matrix for unit vectors float3x3 tangentToLocal = CalcTangentToLocal(input); - float3x3 tangentToWorld = CalcTangentToWorld(world, tangentToLocal); + float3x3 tangentToWorld = CalcTangentToWorld(object.WorldMatrix, tangentToLocal); output.Geometry.WorldNormal = tangentToWorld[2]; output.Geometry.WorldTangent.xyz = tangentToWorld[0]; output.Geometry.WorldTangent.w = input.Tangent.w ? -1.0f : +1.0f; @@ -361,10 +332,11 @@ VertexOutput VS(ModelInput input) // Get material input params if need to evaluate any material property #if USE_POSITION_OFFSET || USE_TESSELLATION || USE_CUSTOM_VERTEX_INTERPOLATORS MaterialInput materialInput = GetGeometryMaterialInput(output.Geometry); - materialInput.TwoSidedSign = WorldDeterminantSign; + materialInput.TwoSidedSign = object.WorldDeterminantSign; materialInput.SvPosition = output.Position; materialInput.PreSkinnedPosition = input.Position.xyz; materialInput.PreSkinnedNormal = tangentToLocal[2].xyz; + materialInput.Object = object; Material material = GetMaterialVS(materialInput); #endif @@ -392,33 +364,27 @@ META_VS(true, FEATURE_LEVEL_ES2) META_PERMUTATION_1(USE_INSTANCING=0) META_PERMUTATION_1(USE_INSTANCING=1) META_VS_IN_ELEMENT(POSITION, 0, R32G32B32_FLOAT, 0, 0, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(ATTRIBUTE,0, R32G32B32A32_FLOAT,3, 0, PER_INSTANCE, 1, USE_INSTANCING) -META_VS_IN_ELEMENT(ATTRIBUTE,1, R32G32B32A32_FLOAT,3, ALIGN, PER_INSTANCE, 1, USE_INSTANCING) -META_VS_IN_ELEMENT(ATTRIBUTE,2, R32G32B32_FLOAT, 3, ALIGN, PER_INSTANCE, 1, USE_INSTANCING) -META_VS_IN_ELEMENT(ATTRIBUTE,3, R32G32B32_FLOAT, 3, ALIGN, PER_INSTANCE, 1, USE_INSTANCING) -META_VS_IN_ELEMENT(ATTRIBUTE,4, R16G16B16A16_FLOAT,3, ALIGN, PER_INSTANCE, 1, USE_INSTANCING) +META_VS_IN_ELEMENT(ATTRIBUTE,0, R32_UINT, 3, 0, PER_INSTANCE, 1, USE_INSTANCING) float4 VS_Depth(ModelInput_PosOnly input) : SV_Position { + // Load object data #if USE_INSTANCING - float4x4 world = GetInstanceTransform(input); + uint objectIndex = input.ObjectIndex; #else - float4x4 world = ToMatrix4x4(WorldMatrix); + uint objectIndex = DrawObjectIndex; #endif - float3 worldPosition = mul(float4(input.Position.xyz, 1), world).xyz; + ObjectData object = LoadObject(ObjectsBuffer, objectIndex); + + // Transform vertex position into the screen + float3 worldPosition = mul(float4(input.Position.xyz, 1), object.WorldMatrix).xyz; float4 position = mul(float4(worldPosition, 1), ViewProjectionMatrix); return position; } #if USE_SKINNING -// The skeletal bones matrix buffer (stored as 4x3, 3 float4 behind each other) -Buffer BoneMatrices : register(t0); - #if PER_BONE_MOTION_BLUR -// The skeletal bones matrix buffer from the previous frame -Buffer PrevBoneMatrices : register(t1); - float3x4 GetPrevBoneMatrix(int index) { float4 a = PrevBoneMatrices[index * 3]; @@ -497,6 +463,10 @@ META_VS_IN_ELEMENT(BLENDWEIGHT, 0, R16G16B16A16_FLOAT,0, ALIGN, PER_VERTEX, 0, VertexOutput VS_Skinned(ModelInput_Skinned input) { VertexOutput output; + + // Load object data + output.Geometry.ObjectIndex = DrawObjectIndex; + ObjectData object = LoadObject(ObjectsBuffer, output.Geometry.ObjectIndex); // Perform skinning float3x4 boneMatrix = GetBoneMatrix(input); @@ -504,13 +474,12 @@ VertexOutput VS_Skinned(ModelInput_Skinned input) float3x3 tangentToLocal = SkinTangents(input, boneMatrix); // Compute world space vertex position - CalculateInstanceTransform(input); - output.Geometry.WorldPosition = mul(float4(position, 1), world).xyz; + output.Geometry.WorldPosition = mul(float4(position, 1), object.WorldMatrix).xyz; #if PER_BONE_MOTION_BLUR float3 prevPosition = SkinPrevPosition(input); - output.Geometry.PrevWorldPosition = mul(float4(prevPosition, 1), ToMatrix4x4(PrevWorldMatrix)).xyz; + output.Geometry.PrevWorldPosition = mul(float4(prevPosition, 1), object.PrevWorldMatrix).xyz; #else - output.Geometry.PrevWorldPosition = mul(float4(position, 1), ToMatrix4x4(PrevWorldMatrix)).xyz; + output.Geometry.PrevWorldPosition = mul(float4(position, 1), object.PrevWorldMatrix).xyz; #endif // Compute clip space position @@ -522,15 +491,9 @@ VertexOutput VS_Skinned(ModelInput_Skinned input) output.Geometry.VertexColor = float4(0, 0, 0, 1); #endif output.Geometry.LightmapUV = float2(0, 0); - output.Geometry.InstanceOrigin = world[3].xyz; -#if USE_INSTANCING - output.Geometry.InstanceParams = float2(input.InstanceOrigin.w, input.InstanceTransform1.w); -#else - output.Geometry.InstanceParams = float2(PerInstanceRandom, LODDitherFactor); -#endif // Calculate tanget space to world space transformation matrix for unit vectors - float3x3 tangentToWorld = CalcTangentToWorld(world, tangentToLocal); + float3x3 tangentToWorld = CalcTangentToWorld(object.WorldMatrix, tangentToLocal); output.Geometry.WorldNormal = tangentToWorld[2]; output.Geometry.WorldTangent.xyz = tangentToWorld[0]; output.Geometry.WorldTangent.w = input.Tangent.w ? -1.0f : +1.0f; @@ -538,10 +501,11 @@ VertexOutput VS_Skinned(ModelInput_Skinned input) // Get material input params if need to evaluate any material property #if USE_POSITION_OFFSET || USE_TESSELLATION || USE_CUSTOM_VERTEX_INTERPOLATORS MaterialInput materialInput = GetGeometryMaterialInput(output.Geometry); - materialInput.TwoSidedSign = WorldDeterminantSign; + materialInput.TwoSidedSign = object.WorldDeterminantSign; materialInput.SvPosition = output.Position; materialInput.PreSkinnedPosition = input.Position.xyz; materialInput.PreSkinnedNormal = tangentToLocal[2].xyz; + materialInput.Object = object; Material material = GetMaterialVS(materialInput); #endif @@ -568,12 +532,12 @@ VertexOutput VS_Skinned(ModelInput_Skinned input) #if USE_DITHERED_LOD_TRANSITION -void ClipLODTransition(PixelInput input) +void ClipLODTransition(MaterialInput input) { - float ditherFactor = input.Geometry.InstanceParams.y; + float ditherFactor = input.Object.LODDitherFactor; if (abs(ditherFactor) > 0.001) { - float randGrid = cos(dot(floor(input.Position.xy), float2(347.83452793, 3343.28371863))); + float randGrid = cos(dot(floor(input.SvPosition.xy), float2(347.83452793, 3343.28371863))); float randGridFrac = frac(randGrid * 1000.0); half mask = (ditherFactor < 0.0) ? (ditherFactor + 1.0 > randGridFrac) : (ditherFactor < randGridFrac); clip(mask - 0.001); @@ -586,14 +550,13 @@ void ClipLODTransition(PixelInput input) META_PS(true, FEATURE_LEVEL_ES2) void PS_Depth(PixelInput input) { + MaterialInput materialInput = GetMaterialInput(input); #if USE_DITHERED_LOD_TRANSITION - // LOD masking - ClipLODTransition(input); + ClipLODTransition(materialInput); #endif #if MATERIAL_MASKED || MATERIAL_BLEND != MATERIAL_BLEND_OPAQUE // Get material parameters - MaterialInput materialInput = GetMaterialInput(input); Material material = GetMaterialPS(materialInput); // Perform per pixel clipping diff --git a/Content/Editor/MaterialTemplates/Terrain.shader b/Content/Editor/MaterialTemplates/Terrain.shader index 71504f6ed..f7819c863 100644 --- a/Content/Editor/MaterialTemplates/Terrain.shader +++ b/Content/Editor/MaterialTemplates/Terrain.shader @@ -28,6 +28,7 @@ float4 HeightmapUVScaleBias; float4 NeighborLOD; float2 OffsetUV; float2 Dummy0; +float4 LightmapArea; @1META_CB_END // Terrain data @@ -88,6 +89,7 @@ struct MaterialInput float3 PreSkinnedPosition; float3 PreSkinnedNormal; float HolesMask; + ObjectData Object; #if USE_TERRAIN_LAYERS float4 Layers[TERRAIN_LAYERS_DATA_SIZE]; #endif @@ -147,9 +149,23 @@ GeometryData InterpolateGeometry(GeometryData p0, float w0, GeometryData p1, flo #endif +ObjectData GetObject() +{ + ObjectData object = (ObjectData)0; + object.WorldMatrix = ToMatrix4x4(WorldMatrix); + object.PrevWorldMatrix = object.WorldMatrix; + object.GeometrySize = float3(1, 1, 1); + object.PerInstanceRandom = PerInstanceRandom; + object.WorldDeterminantSign = WorldDeterminantSign; + object.LODDitherFactor = 0.0f; + object.LightmapArea = LightmapArea; + return object; +} + MaterialInput GetMaterialInput(PixelInput input) { MaterialInput output = GetGeometryMaterialInput(input.Geometry); + output.Object = GetObject(); output.TwoSidedSign = WorldDeterminantSign * (input.IsFrontFace ? 1.0 : -1.0); output.SvPosition = input.Position; #if USE_CUSTOM_VERTEX_INTERPOLATORS @@ -396,6 +412,7 @@ VertexOutput VS(TerrainVertexInput input) // Get material input params if need to evaluate any material property #if USE_POSITION_OFFSET || USE_TESSELLATION || USE_CUSTOM_VERTEX_INTERPOLATORS MaterialInput materialInput = (MaterialInput)0; + materialInput.Object = GetObject(); materialInput.WorldPosition = output.Geometry.WorldPosition; materialInput.TexCoord = output.Geometry.TexCoord; #if USE_LIGHTMAP diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp index 562a8b706..530c5c662 100644 --- a/Source/Engine/Foliage/Foliage.cpp +++ b/Source/Engine/Foliage/Foliage.cpp @@ -116,6 +116,7 @@ void Foliage::DrawInstance(RenderContext& renderContext, FoliageInstance& instan ASSERT_LOW_LAYER(key.Mat); e->DrawCall.Material = key.Mat; e->DrawCall.Surface.Lightmap = EnumHasAnyFlags(_staticFlags, StaticFlags::Lightmap) && _scene ? _scene->LightmapsData.GetReadyLightmap(key.Lightmap) : nullptr; + e->DrawCall.Surface.GeometrySize = key.Geo->GetBox().GetSize(); } // Add instance to the draw batch @@ -124,13 +125,8 @@ void Foliage::DrawInstance(RenderContext& renderContext, FoliageInstance& instan const Transform transform = _transform.LocalToWorld(instance.Transform); const Float3 translation = transform.Translation - renderContext.View.Origin; Matrix::Transformation(transform.Scale, transform.Orientation, translation, world); - instanceData.InstanceOrigin = Float3(world.M41, world.M42, world.M43); - instanceData.PerInstanceRandom = instance.Random; - instanceData.InstanceTransform1 = Float3(world.M11, world.M12, world.M13); - instanceData.LODDitherFactor = lodDitherFactor; - instanceData.InstanceTransform2 = Float3(world.M21, world.M22, world.M23); - instanceData.InstanceTransform3 = Float3(world.M31, world.M32, world.M33); - instanceData.InstanceLightmapArea = Half4(instance.Lightmap.UVsArea); + constexpr float worldDeterminantSign = 1.0f; + instanceData.Store(world, world, instance.Lightmap.UVsArea, drawCall.DrawCall.Surface.GeometrySize, instance.Random, worldDeterminantSign, lodDitherFactor); } } @@ -456,6 +452,7 @@ void Foliage::DrawType(RenderContext& renderContext, const FoliageType& type, Dr continue; drawCall.DrawCall.Material = material; + drawCall.DrawCall.Surface.GeometrySize = mesh.GetBox().GetSize(); } } @@ -479,18 +476,7 @@ void Foliage::DrawType(RenderContext& renderContext, const FoliageType& type, Dr mesh.GetDrawCallGeometry(batch.DrawCall); batch.DrawCall.InstanceCount = 1; auto& firstInstance = batch.Instances[0]; - batch.DrawCall.ObjectPosition = firstInstance.InstanceOrigin; - batch.DrawCall.PerInstanceRandom = firstInstance.PerInstanceRandom; - auto lightmapArea = firstInstance.InstanceLightmapArea.ToFloat4(); - batch.DrawCall.Surface.LightmapUVsArea = *(Rectangle*)&lightmapArea; - batch.DrawCall.Surface.LODDitherFactor = firstInstance.LODDitherFactor; - batch.DrawCall.World.SetRow1(Float4(firstInstance.InstanceTransform1, 0.0f)); - batch.DrawCall.World.SetRow2(Float4(firstInstance.InstanceTransform2, 0.0f)); - batch.DrawCall.World.SetRow3(Float4(firstInstance.InstanceTransform3, 0.0f)); - batch.DrawCall.World.SetRow4(Float4(firstInstance.InstanceOrigin, 1.0f)); - batch.DrawCall.Surface.PrevWorld = batch.DrawCall.World; - batch.DrawCall.Surface.GeometrySize = mesh.GetBox().GetSize(); - batch.DrawCall.WorldDeterminantSign = 1; + firstInstance.Load(batch.DrawCall); if (EnumHasAnyFlags(drawModes, DrawPass::Forward)) { @@ -499,15 +485,7 @@ void Foliage::DrawType(RenderContext& renderContext, const FoliageType& type, Dr for (int32 j = 0; j < batch.Instances.Count(); j++) { auto& instance = batch.Instances[j]; - drawCall.ObjectPosition = instance.InstanceOrigin; - drawCall.PerInstanceRandom = instance.PerInstanceRandom; - lightmapArea = instance.InstanceLightmapArea.ToFloat4(); - drawCall.Surface.LightmapUVsArea = *(Rectangle*)&lightmapArea; - drawCall.Surface.LODDitherFactor = instance.LODDitherFactor; - drawCall.World.SetRow1(Float4(instance.InstanceTransform1, 0.0f)); - drawCall.World.SetRow2(Float4(instance.InstanceTransform2, 0.0f)); - drawCall.World.SetRow3(Float4(instance.InstanceTransform3, 0.0f)); - drawCall.World.SetRow4(Float4(instance.InstanceOrigin, 1.0f)); + instance.Load(drawCall); const int32 drawCallIndex = renderContext.List->DrawCalls.Add(drawCall); renderContext.List->DrawCallsLists[(int32)DrawCallsListType::Forward].Indices.Add(drawCallIndex); } diff --git a/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp b/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp index 9b2654f21..714805f45 100644 --- a/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp @@ -29,7 +29,7 @@ void DecalMaterialShader::Bind(BindParameters& params) // Prepare auto context = params.GPUContext; auto& view = params.RenderContext.View; - auto& drawCall = *params.FirstDrawCall; + auto& drawCall = *params.DrawCall; Span cb(_cbData.Get(), _cbData.Count()); ASSERT_LOW_LAYER(cb.Length() >= sizeof(DecalMaterialShaderData)); auto materialData = reinterpret_cast(cb.Get()); diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp index a08797bdb..152edcfae 100644 --- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp @@ -3,7 +3,6 @@ #include "DeferredMaterialShader.h" #include "MaterialShaderFeatures.h" #include "MaterialParams.h" -#include "Engine/Core/Math/Matrix3x4.h" #include "Engine/Graphics/RenderBuffers.h" #include "Engine/Graphics/RenderView.h" #include "Engine/Renderer/DrawCall.h" @@ -17,16 +16,6 @@ #include "Engine/Graphics/GPULimits.h" #include "Engine/Graphics/RenderTask.h" -PACK_STRUCT(struct DeferredMaterialShaderData { - Matrix3x4 WorldMatrix; - Matrix3x4 PrevWorldMatrix; - Float2 Dummy0; - float LODDitherFactor; - float PerInstanceRandom; - Float3 GeometrySize; - float WorldDeterminantSign; - }); - DrawPass DeferredMaterialShader::GetDrawModes() const { return DrawPass::Depth | DrawPass::GBuffer | DrawPass::GlobalSurfaceAtlas | DrawPass::MotionVectors | DrawPass::QuadOverdraw; @@ -39,22 +28,17 @@ bool DeferredMaterialShader::CanUseLightmap() const bool DeferredMaterialShader::CanUseInstancing(InstancingHandler& handler) const { - handler = { SurfaceDrawCallHandler::GetHash, SurfaceDrawCallHandler::CanBatch, SurfaceDrawCallHandler::WriteDrawCall, }; + handler = { SurfaceDrawCallHandler::GetHash, SurfaceDrawCallHandler::CanBatch, }; return true; } void DeferredMaterialShader::Bind(BindParameters& params) { - //PROFILE_CPU(); - // Prepare auto context = params.GPUContext; auto& view = params.RenderContext.View; - auto& drawCall = *params.FirstDrawCall; + auto& drawCall = *params.DrawCall; Span cb(_cbData.Get(), _cbData.Count()); - ASSERT_LOW_LAYER(cb.Length() >= sizeof(DeferredMaterialShaderData)); - auto materialData = reinterpret_cast(cb.Get()); - cb = Span(cb.Get() + sizeof(DeferredMaterialShaderData), cb.Length() - sizeof(DeferredMaterialShaderData)); - int32 srv = 2; + int32 srv = 3; // Setup features const bool useLightmap = _info.BlendMode == MaterialBlendMode::Opaque && LightmapFeature::Bind(params, cb, srv); @@ -68,28 +52,19 @@ void DeferredMaterialShader::Bind(BindParameters& params) bindMeta.CanSampleDepth = false; bindMeta.CanSampleGBuffer = false; MaterialParams::Bind(params.ParamsLink, bindMeta); + context->BindSR(0, params.ObjectBuffer); - // Setup material constants - { - materialData->WorldMatrix.SetMatrixTranspose(drawCall.World); - materialData->PrevWorldMatrix.SetMatrixTranspose(drawCall.Surface.PrevWorld); - materialData->WorldDeterminantSign = drawCall.WorldDeterminantSign; - materialData->LODDitherFactor = drawCall.Surface.LODDitherFactor; - materialData->PerInstanceRandom = drawCall.PerInstanceRandom; - materialData->GeometrySize = drawCall.Surface.GeometrySize; - } - - // Check if is using mesh skinning + // Check if using mesh skinning const bool useSkinning = drawCall.Surface.Skinning != nullptr; bool perBoneMotionBlur = false; if (useSkinning) { // Bind skinning buffer ASSERT(drawCall.Surface.Skinning->IsReady()); - context->BindSR(0, drawCall.Surface.Skinning->BoneMatrices->View()); + context->BindSR(1, drawCall.Surface.Skinning->BoneMatrices->View()); if (drawCall.Surface.Skinning->PrevBoneMatrices && drawCall.Surface.Skinning->PrevBoneMatrices->IsAllocated()) { - context->BindSR(1, drawCall.Surface.Skinning->PrevBoneMatrices->View()); + context->BindSR(2, drawCall.Surface.Skinning->PrevBoneMatrices->View()); perBoneMotionBlur = true; } } @@ -116,8 +91,8 @@ void DeferredMaterialShader::Bind(BindParameters& params) 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; + ASSERT_LOW_LAYER(!(useSkinning && params.Instanced)); // No support for instancing skinned meshes + const auto cache = params.Instanced ? &_cacheInstanced : &_cache; PipelineStateCache* psCache = cache->GetPS(view.Pass, useLightmap, useSkinning, perBoneMotionBlur); ASSERT(psCache); GPUPipelineState* state = psCache->GetPS(cullMode, wireframe); diff --git a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp index f5b7f2368..434d1ef05 100644 --- a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp @@ -37,7 +37,7 @@ void DeformableMaterialShader::Bind(BindParameters& params) // Prepare auto context = params.GPUContext; auto& view = params.RenderContext.View; - auto& drawCall = *params.FirstDrawCall; + auto& drawCall = *params.DrawCall; Span cb(_cbData.Get(), _cbData.Count()); ASSERT_LOW_LAYER(cb.Length() >= sizeof(DeformableMaterialShaderData)); auto materialData = reinterpret_cast(cb.Get()); diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp index eb843896c..23e9ec0b7 100644 --- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp @@ -3,7 +3,6 @@ #include "ForwardMaterialShader.h" #include "MaterialShaderFeatures.h" #include "MaterialParams.h" -#include "Engine/Core/Math/Matrix3x4.h" #include "Engine/Graphics/GPUContext.h" #include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/GPULimits.h" @@ -18,16 +17,6 @@ #include "Engine/Renderer/Lightmaps.h" #endif -PACK_STRUCT(struct ForwardMaterialShaderData { - Matrix3x4 WorldMatrix; - Matrix3x4 PrevWorldMatrix; - Float2 Dummy0; - float LODDitherFactor; - float PerInstanceRandom; - Float3 GeometrySize; - float WorldDeterminantSign; - }); - DrawPass ForwardMaterialShader::GetDrawModes() const { return _drawModes; @@ -35,7 +24,7 @@ DrawPass ForwardMaterialShader::GetDrawModes() const bool ForwardMaterialShader::CanUseInstancing(InstancingHandler& handler) const { - handler = { SurfaceDrawCallHandler::GetHash, SurfaceDrawCallHandler::CanBatch, SurfaceDrawCallHandler::WriteDrawCall, }; + handler = { SurfaceDrawCallHandler::GetHash, SurfaceDrawCallHandler::CanBatch, }; return true; } @@ -44,12 +33,9 @@ void ForwardMaterialShader::Bind(BindParameters& params) // Prepare auto context = params.GPUContext; auto& view = params.RenderContext.View; - auto& drawCall = *params.FirstDrawCall; + auto& drawCall = *params.DrawCall; Span cb(_cbData.Get(), _cbData.Count()); - ASSERT_LOW_LAYER(cb.Length() >= sizeof(ForwardMaterialShaderData)); - auto materialData = reinterpret_cast(cb.Get()); - cb = Span(cb.Get() + sizeof(ForwardMaterialShaderData), cb.Length() - sizeof(ForwardMaterialShaderData)); - int32 srv = 2; + int32 srv = 3; // Setup features if ((_info.FeaturesFlags & MaterialFeaturesFlags::GlobalIllumination) != MaterialFeaturesFlags::None) @@ -65,24 +51,15 @@ void ForwardMaterialShader::Bind(BindParameters& params) bindMeta.CanSampleDepth = GPUDevice::Instance->Limits.HasReadOnlyDepth; bindMeta.CanSampleGBuffer = true; MaterialParams::Bind(params.ParamsLink, bindMeta); + context->BindSR(0, params.ObjectBuffer); - // Check if is using mesh skinning + // Check if using mesh skinning const bool useSkinning = drawCall.Surface.Skinning != nullptr; if (useSkinning) { // Bind skinning buffer ASSERT(drawCall.Surface.Skinning->IsReady()); - context->BindSR(0, drawCall.Surface.Skinning->BoneMatrices->View()); - } - - // Setup material constants - { - materialData->WorldMatrix.SetMatrixTranspose(drawCall.World); - materialData->PrevWorldMatrix.SetMatrixTranspose(drawCall.Surface.PrevWorld); - materialData->WorldDeterminantSign = drawCall.WorldDeterminantSign; - materialData->LODDitherFactor = drawCall.Surface.LODDitherFactor; - materialData->PerInstanceRandom = drawCall.PerInstanceRandom; - materialData->GeometrySize = drawCall.Surface.GeometrySize; + context->BindSR(1, drawCall.Surface.Skinning->BoneMatrices->View()); } // Bind constants @@ -107,8 +84,8 @@ void ForwardMaterialShader::Bind(BindParameters& params) 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; + ASSERT_LOW_LAYER(!(useSkinning && params.Instanced)); // No support for instancing skinned meshes + const auto cacheObj = params.Instanced ? &_cacheInstanced : &_cache; PipelineStateCache* psCache = cacheObj->GetPS(view.Pass, useSkinning); ASSERT(psCache); GPUPipelineState* state = psCache->GetPS(cullMode, wireframe); diff --git a/Source/Engine/Graphics/Materials/IMaterial.h b/Source/Engine/Graphics/Materials/IMaterial.h index 5235dd59e..90d44897e 100644 --- a/Source/Engine/Graphics/Materials/IMaterial.h +++ b/Source/Engine/Graphics/Materials/IMaterial.h @@ -8,6 +8,7 @@ struct MaterialParamsLink; class GPUShader; class GPUContext; class GPUTextureView; +class GPUBufferView; class GPUConstantBuffer; class RenderBuffers; class SceneRenderTask; @@ -120,7 +121,6 @@ public: { void (*GetHash)(const DrawCall& drawCall, uint32& batchKey); bool (*CanBatch)(const DrawCall& a, const DrawCall& b, DrawPass pass); - void (*WriteDrawCall)(struct InstanceData* instanceData, const DrawCall& drawCall); }; /// @@ -131,7 +131,7 @@ public: virtual bool CanUseInstancing(InstancingHandler& handler) const { #if BUILD_DEBUG - handler = { nullptr, nullptr, nullptr }; + handler = { nullptr, nullptr }; #endif return false; } @@ -144,11 +144,12 @@ public: { GPUContext* GPUContext; const RenderContext& RenderContext; - const DrawCall* FirstDrawCall; - int32 DrawCallsCount; + GPUBufferView* ObjectBuffer = nullptr; + const ::DrawCall* DrawCall = nullptr; MaterialParamsLink* ParamsLink = nullptr; void* CustomData = nullptr; float TimeParam; + bool Instanced = false; /// /// The input scene color. It's optional and used in forward/postFx rendering. @@ -156,11 +157,12 @@ public: GPUTextureView* Input = nullptr; BindParameters(::GPUContext* context, const ::RenderContext& renderContext); - BindParameters(::GPUContext* context, const ::RenderContext& renderContext, const DrawCall& drawCall); - BindParameters(::GPUContext* context, const ::RenderContext& renderContext, const DrawCall* firstDrawCall, int32 drawCallsCount); + BindParameters(::GPUContext* context, const ::RenderContext& renderContext, const ::DrawCall& drawCall, bool instanced = false); // Per-view shared constant buffer (see ViewData in MaterialCommon.hlsl). static GPUConstantBuffer* PerViewConstants; + // Per-draw shared constant buffer (see ViewData in MaterialCommon.hlsl). + static GPUConstantBuffer* PerDrawConstants; // Binds the shared per-view constant buffer at slot 1 (see ViewData in MaterialCommon.hlsl) void BindViewData(); diff --git a/Source/Engine/Graphics/Materials/MaterialShader.cpp b/Source/Engine/Graphics/Materials/MaterialShader.cpp index beaedc324..fe1d1db2a 100644 --- a/Source/Engine/Graphics/Materials/MaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/MaterialShader.cpp @@ -38,31 +38,21 @@ GPU_CB_STRUCT(MaterialShaderDataPerView { IMaterial::BindParameters::BindParameters(::GPUContext* context, const ::RenderContext& renderContext) : GPUContext(context) , RenderContext(renderContext) - , FirstDrawCall(nullptr) - , DrawCallsCount(0) , TimeParam(Time::Draw.UnscaledTime.GetTotalSeconds()) { } -IMaterial::BindParameters::BindParameters(::GPUContext* context, const ::RenderContext& renderContext, const DrawCall& drawCall) +IMaterial::BindParameters::BindParameters(::GPUContext* context, const ::RenderContext& renderContext, const ::DrawCall& drawCall, bool instanced) : GPUContext(context) , RenderContext(renderContext) - , FirstDrawCall(&drawCall) - , DrawCallsCount(1) - , TimeParam(Time::Draw.UnscaledTime.GetTotalSeconds()) -{ -} - -IMaterial::BindParameters::BindParameters(::GPUContext* context, const ::RenderContext& renderContext, const DrawCall* firstDrawCall, int32 drawCallsCount) - : GPUContext(context) - , RenderContext(renderContext) - , FirstDrawCall(firstDrawCall) - , DrawCallsCount(drawCallsCount) + , DrawCall(&drawCall) , TimeParam(Time::Draw.UnscaledTime.GetTotalSeconds()) + , Instanced(instanced) { } GPUConstantBuffer* IMaterial::BindParameters::PerViewConstants = nullptr; +GPUConstantBuffer* IMaterial::BindParameters::PerDrawConstants = nullptr; void IMaterial::BindParameters::BindViewData() { @@ -70,6 +60,7 @@ void IMaterial::BindParameters::BindViewData() if (!PerViewConstants) { PerViewConstants = GPUDevice::Instance->CreateConstantBuffer(sizeof(MaterialShaderDataPerView), TEXT("PerViewConstants")); + PerDrawConstants = GPUDevice::Instance->CreateConstantBuffer(sizeof(MaterialShaderDataPerDraw), TEXT("PerDrawConstants")); } // Setup data diff --git a/Source/Engine/Graphics/Materials/MaterialShader.h b/Source/Engine/Graphics/Materials/MaterialShader.h index 223289a46..3bea7a2ec 100644 --- a/Source/Engine/Graphics/Materials/MaterialShader.h +++ b/Source/Engine/Graphics/Materials/MaterialShader.h @@ -10,13 +10,19 @@ /// /// Current materials shader version. /// -#define MATERIAL_GRAPH_VERSION 166 +#define MATERIAL_GRAPH_VERSION 167 class Material; class GPUShader; class GPUConstantBuffer; class MemoryReadStream; +// Draw pipeline constant buffer (with per-draw constants at slot 2) +GPU_CB_STRUCT(MaterialShaderDataPerDraw { + Float3 DrawPadding; + uint32 DrawObjectIndex; + }); + /// /// Represents material shader that can be used to render objects, visuals or effects. Contains a dedicated shader. /// diff --git a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp index c36fd9758..1582c75da 100644 --- a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp +++ b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp @@ -16,7 +16,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span= sizeof(Data)); const int32 envProbeShaderRegisterIndex = srv + 0; @@ -118,8 +118,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span& cb, int32& srv) { - auto& drawCall = *params.FirstDrawCall; - ASSERT_LOW_LAYER(cb.Length() >= sizeof(Data)); + auto& drawCall = *params.DrawCall; const bool useLightmap = EnumHasAnyFlags(params.RenderContext.View.Flags, ViewFlags::GI) #if USE_EDITOR @@ -134,13 +133,15 @@ bool LightmapFeature::Bind(MaterialShader::BindParameters& params, Span& c params.GPUContext->BindSR(srv + 0, lightmap0); params.GPUContext->BindSR(srv + 1, lightmap1); params.GPUContext->BindSR(srv + 2, lightmap2); - - // Set lightmap data - auto& data = *(Data*)cb.Get(); - data.LightmapArea = drawCall.Features.LightmapUVsArea; + } + else + { + // Free texture slots + params.GPUContext->UnBindSR(srv + 0); + params.GPUContext->UnBindSR(srv + 1); + params.GPUContext->UnBindSR(srv + 2); } - cb = Span(cb.Get() + sizeof(Data), cb.Length() - sizeof(Data)); srv += SRVs; return useLightmap; } diff --git a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h index 81a6e260d..a6c829e12 100644 --- a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h +++ b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h @@ -63,11 +63,6 @@ struct LightmapFeature : MaterialShaderFeature { enum { SRVs = 3 }; - PACK_STRUCT(struct Data - { - Rectangle LightmapArea; - }); - static bool Bind(MaterialShader::BindParameters& params, Span& cb, int32& srv); #if USE_EDITOR static void Generate(GeneratorData& data); diff --git a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp index 998a77843..f60742ccc 100644 --- a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp @@ -48,7 +48,7 @@ void ParticleMaterialShader::Bind(BindParameters& params) // Prepare auto context = params.GPUContext; auto& view = params.RenderContext.View; - auto& drawCall = *params.FirstDrawCall; + auto& drawCall = *params.DrawCall; const uint32 sortedIndicesOffset = drawCall.Particle.Module->SortedIndicesOffset; Span cb(_cbData.Get(), _cbData.Count()); ASSERT_LOW_LAYER(cb.Length() >= sizeof(ParticleMaterialShaderData)); diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp index 214284176..2a040b55a 100644 --- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp @@ -28,6 +28,7 @@ PACK_STRUCT(struct TerrainMaterialShaderData { Float4 NeighborLOD; // Per component LOD index for chunk neighbors ordered: top, left, right, bottom Float2 OffsetUV; // Offset applied to the texture coordinates (used to implement seamless UVs based on chunk location relative to terrain root) Float2 Dummy0; + Float4 LightmapArea; }); DrawPass TerrainMaterialShader::GetDrawModes() const @@ -45,7 +46,7 @@ void TerrainMaterialShader::Bind(BindParameters& params) // Prepare auto context = params.GPUContext; auto& view = params.RenderContext.View; - auto& drawCall = *params.FirstDrawCall; + auto& drawCall = *params.DrawCall; Span cb(_cbData.Get(), _cbData.Count()); ASSERT_LOW_LAYER(cb.Length() >= sizeof(TerrainMaterialShaderData)); auto materialData = reinterpret_cast(cb.Get()); @@ -83,6 +84,7 @@ void TerrainMaterialShader::Bind(BindParameters& params) materialData->HeightmapUVScaleBias = drawCall.Terrain.HeightmapUVScaleBias; materialData->NeighborLOD = drawCall.Terrain.NeighborLOD; materialData->OffsetUV = drawCall.Terrain.OffsetUV; + materialData->LightmapArea = *(Float4*)&drawCall.Terrain.LightmapUVsArea; } // Bind terrain textures diff --git a/Source/Engine/Graphics/Materials/VolumeParticleMaterialShader.cpp b/Source/Engine/Graphics/Materials/VolumeParticleMaterialShader.cpp index 585b4bf29..5b9bb27a6 100644 --- a/Source/Engine/Graphics/Materials/VolumeParticleMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/VolumeParticleMaterialShader.cpp @@ -37,7 +37,7 @@ void VolumeParticleMaterialShader::Bind(BindParameters& params) // Prepare auto context = params.GPUContext; const RenderView& view = params.RenderContext.View; - auto& drawCall = *params.FirstDrawCall; + auto& drawCall = *params.DrawCall; Span cb(_cbData.Get(), _cbData.Count()); ASSERT_LOW_LAYER(cb.Length() >= sizeof(VolumeParticleMaterialShaderData)); auto materialData = reinterpret_cast(cb.Get()); diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp index f168ccd79..766e08a39 100644 --- a/Source/Engine/Graphics/Models/Mesh.cpp +++ b/Source/Engine/Graphics/Models/Mesh.cpp @@ -382,7 +382,7 @@ void Mesh::Render(GPUContext* context) const context->BindVB(ToSpan((GPUBuffer**)_vertexBuffers, 3)); context->BindIB(_indexBuffer); - context->DrawIndexedInstanced(_triangles * 3, 1, 0, 0, 0); + context->DrawIndexed(_triangles * 3); } void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals, DrawPass drawModes, float perInstanceRandom, int8 sortOrder) const diff --git a/Source/Engine/Renderer/Editor/LODPreview.cpp b/Source/Engine/Renderer/Editor/LODPreview.cpp index 2f188bcd0..d3a633405 100644 --- a/Source/Engine/Renderer/Editor/LODPreview.cpp +++ b/Source/Engine/Renderer/Editor/LODPreview.cpp @@ -7,7 +7,6 @@ #include "Engine/Content/Content.h" #include "Engine/Content/Assets/Model.h" #include "Engine/Graphics/GPUDevice.h" -#include "Engine/Graphics/RenderTask.h" #include "Engine/Renderer/DrawCall.h" #include "Engine/Renderer/RenderList.h" #include "Engine/Renderer/GBufferPass.h" @@ -47,7 +46,7 @@ void LODPreviewMaterialShader::Bind(BindParameters& params) { // Find the LOD that produced this draw call int32 lodIndex = 0; - auto& drawCall = *params.FirstDrawCall; + auto& drawCall = *params.DrawCall; const ModelLOD* drawCallModelLod; if (GBufferPass::IndexBufferToModelLOD.TryGet(drawCall.Geometry.IndexBuffer, drawCallModelLod)) { diff --git a/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp b/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp index 287fd006c..47fbbe3df 100644 --- a/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp +++ b/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp @@ -108,7 +108,7 @@ void LightmapUVsDensityMaterialShader::Bind(BindParameters& params) { // Prepare auto context = params.GPUContext; - auto& drawCall = *params.FirstDrawCall; + auto& drawCall = *params.DrawCall; // Setup auto shader = _shader->GetShader(); diff --git a/Source/Engine/Renderer/Editor/MaterialComplexity.cpp b/Source/Engine/Renderer/Editor/MaterialComplexity.cpp index 1d7534485..afe66a8b2 100644 --- a/Source/Engine/Renderer/Editor/MaterialComplexity.cpp +++ b/Source/Engine/Renderer/Editor/MaterialComplexity.cpp @@ -48,7 +48,7 @@ DrawPass MaterialComplexityMaterialShader::WrapperShader::GetDrawModes() const void MaterialComplexityMaterialShader::WrapperShader::Bind(BindParameters& params) { - auto& drawCall = *params.FirstDrawCall; + auto& drawCall = *params.DrawCall; // Get original material from the draw call IMaterial* material = nullptr; diff --git a/Source/Engine/Renderer/Editor/VertexColors.cpp b/Source/Engine/Renderer/Editor/VertexColors.cpp index 6da039561..1f937439a 100644 --- a/Source/Engine/Renderer/Editor/VertexColors.cpp +++ b/Source/Engine/Renderer/Editor/VertexColors.cpp @@ -61,7 +61,7 @@ void VertexColorsMaterialShader::Bind(BindParameters& params) { // Prepare auto context = params.GPUContext; - auto& drawCall = *params.FirstDrawCall; + auto& drawCall = *params.DrawCall; // Setup auto shader = _shader->GetShader(); diff --git a/Source/Engine/Renderer/GBufferPass.cpp b/Source/Engine/Renderer/GBufferPass.cpp index 500e62f12..4d0826476 100644 --- a/Source/Engine/Renderer/GBufferPass.cpp +++ b/Source/Engine/Renderer/GBufferPass.cpp @@ -509,7 +509,7 @@ void GBufferPass::DrawDecals(RenderContext& renderContext, GPUTextureView* light drawCall.World = decal.World; decal.Material->Bind(bindParams); // TODO: use hardware instancing - context->DrawIndexedInstanced(drawCall.Draw.IndicesCount, 1, 0, 0, 0); + context->DrawIndexed(drawCall.Draw.IndicesCount); } context->ResetSR(); diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index e76c19b4e..8077049a9 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -849,6 +849,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co // Clear draw calls list renderContextTiles.List->DrawCalls.Clear(); renderContextTiles.List->BatchedDrawCalls.Clear(); + renderContextTiles.List->ObjectBuffer.Clear(); drawCallsListGBuffer.Indices.Clear(); drawCallsListGBuffer.PreBatchedDrawCalls.Clear(); drawCallsListGBufferNoDecals.Indices.Clear(); diff --git a/Source/Engine/Renderer/RenderList.cpp b/Source/Engine/Renderer/RenderList.cpp index b85bbed1b..e96a7a9a9 100644 --- a/Source/Engine/Renderer/RenderList.cpp +++ b/Source/Engine/Renderer/RenderList.cpp @@ -3,6 +3,7 @@ #include "RenderList.h" #include "Engine/Core/Collections/Sorting.h" #include "Engine/Graphics/Materials/IMaterial.h" +#include "Engine/Graphics/Materials/MaterialShader.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Graphics/GPUContext.h" #include "Engine/Graphics/GPUDevice.h" @@ -21,6 +22,7 @@ static_assert(sizeof(DrawCall) <= 288, "Too big draw call data size."); static_assert(sizeof(DrawCall::Surface) >= sizeof(DrawCall::Terrain), "Wrong draw call data size."); static_assert(sizeof(DrawCall::Surface) >= sizeof(DrawCall::Particle), "Wrong draw call data size."); static_assert(sizeof(DrawCall::Surface) >= sizeof(DrawCall::Custom), "Wrong draw call data size."); +static_assert(sizeof(ShaderObjectData) == sizeof(Float4) * ARRAY_COUNT(ShaderObjectData::Raw), "Wrong object data."); namespace { @@ -34,6 +36,40 @@ namespace CriticalSection MemPoolLocker; } +void ShaderObjectData::Store(const Matrix& worldMatrix, const Matrix& prevWorldMatrix, const Rectangle& lightmapUVsArea, const Float3& geometrySize, float perInstanceRandom, float worldDeterminantSign, float lodDitherFactor) +{ + Half4 lightmapUVsAreaPacked(*(Float4*)&lightmapUVsArea); + Float2 lightmapUVsAreaPackedAliased = *(Float2*)&lightmapUVsAreaPacked; + Raw[0] = Float4(worldMatrix.M11, worldMatrix.M12, worldMatrix.M13, worldMatrix.M41); + Raw[1] = Float4(worldMatrix.M21, worldMatrix.M22, worldMatrix.M23, worldMatrix.M42); + Raw[2] = Float4(worldMatrix.M31, worldMatrix.M32, worldMatrix.M33, worldMatrix.M43); + Raw[3] = Float4(prevWorldMatrix.M11, prevWorldMatrix.M12, prevWorldMatrix.M13, prevWorldMatrix.M41); + Raw[4] = Float4(prevWorldMatrix.M21, prevWorldMatrix.M22, prevWorldMatrix.M23, prevWorldMatrix.M42); + Raw[5] = Float4(prevWorldMatrix.M31, prevWorldMatrix.M32, prevWorldMatrix.M33, prevWorldMatrix.M43); + Raw[6] = Float4(geometrySize, perInstanceRandom); + Raw[7] = Float4(worldDeterminantSign, lodDitherFactor, lightmapUVsAreaPackedAliased.X, lightmapUVsAreaPackedAliased.Y); + // TODO: pack WorldDeterminantSign and LODDitherFactor +} + +void ShaderObjectData::Load(Matrix& worldMatrix, Matrix& prevWorldMatrix, Rectangle& lightmapUVsArea, Float3& geometrySize, float& perInstanceRandom, float& worldDeterminantSign, float& lodDitherFactor) const +{ + worldMatrix.SetRow1(Float4(Float3(Raw[0]), 0.0f)); + worldMatrix.SetRow2(Float4(Float3(Raw[1]), 0.0f)); + worldMatrix.SetRow3(Float4(Float3(Raw[2]), 0.0f)); + worldMatrix.SetRow4(Float4(Raw[0].W, Raw[1].W, Raw[2].W, 1.0f)); + prevWorldMatrix.SetRow1(Float4(Float3(Raw[3]), 0.0f)); + prevWorldMatrix.SetRow2(Float4(Float3(Raw[4]), 0.0f)); + prevWorldMatrix.SetRow3(Float4(Float3(Raw[5]), 0.0f)); + prevWorldMatrix.SetRow4(Float4(Raw[3].W, Raw[4].W, Raw[5].W, 1.0f)); + geometrySize = Float3(Raw[6]); + perInstanceRandom = Raw[6].W; + worldDeterminantSign = Raw[7].X; + lodDitherFactor = Raw[7].Y; + Float2 lightmapUVsAreaPackedAliased(Raw[7].Z, Raw[7].W); + Half4 lightmapUVsAreaPacked(*(Half4*)&lightmapUVsAreaPackedAliased); + *(Float4*)&lightmapUVsArea = lightmapUVsAreaPacked.ToFloat4(); +} + bool RenderLightData::CanRenderShadow(const RenderView& view) const { bool result = false; @@ -406,7 +442,8 @@ RenderList::RenderList(const SpawnParams& params) , AtmosphericFog(nullptr) , Fog(nullptr) , Blendable(32) - , _instanceBuffer(1024 * sizeof(InstanceData), sizeof(InstanceData), TEXT("Instance Buffer")) + , ObjectBuffer(0, PixelFormat::R32G32B32A32_Float, false, TEXT("Object Bufffer")) + , _instanceBuffer(0, sizeof(ShaderObjectDrawInstanceData), TEXT("Instance Buffer")) { } @@ -439,6 +476,7 @@ void RenderList::Clear() Settings = PostProcessSettings(); Blendable.Clear(); _instanceBuffer.Clear(); + ObjectBuffer.Clear(); } struct PackedSortKey @@ -480,18 +518,6 @@ FORCE_INLINE void CalculateSortKey(const RenderContext& renderContext, DrawCall& drawCall.SortKey = key.Data; } -FORCE_INLINE bool CanBatchDrawCalls(const DrawCall& a, const DrawCall& b, DrawPass pass) -{ - IMaterial::InstancingHandler handlerA, handlerB; - return a.Material->CanUseInstancing(handlerA) && - b.Material->CanUseInstancing(handlerB) && - a.InstanceCount != 0 && - b.InstanceCount != 0 && - handlerA.CanBatch == handlerB.CanBatch && - handlerA.CanBatch(a, b, pass) && - a.WorldDeterminantSign * b.WorldDeterminantSign > 0; -} - void RenderList::AddDrawCall(const RenderContext& renderContext, DrawPass drawModes, StaticFlags staticFlags, DrawCall& drawCall, bool receivesDecals, int8 sortOrder) { #if ENABLE_ASSERTION_LOW_LAYERS @@ -586,9 +612,32 @@ void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawP } } +void RenderList::BuildObjectsBuffer() { + int32 count = DrawCalls.Count(); + for (const auto& e : BatchedDrawCalls) + count += e.Instances.Count(); + ObjectBuffer.Clear(); + if (count == 0) + return; + PROFILE_CPU(); + ObjectBuffer.Data.Resize(count * sizeof(ShaderObjectData)); + auto* src = (const DrawCall*)DrawCalls.Get(); + auto* dst = (ShaderObjectData*)ObjectBuffer.Data.Get(); + for (int32 i = 0; i < DrawCalls.Count(); i++) { + dst->Store(src[i]); + dst++; } + int32 startIndex = DrawCalls.Count(); + for (auto& batch : BatchedDrawCalls) + { + batch.ObjectsStartIndex = startIndex; + Platform::MemoryCopy(dst, batch.Instances.Get(), batch.Instances.Count() * sizeof(ShaderObjectData)); + dst += batch.Instances.Count(); + startIndex += batch.Instances.Count(); + } + ZoneValue(ObjectBuffer.Data.Count() / 1024); // Objects Buffer size in kB } void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseDistance, DrawCallsList& list, const RenderListBuffer& drawCalls, DrawPass pass, bool stable) @@ -642,15 +691,24 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD const DrawCall& drawCall = drawCallsData[listData[i]]; int32 batchSize = 1; int32 instanceCount = drawCall.InstanceCount; - - // Check the following draw calls sequence to merge them - for (int32 j = i + 1; j < listSize; j++) + IMaterial::InstancingHandler drawCallHandler, otherHandler; + if (instanceCount != 0 && drawCall.Material->CanUseInstancing(drawCallHandler)) { - const DrawCall& other = drawCallsData[listData[j]]; - if (!CanBatchDrawCalls(drawCall, other, pass)) - break; - batchSize++; - instanceCount += other.InstanceCount; + // Check the following draw calls sequence to merge them + for (int32 j = i + 1; j < listSize; j++) + { + const DrawCall& other = drawCallsData[listData[j]]; + const bool canBatch = + other.Material->CanUseInstancing(otherHandler) && + other.InstanceCount != 0 && + drawCallHandler.CanBatch == otherHandler.CanBatch && + drawCallHandler.CanBatch(drawCall, other, pass) && + drawCall.WorldDeterminantSign * other.WorldDeterminantSign > 0; + if (!canBatch) + break; + batchSize++; + instanceCount += other.InstanceCount; + } } DrawBatch batch; @@ -677,72 +735,86 @@ FORCE_INLINE bool CanUseInstancing(DrawPass pass) return pass == DrawPass::GBuffer || pass == DrawPass::Depth; } -void RenderList::ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list, const RenderListBuffer& drawCalls, GPUTextureView* input) +FORCE_INLINE bool DrawsEqual(const DrawCall* a, const DrawCall* b) +{ + return a->Geometry.IndexBuffer == b->Geometry.IndexBuffer && + a->Draw.IndicesCount == b->Draw.IndicesCount && + a->Draw.StartIndex == b->Draw.StartIndex && + Platform::MemoryCompare(a->Geometry.VertexBuffers, b->Geometry.VertexBuffers, sizeof(a->Geometry.VertexBuffers) + sizeof(a->Geometry.VertexBuffersOffsets)) == 0; +} + +void RenderList::ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list, RenderList* drawCallsList, GPUTextureView* input) { if (list.IsEmpty()) return; PROFILE_GPU_CPU("Drawing"); - const auto* drawCallsData = drawCalls.Get(); + const auto* drawCallsData = drawCallsList->DrawCalls.Get(); const auto* listData = list.Indices.Get(); const auto* batchesData = list.Batches.Get(); const auto context = GPUDevice::Instance->GetMainContext(); bool useInstancing = list.CanUseInstancing && CanUseInstancing(renderContext.View.Pass) && GPUDevice::Instance->Limits.HasInstancing; TaaJitterRemoveContext taaJitterRemove(renderContext.View); + // Lazy-init objects buffer (if user didn't do it) + if (drawCallsList->ObjectBuffer.Data.IsEmpty()) + { + drawCallsList->BuildObjectsBuffer(); + drawCallsList->ObjectBuffer.Flush(context); + } + // Clear SR slots to prevent any resources binding issues (leftovers from the previous passes) context->ResetSR(); // Prepare instance buffer if (useInstancing) { - int32 instancedBatchesCount = 0; + // Estimate the maximum amount of elements for all instanced draws + int32 instancesCount = 0; for (int32 i = 0; i < list.Batches.Count(); i++) { - auto& batch = batchesData[i]; + const DrawBatch& batch = batchesData[i]; if (batch.BatchSize > 1) - instancedBatchesCount += batch.BatchSize; + instancesCount += batch.BatchSize; } for (int32 i = 0; i < list.PreBatchedDrawCalls.Count(); i++) { - auto& batch = BatchedDrawCalls.Get()[list.PreBatchedDrawCalls.Get()[i]]; - if (batch.Instances.Count() > 1) - instancedBatchesCount += batch.Instances.Count(); + const BatchedDrawCall& batch = BatchedDrawCalls.Get()[list.PreBatchedDrawCalls.Get()[i]]; + instancesCount += batch.Instances.Count(); } - if (instancedBatchesCount != 0) + if (instancesCount != 0) { PROFILE_CPU_NAMED("Build Instancing"); _instanceBuffer.Clear(); - _instanceBuffer.Data.Resize(instancedBatchesCount * sizeof(InstanceData)); - auto instanceData = (InstanceData*)_instanceBuffer.Data.Get(); + _instanceBuffer.Data.Resize(instancesCount * sizeof(ShaderObjectDrawInstanceData)); + auto instanceData = (ShaderObjectDrawInstanceData*)_instanceBuffer.Data.Get(); // Write to instance buffer for (int32 i = 0; i < list.Batches.Count(); i++) { - auto& batch = batchesData[i]; + const DrawBatch& batch = batchesData[i]; if (batch.BatchSize > 1) { - IMaterial::InstancingHandler handler; - drawCallsData[listData[batch.StartIndex]].Material->CanUseInstancing(handler); for (int32 j = 0; j < batch.BatchSize; j++) { - auto& drawCall = drawCallsData[listData[batch.StartIndex + j]]; - handler.WriteDrawCall(instanceData, drawCall); + instanceData->ObjectIndex = listData[batch.StartIndex + j]; instanceData++; } } } for (int32 i = 0; i < list.PreBatchedDrawCalls.Count(); i++) { - auto& batch = BatchedDrawCalls.Get()[list.PreBatchedDrawCalls.Get()[i]]; - if (batch.Instances.Count() > 1) + const BatchedDrawCall& batch = BatchedDrawCalls.Get()[list.PreBatchedDrawCalls.Get()[i]]; + for (int32 j = 0; j < batch.Instances.Count(); j++) { - Platform::MemoryCopy(instanceData, batch.Instances.Get(), batch.Instances.Count() * sizeof(InstanceData)); - instanceData += batch.Instances.Count(); + instanceData->ObjectIndex = batch.ObjectsStartIndex + j; + instanceData++; } } + ASSERT((byte*)instanceData == _instanceBuffer.Data.end()); // Upload data _instanceBuffer.Flush(context); + ZoneValue(instancesCount); } else { @@ -752,132 +824,122 @@ void RenderList::ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsL } // Execute draw calls - int32 draws = list.Batches.Count(); + int32 materialBinds = list.Batches.Count(); MaterialBase::BindParameters bindParams(context, renderContext); + bindParams.ObjectBuffer = drawCallsList->ObjectBuffer.GetBuffer()->View(); bindParams.Input = input; bindParams.BindViewData(); + MaterialShaderDataPerDraw perDraw; + perDraw.DrawPadding = Float3::Zero; + GPUConstantBuffer* perDrawCB = IMaterial::BindParameters::PerDrawConstants; + context->BindCB(2, perDrawCB); // TODO: use rootSignature/pushConstants on D3D12/Vulkan + constexpr int32 vbMax = ARRAY_COUNT(DrawCall::Geometry.VertexBuffers); if (useInstancing) { + GPUBuffer* vb[vbMax + 1]; + uint32 vbOffsets[vbMax + 1]; + vb[3] = _instanceBuffer.GetBuffer(); // Pass object index in a vertex stream at slot 3 (used by VS in Surface.shader) + vbOffsets[3] = 0; int32 instanceBufferOffset = 0; - GPUBuffer* vb[4]; - uint32 vbOffsets[4]; for (int32 i = 0; i < list.Batches.Count(); i++) { - auto& batch = batchesData[i]; - const DrawCall& drawCall = drawCallsData[listData[batch.StartIndex]]; + const DrawBatch& batch = batchesData[i]; + uint32 drawCallIndex = listData[batch.StartIndex]; + const DrawCall& drawCall = drawCallsData[drawCallIndex]; - int32 vbCount = 0; - while (vbCount < ARRAY_COUNT(drawCall.Geometry.VertexBuffers) && drawCall.Geometry.VertexBuffers[vbCount]) + bindParams.Instanced = batch.BatchSize != 1; + bindParams.DrawCall = &drawCall; + bindParams.DrawCall->Material->Bind(bindParams); + + if (bindParams.Instanced) { - vb[vbCount] = drawCall.Geometry.VertexBuffers[vbCount]; - vbOffsets[vbCount] = drawCall.Geometry.VertexBuffersOffsets[vbCount]; - vbCount++; - } - for (int32 j = vbCount; j < ARRAY_COUNT(drawCall.Geometry.VertexBuffers); j++) - { - vb[vbCount] = nullptr; - vbOffsets[vbCount] = 0; - } + // One or more draw calls per batch + const DrawCall* activeDraw = &drawCall; + int32 activeCount = 1; + for (int32 j = 1; j <= batch.BatchSize; j++) + { + if (j != batch.BatchSize && DrawsEqual(activeDraw, drawCallsData + listData[batch.StartIndex + j])) + { + // Group two draw calls into active draw call + activeCount++; + continue; + } - bindParams.FirstDrawCall = &drawCall; - bindParams.DrawCallsCount = batch.BatchSize; - drawCall.Material->Bind(bindParams); + // Draw whole active draw (instanced) + Platform::MemoryCopy(vb, activeDraw->Geometry.VertexBuffers, sizeof(DrawCall::Geometry.VertexBuffers)); + Platform::MemoryCopy(vbOffsets, activeDraw->Geometry.VertexBuffersOffsets, sizeof(DrawCall::Geometry.VertexBuffersOffsets)); + context->BindIB(activeDraw->Geometry.IndexBuffer); + context->BindVB(ToSpan(vb, ARRAY_COUNT(vb)), vbOffsets); + context->DrawIndexedInstanced(activeDraw->Draw.IndicesCount, activeCount, instanceBufferOffset, 0, activeDraw->Draw.StartIndex); + instanceBufferOffset += activeCount; - context->BindIB(drawCall.Geometry.IndexBuffer); - - if (drawCall.InstanceCount == 0) - { - // No support for batching indirect draw calls - ASSERT_LOW_LAYER(batch.BatchSize == 1); - - context->BindVB(ToSpan(vb, vbCount), vbOffsets); - context->DrawIndexedInstancedIndirect(drawCall.Draw.IndirectArgsBuffer, drawCall.Draw.IndirectArgsOffset); + // Reset active draw + activeDraw = drawCallsData + listData[batch.StartIndex + j]; + activeCount = 1; + } } else { - if (batch.BatchSize == 1) + // Pass object index in constant buffer + perDraw.DrawObjectIndex = drawCallIndex; + context->UpdateCB(perDrawCB, &perDraw); + + // Single-draw call batch + context->BindIB(drawCall.Geometry.IndexBuffer); + context->BindVB(ToSpan(drawCall.Geometry.VertexBuffers, vbMax), drawCall.Geometry.VertexBuffersOffsets); + if (drawCall.InstanceCount == 0) { - context->BindVB(ToSpan(vb, vbCount), vbOffsets); - context->DrawIndexedInstanced(drawCall.Draw.IndicesCount, batch.InstanceCount, 0, 0, drawCall.Draw.StartIndex); + context->DrawIndexedInstancedIndirect(drawCall.Draw.IndirectArgsBuffer, drawCall.Draw.IndirectArgsOffset); } else { - vbCount = 3; - vb[vbCount] = _instanceBuffer.GetBuffer(); - vbOffsets[vbCount] = 0; - vbCount++; - context->BindVB(ToSpan(vb, vbCount), vbOffsets); - context->DrawIndexedInstanced(drawCall.Draw.IndicesCount, batch.InstanceCount, instanceBufferOffset, 0, drawCall.Draw.StartIndex); - instanceBufferOffset += batch.BatchSize; + context->DrawIndexedInstanced(drawCall.Draw.IndicesCount, batch.InstanceCount, 0, 0, drawCall.Draw.StartIndex); } } } for (int32 i = 0; i < list.PreBatchedDrawCalls.Count(); i++) { - auto& batch = BatchedDrawCalls.Get()[list.PreBatchedDrawCalls.Get()[i]]; - auto& drawCall = batch.DrawCall; + const BatchedDrawCall& batch = BatchedDrawCalls.Get()[list.PreBatchedDrawCalls.Get()[i]]; + const DrawCall& drawCall = batch.DrawCall; - int32 vbCount = 0; - while (vbCount < ARRAY_COUNT(drawCall.Geometry.VertexBuffers) && drawCall.Geometry.VertexBuffers[vbCount]) - { - vb[vbCount] = drawCall.Geometry.VertexBuffers[vbCount]; - vbOffsets[vbCount] = drawCall.Geometry.VertexBuffersOffsets[vbCount]; - vbCount++; - } - for (int32 j = vbCount; j < ARRAY_COUNT(drawCall.Geometry.VertexBuffers); j++) - { - vb[vbCount] = nullptr; - vbOffsets[vbCount] = 0; - } - - bindParams.FirstDrawCall = &drawCall; - bindParams.DrawCallsCount = batch.Instances.Count(); - drawCall.Material->Bind(bindParams); + bindParams.Instanced = true; + bindParams.DrawCall = &drawCall; + bindParams.DrawCall->Material->Bind(bindParams); + Platform::MemoryCopy(vb, drawCall.Geometry.VertexBuffers, sizeof(DrawCall::Geometry.VertexBuffers)); + Platform::MemoryCopy(vbOffsets, drawCall.Geometry.VertexBuffersOffsets, sizeof(DrawCall::Geometry.VertexBuffersOffsets)); context->BindIB(drawCall.Geometry.IndexBuffer); + context->BindVB(ToSpan(vb, vbMax + 1), vbOffsets); if (drawCall.InstanceCount == 0) { - ASSERT_LOW_LAYER(batch.Instances.Count() == 1); - context->BindVB(ToSpan(vb, vbCount), vbOffsets); context->DrawIndexedInstancedIndirect(drawCall.Draw.IndirectArgsBuffer, drawCall.Draw.IndirectArgsOffset); } else { - if (batch.Instances.Count() == 1) - { - context->BindVB(ToSpan(vb, vbCount), vbOffsets); - context->DrawIndexedInstanced(drawCall.Draw.IndicesCount, batch.Instances.Count(), 0, 0, drawCall.Draw.StartIndex); - } - else - { - vbCount = 3; - vb[vbCount] = _instanceBuffer.GetBuffer(); - vbOffsets[vbCount] = 0; - vbCount++; - context->BindVB(ToSpan(vb, vbCount), vbOffsets); - context->DrawIndexedInstanced(drawCall.Draw.IndicesCount, batch.Instances.Count(), instanceBufferOffset, 0, drawCall.Draw.StartIndex); - instanceBufferOffset += batch.Instances.Count(); - } + context->DrawIndexedInstanced(drawCall.Draw.IndicesCount, batch.Instances.Count(), instanceBufferOffset, 0, drawCall.Draw.StartIndex); + instanceBufferOffset += batch.Instances.Count(); } } - draws += list.PreBatchedDrawCalls.Count(); + materialBinds += list.PreBatchedDrawCalls.Count(); } else { - bindParams.DrawCallsCount = 1; for (int32 i = 0; i < list.Batches.Count(); i++) { - auto& batch = batchesData[i]; + const DrawBatch& batch = batchesData[i]; + + bindParams.DrawCall = drawCallsData + listData[batch.StartIndex]; + bindParams.DrawCall->Material->Bind(bindParams); for (int32 j = 0; j < batch.BatchSize; j++) { - const DrawCall& drawCall = drawCalls[listData[batch.StartIndex + j]]; - bindParams.FirstDrawCall = &drawCall; - drawCall.Material->Bind(bindParams); + perDraw.DrawObjectIndex = listData[batch.StartIndex + j]; + context->UpdateCB(perDrawCB, &perDraw); + const DrawCall& drawCall = drawCallsData[perDraw.DrawObjectIndex]; context->BindIB(drawCall.Geometry.IndexBuffer); - context->BindVB(ToSpan(drawCall.Geometry.VertexBuffers, 3), drawCall.Geometry.VertexBuffersOffsets); + context->BindVB(ToSpan(drawCall.Geometry.VertexBuffers, vbMax), drawCall.Geometry.VertexBuffersOffsets); if (drawCall.InstanceCount == 0) { @@ -891,43 +953,38 @@ void RenderList::ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsL } for (int32 i = 0; i < list.PreBatchedDrawCalls.Count(); i++) { - auto& batch = BatchedDrawCalls.Get()[list.PreBatchedDrawCalls.Get()[i]]; - auto drawCall = batch.DrawCall; - drawCall.ObjectRadius = 0.0f; - bindParams.FirstDrawCall = &drawCall; - const auto* instancesData = batch.Instances.Get(); + const BatchedDrawCall& batch = BatchedDrawCalls.Get()[list.PreBatchedDrawCalls.Get()[i]]; + const DrawCall& drawCall = batch.DrawCall; + + bindParams.DrawCall = &drawCall; + bindParams.DrawCall->Material->Bind(bindParams); + + context->BindIB(drawCall.Geometry.IndexBuffer); + context->BindVB(ToSpan(drawCall.Geometry.VertexBuffers, vbMax), drawCall.Geometry.VertexBuffersOffsets); for (int32 j = 0; j < batch.Instances.Count(); j++) { - auto& instance = instancesData[j]; - drawCall.ObjectPosition = instance.InstanceOrigin; - drawCall.PerInstanceRandom = instance.PerInstanceRandom; - auto lightmapArea = instance.InstanceLightmapArea.ToFloat4(); - drawCall.Surface.LightmapUVsArea = *(Rectangle*)&lightmapArea; - drawCall.Surface.LODDitherFactor = instance.LODDitherFactor; - drawCall.World.SetRow1(Float4(instance.InstanceTransform1, 0.0f)); - drawCall.World.SetRow2(Float4(instance.InstanceTransform2, 0.0f)); - drawCall.World.SetRow3(Float4(instance.InstanceTransform3, 0.0f)); - drawCall.World.SetRow4(Float4(instance.InstanceOrigin, 1.0f)); - drawCall.Material->Bind(bindParams); + perDraw.DrawObjectIndex = batch.ObjectsStartIndex + j; + context->UpdateCB(perDrawCB, &perDraw); - context->BindIB(drawCall.Geometry.IndexBuffer); - context->BindVB(ToSpan(drawCall.Geometry.VertexBuffers, 3), drawCall.Geometry.VertexBuffersOffsets); context->DrawIndexedInstanced(drawCall.Draw.IndicesCount, drawCall.InstanceCount, 0, 0, drawCall.Draw.StartIndex); } - draws += batch.Instances.Count(); } + materialBinds += list.PreBatchedDrawCalls.Count(); if (list.Batches.IsEmpty() && list.Indices.Count() != 0) { - // Draw calls list has nto been batched so execute draw calls separately + // Draw calls list has bot been batched so execute draw calls separately for (int32 j = 0; j < list.Indices.Count(); j++) { - const DrawCall& drawCall = drawCalls[listData[j]]; - bindParams.FirstDrawCall = &drawCall; + perDraw.DrawObjectIndex = listData[j]; + context->UpdateCB(perDrawCB, &perDraw); + + const DrawCall& drawCall = drawCallsData[perDraw.DrawObjectIndex]; + bindParams.DrawCall = &drawCall; drawCall.Material->Bind(bindParams); context->BindIB(drawCall.Geometry.IndexBuffer); - context->BindVB(ToSpan(drawCall.Geometry.VertexBuffers, 3), drawCall.Geometry.VertexBuffersOffsets); + context->BindVB(ToSpan(drawCall.Geometry.VertexBuffers, vbMax), drawCall.Geometry.VertexBuffersOffsets); if (drawCall.InstanceCount == 0) { @@ -938,10 +995,10 @@ void RenderList::ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsL context->DrawIndexedInstanced(drawCall.Draw.IndicesCount, drawCall.InstanceCount, 0, 0, drawCall.Draw.StartIndex); } } - draws += list.Indices.Count(); + materialBinds += list.Indices.Count(); } } - ZoneValue(draws); + ZoneValue(materialBinds); // Material shaders bindings count } void SurfaceDrawCallHandler::GetHash(const DrawCall& drawCall, uint32& batchKey) @@ -971,14 +1028,3 @@ bool SurfaceDrawCallHandler::CanBatch(const DrawCall& a, const DrawCall& b, Draw } return false; } - -void SurfaceDrawCallHandler::WriteDrawCall(InstanceData* instanceData, const DrawCall& drawCall) -{ - instanceData->InstanceOrigin = Float3(drawCall.World.M41, drawCall.World.M42, drawCall.World.M43); - instanceData->PerInstanceRandom = drawCall.PerInstanceRandom; - instanceData->InstanceTransform1 = Float3(drawCall.World.M11, drawCall.World.M12, drawCall.World.M13); - instanceData->LODDitherFactor = drawCall.Surface.LODDitherFactor; - instanceData->InstanceTransform2 = Float3(drawCall.World.M21, drawCall.World.M22, drawCall.World.M23); - instanceData->InstanceTransform3 = Float3(drawCall.World.M31, drawCall.World.M32, drawCall.World.M33); - instanceData->InstanceLightmapArea = Half4(drawCall.Surface.LightmapUVsArea); -} diff --git a/Source/Engine/Renderer/RenderList.h b/Source/Engine/Renderer/RenderList.h index 5b8c66647..aa484fceb 100644 --- a/Source/Engine/Renderer/RenderList.h +++ b/Source/Engine/Renderer/RenderList.h @@ -239,7 +239,8 @@ struct DrawBatch struct BatchedDrawCall { DrawCall DrawCall; - Array Instances; + uint16 ObjectsStartIndex = 0; // Index of the instances start in the ObjectsBuffer (set internally). + Array Instances; }; /// @@ -413,6 +414,11 @@ public: /// Float3 FrustumCornersVs[8]; + /// + /// Objects buffer that contains ShaderObjectData for each DrawCall. + /// + DynamicTypedBuffer ObjectBuffer; + private: DynamicVertexBuffer _instanceBuffer; @@ -517,6 +523,11 @@ public: /// Object sorting key. void AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, DrawCall& drawCall, bool receivesDecals = true, int8 sortOrder = 0); + /// + /// Writes all draw calls into large objects buffer (used for random-access object data access on a GPU). Can be executed in async. + /// + void BuildObjectsBuffer(); + /// /// Sorts the collected draw calls list. /// @@ -549,7 +560,7 @@ public: /// The input scene color. It's optional and used in forward/postFx rendering. API_FUNCTION() FORCE_INLINE void ExecuteDrawCalls(API_PARAM(Ref) const RenderContext& renderContext, DrawCallsListType listType, GPUTextureView* input = nullptr) { - ExecuteDrawCalls(renderContext, DrawCallsLists[(int32)listType], DrawCalls, input); + ExecuteDrawCalls(renderContext, DrawCallsLists[(int32)listType], this, input); } /// @@ -560,7 +571,7 @@ public: /// The input scene color. It's optional and used in forward/postFx rendering. FORCE_INLINE void ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list, GPUTextureView* input = nullptr) { - ExecuteDrawCalls(renderContext, list, DrawCalls, input); + ExecuteDrawCalls(renderContext, list, this, input); } /// @@ -568,28 +579,43 @@ public: /// /// The rendering context. /// The collected draw calls indices list. - /// The collected draw calls list. + /// The collected draw calls list owner. /// The input scene color. It's optional and used in forward/postFx rendering. - void ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list, const RenderListBuffer& drawCalls, GPUTextureView* input); + void ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list, RenderList* drawCallsList, GPUTextureView* input); }; /// -/// Represents data per instance element used for instanced rendering. +/// Represents a single object information for GPU rendering. /// -PACK_STRUCT(struct FLAXENGINE_API InstanceData +GPU_CB_STRUCT(ShaderObjectData { - Float3 InstanceOrigin; - float PerInstanceRandom; - Float3 InstanceTransform1; - float LODDitherFactor; - Float3 InstanceTransform2; - Float3 InstanceTransform3; - Half4 InstanceLightmapArea; + Float4 Raw[8]; + + void FLAXENGINE_API Store(const Matrix& worldMatrix, const Matrix& prevWorldMatrix, const Rectangle& lightmapUVsArea, const Float3& geometrySize, float perInstanceRandom = 0.0f, float worldDeterminantSign = 1.0f, float lodDitherFactor = 0.0f); + void FLAXENGINE_API Load(Matrix& worldMatrix, Matrix& prevWorldMatrix, Rectangle& lightmapUVsArea, Float3& geometrySize, float& perInstanceRandom, float& worldDeterminantSign, float& lodDitherFactor) const; + + FORCE_INLINE void Store(const DrawCall& drawCall) + { + Store(drawCall.World, drawCall.Surface.PrevWorld, drawCall.Surface.LightmapUVsArea, drawCall.Surface.GeometrySize, drawCall.PerInstanceRandom, drawCall.WorldDeterminantSign, drawCall.Surface.LODDitherFactor); + } + + FORCE_INLINE void Load(DrawCall& drawCall) const + { + Load(drawCall.World, drawCall.Surface.PrevWorld, drawCall.Surface.LightmapUVsArea, drawCall.Surface.GeometrySize, drawCall.PerInstanceRandom, drawCall.WorldDeterminantSign, drawCall.Surface.LODDitherFactor); + drawCall.ObjectPosition = drawCall.World.GetTranslation(); + } + }); + +/// +/// Represents data passed to Vertex Shader used for instanced rendering (per-instance element). +/// +PACK_STRUCT(struct ShaderObjectDrawInstanceData + { + uint32 ObjectIndex; }); struct SurfaceDrawCallHandler { static void GetHash(const DrawCall& drawCall, uint32& batchKey); static bool CanBatch(const DrawCall& a, const DrawCall& b, DrawPass pass); - static void WriteDrawCall(InstanceData* instanceData, const DrawCall& drawCall); }; diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index d6fbb17cc..d4e5b2590 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -428,6 +428,9 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont // Sort draw calls { PROFILE_CPU_NAMED("Sort Draw Calls"); + // TODO: run all of these functions in async via jobs + for (int32 i = 0; i < renderContextBatch.Contexts.Count(); i++) + renderContextBatch.Contexts[i].List->BuildObjectsBuffer(); renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::GBuffer); renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::GBufferNoDecals); renderContext.List->SortDrawCalls(renderContext, true, DrawCallsListType::Forward); @@ -440,6 +443,11 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont shadowContext.List->SortDrawCalls(shadowContext, false, DrawCallsListType::Depth, DrawPass::Depth); shadowContext.List->SortDrawCalls(shadowContext, false, shadowContext.List->ShadowDepthDrawCallsList, renderContext.List->DrawCalls, DrawPass::Depth); } + { + PROFILE_CPU_NAMED("FlushObjectsBuffer"); + for (int32 i = 0; i < renderContextBatch.Contexts.Count(); i++) + renderContextBatch.Contexts[i].List->ObjectBuffer.Flush(context); + } } // Get the light accumulation buffer diff --git a/Source/Engine/Renderer/ShadowsPass.cpp b/Source/Engine/Renderer/ShadowsPass.cpp index 15ac7a097..382c0be55 100644 --- a/Source/Engine/Renderer/ShadowsPass.cpp +++ b/Source/Engine/Renderer/ShadowsPass.cpp @@ -1390,7 +1390,7 @@ void ShadowsPass::RenderShadowMaps(RenderContextBatch& renderContextBatch) if (!shadowContextStatic.List->DrawCallsLists[(int32)DrawCallsListType::Depth].IsEmpty() || !shadowContextStatic.List->ShadowDepthDrawCallsList.IsEmpty()) { shadowContextStatic.List->ExecuteDrawCalls(shadowContextStatic, DrawCallsListType::Depth); - shadowContextStatic.List->ExecuteDrawCalls(shadowContextStatic, shadowContextStatic.List->ShadowDepthDrawCallsList, renderContext.List->DrawCalls, nullptr); + shadowContextStatic.List->ExecuteDrawCalls(shadowContextStatic, shadowContextStatic.List->ShadowDepthDrawCallsList, renderContext.List, nullptr); tile.HasStaticGeometry = true; } } @@ -1452,7 +1452,7 @@ void ShadowsPass::RenderShadowMaps(RenderContextBatch& renderContextBatch) // Draw objects depth auto& shadowContext = renderContextBatch.Contexts[atlasLight.ContextIndex + contextIndex++]; shadowContext.List->ExecuteDrawCalls(shadowContext, DrawCallsListType::Depth); - shadowContext.List->ExecuteDrawCalls(shadowContext, shadowContext.List->ShadowDepthDrawCallsList, renderContext.List->DrawCalls, nullptr); + shadowContext.List->ExecuteDrawCalls(shadowContext, shadowContext.List->ShadowDepthDrawCallsList, renderContext.List, nullptr); if (atlasLight.HasStaticShadowContext) { auto& shadowContextStatic = renderContextBatch.Contexts[atlasLight.ContextIndex + contextIndex++]; @@ -1462,7 +1462,7 @@ void ShadowsPass::RenderShadowMaps(RenderContextBatch& renderContextBatch) { // Draw static objects directly to the shadow map shadowContextStatic.List->ExecuteDrawCalls(shadowContextStatic, DrawCallsListType::Depth); - shadowContextStatic.List->ExecuteDrawCalls(shadowContextStatic, shadowContextStatic.List->ShadowDepthDrawCallsList, renderContext.List->DrawCalls, nullptr); + shadowContextStatic.List->ExecuteDrawCalls(shadowContextStatic, shadowContextStatic.List->ShadowDepthDrawCallsList, renderContext.List, nullptr); } tile.HasStaticGeometry = true; } diff --git a/Source/Engine/Renderer/VolumetricFogPass.cpp b/Source/Engine/Renderer/VolumetricFogPass.cpp index 5a6fe1d02..2b9a4b441 100644 --- a/Source/Engine/Renderer/VolumetricFogPass.cpp +++ b/Source/Engine/Renderer/VolumetricFogPass.cpp @@ -408,7 +408,6 @@ void VolumetricFogPass::Render(RenderContext& renderContext) InitCircleBuffer(); MaterialBase::BindParameters bindParams(context, renderContext); - bindParams.DrawCallsCount = 1; CustomData customData; customData.Shader = _shader->GetShader(); customData.GridSize = cache.GridSize; @@ -435,7 +434,7 @@ void VolumetricFogPass::Render(RenderContext& renderContext) // Setup material shader data customData.ParticleIndex = drawCall.Particle.VolumetricFog.ParticleIndex; - bindParams.FirstDrawCall = &drawCall; + bindParams.DrawCall = &drawCall; drawCall.Material->Bind(bindParams); // Setup volumetric shader data diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp index 8cacddf51..02b5ded87 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp @@ -461,7 +461,7 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo switch (baseLayer->Domain) { case MaterialDomain::Surface: - srv = 2; // Skinning Bones + Prev Bones + srv = 3; // Objects + Skinning Bones + Prev Bones break; case MaterialDomain::Decal: srv = 1; // Depth buffer diff --git a/Source/Shaders/MaterialCommon.hlsl b/Source/Shaders/MaterialCommon.hlsl index 0660e5cf9..04e3a037e 100644 --- a/Source/Shaders/MaterialCommon.hlsl +++ b/Source/Shaders/MaterialCommon.hlsl @@ -58,6 +58,9 @@ #ifndef USE_PER_VIEW_CONSTANTS #define USE_PER_VIEW_CONSTANTS 0 #endif +#ifndef USE_PER_DRAW_CONSTANTS +#define USE_PER_DRAW_CONSTANTS 0 +#endif #ifndef MATERIAL_TESSELLATION #define MATERIAL_TESSELLATION MATERIAL_TESSELLATION_NONE #endif @@ -68,6 +71,65 @@ #define PER_BONE_MOTION_BLUR 0 #endif +// Object properties +struct ObjectData +{ + float4x4 WorldMatrix; + float4x4 PrevWorldMatrix; + float3 GeometrySize; + float WorldDeterminantSign; + float LODDitherFactor; + float PerInstanceRandom; + float4 LightmapArea; +}; + +float2 UnpackHalf2(uint xy) +{ + return float2(f16tof32(xy & 0xffff), f16tof32(xy >> 16)); +} + +// Loads the object data from the global buffer +ObjectData LoadObject(Buffer objectsBuffer, uint objectIndex) +{ + // This must match ShaderObjectData::Store + objectIndex *= 8; + ObjectData object = (ObjectData)0; + float4 vector0 = objectsBuffer.Load(objectIndex + 0); + float4 vector1 = objectsBuffer.Load(objectIndex + 1); + float4 vector2 = objectsBuffer.Load(objectIndex + 2); + float4 vector3 = objectsBuffer.Load(objectIndex + 3); + float4 vector4 = objectsBuffer.Load(objectIndex + 4); + float4 vector5 = objectsBuffer.Load(objectIndex + 5); + float4 vector6 = objectsBuffer.Load(objectIndex + 6); + float4 vector7 = objectsBuffer.Load(objectIndex + 7); + object.WorldMatrix[0] = float4(vector0.xyz, 0.0f); + object.WorldMatrix[1] = float4(vector1.xyz, 0.0f); + object.WorldMatrix[2] = float4(vector2.xyz, 0.0f); + object.WorldMatrix[3] = float4(vector0.w, vector1.w, vector2.w, 1.0f); + object.PrevWorldMatrix[0] = float4(vector3.xyz, 0.0f); + object.PrevWorldMatrix[1] = float4(vector4.xyz, 0.0f); + object.PrevWorldMatrix[2] = float4(vector5.xyz, 0.0f); + object.PrevWorldMatrix[3] = float4(vector3.w, vector4.w, vector5.w, 1.0f); + object.GeometrySize = vector6.xyz; + object.PerInstanceRandom = vector6.w; + object.WorldDeterminantSign = vector7.x; + object.LODDitherFactor = vector7.y; + object.LightmapArea.xy = UnpackHalf2(asuint(vector7.z)); + object.LightmapArea.zw = UnpackHalf2(asuint(vector7.w)); + return object; +} + +// Loads the object data from the constant buffer into the variable +#define LoadObjectFromCB(var) \ + var = (ObjectData)0; \ + var.WorldMatrix = ToMatrix4x4(WorldMatrix); \ + var.PrevWorldMatrix = ToMatrix4x4(PrevWorldMatrix); \ + var.GeometrySize = GeometrySize; \ + var.PerInstanceRandom = PerInstanceRandom; \ + var.WorldDeterminantSign = WorldDeterminantSign; \ + var.LODDitherFactor = LODDitherFactor; \ + var.LightmapArea = LightmapArea; + // Material properties struct Material { @@ -110,6 +172,15 @@ cbuffer ViewData : register(b1) }; #endif +// Draw pipeline constant buffer (with per-draw constants at slot 2) +#if USE_PER_DRAW_CONSTANTS +cbuffer DrawData : register(b2) +{ + float3 DrawPadding; + uint DrawObjectIndex; +}; +#endif + struct ModelInput { float3 Position : POSITION; @@ -121,11 +192,7 @@ struct ModelInput half4 Color : COLOR; #endif #if USE_INSTANCING - float4 InstanceOrigin : ATTRIBUTE0; // .w contains PerInstanceRandom - float4 InstanceTransform1 : ATTRIBUTE1; // .w contains LODDitherFactor - float3 InstanceTransform2 : ATTRIBUTE2; - float3 InstanceTransform3 : ATTRIBUTE3; - half4 InstanceLightmapArea : ATTRIBUTE4; + uint ObjectIndex : ATTRIBUTE0; #endif }; @@ -133,11 +200,7 @@ struct ModelInput_PosOnly { float3 Position : POSITION; #if USE_INSTANCING - float4 InstanceOrigin : ATTRIBUTE0; // .w contains PerInstanceRandom - float4 InstanceTransform1 : ATTRIBUTE1; // .w contains LODDitherFactor - float3 InstanceTransform2 : ATTRIBUTE2; - float3 InstanceTransform3 : ATTRIBUTE3; - half4 InstanceLightmapArea : ATTRIBUTE4; + uint ObjectIndex : ATTRIBUTE0; #endif };