From 2dfb1058b2d041d8639ba01ad9f3967a2e990ab9 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 26 Mar 2024 11:29:01 +0100 Subject: [PATCH] Optimize world matrix storage for drawable objects to use `Matrix3x4` instead of full matrix --- .../Editor/MaterialTemplates/Particle.shader | 26 ++++++------ .../Editor/MaterialTemplates/Surface.shader | 14 +++---- .../Editor/MaterialTemplates/Terrain.shader | 13 +++--- .../MaterialTemplates/VolumeParticle.shader | 12 +++--- Source/Engine/Core/Math/Matrix.cpp | 37 +++++++++++++++++ Source/Engine/Core/Math/Matrix3x4.h | 41 +++---------------- .../Materials/DeferredMaterialShader.cpp | 9 ++-- .../Materials/ForwardMaterialShader.cpp | 9 ++-- .../Graphics/Materials/MaterialShader.h | 2 +- .../Materials/ParticleMaterialShader.cpp | 11 +++-- .../Materials/TerrainMaterialShader.cpp | 5 ++- .../VolumeParticleMaterialShader.cpp | 11 +++-- .../Renderer/GlobalSignDistanceFieldPass.cpp | 25 +++++------ Source/Shaders/Common.hlsl | 6 +++ Source/Shaders/GlobalSignDistanceField.shader | 18 ++++---- 15 files changed, 134 insertions(+), 105 deletions(-) diff --git a/Content/Editor/MaterialTemplates/Particle.shader b/Content/Editor/MaterialTemplates/Particle.shader index 3f6b03a58..5cdbc40a5 100644 --- a/Content/Editor/MaterialTemplates/Particle.shader +++ b/Content/Editor/MaterialTemplates/Particle.shader @@ -26,7 +26,7 @@ struct RibbonInput // Primary constant buffer (with additional material parameters) META_CB_BEGIN(0, Data) -float4x4 WorldMatrix; +float4x3 WorldMatrix; uint SortedIndicesOffset; float PerInstanceRandom; int ParticleStride; @@ -45,7 +45,7 @@ int RibbonWidthOffset; int RibbonTwistOffset; int RibbonFacingVectorOffset; uint RibbonSegmentCount; -float4x4 WorldMatrixInverseTransposed; +float4x3 WorldMatrixInverseTransposed; @1META_CB_END // Particles attributes buffer @@ -138,7 +138,7 @@ MaterialInput GetMaterialInput(PixelInput input) #if USE_INSTANCING #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)) #else -#define GetInstanceTransform(input) WorldMatrix; +#define GetInstanceTransform(input) ToMatrix4x4(WorldMatrix); #endif // Removes the scale vector from the local to world transformation matrix (supports instancing) @@ -264,12 +264,12 @@ float4 GetParticleVec4(uint particleIndex, int offset) float3 TransformParticlePosition(float3 input) { - return mul(float4(input, 1.0f), WorldMatrix).xyz; + return mul(float4(input, 1.0f), ToMatrix4x4(WorldMatrix)).xyz; } float3 TransformParticleVector(float3 input) { - return mul(float4(input, 0.0f), WorldMatrixInverseTransposed).xyz; + return mul(float4(input, 0.0f), ToMatrix4x4(WorldMatrixInverseTransposed)).xyz; } @8 @@ -333,7 +333,7 @@ VertexOutput VS_Sprite(SpriteInput input, uint particleIndex : SV_InstanceID) float2 spriteSize = GetParticleVec2(particleIndex, SpriteSizeOffset); int spriteFacingMode = SpriteFacingModeOffset != -1 ? GetParticleInt(particleIndex, SpriteFacingModeOffset) : -1; - float4x4 world = WorldMatrix; + float4x4 world = ToMatrix4x4(WorldMatrix); float3x3 eulerMatrix = EulerMatrix(radians(particleRotation)); float3x3 viewRot = transpose((float3x3)ViewMatrix); float3 position = mul(float4(particlePosition, 1), world).xyz; @@ -463,11 +463,12 @@ VertexOutput VS_Model(ModelInput input, uint particleIndex : SV_InstanceID) } // Read particle data + float4x4 worldMatrix = ToMatrix4x4(WorldMatrix); float3 particlePosition = GetParticleVec3(particleIndex, PositionOffset); float3 particleScale = GetParticleVec3(particleIndex, ScaleOffset); float3 particleRotation = GetParticleVec3(particleIndex, RotationOffset); int modelFacingMode = ModelFacingModeOffset != -1 ? GetParticleInt(particleIndex, ModelFacingModeOffset) : -1; - float3 position = mul(float4(particlePosition, 1), WorldMatrix).xyz; + float3 position = mul(float4(particlePosition, 1), worldMatrix).xyz; // Compute final vertex position in the world float3x3 eulerMatrix = EulerMatrix(radians(particleRotation)); @@ -506,7 +507,7 @@ VertexOutput VS_Model(ModelInput input, uint particleIndex : SV_InstanceID) world = mul(world, scaleMatrix); } world = transpose(world); - world = mul(world, WorldMatrix); + world = mul(world, worldMatrix); // Calculate the vertex position in world space output.WorldPosition = mul(float4(input.Position, 1), world).xyz; @@ -520,12 +521,12 @@ VertexOutput VS_Model(ModelInput input, uint particleIndex : SV_InstanceID) #if USE_VERTEX_COLOR output.VertexColor = input.Color; #endif - output.InstanceOrigin = WorldMatrix[3].xyz; + output.InstanceOrigin = worldMatrix[3].xyz; output.InstanceParams = PerInstanceRandom; // Calculate tanget space to world space transformation matrix for unit vectors half3x3 tangentToLocal = CalcTangentToLocal(input); - half3x3 tangentToWorld = CalcTangentToWorld(WorldMatrix, tangentToLocal); + half3x3 tangentToWorld = CalcTangentToWorld(worldMatrix, tangentToLocal); output.TBN = tangentToWorld; // Get material input params if need to evaluate any material property @@ -625,12 +626,13 @@ VertexOutput VS_Ribbon(RibbonInput input, uint vertexIndex : SV_VertexID) #if USE_VERTEX_COLOR output.VertexColor = 1; #endif - output.InstanceOrigin = WorldMatrix[3].xyz; + float4x4 world = ToMatrix4x4(WorldMatrix); + output.InstanceOrigin = world[3].xyz; output.InstanceParams = PerInstanceRandom; // Calculate tanget space to world space transformation matrix for unit vectors half3x3 tangentToLocal = float3x3(tangentRight, tangentUp, cross(tangentRight, tangentUp)); - half3x3 tangentToWorld = CalcTangentToWorld(WorldMatrix, tangentToLocal); + half3x3 tangentToWorld = CalcTangentToWorld(world, tangentToLocal); output.TBN = tangentToWorld; // Get material input params if need to evaluate any material property diff --git a/Content/Editor/MaterialTemplates/Surface.shader b/Content/Editor/MaterialTemplates/Surface.shader index 1e8589ff2..f206d58fb 100644 --- a/Content/Editor/MaterialTemplates/Surface.shader +++ b/Content/Editor/MaterialTemplates/Surface.shader @@ -10,8 +10,8 @@ @7 // Primary constant buffer (with additional material parameters) META_CB_BEGIN(0, Data) -float4x4 WorldMatrix; -float4x4 PrevWorldMatrix; +float4x3 WorldMatrix; +float4x3 PrevWorldMatrix; float2 Dummy0; float LODDitherFactor; float PerInstanceRandom; @@ -171,7 +171,7 @@ MaterialInput GetMaterialInput(PixelInput input) #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 = WorldMatrix; output.Geometry.InstanceTransform1 = world[0].xyz; output.Geometry.InstanceTransform2 = world[1].xyz; output.Geometry.InstanceTransform3 = world[2].xyz; +#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) @@ -328,7 +328,7 @@ VertexOutput VS(ModelInput input) // 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), PrevWorldMatrix).xyz; + output.Geometry.PrevWorldPosition = mul(float4(input.Position.xyz, 1), ToMatrix4x4(PrevWorldMatrix)).xyz; // Compute clip space position output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix); @@ -402,7 +402,7 @@ float4 VS_Depth(ModelInput_PosOnly input) : SV_Position #if USE_INSTANCING float4x4 world = GetInstanceTransform(input); #else - float4x4 world = WorldMatrix; + float4x4 world = ToMatrix4x4(WorldMatrix); #endif float3 worldPosition = mul(float4(input.Position.xyz, 1), world).xyz; float4 position = mul(float4(worldPosition, 1), ViewProjectionMatrix); @@ -511,9 +511,9 @@ VertexOutput VS_Skinned(ModelInput_Skinned input) output.Geometry.WorldPosition = mul(float4(position, 1), world).xyz; #if PER_BONE_MOTION_BLUR float3 prevPosition = SkinPrevPosition(input); - output.Geometry.PrevWorldPosition = mul(float4(prevPosition, 1), PrevWorldMatrix).xyz; + output.Geometry.PrevWorldPosition = mul(float4(prevPosition, 1), ToMatrix4x4(PrevWorldMatrix)).xyz; #else - output.Geometry.PrevWorldPosition = mul(float4(position, 1), PrevWorldMatrix).xyz; + output.Geometry.PrevWorldPosition = mul(float4(position, 1), ToMatrix4x4(PrevWorldMatrix)).xyz; #endif // Compute clip space position diff --git a/Content/Editor/MaterialTemplates/Terrain.shader b/Content/Editor/MaterialTemplates/Terrain.shader index 32395d583..71504f6ed 100644 --- a/Content/Editor/MaterialTemplates/Terrain.shader +++ b/Content/Editor/MaterialTemplates/Terrain.shader @@ -17,7 +17,7 @@ @7 // Primary constant buffer (with additional material parameters) META_CB_BEGIN(0, Data) -float4x4 WorldMatrix; +float4x3 WorldMatrix; float3 WorldInvScale; float WorldDeterminantSign; float PerInstanceRandom; @@ -194,7 +194,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)WorldMatrix; + float3x3 localToWorld = (float3x3)ToMatrix4x4(WorldMatrix); //localToWorld = RemoveScaleFromLocalToWorld(localToWorld); return mul(localVector, localToWorld); } @@ -202,7 +202,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)WorldMatrix; + float3x3 localToWorld = (float3x3)ToMatrix4x4(WorldMatrix); //localToWorld = RemoveScaleFromLocalToWorld(localToWorld); return mul(localToWorld, worldVector); } @@ -210,7 +210,7 @@ float3 TransformWorldVectorToLocal(MaterialInput input, float3 worldVector) // Gets the current object position float3 GetObjectPosition(MaterialInput input) { - return WorldMatrix[3].xyz; + return ToMatrix4x4(WorldMatrix)[3].xyz; } // Gets the current object size @@ -365,7 +365,8 @@ VertexOutput VS(TerrainVertexInput input) float3 position = float3(positionXZ.x, height, positionXZ.y); // Compute world space vertex position - output.Geometry.WorldPosition = mul(float4(position, 1), WorldMatrix).xyz; + float4x4 worldMatrix = ToMatrix4x4(WorldMatrix); + output.Geometry.WorldPosition = mul(float4(position, 1), worldMatrix).xyz; // Compute clip space position output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix); @@ -389,7 +390,7 @@ VertexOutput VS(TerrainVertexInput input) // Compute world space normal vector float3x3 tangentToLocal = CalcTangentBasisFromWorldNormal(normal); - float3x3 tangentToWorld = CalcTangentToWorld(WorldMatrix, tangentToLocal); + float3x3 tangentToWorld = CalcTangentToWorld(worldMatrix, tangentToLocal); output.Geometry.WorldNormal = tangentToWorld[2]; // Get material input params if need to evaluate any material property diff --git a/Content/Editor/MaterialTemplates/VolumeParticle.shader b/Content/Editor/MaterialTemplates/VolumeParticle.shader index c21e7c3bb..3d182e0fd 100644 --- a/Content/Editor/MaterialTemplates/VolumeParticle.shader +++ b/Content/Editor/MaterialTemplates/VolumeParticle.shader @@ -13,8 +13,8 @@ // Primary constant buffer (with additional material parameters) META_CB_BEGIN(0, Data) float4x4 InverseViewProjectionMatrix; -float4x4 WorldMatrix; -float4x4 WorldMatrixInverseTransposed; +float4x3 WorldMatrix; +float4x3 WorldMatrixInverseTransposed; float3 GridSize; float PerInstanceRandom; float Dummy0; @@ -49,7 +49,7 @@ struct MaterialInput #endif }; -#define GetInstanceTransform(input) WorldMatrix; +#define GetInstanceTransform(input) ToMatrix4x4(WorldMatrix); // Removes the scale vector from the local to world transformation matrix (supports instancing) float3x3 RemoveScaleFromLocalToWorld(float3x3 localToWorld) @@ -170,12 +170,12 @@ float4 GetParticleVec4(uint particleIndex, int offset) float3 TransformParticlePosition(float3 input) { - return mul(float4(input, 1.0f), WorldMatrix).xyz; + return mul(float4(input, 1.0f), ToMatrix4x4(WorldMatrix)).xyz; } float3 TransformParticleVector(float3 input) { - return mul(float4(input, 0.0f), WorldMatrixInverseTransposed).xyz; + return mul(float4(input, 0.0f), ToMatrix4x4(WorldMatrixInverseTransposed)).xyz; } @8 @@ -219,7 +219,7 @@ void PS_VolumetricFog(Quad_GS2PS input, out float4 VBufferA : SV_Target0, out fl materialInput.ParticleIndex = ParticleIndex; materialInput.TBN = float3x3(float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1)); materialInput.TwoSidedSign = 1.0f; - materialInput.InstanceOrigin = WorldMatrix[3].xyz; + materialInput.InstanceOrigin = ToMatrix4x4(WorldMatrix)[3].xyz; materialInput.InstanceParams = PerInstanceRandom; materialInput.SvPosition = clipPos; Material material = GetMaterialPS(materialInput); diff --git a/Source/Engine/Core/Math/Matrix.cpp b/Source/Engine/Core/Math/Matrix.cpp index 8445bd84a..5fc2321e1 100644 --- a/Source/Engine/Core/Math/Matrix.cpp +++ b/Source/Engine/Core/Math/Matrix.cpp @@ -2,6 +2,7 @@ #include "Matrix.h" #include "Matrix3x3.h" +#include "Matrix3x4.h" #include "Vector2.h" #include "Quaternion.h" #include "Transform.h" @@ -887,3 +888,39 @@ Float4 Matrix::TransformPosition(const Matrix& m, const Float4& v) m.Values[0][3] * v.Raw[0] + m.Values[1][3] * v.Raw[1] + m.Values[2][3] * v.Raw[2] + m.Values[3][3] * v.Raw[3] ); } + +void Matrix3x4::SetMatrix(const Matrix& m) +{ + const float* src = m.Raw; + float* dst = Raw; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; + dst[8] = src[8]; + dst[9] = src[9]; + dst[10] = src[10]; + dst[11] = src[11]; +} + +void Matrix3x4::SetMatrixTranspose(const Matrix& m) +{ + const float* src = m.Raw; + float* dst = Raw; + dst[0] = src[0]; + dst[1] = src[4]; + dst[2] = src[8]; + dst[3] = src[12]; + dst[4] = src[1]; + dst[5] = src[5]; + dst[6] = src[9]; + dst[7] = src[13]; + dst[8] = src[2]; + dst[9] = src[6]; + dst[10] = src[10]; + dst[11] = src[14]; +} diff --git a/Source/Engine/Core/Math/Matrix3x4.h b/Source/Engine/Core/Math/Matrix3x4.h index aee3570a1..91133f816 100644 --- a/Source/Engine/Core/Math/Matrix3x4.h +++ b/Source/Engine/Core/Math/Matrix3x4.h @@ -9,43 +9,14 @@ /// struct FLAXENGINE_API Matrix3x4 { - float M[3][4]; - - void SetMatrix(const Matrix& m) + union { - const float* src = m.Raw; - float* dst = &M[0][0]; - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst[3] = src[3]; - dst[4] = src[4]; - dst[5] = src[5]; - dst[6] = src[6]; - dst[7] = src[7]; - dst[8] = src[8]; - dst[9] = src[9]; - dst[10] = src[10]; - dst[11] = src[11]; - } + float Values[3][4]; + float Raw[12]; + }; - void SetMatrixTranspose(const Matrix& m) - { - const float* src = m.Raw; - float* dst = &M[0][0]; - dst[0] = src[0]; - dst[1] = src[4]; - dst[2] = src[8]; - dst[3] = src[12]; - dst[4] = src[1]; - dst[5] = src[5]; - dst[6] = src[9]; - dst[7] = src[13]; - dst[8] = src[2]; - dst[9] = src[6]; - dst[10] = src[10]; - dst[11] = src[14]; - } + void SetMatrix(const Matrix& m); + void SetMatrixTranspose(const Matrix& m); }; template<> diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp index eeffb67d3..88dd34b35 100644 --- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp @@ -3,6 +3,7 @@ #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,8 +18,8 @@ #include "Engine/Graphics/RenderTask.h" PACK_STRUCT(struct DeferredMaterialShaderData { - Matrix WorldMatrix; - Matrix PrevWorldMatrix; + Matrix3x4 WorldMatrix; + Matrix3x4 PrevWorldMatrix; Float2 Dummy0; float LODDitherFactor; float PerInstanceRandom; @@ -70,8 +71,8 @@ void DeferredMaterialShader::Bind(BindParameters& params) // Setup material constants { - Matrix::Transpose(drawCall.World, materialData->WorldMatrix); - Matrix::Transpose(drawCall.Surface.PrevWorld, materialData->PrevWorldMatrix); + materialData->WorldMatrix.SetMatrixTranspose(drawCall.World); + materialData->PrevWorldMatrix.SetMatrixTranspose(drawCall.Surface.PrevWorld); materialData->WorldDeterminantSign = drawCall.WorldDeterminantSign; materialData->LODDitherFactor = drawCall.Surface.LODDitherFactor; materialData->PerInstanceRandom = drawCall.PerInstanceRandom; diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp index af2ad7957..6707fb802 100644 --- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp @@ -3,6 +3,7 @@ #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,8 +19,8 @@ #endif PACK_STRUCT(struct ForwardMaterialShaderData { - Matrix WorldMatrix; - Matrix PrevWorldMatrix; + Matrix3x4 WorldMatrix; + Matrix3x4 PrevWorldMatrix; Float2 Dummy0; float LODDitherFactor; float PerInstanceRandom; @@ -76,8 +77,8 @@ void ForwardMaterialShader::Bind(BindParameters& params) // Setup material constants { - Matrix::Transpose(drawCall.World, materialData->WorldMatrix); - Matrix::Transpose(drawCall.Surface.PrevWorld, materialData->PrevWorldMatrix); + materialData->WorldMatrix.SetMatrixTranspose(drawCall.World); + materialData->PrevWorldMatrix.SetMatrixTranspose(drawCall.Surface.PrevWorld); materialData->WorldDeterminantSign = drawCall.WorldDeterminantSign; materialData->LODDitherFactor = drawCall.Surface.LODDitherFactor; materialData->PerInstanceRandom = drawCall.PerInstanceRandom; diff --git a/Source/Engine/Graphics/Materials/MaterialShader.h b/Source/Engine/Graphics/Materials/MaterialShader.h index d79ef49b0..7a5b842e2 100644 --- a/Source/Engine/Graphics/Materials/MaterialShader.h +++ b/Source/Engine/Graphics/Materials/MaterialShader.h @@ -10,7 +10,7 @@ /// /// Current materials shader version. /// -#define MATERIAL_GRAPH_VERSION 161 +#define MATERIAL_GRAPH_VERSION 162 class Material; class GPUShader; diff --git a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp index cd0fb31f4..998a77843 100644 --- a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp @@ -3,6 +3,7 @@ #include "ParticleMaterialShader.h" #include "MaterialShaderFeatures.h" #include "MaterialParams.h" +#include "Engine/Core/Math/Matrix3x4.h" #include "Engine/Renderer/DrawCall.h" #include "Engine/Renderer/RenderList.h" #include "Engine/Graphics/RenderView.h" @@ -15,7 +16,7 @@ #include "Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.h" PACK_STRUCT(struct ParticleMaterialShaderData { - Matrix WorldMatrix; + Matrix3x4 WorldMatrix; uint32 SortedIndicesOffset; float PerInstanceRandom; int32 ParticleStride; @@ -34,7 +35,7 @@ PACK_STRUCT(struct ParticleMaterialShaderData { int32 RibbonTwistOffset; int32 RibbonFacingVectorOffset; uint32 RibbonSegmentCount; - Matrix WorldMatrixInverseTransposed; + Matrix3x4 WorldMatrixInverseTransposed; }); DrawPass ParticleMaterialShader::GetDrawModes() const @@ -101,7 +102,7 @@ void ParticleMaterialShader::Bind(BindParameters& params) static StringView ParticleScaleOffset(TEXT("Scale")); static StringView ParticleModelFacingModeOffset(TEXT("ModelFacingMode")); - Matrix::Transpose(drawCall.World, materialData->WorldMatrix); + materialData->WorldMatrix.SetMatrixTranspose(drawCall.World); materialData->SortedIndicesOffset = drawCall.Particle.Particles->GPU.SortedIndices && params.RenderContext.View.Pass != DrawPass::Depth ? sortedIndicesOffset : 0xFFFFFFFF; materialData->PerInstanceRandom = drawCall.PerInstanceRandom; materialData->ParticleStride = drawCall.Particle.Particles->Stride; @@ -113,7 +114,9 @@ void ParticleMaterialShader::Bind(BindParameters& params) materialData->RotationOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRotationOffset, ParticleAttribute::ValueTypes::Float3, -1); materialData->ScaleOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleScaleOffset, ParticleAttribute::ValueTypes::Float3, -1); materialData->ModelFacingModeOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleModelFacingModeOffset, ParticleAttribute::ValueTypes::Int, -1); - Matrix::Invert(drawCall.World, materialData->WorldMatrixInverseTransposed); + Matrix worldMatrixInverseTransposed; + Matrix::Invert(drawCall.World, worldMatrixInverseTransposed); + materialData->WorldMatrixInverseTransposed.SetMatrix(worldMatrixInverseTransposed); } // Select pipeline state based on current pass and render mode diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp index bcf194907..19415c891 100644 --- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp @@ -3,6 +3,7 @@ #include "TerrainMaterialShader.h" #include "MaterialShaderFeatures.h" #include "MaterialParams.h" +#include "Engine/Core/Math/Matrix3x4.h" #include "Engine/Graphics/GPUContext.h" #include "Engine/Graphics/GPULimits.h" #include "Engine/Graphics/GPUDevice.h" @@ -16,7 +17,7 @@ #include "Engine/Terrain/TerrainPatch.h" PACK_STRUCT(struct TerrainMaterialShaderData { - Matrix WorldMatrix; + Matrix3x4 WorldMatrix; Float3 WorldInvScale; float WorldDeterminantSign; float PerInstanceRandom; @@ -66,7 +67,7 @@ void TerrainMaterialShader::Bind(BindParameters& params) // Setup material constants { - Matrix::Transpose(drawCall.World, materialData->WorldMatrix); + materialData->WorldMatrix.SetMatrixTranspose(drawCall.World); const float scaleX = Float3(drawCall.World.M11, drawCall.World.M12, drawCall.World.M13).Length(); const float scaleY = Float3(drawCall.World.M21, drawCall.World.M22, drawCall.World.M23).Length(); const float scaleZ = Float3(drawCall.World.M31, drawCall.World.M32, drawCall.World.M33).Length(); diff --git a/Source/Engine/Graphics/Materials/VolumeParticleMaterialShader.cpp b/Source/Engine/Graphics/Materials/VolumeParticleMaterialShader.cpp index 106682148..585b4bf29 100644 --- a/Source/Engine/Graphics/Materials/VolumeParticleMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/VolumeParticleMaterialShader.cpp @@ -3,6 +3,7 @@ #include "VolumeParticleMaterialShader.h" #include "MaterialShaderFeatures.h" #include "MaterialParams.h" +#include "Engine/Core/Math/Matrix3x4.h" #include "Engine/Renderer/DrawCall.h" #include "Engine/Renderer/VolumetricFogPass.h" #include "Engine/Renderer/RenderList.h" @@ -16,8 +17,8 @@ PACK_STRUCT(struct VolumeParticleMaterialShaderData { Matrix InverseViewProjectionMatrix; - Matrix WorldMatrix; - Matrix WorldMatrixInverseTransposed; + Matrix3x4 WorldMatrix; + Matrix3x4 WorldMatrixInverseTransposed; Float3 GridSize; float PerInstanceRandom; float Dummy0; @@ -76,8 +77,10 @@ void VolumeParticleMaterialShader::Bind(BindParameters& params) // Setup material constants { Matrix::Transpose(view.IVP, materialData->InverseViewProjectionMatrix); - Matrix::Transpose(drawCall.World, materialData->WorldMatrix); - Matrix::Invert(drawCall.World, materialData->WorldMatrixInverseTransposed); + materialData->WorldMatrix.SetMatrixTranspose(drawCall.World); + Matrix worldMatrixInverseTransposed; + Matrix::Invert(drawCall.World, worldMatrixInverseTransposed); + materialData->WorldMatrixInverseTransposed.SetMatrix(worldMatrixInverseTransposed); materialData->GridSize = customData->GridSize; materialData->PerInstanceRandom = drawCall.PerInstanceRandom; materialData->VolumetricFogMaxDistance = customData->VolumetricFogMaxDistance; diff --git a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp index 278802995..ca4733496 100644 --- a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp +++ b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp @@ -3,6 +3,7 @@ #include "GlobalSignDistanceFieldPass.h" #include "RenderList.h" #include "Engine/Core/Math/Vector3.h" +#include "Engine/Core/Math/Matrix3x4.h" #include "Engine/Core/Collections/HashSet.h" #include "Engine/Engine/Engine.h" #include "Engine/Content/Content.h" @@ -39,8 +40,8 @@ static_assert(GLOBAL_SDF_RASTERIZE_MODEL_MAX_COUNT % 4 == 0, "Must be multiple o PACK_STRUCT(struct ObjectRasterizeData { - Matrix WorldToVolume; // TODO: use 3x4 matrix - Matrix VolumeToWorld; // TODO: use 3x4 matrix + Matrix3x4 WorldToVolume; + Matrix3x4 VolumeToWorld; Float3 VolumeToUVWMul; float MipOffset; Float3 VolumeToUVWAdd; @@ -670,15 +671,15 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex // Add object data for the GPU buffer uint16 dataIndex = _objectsBufferCount++; ObjectRasterizeData objectData; - Matrix localToWorldM, worldToLocal, volumeToWorld; - Matrix::Transformation(object.LocalToWorld.Scale, object.LocalToWorld.Orientation, object.LocalToWorld.Translation - _sdfData->Origin, localToWorldM); - Matrix::Invert(localToWorldM, worldToLocal); + Matrix localToWorld, worldToLocal, volumeToWorld; + Matrix::Transformation(object.LocalToWorld.Scale, object.LocalToWorld.Orientation, object.LocalToWorld.Translation - _sdfData->Origin, localToWorld); + Matrix::Invert(localToWorld, worldToLocal); BoundingBox localVolumeBounds(object.SDF->LocalBoundsMin, object.SDF->LocalBoundsMax); Float3 volumeLocalBoundsExtent = localVolumeBounds.GetSize() * 0.5f; Matrix worldToVolume = worldToLocal * Matrix::Translation(-(localVolumeBounds.Minimum + volumeLocalBoundsExtent)); Matrix::Invert(worldToVolume, volumeToWorld); - Matrix::Transpose(worldToVolume, objectData.WorldToVolume); - Matrix::Transpose(volumeToWorld, objectData.VolumeToWorld); + objectData.WorldToVolume.SetMatrixTranspose(worldToVolume); + objectData.VolumeToWorld.SetMatrixTranspose(volumeToWorld); objectData.VolumeLocalBoundsExtent = volumeLocalBoundsExtent; objectData.VolumeToUVWMul = object.SDF->LocalToUVWMul; objectData.VolumeToUVWAdd = object.SDF->LocalToUVWAdd + (localVolumeBounds.Minimum + volumeLocalBoundsExtent) * object.SDF->LocalToUVWMul; @@ -702,11 +703,11 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex // Add object data for the GPU buffer uint16 dataIndex = _objectsBufferCount++; ObjectRasterizeData objectData; - Matrix localToWorldM, worldToLocal; - Matrix::Transformation(object.LocalToWorld.Scale, object.LocalToWorld.Orientation, object.LocalToWorld.Translation - _sdfData->Origin, localToWorldM); - Matrix::Invert(localToWorldM, worldToLocal); - Matrix::Transpose(worldToLocal, objectData.WorldToVolume); - Matrix::Transpose(localToWorldM, objectData.VolumeToWorld); + Matrix localToWorld, worldToLocal; + Matrix::Transformation(object.LocalToWorld.Scale, object.LocalToWorld.Orientation, object.LocalToWorld.Translation - _sdfData->Origin, localToWorld); + Matrix::Invert(localToWorld, worldToLocal); + objectData.WorldToVolume.SetMatrixTranspose(worldToLocal); + objectData.VolumeToWorld.SetMatrixTranspose(localToWorld); objectData.VolumeToUVWMul = Float3(object.LocalToUV.X, 1.0f, object.LocalToUV.Y); objectData.VolumeToUVWAdd = Float3(object.LocalToUV.Z, 0.0f, object.LocalToUV.W); objectData.MipOffset = (float)_cascadeIndex * 0.5f; // Use lower-quality mip for far cascades diff --git a/Source/Shaders/Common.hlsl b/Source/Shaders/Common.hlsl index 4fa3b5bb2..74335d87a 100644 --- a/Source/Shaders/Common.hlsl +++ b/Source/Shaders/Common.hlsl @@ -230,4 +230,10 @@ float4 SampleUnwrappedTexture3D(Texture2D tex, SamplerState s, float3 uvw, float return lerp(rg0, rg1, fracW); } +// Converts compact 4x3 object transformation matrix into a full 4x4 matrix. +float4x4 ToMatrix4x4(float4x3 m) +{ + return float4x4(float4(m[0].xyz, 0.0f), float4(m[1].xyz, 0.0f), float4(m[2].xyz, 0.0f), float4(m._m30, m._m31, m._m32, 1.0f)); +} + #endif diff --git a/Source/Shaders/GlobalSignDistanceField.shader b/Source/Shaders/GlobalSignDistanceField.shader index 882e96306..9810c53f8 100644 --- a/Source/Shaders/GlobalSignDistanceField.shader +++ b/Source/Shaders/GlobalSignDistanceField.shader @@ -11,8 +11,8 @@ struct ObjectRasterizeData { - float4x4 WorldToVolume; // TODO: use 3x4 matrix - float4x4 VolumeToWorld; // TODO: use 3x4 matrix + float4x3 WorldToVolume; + float4x3 VolumeToWorld; float3 VolumeToUVWMul; float MipOffset; float3 VolumeToUVWAdd; @@ -74,14 +74,15 @@ Texture3D ObjectsTextures[GLOBAL_SDF_RASTERIZE_MODEL_MAX_COUNT] : registe float DistanceToModelSDF(float minDistance, ObjectRasterizeData modelData, Texture3D modelSDFTex, float3 worldPos) { // Object scaling is the length of the rows - float3 volumeToWorldScale = float3(length(modelData.VolumeToWorld[0]), length(modelData.VolumeToWorld[1]), length(modelData.VolumeToWorld[2])); + float4x4 volumeToWorld = ToMatrix4x4(modelData.VolumeToWorld); + float3 volumeToWorldScale = float3(length(volumeToWorld[0]), length(volumeToWorld[1]), length(volumeToWorld[2])); float volumeScale = min(volumeToWorldScale.x, min(volumeToWorldScale.y, volumeToWorldScale.z)); // Compute SDF volume UVs and distance in world-space to the volume bounds - float3 volumePos = mul(float4(worldPos, 1), modelData.WorldToVolume).xyz; + float3 volumePos = mul(float4(worldPos, 1), ToMatrix4x4(modelData.WorldToVolume)).xyz; float3 volumeUV = volumePos * modelData.VolumeToUVWMul + modelData.VolumeToUVWAdd; float3 volumePosClamped = clamp(volumePos, -modelData.VolumeLocalBoundsExtent, modelData.VolumeLocalBoundsExtent); - float3 worldPosClamped = mul(float4(volumePosClamped, 1), modelData.VolumeToWorld).xyz; + float3 worldPosClamped = mul(float4(volumePosClamped, 1), volumeToWorld).xyz; float distanceToVolume = distance(worldPos, worldPosClamped); if (distanceToVolume < 0.01f) distanceToVolume = length((volumePos - volumePosClamped) * volumeToWorldScale); @@ -152,7 +153,7 @@ void CS_RasterizeHeightfield(uint3 DispatchThreadId : SV_DispatchThreadID) ObjectRasterizeData objectData = ObjectsBuffer[Objects[i / 4][i % 4]]; // Convert voxel world-space position into heightfield local-space position and get heightfield UV - float3 volumePos = mul(float4(voxelWorldPos, 1), objectData.WorldToVolume).xyz; + float3 volumePos = mul(float4(voxelWorldPos, 1), ToMatrix4x4(objectData.WorldToVolume)).xyz; float3 volumeUV = volumePos * objectData.VolumeToUVWMul + objectData.VolumeToUVWAdd; float2 heightfieldUV = float2(volumeUV.x, volumeUV.z); @@ -168,8 +169,9 @@ void CS_RasterizeHeightfield(uint3 DispatchThreadId : SV_DispatchThreadID) float height = (float)((int)(heightmapValue.x * 255.0) + ((int)(heightmapValue.y * 255) << 8)) / 65535.0; float2 positionXZ = volumePos.xz; float3 position = float3(positionXZ.x, height, positionXZ.y); - float3 heightfieldPosition = mul(float4(position, 1), objectData.VolumeToWorld).xyz; - float3 heightfieldNormal = normalize(float3(objectData.VolumeToWorld[0].y, objectData.VolumeToWorld[1].y, objectData.VolumeToWorld[2].y)); + float4x4 volumeToWorld = ToMatrix4x4(objectData.VolumeToWorld); + float3 heightfieldPosition = mul(float4(position, 1), volumeToWorld).xyz; + float3 heightfieldNormal = normalize(float3(volumeToWorld[0].y, volumeToWorld[1].y, volumeToWorld[2].y)); // Calculate distance from voxel center to the heightfield float objectDistance = dot(heightfieldNormal, voxelWorldPos - heightfieldPosition);