Files
UnrealEngineUWP/Engine/Shaders/MeshParticleVertexFactory.usf
Joe Tidmarsh 614aff6627 Remove scaling when calculating tangents for instanced mesh particles
#ttp 335591 - RENDERING: PARTICLE: Mesh emitters which utilize a material with a normal map are distorted

[CL 2225388 by Joe Tidmarsh in Main branch]
2014-07-21 05:23:27 -04:00

549 lines
18 KiB
Plaintext

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
MeshParticleVertexFactory.usf: Mesh particle vertex factory shader code.
=============================================================================*/
#include "VertexFactoryCommon.usf"
// These are only enabled for SM5 due to limited interpolators elsewhere
#define USE_PARTICLE_NODES (FEATURE_LEVEL >= FEATURE_LEVEL_SM5)
float4x4 PreviousLocalToWorld;
#if !PARTICLE_MESH_INSTANCED
float4 Transform1;
float4 Transform2;
float4 Transform3;
float4 SubUVParams;
float SubUVLerp;
float4 DynamicParameter;
float4 ParticleColor;
#endif
struct FVertexFactoryInput
{
float4 Position : ATTRIBUTE0;
half3 TangentX : ATTRIBUTE1;
// TangentZ.w contains sign of tangent basis determinant
half4 TangentZ : ATTRIBUTE2;
half4 VertexColor : ATTRIBUTE3;
#if NUM_MATERIAL_TEXCOORDS_VERTEX
float2 TexCoords[NUM_MATERIAL_TEXCOORDS_VERTEX] : ATTRIBUTE4;
#elif USE_PARTICLE_SUBUVS
float2 TexCoords[1] : ATTRIBUTE4;
#endif
#if PARTICLE_MESH_INSTANCED
float4 Transform1 : ATTRIBUTE8;
float4 Transform2 : ATTRIBUTE9;
float4 Transform3 : ATTRIBUTE10;
int4 SubUVParams : ATTRIBUTE11;
/** X: SubUV lerp Y: Particle relative time. */
float2 SubUVLerpAndRelTime : ATTRIBUTE12;
#if USE_DYNAMIC_PARAMETERS
float4 DynamicParameter : ATTRIBUTE13;
#endif //USE_DYNAMIC_PARAMETERS
float4 ParticleColor : ATTRIBUTE14;
/** The velocity of the particle, XYZ: direction, W: speed. */
float4 ParticleVelocity : ATTRIBUTE15;
#endif
};
struct FVertexFactoryInterpolantsVSToPS
{
TANGENTTOWORLD_INTERPOLATOR_BLOCK
#if USE_PARTICLE_SUBUVS
float4 SubUV0AndTexCoord0 : TEXCOORD1;
float4 SubUV1AndLerp : TEXCOORD2;
#else
#if NUM_MATERIAL_TEXCOORDS
#if ES2_PROFILE
// Avoid dependent texture fetches, put all UVs in xy
float2 TexCoords[NUM_MATERIAL_TEXCOORDS] : TEXCOORD0;
#else
float4 TexCoords[(NUM_MATERIAL_TEXCOORDS+1)/2] : TEXCOORD0;
#endif
#endif
#endif
#if INTERPOLATE_VERTEX_COLOR
float4 VertexColor : COLOR0;
#endif
#if NEEDS_PARTICLE_COLOR
float4 ParticleColor : COLOR1;
#endif
#if USE_DYNAMIC_PARAMETERS
float4 DynamicParameter : COLOR2;
#endif
#if USE_PARTICLE_NODES
/** Particle world position. */
float3 ParticlePosition : PARTICLE_POSITION;
/** The velocity of the particle, XYZ: direction, W: speed. */
float4 ParticleVelocity : PARTICLE_VELOCITY;
/** Relative alive time of the particle */
float ParticleTime : PARTICLE_TIME;
#endif
};
struct FVertexFactoryIntermediates
{
/** The color of the vertex. */
float4 VertexColor;
/** The color of the particle. */
float4 ParticleColor;
/** The texture coordinates for the vertex. */
#if NUM_MATERIAL_TEXCOORDS_VERTEX
float2 TexCoords[NUM_MATERIAL_TEXCOORDS_VERTEX];
#endif
#if USE_PARTICLE_SUBUVS
float4 SubUVCoords;
float SubUVLerp;
#endif
#if USE_DYNAMIC_PARAMETERS
/** Optional dynamic parameter for the particle. */
float4 DynamicParameter;
#endif //USE_DYNAMIC_PARAMETERS
/** The velocity of the particle, XYZ: direction, W: speed. */
float4 ParticleVelocity;
/** Particle (non-translated) world space position. */
float3 ParticleWorldPosition;
/** Relative time. */
float RelativeTime;
};
/** Converts from vertex factory specific interpolants to a FMaterialPixelParameters, which is used by material inputs. */
FMaterialPixelParameters GetMaterialPixelParameters(FVertexFactoryInterpolantsVSToPS Interpolants, float4 PixelPosition)
{
// GetMaterialPixelParameters is responsible for fully initializing the result
FMaterialPixelParameters Result = MakeInitializedMaterialPixelParameters();
#if USE_PARTICLE_SUBUVS
#if NUM_MATERIAL_TEXCOORDS
UNROLL
for( int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS; CoordinateIndex++ )
{
Result.TexCoords[CoordinateIndex] = Interpolants.SubUV0AndTexCoord0.zw;
}
#endif
Result.Particle.SubUVCoords[0] = Interpolants.SubUV0AndTexCoord0.xy;
Result.Particle.SubUVCoords[1] = Interpolants.SubUV1AndLerp.xy;
Result.Particle.SubUVLerp = Interpolants.SubUV1AndLerp.z;
#elif NUM_MATERIAL_TEXCOORDS
#if ES2_PROFILE
UNROLL
for( int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS; CoordinateIndex++ )
{
Result.TexCoords[CoordinateIndex] = Interpolants.TexCoords[CoordinateIndex].xy;
}
#else
UNROLL
for(int CoordinateIndex = 0;CoordinateIndex < NUM_MATERIAL_TEXCOORDS;CoordinateIndex += 2)
{
Result.TexCoords[CoordinateIndex] = Interpolants.TexCoords[CoordinateIndex/2].xy;
if(CoordinateIndex + 1 < NUM_MATERIAL_TEXCOORDS)
{
Result.TexCoords[CoordinateIndex + 1] = Interpolants.TexCoords[CoordinateIndex/2].wz;
}
}
#endif
#endif
half3 TangentToWorld0 = Interpolants.TangentToWorld0.xyz;
half4 TangentToWorld2 = Interpolants.TangentToWorld2;
Result.UnMirrored = TangentToWorld2.w;
#if INTERPOLATE_VERTEX_COLOR
Result.VertexColor = Interpolants.VertexColor;
#else
Result.VertexColor = 0;
#endif
#if NEEDS_PARTICLE_COLOR
Result.Particle.Color = Interpolants.ParticleColor;
#endif
#if USE_DYNAMIC_PARAMETERS
Result.Particle.DynamicParameter = Interpolants.DynamicParameter;
#else
Result.Particle.DynamicParameter = float4(1,1,1,1);
#endif //USE_DYNAMIC_PARAMETERS
#if USE_PARTICLE_NODES
Result.Particle.PositionAndSize.xyz = Interpolants.ParticlePosition.xyz;
Result.Particle.PositionAndSize.w = 1;
Result.Particle.Velocity = Interpolants.ParticleVelocity;
Result.Particle.RelativeTime = Interpolants.ParticleTime;
#endif
Result.Particle.MotionBlurFade = 1.0f;
Result.TangentToWorld = AssembleTangentToWorld( TangentToWorld0, TangentToWorld2 );
Result.TwoSidedSign = 1;
return Result;
}
/** Converts from vertex factory specific input to a FMaterialVertexParameters, which is used by vertex shader material inputs. */
FMaterialVertexParameters GetMaterialVertexParameters( FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float3 WorldPosition, float3x3 TangentToLocal )
{
FMaterialVertexParameters Result = (FMaterialVertexParameters)0;
Result.WorldPosition = WorldPosition - View.PreViewTranslation;
Result.VertexColor = Intermediates.VertexColor;
Result.Particle.PositionAndSize.xyz = Intermediates.ParticleWorldPosition.xyz;
Result.Particle.PositionAndSize.w = 1;
Result.Particle.Velocity = Intermediates.ParticleVelocity;
Result.Particle.RelativeTime = Intermediates.RelativeTime;
#if USE_DYNAMIC_PARAMETERS
Result.Particle.DynamicParameter = Intermediates.DynamicParameter;
#endif //USE_DYNAMIC_PARAMETERS
#if PARTICLE_MESH_INSTANCED
float4x4 Transform = float4x4( Input.Transform1, Input.Transform2, Input.Transform3, float4(0 ,0, 0, 1));
#else
float4x4 Transform = float4x4( Transform1, Transform2, Transform3, float4(0 ,0, 0, 1));
#endif
Result.InstanceLocalToWorld = Transform;
Result.TangentToWorld = mul(TangentToLocal, transpose( (float3x3)Transform ) );
#if NUM_MATERIAL_TEXCOORDS_VERTEX
for(int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS_VERTEX; CoordinateIndex++)
{
Result.TexCoords[CoordinateIndex] = Intermediates.TexCoords[CoordinateIndex];
}
#endif
return Result;
}
#if NEEDS_LIGHTMAP_COORDINATE
void GetLightMapCoordinates(FVertexFactoryInterpolantsVSToPS Interpolants, out float2 LightmapUV0, out float2 LightmapUV1)
{
LightmapUV0 = LightmapUV1 = 0;
}
half2 GetShadowMapCoordinate(FVertexFactoryInterpolantsVSToPS Interpolants)
{
return 0;
}
#endif
float4 CalcWorldPosition(float4 Position, float4 Transform1, float4 Transform2, float4 Transform3)
{
float3x4 Transform = float3x4(Transform1, Transform2, Transform3);
float3 WorldPosition = mul(Transform, Position) + View.PreViewTranslation;
return float4(WorldPosition,Position.w);
}
FVertexFactoryIntermediates GetVertexFactoryIntermediates(FVertexFactoryInput Input)
{
FVertexFactoryIntermediates Intermediates = (FVertexFactoryIntermediates)0;
// Swizzle vertex color.
Intermediates.VertexColor = Input.VertexColor FCOLOR_COMPONENT_SWIZZLE;
// World position.
#if PARTICLE_MESH_INSTANCED
float3 ParticleWorldPosition = float3( Input.Transform1.w, Input.Transform2.w, Input.Transform3.w);
#else
float3 ParticleWorldPosition = float3( Transform1.w, Transform2.w, Transform3.w);
#endif
Intermediates.ParticleWorldPosition = ParticleWorldPosition;
#if PARTICLE_MESH_INSTANCED
Intermediates.ParticleColor = Input.ParticleColor;
#else
Intermediates.ParticleColor = ParticleColor;
#endif
#if NUM_MATERIAL_TEXCOORDS_VERTEX
for(int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS_VERTEX; CoordinateIndex++)
{
Intermediates.TexCoords[CoordinateIndex] = Input.TexCoords[CoordinateIndex].xy;
}
#endif
#if USE_PARTICLE_SUBUVS
#if PARTICLE_MESH_INSTANCED
Intermediates.SubUVCoords.xy = (float2( Input.SubUVParams.x, Input.SubUVParams.y ) + Input.TexCoords[0].xy) * MeshParticleVF.SubImageSize.xy;
Intermediates.SubUVCoords.zw = (float2( Input.SubUVParams.z, Input.SubUVParams.w ) + Input.TexCoords[0].xy) * MeshParticleVF.SubImageSize.xy;
Intermediates.SubUVLerp = Input.SubUVLerpAndRelTime.x;
#else
Intermediates.SubUVCoords.xy = (float2( SubUVParams.x, SubUVParams.y ) + Input.TexCoords[0].xy) * MeshParticleVF.SubImageSize.xy;
Intermediates.SubUVCoords.zw = (float2( SubUVParams.z, SubUVParams.w ) + Input.TexCoords[0].xy) * MeshParticleVF.SubImageSize.xy;
Intermediates.SubUVLerp = SubUVLerp.x;
#endif
#endif
#if USE_DYNAMIC_PARAMETERS
#if PARTICLE_MESH_INSTANCED
Intermediates.DynamicParameter = Input.DynamicParameter;
#else
Intermediates.DynamicParameter = DynamicParameter;
#endif
#endif //USE_DYNAMIC_PARAMETERS
Intermediates.ParticleWorldPosition = ParticleWorldPosition.xyz;
#if PARTICLE_MESH_INSTANCED
Intermediates.ParticleVelocity = Input.ParticleVelocity;
Intermediates.RelativeTime = Input.SubUVLerpAndRelTime.y;
#else
Intermediates.ParticleVelocity = float4(0,1,0,0); // TODO: We don't have this data when instancing is disabled. Should we?
Intermediates.RelativeTime = 0;
#endif
return Intermediates;
}
/**
* Get the 3x3 tangent basis vectors for this vertex factory
* this vertex factory will calculate the binormal on-the-fly
*
* @param Input - vertex input stream structure
* @return 3x3 matrix
*/
float3x3 VertexFactoryGetTangentToLocal( FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates )
{
float3x3 Result=0;
float4 TangentZ = TangentBias(Input.TangentZ);
// pass-thru the tangent
Result[0] = TangentBias(Input.TangentX);
// pass-thru the normal
Result[2] = TangentZ.xyz;
// derive the binormal by getting the cross product of the normal and tangent
Result[1] = cross(Result[2], Result[0]) * TangentZ.w;
// Recalculate TangentX off of the other two vectors
// This corrects quantization error since TangentX was passed in as a quantized vertex input
// The error shows up most in specular off of a mesh with a smoothed UV seam (normal is smooth, but tangents vary across the seam)
Result[0] = cross(Result[1], Result[2]) * TangentZ.w;
return Result;
}
// @return translated world position
float4 VertexFactoryGetWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
#if PARTICLE_MESH_INSTANCED
return CalcWorldPosition(Input.Position, Input.Transform1, Input.Transform2, Input.Transform3);
#else
return CalcWorldPosition(Input.Position, Transform1, Transform2, Transform3);
#endif
}
float4 VertexFactoryGetRasterizedWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float4 InWorldPosition)
{
return InWorldPosition;
}
void CalcTangentToWorld(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, out float3 TangentToWorld0, out float4 TangentToWorld2)
{
float3x3 TangentToLocal = VertexFactoryGetTangentToLocal(Input, Intermediates);
#if PARTICLE_MESH_INSTANCED
float3x3 Transform = float3x3(Input.Transform1.xyz, Input.Transform2.xyz, Input.Transform3.xyz);
#else
float3x3 Transform = float3x3(Transform1.xyz, Transform2.xyz, Transform3.xyz);
#endif
float3x3 TangentToWorld = mul(TangentToLocal, transpose(Transform));
// Normalize to remove scaling. Incorrect but faster than computing the inverse-transpose.
TangentToWorld0 = normalize(TangentToWorld[0]);
TangentToWorld2 = normalize(float4(TangentToWorld[2], TangentBias(Input.TangentZ.w) * Primitive.LocalToWorldDeterminantSign));
}
FVertexFactoryInterpolantsVSToPS VertexFactoryGetInterpolantsVSToPS(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, FMaterialVertexParameters VertexParameters)
{
FVertexFactoryInterpolantsVSToPS Interpolants;
#if USE_PARTICLE_SUBUVS
Interpolants.SubUV0AndTexCoord0.xy = Intermediates.SubUVCoords.xy;
Interpolants.SubUV1AndLerp.xy = Intermediates.SubUVCoords.zw;
Interpolants.SubUV1AndLerp.zw = Intermediates.SubUVLerp.xx;
#if NUM_MATERIAL_TEXCOORDS
float2 CustomizedUVs[NUM_MATERIAL_TEXCOORDS];
GetMaterialCustomizedUVs(VertexParameters, CustomizedUVs);
Interpolants.SubUV0AndTexCoord0.zw = CustomizedUVs[0];
#else
Interpolants.SubUV0AndTexCoord0.zw = 0;
#endif
#elif NUM_MATERIAL_TEXCOORDS
#if ES2_PROFILE
GetMaterialCustomizedUVs(VertexParameters, Interpolants.TexCoords);
#else
// Ensure the unused components of the last packed texture coordinate are initialized.
Interpolants.TexCoords[(NUM_MATERIAL_TEXCOORDS + 1) / 2 - 1] = 0;
float2 CustomizedUVs[NUM_MATERIAL_TEXCOORDS];
GetMaterialCustomizedUVs(VertexParameters, CustomizedUVs);
UNROLL
for(int CoordinateIndex = 0;CoordinateIndex < NUM_MATERIAL_TEXCOORDS;CoordinateIndex += 2)
{
Interpolants.TexCoords[CoordinateIndex / 2].xy = CustomizedUVs[CoordinateIndex];
if(CoordinateIndex + 1 < NUM_MATERIAL_TEXCOORDS)
{
Interpolants.TexCoords[CoordinateIndex / 2].wz = CustomizedUVs[CoordinateIndex + 1];
}
}
#endif
#endif
Interpolants.TangentToWorld0.w = 0;
CalcTangentToWorld(Input, Intermediates, Interpolants.TangentToWorld0.xyz, Interpolants.TangentToWorld2);
#if INTERPOLATE_VERTEX_COLOR
Interpolants.VertexColor = Intermediates.VertexColor;
#endif
#if NEEDS_PARTICLE_COLOR
Interpolants.ParticleColor = Intermediates.ParticleColor;
#endif
#if USE_DYNAMIC_PARAMETERS
Interpolants.DynamicParameter = Intermediates.DynamicParameter;
#endif //USE_DYNAMIC_PARAMETERS
#if USE_PARTICLE_NODES
Interpolants.ParticlePosition = Intermediates.ParticleWorldPosition;
Interpolants.ParticleVelocity = Intermediates.ParticleVelocity;
Interpolants.ParticleTime = Intermediates.RelativeTime;
#endif
return Interpolants;
}
// @return previous translated world position
float4 VertexFactoryGetPreviousWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
// The previous local to world instance transform isn't available.
#if PARTICLE_MESH_INSTANCED
return CalcWorldPosition(Input.Position, Input.Transform1, Input.Transform2, Input.Transform3);
#else
return CalcWorldPosition(Input.Position, Transform1, Transform2, Transform3);
#endif
}
#if USING_TESSELLATION
struct FVertexFactoryInterpolantsVSToDS
{
FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS;
};
float2 VertexFactoryGetTextureCoordinateDS( FVertexFactoryInterpolantsVSToDS Interpolants )
{
#if NUM_MATERIAL_TEXCOORDS
return Interpolants.InterpolantsVSToPS.TexCoords[0].xy;
#else // #if NUM_MATERIAL_TEXCOORDS
return float2(0,0);
#endif // #if NUM_MATERIAL_TEXCOORDS
}
FVertexFactoryInterpolantsVSToPS VertexFactoryAssignInterpolants(FVertexFactoryInterpolantsVSToDS Input)
{
return Input.InterpolantsVSToPS;
}
/** Converts from vertex factory specific interpolants to a FMaterialTessellationParameters, which is used by material inputs. */
FMaterialTessellationParameters GetMaterialTessellationParameters(FVertexFactoryInterpolantsVSToDS Interpolants, float3 CameraLocalWorldPosition)
{
FMaterialTessellationParameters Result;
#if NUM_MATERIAL_TEXCOORDS
UNROLL
for(int CoordinateIndex = 0;CoordinateIndex < NUM_MATERIAL_TEXCOORDS;CoordinateIndex += 2)
{
Result.TexCoords[CoordinateIndex] = Interpolants.InterpolantsVSToPS.TexCoords[CoordinateIndex/2].xy;
if(CoordinateIndex + 1 < NUM_MATERIAL_TEXCOORDS)
{
Result.TexCoords[CoordinateIndex + 1] = Interpolants.InterpolantsVSToPS.TexCoords[CoordinateIndex/2].wz;
}
}
#endif
Result.VertexColor = float4(1,1,1,1);
half3 TangentToWorld0 = Interpolants.InterpolantsVSToPS.TangentToWorld0.xyz;
half4 TangentToWorld2 = Interpolants.InterpolantsVSToPS.TangentToWorld2;
Result.TangentToWorld = AssembleTangentToWorld( TangentToWorld0, TangentToWorld2 );
Result.TangentToWorldPreScale = 1;
Result.WorldPosition = CameraLocalWorldPosition + View.ViewOrigin.xyz;
return Result;
}
FVertexFactoryInterpolantsVSToDS VertexFactoryGetInterpolantsVSToDS(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, FMaterialVertexParameters VertexParameters)
{
FVertexFactoryInterpolantsVSToDS Interpolants;
Interpolants.InterpolantsVSToPS = VertexFactoryGetInterpolantsVSToPS(Input, Intermediates, VertexParameters);
return Interpolants;
}
FVertexFactoryInterpolantsVSToDS VertexFactoryInterpolate(FVertexFactoryInterpolantsVSToDS a, float aInterp, FVertexFactoryInterpolantsVSToDS b, float bInterp)
{
FVertexFactoryInterpolantsVSToDS O;
// Do we really need to interpolate TangentToWorld2 here? It should be replaced by the
// interpolated normal from 'whatever' interpolation scheme we're using
TESSELLATION_INTERPOLATE_MEMBER(InterpolantsVSToPS.TangentToWorld0.xyz);
TESSELLATION_INTERPOLATE_MEMBER(InterpolantsVSToPS.TangentToWorld2);
#if INTERPOLATE_VERTEX_COLOR
TESSELLATION_INTERPOLATE_MEMBER(InterpolantsVSToPS.VertexColor);
#endif
#if NEEDS_PARTICLE_COLOR
TESSELLATION_INTERPOLATE_MEMBER(InterpolantsVSToPS.ParticleColor);
#endif
#if NUM_MATERIAL_TEXCOORDS
for (int i = 0; i < (NUM_MATERIAL_TEXCOORDS + 1) / 2; ++i)
{
TESSELLATION_INTERPOLATE_MEMBER(InterpolantsVSToPS.TexCoords[i]);
}
#endif
#if USE_DYNAMIC_PARAMETERS
TESSELLATION_INTERPOLATE_MEMBER(InterpolantsVSToPS.DynamicParameter);
#endif //USE_DYNAMIC_PARAMETERS
return O;
}
float3x3 VertexFactoryGetTangentToLocalDS(FVertexFactoryInterpolantsVSToDS Interpolants)
{
// This duplicates stuff already going on in GetMaterialTessellationParameters(), so
// maybe the hull shader could leverage that instead?
half3 TangentToWorld0 = Interpolants.InterpolantsVSToPS.TangentToWorld0.xyz;
half4 TangentToWorld2 = Interpolants.InterpolantsVSToPS.TangentToWorld2;
float3x3 TangentToWorld = AssembleTangentToWorld( TangentToWorld0, TangentToWorld2 );
return TangentToWorld;
}
#endif // #if USING_TESSELLATION