You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
removed usage of ComputeWorldWorldPosCamRelative() where possible for better quality and performance, used SvPositionToTranslatedWorld() instead [CL 2699869 by Martin Mittring in Main branch]
587 lines
21 KiB
Plaintext
587 lines
21 KiB
Plaintext
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
ParticleGPUSpriteVertexFactory.usf: Vertex factory for GPU simulated particles.
|
|
=============================================================================*/
|
|
|
|
#define PARTICLE_SPRITE_FACTORY 1
|
|
|
|
#include "VertexFactoryCommon.usf"
|
|
#include "ParticleVertexFactoryCommon.usf"
|
|
|
|
#define USE_PARTICLE_LIGHTING_OFFSET (FEATURE_LEVEL >= FEATURE_LEVEL_SM5 && !MATERIAL_SHADINGMODEL_UNLIT)
|
|
#define USE_PARTICLE_POSITION (FEATURE_LEVEL >= FEATURE_LEVEL_SM5 && NEEDS_PARTICLE_POSITION)
|
|
#define USE_PARTICLE_VELOCITY (FEATURE_LEVEL >= FEATURE_LEVEL_SM5 && NEEDS_PARTICLE_VELOCITY)
|
|
#define USE_PARTICLE_TIME (FEATURE_LEVEL >= FEATURE_LEVEL_SM5 && NEEDS_PARTICLE_TIME)
|
|
#define USE_SPHERICAL_NORMALS (GENERATE_SPHERICAL_PARTICLE_NORMALS && USE_PARTICLE_POSITION)
|
|
#define USE_PARTICLE_SIZE (FEATURE_LEVEL >= FEATURE_LEVEL_SM5 && NEEDS_PARTICLE_SIZE)
|
|
|
|
/** Buffer containing particle indices. */
|
|
#if COMPILER_METAL
|
|
// Metal does not have buffer SRVs, so data types have to match
|
|
#undef half2
|
|
Buffer<half2> ParticleIndices;
|
|
#else
|
|
Buffer<float2> ParticleIndices;
|
|
#endif
|
|
|
|
/** Offset in to the particle indices buffer. */
|
|
uint ParticleIndicesOffset;
|
|
|
|
/** Texture containing positions for all particles. */
|
|
Texture2D PositionTexture;
|
|
SamplerState PositionTextureSampler;
|
|
Texture2D VelocityTexture;
|
|
SamplerState VelocityTextureSampler;
|
|
Texture2D AttributesTexture;
|
|
SamplerState AttributesTextureSampler;
|
|
Texture2D CurveTexture;
|
|
SamplerState CurveTextureSampler;
|
|
|
|
/**
|
|
* Vertex attributes to fetch.
|
|
*/
|
|
struct FVertexFactoryInput
|
|
{
|
|
/** Unique vertex ID. */
|
|
uint VertexId : SV_VertexID;
|
|
/** Unique instance ID. */
|
|
uint InstanceId : SV_InstanceID;
|
|
/** Per-vertex: texture coordinate. */
|
|
float2 TexCoord : ATTRIBUTE0;
|
|
};
|
|
|
|
/**
|
|
* Attributes to interpolate from the vertex shader to the pixel shader.
|
|
*/
|
|
struct FVertexFactoryInterpolantsVSToPS
|
|
{
|
|
#if NUM_MATERIAL_TEXCOORDS
|
|
float4 TexCoords[(NUM_MATERIAL_TEXCOORDS + 1) / 2] : TEXCOORD0;
|
|
#endif
|
|
|
|
#if USE_PARTICLE_SUBUVS
|
|
float4 ParticleSubUVs : PARTICLE_SUBUVS;
|
|
#endif
|
|
|
|
/** X: SubImageLerp Y:RelativeTime Z:MotionBlurFade */
|
|
float3 Misc : TEXCOORD4;
|
|
|
|
#if NEEDS_PARTICLE_COLOR
|
|
/** Sprite color. */
|
|
float4 Color : TEXCOORD5;
|
|
#endif
|
|
|
|
/** Particle position and size. */
|
|
#if USE_PARTICLE_POSITION
|
|
float4 ParticlePositionAndSize : PARTICLE_POSITION;
|
|
#endif
|
|
|
|
/** The velocity of the particle, XYZ: direction, W: speed. */
|
|
#if USE_PARTICLE_VELOCITY
|
|
float4 ParticleVelocity : PARTICLE_VELOCITY;
|
|
#endif
|
|
|
|
#if USE_PARTICLE_LIGHTING_OFFSET
|
|
float3 LightingPositionOffset : PARTICLE_LIGHTING_OFFSET;
|
|
#endif
|
|
|
|
#if !USE_SPHERICAL_NORMALS
|
|
float4 TangentToWorld0 : TANGENTX;
|
|
float4 TangentToWorld2 : TANGENTZ;
|
|
#endif
|
|
|
|
/** The size of the particle. */
|
|
#if USE_PARTICLE_SIZE
|
|
float2 ParticleSize : PARTICLE_SIZE;
|
|
#endif
|
|
};
|
|
|
|
/**
|
|
* Intermediate values computed in the vertex shader.
|
|
*/
|
|
struct FVertexFactoryIntermediates
|
|
{
|
|
/** The position of the particle in translated world space. */
|
|
float3 ParticleWorldPosition;
|
|
/** The position of the vertex in translated world space. */
|
|
float3 VertexWorldPosition;
|
|
|
|
#if USE_PARTICLE_LIGHTING_OFFSET
|
|
float3 LightingPositionOffset;
|
|
#endif
|
|
|
|
/** The texture coordinate at this vertex. */
|
|
float4 TexCoord;
|
|
/** The sprite tangent in world space (+V). */
|
|
float3 TangentUp;
|
|
/** The sprite tangent in world space (+U). */
|
|
float3 TangentRight;
|
|
/** The color of the sprite. */
|
|
float4 Color;
|
|
/** The velocity of the particle, XYZ: direction, W: speed. */
|
|
float4 ParticleVelocity;
|
|
/** The sub-image lerp. */
|
|
float SubImageLerp;
|
|
/** Relative time. */
|
|
float RelativeTime;
|
|
/** Amount to fade the sprite due to camera motion blur. */
|
|
float MotionBlurFade;
|
|
/** Radius of the particle when represented by a sphere. */
|
|
float ParticleRadius;
|
|
/** Size of the particle. */
|
|
float2 ParticleSize;
|
|
};
|
|
|
|
float3 SafeNormalize(float3 V)
|
|
{
|
|
return V / sqrt(max(dot(V,V),0.01));
|
|
}
|
|
|
|
/**
|
|
* Compute the tangents for a sprite given a rotation.
|
|
* @param OutUp - The tangent vector pointing up in screen space.
|
|
* @param OutRight - The tangent vector pointing right in screen space.
|
|
* @param Rotation - The rotation of the sprite.
|
|
* @param ParticleWorldPosition - World position of the particle.
|
|
* @param ParticleWorldDirection - World space direction in which the particle is traveling.
|
|
*/
|
|
void GetSpriteTangents(
|
|
out float3 OutUp,
|
|
out float3 OutRight,
|
|
float Rotation,
|
|
float3 ParticleWorldPosition,
|
|
float3 ParticleWorldDirection )
|
|
{
|
|
// Select camera up/right vectors.
|
|
float3 CameraRight = lerp(View.ViewRight, EmitterDynamicUniforms.AxisLockRight.xyz, EmitterDynamicUniforms.AxisLockRight.w);
|
|
float3 CameraUp = lerp(-View.ViewUp, EmitterDynamicUniforms.AxisLockUp.xyz, EmitterDynamicUniforms.AxisLockUp.w);
|
|
|
|
// Determine the vector from the particle to the camera and the particle's movement direction.
|
|
float3 CameraDirection = SafeNormalize(View.TranslatedWorldCameraOrigin - ParticleWorldPosition.xyz);
|
|
float3 RightVector = CameraRight.xyz;
|
|
float3 UpVector = CameraUp.xyz;
|
|
|
|
FLATTEN
|
|
if (EmitterUniforms.TangentSelector.y > 0)
|
|
{
|
|
// Tangent vectors for PSA_Velocity.
|
|
RightVector = SafeNormalize(cross(CameraDirection, ParticleWorldDirection));
|
|
UpVector = -ParticleWorldDirection;
|
|
}
|
|
else if (EmitterUniforms.TangentSelector.z > 0)
|
|
{
|
|
// Tangent vectors for rotation locked about an axis.
|
|
RightVector = EmitterDynamicUniforms.AxisLockRight.xyz;
|
|
UpVector = -SafeNormalize(cross(RightVector,CameraDirection));
|
|
}
|
|
else if (EmitterUniforms.TangentSelector.w > 0)
|
|
{
|
|
// Tangent vectors for camera facing position.
|
|
RightVector = SafeNormalize(cross(CameraDirection,float3(0,0,1)));
|
|
UpVector = cross(CameraDirection, RightVector);
|
|
}
|
|
|
|
// Determine the angle of rotation.
|
|
float SinRotation; // = 0
|
|
float CosRotation; // = 1
|
|
const float SpriteRotation = Rotation + EmitterUniforms.RotationBias;
|
|
sincos(SpriteRotation, SinRotation, CosRotation);
|
|
|
|
// Rotate the sprite to determine final tangents.
|
|
OutRight = SinRotation * UpVector + CosRotation * RightVector;
|
|
OutUp = CosRotation * UpVector - SinRotation * RightVector;
|
|
}
|
|
|
|
/**
|
|
* Computes intermediates for the given vertex.
|
|
* @param Input - Vertex attributes.
|
|
* @returns the computed intermediate values.
|
|
*/
|
|
FVertexFactoryIntermediates GetVertexFactoryIntermediates( FVertexFactoryInput Input )
|
|
{
|
|
// Sample the position and velocity textures to get the current state of the particle.
|
|
uint InstanceId = Input.InstanceId * PARTICLES_PER_INSTANCE + Input.VertexId / 4;
|
|
float2 ParticleIndex = ParticleIndices[ParticleIndicesOffset + InstanceId];
|
|
float4 PositionSample = Texture2DSampleLevel(PositionTexture, PositionTextureSampler, ParticleIndex, 0);
|
|
float4 VelocitySample = Texture2DSampleLevel(VelocityTexture, VelocityTextureSampler, ParticleIndex, 0);
|
|
float4 AttributeSample = Texture2DSampleLevel(AttributesTexture, AttributesTextureSampler, ParticleIndex, 0);
|
|
|
|
// For clarity, store some information in local variables.
|
|
const float RelativeTime = PositionSample.w;
|
|
const float IsAlive = step( RelativeTime, 1.0f );
|
|
float3 ParticlePosition = PositionSample.xyz;
|
|
|
|
// Put velocity in to world space.
|
|
float3 ParticleWorldVelocity = mul(VelocitySample.xyz, GetLocalToWorld3x3()).xyz;
|
|
|
|
// Add a small bias to the direction to prevent issues when velocity is zero.
|
|
float3 ParticleDirection = normalize(ParticleWorldVelocity.xyz + float3(0,0,0.0001f));
|
|
float ParticleSpeed = length(ParticleWorldVelocity.xyz);
|
|
|
|
// Sample the color curve.
|
|
const float4 InitialColor = float4(1,1,1,1);
|
|
float2 ColorCurveTexCoord = EmitterUniforms.ColorCurve.xy +
|
|
EmitterUniforms.ColorCurve.zw * RelativeTime;
|
|
float4 ColorCurveSample = Texture2DSampleLevel(CurveTexture, CurveTextureSampler, ColorCurveTexCoord, 0 );
|
|
float4 ColorScale = ColorCurveSample * EmitterUniforms.ColorScale + EmitterUniforms.ColorBias;
|
|
float4 Color = ColorScale * InitialColor * EmitterDynamicUniforms.DynamicColor;
|
|
|
|
// Sample the curve containing misc. attributes.
|
|
float2 MiscCurveTexCoord = EmitterUniforms.MiscCurve.xy +
|
|
EmitterUniforms.MiscCurve.zw * RelativeTime;
|
|
float4 MiscCurveSample = Texture2DSampleLevel(CurveTexture, CurveTextureSampler, MiscCurveTexCoord, 0 );
|
|
float4 MiscCurve = MiscCurveSample * EmitterUniforms.MiscScale + EmitterUniforms.MiscBias;
|
|
|
|
// Compute the size of the sprite. Note it is (0,0) if the sprite is dead.
|
|
// Reconstruct the real size after we've encoded the UV flip mode as sizes > 0.5;
|
|
float2 UVFlipOffset = float2( AttributeSample.x < 0.5 ? 0.0f : -0.5, AttributeSample.y < 0.5 ? 0.0f : -0.5);
|
|
float2 InitialSize = (AttributeSample.xy + UVFlipOffset) * float2(2.0,2.0);
|
|
float2 SizeScale = MiscCurve.xy * EmitterDynamicUniforms.LocalToWorldScale;
|
|
float2 SizeScaleBySpeed = clamp(EmitterUniforms.SizeBySpeed.xy * ParticleSpeed,float2(1,1), EmitterUniforms.SizeBySpeed.zw);
|
|
float2 Size = InitialSize * SizeScale * SizeScaleBySpeed * IsAlive.xx;
|
|
|
|
float2 FlippedUV = Input.TexCoord.xy;
|
|
FlippedUV.x = UVFlipOffset.x == 0.0 ? 1.0 - FlippedUV.x : FlippedUV.x;
|
|
FlippedUV.y = UVFlipOffset.y == 0.0 ? 1.0 - FlippedUV.y : FlippedUV.y;
|
|
|
|
// SubUV.
|
|
float SubImageIndex = MiscCurve.z;
|
|
float SubImageLerp = frac(SubImageIndex);
|
|
float SubImageA = SubImageIndex - SubImageLerp;
|
|
float SubImageB = SubImageA + 1;
|
|
float SubImageAH = fmod( SubImageA, EmitterUniforms.SubImageSize.x );
|
|
float SubImageBH = fmod( SubImageB, EmitterUniforms.SubImageSize.x );
|
|
float SubImageAV = floor( SubImageA * EmitterUniforms.SubImageSize.z );
|
|
float SubImageBV = floor( SubImageB * EmitterUniforms.SubImageSize.z );
|
|
|
|
// Compute the final texture coordinates for both subimages.
|
|
float4 TexCoord;
|
|
TexCoord.xy = (float2( SubImageAH, SubImageAV ) + FlippedUV) * EmitterUniforms.SubImageSize.zw;
|
|
TexCoord.zw = (float2( SubImageBH, SubImageBV ) + FlippedUV) * EmitterUniforms.SubImageSize.zw;
|
|
|
|
// Current rotation of the sprite. Map [0,1] to one full rotation.
|
|
float RotationRate = AttributeSample.w * EmitterUniforms.RotationRateScale;
|
|
float Rotation = AttributeSample.z + RotationRate * RelativeTime;
|
|
Rotation = Rotation * 2.0f * 3.1415926535897932f;
|
|
|
|
// Transform position to (post-view-translation) world space.
|
|
float3 ParticleWorldPosition = TransformLocalToTranslatedWorld(ParticlePosition.xyz).xyz;
|
|
|
|
// Compute tangents for the sprite.
|
|
float3 TangentUp, TangentRight;
|
|
GetSpriteTangents( TangentUp, TangentRight, Rotation, ParticleWorldPosition, ParticleDirection );
|
|
|
|
// Offset of the sprite from the particle's location.
|
|
float3 VertexWorldOffset = Size.x * (Input.TexCoord.x + EmitterUniforms.PivotOffset.x) * TangentRight
|
|
+ Size.y * (Input.TexCoord.y + EmitterUniforms.PivotOffset.y) * TangentUp;
|
|
|
|
// Optional camera motion blur.
|
|
#if USES_PARTICLE_MOTION_BLUR
|
|
float3 MblurVector = -View.WorldCameraMovementSinceLastFrame;
|
|
float3 MblurDirection = normalize(MblurVector + 0.0001f);
|
|
//float MblurFactor = saturate(dot(MblurDirection,normalize(VertexWorldOffset)) * 100000.0f);
|
|
float MblurFactor = clamp(dot(MblurDirection,normalize(VertexWorldOffset)) * 100000.0f,-1.0f,1.0f);
|
|
VertexWorldOffset += (MblurFactor * MblurVector * EmitterUniforms.CameraMotionBlurAmount);
|
|
#endif // #if USES_PARTICLE_MOTION_BLUR
|
|
|
|
// Determine the world position of this vertex (one corner of the sprite).
|
|
float3 VertexWorldPosition = ParticleWorldPosition + VertexWorldOffset;
|
|
|
|
// Build and return the set of intermediates.
|
|
FVertexFactoryIntermediates Intermediates;
|
|
Intermediates.ParticleWorldPosition = ParticleWorldPosition;
|
|
Intermediates.VertexWorldPosition = VertexWorldPosition;
|
|
|
|
#if USE_PARTICLE_LIGHTING_OFFSET
|
|
// Hash function based on the particle ID to generate a uniformly distributed 3d offset
|
|
float3 RandomParticleOffset = frac((ParticleIndex.x + 10) * (ParticleIndex.y + 10) * float3(1341.456345, 2633.578, 5623.983)) * 2 - 1;
|
|
Intermediates.LightingPositionOffset = .5 * View.TranslucencyLightingVolumeInvSize[0].w * RandomParticleOffset;
|
|
#endif
|
|
|
|
Intermediates.TexCoord = TexCoord;
|
|
Intermediates.TangentUp = TangentUp;
|
|
Intermediates.TangentRight = TangentRight;
|
|
Intermediates.Color = Color;
|
|
Intermediates.ParticleVelocity = float4(ParticleDirection, ParticleSpeed);
|
|
Intermediates.SubImageLerp = SubImageLerp;
|
|
Intermediates.RelativeTime = RelativeTime;
|
|
#if USES_PARTICLE_MOTION_BLUR
|
|
Intermediates.MotionBlurFade = MblurFactor;
|
|
#else // #if USES_PARTICLE_MOTION_BLUR
|
|
Intermediates.MotionBlurFade = 0.0f;
|
|
#endif // #if USES_PARTICLE_MOTION_BLUR
|
|
Intermediates.ParticleRadius = .5f * min(Size.x, Size.y);
|
|
Intermediates.ParticleSize = Size;
|
|
return Intermediates;
|
|
}
|
|
|
|
#if NUM_MATERIAL_TEXCOORDS
|
|
float2 GetUV(FVertexFactoryInterpolantsVSToPS Interpolants, int UVIndex)
|
|
{
|
|
float4 UVVector = Interpolants.TexCoords[UVIndex / 2];
|
|
return UVIndex % 2 ? UVVector.zw : UVVector.xy;
|
|
}
|
|
|
|
void SetUV(inout FVertexFactoryInterpolantsVSToPS Interpolants, int UVIndex, float2 InValue)
|
|
{
|
|
FLATTEN
|
|
if (UVIndex % 2)
|
|
{
|
|
Interpolants.TexCoords[UVIndex / 2].zw = InValue;
|
|
}
|
|
else
|
|
{
|
|
Interpolants.TexCoords[UVIndex / 2].xy = InValue;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* Computes material parameterss for a given pixel.
|
|
* @param Interpolants - Attributes interpolated from the vertex shader.
|
|
* @returns per-pixel material parameters.
|
|
*/
|
|
FMaterialPixelParameters GetMaterialPixelParameters( FVertexFactoryInterpolantsVSToPS Interpolants, float4 SvPosition )
|
|
{
|
|
// GetMaterialPixelParameters is responsible for fully initializing the result
|
|
FMaterialPixelParameters Result = MakeInitializedMaterialPixelParameters();
|
|
|
|
#if NUM_MATERIAL_TEXCOORDS
|
|
UNROLL
|
|
for (int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS; CoordinateIndex++)
|
|
{
|
|
Result.TexCoords[CoordinateIndex] = GetUV(Interpolants, CoordinateIndex);
|
|
}
|
|
#endif // NUM_MATERIAL_TEXCOORDS
|
|
|
|
#if USE_PARTICLE_TIME
|
|
Result.Particle.RelativeTime = Interpolants.Misc.y;
|
|
#endif
|
|
|
|
#if USES_PARTICLE_MOTION_BLUR
|
|
Result.Particle.MotionBlurFade = 1.0f - abs(Interpolants.Misc.z);
|
|
#else // #if USES_PARTICLE_MOTION_BLUR
|
|
Result.Particle.MotionBlurFade = 1.0f;
|
|
#endif // #if USES_PARTICLE_MOTION_BLUR
|
|
|
|
#if USE_PARTICLE_VELOCITY
|
|
Result.Particle.Velocity = Interpolants.ParticleVelocity;
|
|
#endif
|
|
|
|
#if USE_PARTICLE_POSITION
|
|
Result.Particle.PositionAndSize = Interpolants.ParticlePositionAndSize;
|
|
#endif
|
|
|
|
#if USE_SPHERICAL_NORMALS
|
|
// can be optimized
|
|
{
|
|
float4 ScreenPosition = SvPositionToScreenPosition(SvPosition);
|
|
float3 TranslatedWorldPosition = SvPositionToTranslatedWorld(SvPosition);
|
|
|
|
Result.TangentToWorld = GetSphericalParticleNormal(TranslatedWorldPosition + View.WorldCameraOrigin, Interpolants.ParticlePositionAndSize.xyz, Interpolants.ParticlePositionAndSize.w);
|
|
}
|
|
#else
|
|
half3 TangentToWorld0 = Interpolants.TangentToWorld0.xyz;
|
|
half4 TangentToWorld2 = Interpolants.TangentToWorld2;
|
|
Result.TangentToWorld = AssembleTangentToWorld(TangentToWorld0, TangentToWorld2);
|
|
#endif
|
|
|
|
#if NEEDS_PARTICLE_COLOR
|
|
Result.Particle.Color = Interpolants.Color;
|
|
#endif
|
|
|
|
Result.VertexColor = 1;
|
|
Result.TwoSidedSign = 1;
|
|
|
|
#if USE_PARTICLE_LIGHTING_OFFSET
|
|
Result.LightingPositionOffset = Interpolants.LightingPositionOffset;
|
|
#endif
|
|
|
|
#if USE_PARTICLE_SUBUVS
|
|
Result.Particle.SubUVCoords[0] = Interpolants.ParticleSubUVs.xy;
|
|
Result.Particle.SubUVCoords[1] = Interpolants.ParticleSubUVs.zw;
|
|
Result.Particle.SubUVLerp = Interpolants.Misc.xx;
|
|
#endif
|
|
|
|
#if USE_PARTICLE_SIZE
|
|
Result.Particle.Size = Interpolants.ParticleSize;
|
|
#endif
|
|
|
|
return Result;
|
|
}
|
|
|
|
/**
|
|
* Computes material parameters for a given vertex.
|
|
* @param Input - Attributes for this vertex.
|
|
* @param Intermediates - Intermediates computed for this vertex.
|
|
* @param WorldPosition - The position of this vertex in world space.
|
|
* @param TangentToLocal - The tangent basis for this vertex.
|
|
* @returns per-vertex material parameters.
|
|
*/
|
|
FMaterialVertexParameters GetMaterialVertexParameters(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float3 WorldPosition, float3x3 TangentToLocal)
|
|
{
|
|
FMaterialVertexParameters Result = (FMaterialVertexParameters)0;
|
|
Result.WorldPosition = WorldPosition;
|
|
Result.VertexColor = 1;
|
|
Result.TangentToWorld = mul(TangentToLocal, GetLocalToWorld3x3());
|
|
|
|
#if USE_PARTICLE_TIME
|
|
Result.Particle.RelativeTime = Intermediates.RelativeTime;
|
|
#endif
|
|
|
|
#if USES_PARTICLE_MOTION_BLUR
|
|
Result.Particle.MotionBlurFade = 1.0f - abs(Intermediates.MotionBlurFade);
|
|
#else // #if USES_PARTICLE_MOTION_BLUR
|
|
Result.Particle.MotionBlurFade = 1.0f;
|
|
#endif // #if USES_PARTICLE_MOTION_BLUR
|
|
|
|
#if USE_PARTICLE_VELOCITY
|
|
Result.Particle.Velocity = Intermediates.ParticleVelocity;
|
|
#endif
|
|
|
|
#if USE_PARTICLE_POSITION
|
|
Result.Particle.PositionAndSize = float4(Intermediates.ParticleWorldPosition - View.PreViewTranslation, Intermediates.ParticleRadius);
|
|
#endif
|
|
|
|
Result.Particle.Color = Intermediates.Color;
|
|
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX >= 1
|
|
Result.TexCoords[0] = Intermediates.TexCoord.xy;
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX >= 2
|
|
Result.TexCoords[1] = Intermediates.TexCoord.zw;
|
|
#endif // >= 2
|
|
#endif // >= 1
|
|
#endif //NUM_MATERIAL_TEXCOORDS
|
|
|
|
#if USE_PARTICLE_SUBUVS
|
|
Result.Particle.SubUVCoords[0] = Intermediates.TexCoord.xy;
|
|
Result.Particle.SubUVCoords[1] = Intermediates.TexCoord.zw;
|
|
#endif
|
|
|
|
#if USE_PARTICLE_SIZE
|
|
Result.Particle.Size = Intermediates.ParticleSize;
|
|
#endif
|
|
return Result;
|
|
}
|
|
|
|
/**
|
|
* Computes the world space position of this vertex.
|
|
* @param Input - Vertex attributes.
|
|
* @param Intermediates - Intermediates computed for this vertex.
|
|
* @returns the position of this vertex in world space.
|
|
*/
|
|
float4 VertexFactoryGetWorldPosition( FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates )
|
|
{
|
|
return float4(Intermediates.VertexWorldPosition,1);
|
|
}
|
|
|
|
float4 VertexFactoryGetRasterizedWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float4 TranslatedWorldPosition)
|
|
{
|
|
#if SPHERICAL_PARTICLE_OPACITY
|
|
// For particles using spherical opacity, move the quad toward the viewer so that it lies in front of the sphere defined by the particle
|
|
// This avoids opaque objects intersecting the particle from causing clipping artifacts due to depth testing
|
|
// The downside is that the particle will clip the near plane sooner
|
|
|
|
float Radius = Intermediates.ParticleRadius;
|
|
return ReprojectPosition(TranslatedWorldPosition, Radius);
|
|
#else
|
|
return TranslatedWorldPosition;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Computes the tangent basis for this vertex in world space.
|
|
* @param Input - Vertex attributes.
|
|
* @param Intermediates - Intermediates computed for this vertex.
|
|
* @returns the tangent basis for this vertex in world space.
|
|
*/
|
|
float3x3 VertexFactoryGetTangentToLocal( FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates )
|
|
{
|
|
float3x3 TangentToLocal;
|
|
TangentToLocal[0] = Intermediates.TangentRight;
|
|
TangentToLocal[1] = Intermediates.TangentUp;
|
|
TangentToLocal[2] = normalize(cross(Intermediates.TangentRight.xyz , Intermediates.TangentUp.xyz));
|
|
return TangentToLocal;
|
|
}
|
|
|
|
/**
|
|
* Constructs values that need to be interpolated from the vertex shader to the pixel shader.
|
|
* @param Input - Vertex attributes.
|
|
* @param Intermediates - Intermediates computed for this vertex.
|
|
* @returns interpolants.
|
|
*/
|
|
FVertexFactoryInterpolantsVSToPS VertexFactoryGetInterpolantsVSToPS( FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, FMaterialVertexParameters VertexParameters )
|
|
{
|
|
FVertexFactoryInterpolantsVSToPS Interpolants;
|
|
|
|
// Initialize the whole struct to 0
|
|
Interpolants = (FVertexFactoryInterpolantsVSToPS)0;
|
|
|
|
#if NUM_MATERIAL_TEXCOORDS
|
|
|
|
float2 CustomizedUVs[NUM_MATERIAL_TEXCOORDS];
|
|
GetMaterialCustomizedUVs(VertexParameters, CustomizedUVs);
|
|
|
|
UNROLL
|
|
for (int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS; CoordinateIndex++)
|
|
{
|
|
SetUV(Interpolants, CoordinateIndex, CustomizedUVs[CoordinateIndex]);
|
|
}
|
|
#endif
|
|
|
|
#if USE_PARTICLE_SUBUVS
|
|
Interpolants.ParticleSubUVs.xy = VertexParameters.Particle.SubUVCoords[0];
|
|
Interpolants.ParticleSubUVs.zw = VertexParameters.Particle.SubUVCoords[1];
|
|
#endif
|
|
|
|
Interpolants.Misc.x = Intermediates.SubImageLerp;
|
|
Interpolants.Misc.y = Intermediates.RelativeTime;
|
|
Interpolants.Misc.z = Intermediates.MotionBlurFade;
|
|
|
|
#if NEEDS_PARTICLE_COLOR
|
|
Interpolants.Color = Intermediates.Color;
|
|
#endif
|
|
|
|
#if USE_PARTICLE_POSITION
|
|
Interpolants.ParticlePositionAndSize = float4(Intermediates.ParticleWorldPosition - View.PreViewTranslation, Intermediates.ParticleRadius);
|
|
#endif
|
|
|
|
#if USE_PARTICLE_VELOCITY
|
|
Interpolants.ParticleVelocity = Intermediates.ParticleVelocity;
|
|
#endif
|
|
|
|
#if USE_PARTICLE_LIGHTING_OFFSET
|
|
Interpolants.LightingPositionOffset = Intermediates.LightingPositionOffset;
|
|
#endif
|
|
|
|
#if !USE_SPHERICAL_NORMALS
|
|
// Note that "local" space for particles is actually oriented in world space! Therefore no rotation is needed.
|
|
float3x3 TangentToWorld = VertexFactoryGetTangentToLocal(Input, Intermediates);
|
|
|
|
float3 TangentToWorld0 = TangentToWorld[0];
|
|
float4 TangentToWorld2 = float4(TangentToWorld[2], sign(determinant(TangentToWorld)));
|
|
|
|
Interpolants.TangentToWorld0 = float4(TangentToWorld0,0);
|
|
Interpolants.TangentToWorld2 = TangentToWorld2;
|
|
#endif
|
|
|
|
#if USE_PARTICLE_SIZE
|
|
Interpolants.ParticleSize = Intermediates.ParticleSize;
|
|
#endif
|
|
|
|
return Interpolants;
|
|
}
|
|
|
|
/**
|
|
* Computes the position of this vertex last frame in world space.
|
|
* @param Input - Vertex attributes.
|
|
* @param Intermediates - Intermediates computed for this vertex.
|
|
* @returns the previous position of this vertex in world space.
|
|
*/
|
|
float4 VertexFactoryGetPreviousWorldPosition( FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates )
|
|
{
|
|
return float4(Intermediates.VertexWorldPosition,1);
|
|
}
|