1169 lines
49 KiB
HLSL
1169 lines
49 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "../VertexFactoryCommon.ush"
|
|
#include "../LightmapData.ush"
|
|
#include "../SplineMeshCommon.ush"
|
|
#if RAYHITGROUPSHADER
|
|
#include "../RayTracing/RayTracingCommon.ush"
|
|
#endif
|
|
#include "../MaterialCache/MaterialCacheCommon.ush"
|
|
#include "NaniteDataDecode.ush"
|
|
#include "NaniteAttributeDecode.ush"
|
|
#include "NaniteSceneCommon.ush"
|
|
#include "NaniteVertexDeformation.ush"
|
|
|
|
// Some platforms may configure custom shader compiler options when compiling Nanite material shaders
|
|
#ifdef OVERRIDE_NANITE_VERTEX_FACTORY_CONFIG_USH
|
|
#include "/Platform/Private/NaniteVertexFactoryConfig.ush"
|
|
#endif
|
|
|
|
#ifndef VIRTUAL_TEXTURE_TARGET
|
|
#define VIRTUAL_TEXTURE_TARGET 0
|
|
#endif
|
|
|
|
#ifndef NANITE_USE_HW_BARYCENTRICS
|
|
#define NANITE_USE_HW_BARYCENTRICS 0
|
|
#endif
|
|
|
|
// Make sure we decode enough texture coordinates to satisfy programmable features
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX > NUM_MATERIAL_TEXCOORDS
|
|
#define NANITE_NUM_TEXCOORDS_TO_DECODE NUM_MATERIAL_TEXCOORDS_VERTEX
|
|
#else
|
|
#define NANITE_NUM_TEXCOORDS_TO_DECODE NUM_MATERIAL_TEXCOORDS
|
|
#endif
|
|
|
|
#if NANITE_PIXEL_PROGRAMMABLE && NANITE_NUM_TEXCOORDS_TO_DECODE < 2
|
|
// Ensure we decode at least 2 texture coordinates in the MS/VS to properly populate the interpolator with valid data.
|
|
#define NANITE_NUM_TEXCOORDS_TO_DECODE_HW_VS 2
|
|
#else
|
|
#define NANITE_NUM_TEXCOORDS_TO_DECODE_HW_VS NANITE_NUM_TEXCOORDS_TO_DECODE
|
|
#endif
|
|
|
|
// Nanite material evaluation is deferred to a screenspace pass sampling the visibility buffer,
|
|
// so the 'interpolants' used in the GBuffer pass are almost all generated in the PixelShader, instead of exported from VS.
|
|
// FNaniteFullscreenVSToPS is the struct containing what actually needs to be passed between VS and PS in the Nanite GBuffer pass.
|
|
struct FVertexFactoryInterpolantsVSToPS
|
|
{
|
|
#if NEEDS_LIGHTMAP_COORDINATE
|
|
nointerpolation float4 LightMapCoordinate : TEXCOORD3;
|
|
nointerpolation float4 LightMapCoordinateDDX: TEXCOORD4;
|
|
nointerpolation float4 LightMapCoordinateDDY: TEXCOORD5;
|
|
#endif
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA && NEEDS_LIGHTMAP_COORDINATE
|
|
nointerpolation uint LightmapDataIndex : LIGHTMAP_ID;
|
|
#endif
|
|
#if INSTANCED_STEREO
|
|
nointerpolation uint EyeIndex : PACKED_EYE_INDEX;
|
|
#endif
|
|
nointerpolation uint ViewIndex : PACKED_VIEW_INDEX;
|
|
nointerpolation uint2 PixelPos : PIXEL_POS;
|
|
};
|
|
|
|
void GetNaniteMaterialSceneData(FVisibleCluster VisibleCluster, inout FPrimitiveSceneData PrimitiveData, inout FInstanceSceneData InstanceData)
|
|
{
|
|
InstanceData = GetInstanceSceneDataUnchecked(VisibleCluster);
|
|
PrimitiveData = GetPrimitiveData(InstanceData.PrimitiveId);
|
|
|
|
#if USE_SPLINEDEFORM
|
|
BRANCH
|
|
if ((PrimitiveData.Flags & PRIMITIVE_SCENE_DATA_FLAG_SPLINE_MESH) != 0 &&
|
|
(InstanceData.Flags & INSTANCE_SCENE_DATA_FLAG_HAS_PAYLOAD_EXTENSION) != 0)
|
|
{
|
|
// Flip the determinant sign if the spline mesh params cause the mesh to mirror
|
|
FSplineMeshShaderParams SplineMeshParams = SplineMeshLoadParamsFromInstancePayload(InstanceData);
|
|
if (SplineMeshParams.StartScale.x < 0.0f != SplineMeshParams.StartScale.y < 0.0f)
|
|
{
|
|
InstanceData.DeterminantSign = -InstanceData.DeterminantSign;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if IS_NANITE_RASTER_PASS
|
|
|
|
struct FVertexFactoryInput
|
|
{
|
|
VF_INSTANCED_STEREO_DECLARE_INPUT_BLOCK()
|
|
VF_MOBILE_MULTI_VIEW_DECLARE_INPUT_BLOCK()
|
|
};
|
|
|
|
struct FVertexFactoryIntermediates
|
|
{
|
|
float3x3 TangentToLocal;
|
|
};
|
|
|
|
FVertexFactoryIntermediates GetVertexFactoryIntermediates(FVertexFactoryInput Input)
|
|
{
|
|
FVertexFactoryIntermediates Intermediates = (FVertexFactoryIntermediates)0;
|
|
return Intermediates;
|
|
};
|
|
|
|
float3x3 VertexFactoryGetTangentToLocal(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
return Intermediates.TangentToLocal;
|
|
}
|
|
|
|
FMaterialVertexParameters GetMaterialVertexParameters(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float3 WorldPosition, float3x3 TangentToLocal, bool bIsPreviousFrame = false)
|
|
{
|
|
FMaterialVertexParameters Result = MakeInitializedMaterialVertexParameters();
|
|
|
|
return Result;
|
|
}
|
|
|
|
#endif // IS_NANITE_RASTER_PASS
|
|
|
|
#if NEEDS_LIGHTMAP_COORDINATE
|
|
|
|
void GetLightMapCoordinates(FVertexFactoryInterpolantsVSToPS Interpolants, out float2 LightmapUV0, out float2 LightmapUV1, out uint LightmapDataIndex)
|
|
{
|
|
LightmapUV0 = Interpolants.LightMapCoordinate.xy * float2(1.0, 0.5);
|
|
LightmapUV1 = LightmapUV0 + float2(0.0, 0.5);
|
|
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
LightmapDataIndex = Interpolants.LightmapDataIndex;
|
|
#else
|
|
LightmapDataIndex = 0;
|
|
#endif
|
|
}
|
|
|
|
void GetLightMapCoordinates(FVertexFactoryInterpolantsVSToPS Interpolants, out FloatDeriv2 LightmapUV0, out FloatDeriv2 LightmapUV1, out uint LightmapDataIndex)
|
|
{
|
|
LightmapUV0 = ConstructFloatDeriv2( Interpolants.LightMapCoordinate.xy * float2(1.0, 0.5),
|
|
Interpolants.LightMapCoordinateDDX.xy * float2(1.0, 0.5),
|
|
Interpolants.LightMapCoordinateDDY.xy * float2(1.0, 0.5));
|
|
|
|
LightmapUV1 = LightmapUV0;
|
|
LightmapUV1.Value += float2(0.0, 0.5);
|
|
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
LightmapDataIndex = Interpolants.LightmapDataIndex;
|
|
#else
|
|
LightmapDataIndex = 0;
|
|
#endif
|
|
}
|
|
|
|
void GetShadowMapCoordinate(FVertexFactoryInterpolantsVSToPS Interpolants, out float2 ShadowMapCoordinate, out uint LightmapDataIndex)
|
|
{
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
LightmapDataIndex = Interpolants.LightmapDataIndex;
|
|
#else
|
|
LightmapDataIndex = 0;
|
|
#endif
|
|
ShadowMapCoordinate = Interpolants.LightMapCoordinate.zw;
|
|
}
|
|
|
|
void GetShadowMapCoordinate(FVertexFactoryInterpolantsVSToPS Interpolants, out FloatDeriv2 ShadowMapCoordinate, out uint LightmapDataIndex)
|
|
{
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
LightmapDataIndex = Interpolants.LightmapDataIndex;
|
|
#else
|
|
LightmapDataIndex = 0;
|
|
#endif
|
|
ShadowMapCoordinate = ConstructFloatDeriv2( Interpolants.LightMapCoordinate.zw,
|
|
Interpolants.LightMapCoordinateDDX.zw,
|
|
Interpolants.LightMapCoordinateDDY.zw);
|
|
}
|
|
|
|
void SetLightMapCoordinate(inout FVertexFactoryInterpolantsVSToPS Interpolants, float2 InLightMapCoordinate, float2 InShadowMapCoordinate)
|
|
{
|
|
Interpolants.LightMapCoordinate.xy = InLightMapCoordinate;
|
|
Interpolants.LightMapCoordinate.zw = InShadowMapCoordinate;
|
|
Interpolants.LightMapCoordinateDDX = 0;
|
|
Interpolants.LightMapCoordinateDDY = 0;
|
|
}
|
|
|
|
void SetLightMapCoordinate(inout FVertexFactoryInterpolantsVSToPS Interpolants, TDual< float2 > InLightMapCoordinate, TDual< float2 > InShadowMapCoordinate)
|
|
{
|
|
Interpolants.LightMapCoordinate = float4(InLightMapCoordinate.Value, InShadowMapCoordinate.Value);
|
|
Interpolants.LightMapCoordinateDDX = float4(InLightMapCoordinate.Value_dx, InShadowMapCoordinate.Value_dy);
|
|
Interpolants.LightMapCoordinateDDY = float4(InLightMapCoordinate.Value_dy, InShadowMapCoordinate.Value_dy);
|
|
}
|
|
|
|
void SetLightMapDataIndex(inout FVertexFactoryInterpolantsVSToPS Interpolants, uint LightmapDataIndex)
|
|
{
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
Interpolants.LightmapDataIndex = LightmapDataIndex;
|
|
#endif
|
|
}
|
|
|
|
#endif // NEEDS_LIGHTMAP_COORDINATE
|
|
|
|
// Determines the tangent to local frame of the specified vertex
|
|
half3x3 CalcVertexTangentToLocal(FPrimitiveSceneData PrimitiveData, FInstanceSceneData InstanceData, FNanitePostDeformVertex Vert)
|
|
{
|
|
half3x3 TangentToLocal;
|
|
|
|
BRANCH
|
|
if(Vert.TangentBasis.TangentXAndSign.w != 0.0f)
|
|
{
|
|
TangentToLocal = NaniteTangentToLocal(Vert.TangentBasis.TangentXAndSign, Vert.TangentBasis.TangentZ);
|
|
}
|
|
else
|
|
{
|
|
TangentToLocal = GetTangentBasis(Vert.TangentBasis.TangentZ);
|
|
}
|
|
|
|
#if USE_SPLINEDEFORM
|
|
BRANCH
|
|
if ((PrimitiveData.Flags & PRIMITIVE_SCENE_DATA_FLAG_SPLINE_MESH) != 0 &&
|
|
(InstanceData.Flags & INSTANCE_SCENE_DATA_FLAG_HAS_PAYLOAD_EXTENSION) != 0)
|
|
{
|
|
FSplineMeshShaderParams SplineMeshParams = SplineMeshLoadParamsFromInstancePayload(InstanceData);
|
|
TangentToLocal = mul(TangentToLocal, SplineMeshCalcSliceRot(SplineMeshParams, Vert.SplineDist));
|
|
}
|
|
#endif
|
|
|
|
return TangentToLocal;
|
|
}
|
|
|
|
void SetVertexParameterInstanceData(inout FMaterialVertexParameters VertexParameters, FInstanceSceneData InstanceData, FPrimitiveSceneData PrimitiveData, bool bEvaluateWorldPositionOffset)
|
|
{
|
|
VertexParameters.PrimitiveId = InstanceData.PrimitiveId;
|
|
VertexParameters.InstanceLocalToWorld = InstanceData.LocalToWorld;
|
|
VertexParameters.InstanceWorldToLocal = InstanceData.WorldToLocal;
|
|
VertexParameters.PrevFrameLocalToWorld = InstanceData.PrevLocalToWorld;
|
|
#if USES_PER_INSTANCE_CUSTOM_DATA
|
|
VertexParameters.CustomDataOffset = InstanceData.CustomDataOffset;
|
|
VertexParameters.CustomDataCount = InstanceData.CustomDataCount;
|
|
#endif
|
|
VertexParameters.PerInstanceRandom = InstanceData.RandomID;
|
|
|
|
VertexParameters.SceneData.PrimitiveId = InstanceData.PrimitiveId;
|
|
VertexParameters.SceneData.InstanceId = InstanceData.RelativeId;
|
|
VertexParameters.SceneData.InstanceData = InstanceData;
|
|
VertexParameters.SceneData.Primitive = PrimitiveData;
|
|
|
|
VertexParameters.bEvaluateWorldPositionOffset = bEvaluateWorldPositionOffset;
|
|
}
|
|
|
|
void SetVertexParameterAttributeData(inout FMaterialVertexParameters VertexParameters, FNanitePostDeformVertex Vert, float4x4 LocalToTranslatedWorld, float3x3 LocalToWorldNoScale)
|
|
{
|
|
half3x3 TangentToLocal = CalcVertexTangentToLocal(VertexParameters.SceneData.Primitive, VertexParameters.SceneData.InstanceData, Vert);
|
|
float4x4 TranslatedWorldToPrimitive = DFFastToTranslatedWorld(VertexParameters.SceneData.Primitive.WorldToLocal, ResolvedView.PreViewTranslation);
|
|
|
|
VertexParameters.WorldPosition = mul(float4(Vert.Position, 1), LocalToTranslatedWorld).xyz;
|
|
VertexParameters.PositionInstanceSpace = Vert.Position;
|
|
VertexParameters.PositionPrimitiveSpace = mul(float4(VertexParameters.WorldPosition, 1), TranslatedWorldToPrimitive).xyz;
|
|
VertexParameters.TangentToWorld = mul(TangentToLocal, LocalToWorldNoScale);
|
|
VertexParameters.VertexColor = Vert.RawAttributeData.Color;
|
|
VertexParameters.PreSkinnedPosition = Vert.PointLocal;
|
|
VertexParameters.PreSkinnedNormal = Vert.PreSkinnedNormal;
|
|
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX
|
|
UNROLL
|
|
for (uint TexCoordIndex = 0; TexCoordIndex < NUM_MATERIAL_TEXCOORDS_VERTEX; ++TexCoordIndex)
|
|
{
|
|
// Protect against case where Nanite max UV count is lower than what the material may define.
|
|
VertexParameters.TexCoords[TexCoordIndex] = Vert.RawAttributeData.TexCoords[min(TexCoordIndex, NANITE_MAX_UVS - 1)];
|
|
}
|
|
#endif
|
|
|
|
VertexParameters.LWCData = MakeMaterialLWCData(VertexParameters);
|
|
}
|
|
|
|
// Group of transforms needed to transform a Nanite vertex
|
|
struct FNaniteVertTransforms
|
|
{
|
|
float4x4 LocalToTranslatedWorld;
|
|
float4x4 PrevLocalToTranslatedWorld;
|
|
float4x4 TranslatedWorldToClip;
|
|
float3x3 LocalToWorldNoScale;
|
|
float3x3 PrevLocalToWorldNoScale;
|
|
float3x3 WorldToLocalVector;
|
|
float3x3 PrevWorldToLocalVector;
|
|
};
|
|
|
|
struct FNaniteTransformedVert
|
|
{
|
|
uint VertIndex;
|
|
float3 PointLocal;
|
|
float3 PointPostDeform;
|
|
float3 PrevPointPostDeform;
|
|
float3 PointWorld;
|
|
float3 PointWorld_NoOffset;
|
|
float4 PointClip;
|
|
float4 NormalClip;
|
|
FNaniteTangentBasis TangentBasis;
|
|
FNaniteRawAttributeData RawAttributeData;
|
|
float SplineDist;
|
|
#if NUM_TEX_COORD_INTERPOLATORS
|
|
float2 CustomizedUVs[NUM_TEX_COORD_INTERPOLATORS];
|
|
#endif
|
|
};
|
|
|
|
// Post-transformed Nanite triangle data
|
|
struct FNaniteTransformedTri
|
|
{
|
|
FNaniteTransformedVert Verts[3];
|
|
};
|
|
|
|
FNaniteVertTransforms CalculateNaniteVertexTransforms(FInstanceSceneData InstanceData, FInstanceDynamicData InstanceDynamicData, FNaniteView NaniteView)
|
|
{
|
|
const float4x4 LocalToTranslatedWorld = InstanceDynamicData.LocalToTranslatedWorld;
|
|
const float4x4 PrevLocalToTranslatedWorld = InstanceDynamicData.PrevLocalToTranslatedWorld;
|
|
const float3 InvNonUniformScale = InstanceData.InvNonUniformScale;
|
|
|
|
// Should be Pow2(InvScale) but that requires renormalization
|
|
float3x3 LocalToWorldNoScale = (float3x3)LocalToTranslatedWorld;
|
|
LocalToWorldNoScale[0] *= InvNonUniformScale.x;
|
|
LocalToWorldNoScale[1] *= InvNonUniformScale.y;
|
|
LocalToWorldNoScale[2] *= InvNonUniformScale.z;
|
|
|
|
float3x3 PrevLocalToWorldNoScale = (float3x3)PrevLocalToTranslatedWorld;
|
|
PrevLocalToWorldNoScale[0] *= InvNonUniformScale.x;
|
|
PrevLocalToWorldNoScale[1] *= InvNonUniformScale.y;
|
|
PrevLocalToWorldNoScale[2] *= InvNonUniformScale.z;
|
|
|
|
float3x3 WorldToLocalVector = DFToFloat3x3(InstanceData.WorldToLocal);
|
|
|
|
// TODO: We need PrevWorldToLocal here, but we don't have it
|
|
const float3 SqInvNonUniformScale = Pow2(InvNonUniformScale);
|
|
float3x3 PrevWorldToLocalVector = DFToFloat3x3(InstanceData.PrevLocalToWorld);
|
|
PrevWorldToLocalVector[0] *= SqInvNonUniformScale.x;
|
|
PrevWorldToLocalVector[1] *= SqInvNonUniformScale.y;
|
|
PrevWorldToLocalVector[2] *= SqInvNonUniformScale.z;
|
|
PrevWorldToLocalVector = transpose(PrevWorldToLocalVector);
|
|
|
|
FNaniteVertTransforms Transforms;
|
|
Transforms.LocalToTranslatedWorld = LocalToTranslatedWorld;
|
|
Transforms.PrevLocalToTranslatedWorld = PrevLocalToTranslatedWorld;
|
|
Transforms.TranslatedWorldToClip = NaniteView.TranslatedWorldToClip;
|
|
Transforms.LocalToWorldNoScale = LocalToWorldNoScale;
|
|
Transforms.PrevLocalToWorldNoScale = PrevLocalToWorldNoScale;
|
|
Transforms.WorldToLocalVector = WorldToLocalVector;
|
|
Transforms.PrevWorldToLocalVector = PrevWorldToLocalVector;
|
|
|
|
return Transforms;
|
|
}
|
|
|
|
HLSL_STATIC_ASSERT(sizeof(FNaniteVertTransforms) == 336, "Unexpected size of FNaniteVertTransforms. Update WaveReadLaneAt to reflect changes.");
|
|
FNaniteVertTransforms WaveReadLaneAt(FNaniteVertTransforms In, uint SrcIndex)
|
|
{
|
|
FNaniteVertTransforms Result;
|
|
|
|
Result.LocalToTranslatedWorld = WaveReadLaneAtMatrix(In.LocalToTranslatedWorld, SrcIndex);
|
|
Result.PrevLocalToTranslatedWorld = WaveReadLaneAtMatrix(In.PrevLocalToTranslatedWorld, SrcIndex);
|
|
Result.TranslatedWorldToClip = WaveReadLaneAtMatrix(In.TranslatedWorldToClip, SrcIndex);
|
|
Result.LocalToWorldNoScale = WaveReadLaneAtMatrix(In.LocalToWorldNoScale, SrcIndex);
|
|
Result.PrevLocalToWorldNoScale = WaveReadLaneAtMatrix(In.PrevLocalToWorldNoScale, SrcIndex);
|
|
Result.WorldToLocalVector = WaveReadLaneAtMatrix(In.WorldToLocalVector, SrcIndex);
|
|
Result.PrevWorldToLocalVector = WaveReadLaneAtMatrix(In.PrevWorldToLocalVector, SrcIndex);
|
|
|
|
return Result;
|
|
}
|
|
|
|
float4 GetNaniteClipPosition(in FNaniteView NaniteView, in FMaterialVertexParameters MaterialParameters, FNaniteVertTransforms Transforms, FNanitePostDeformVertex Vertex, float3 PointWorld)
|
|
{
|
|
#if MATERIAL_CACHE
|
|
#if NUM_MATERIAL_OUTPUTS_GETMATERIALCACHE > 0
|
|
float2 MaterialCacheUV = GetMaterialCache1(MaterialParameters);
|
|
#else // NUM_MATERIAL_OUTPUTS_GETMATERIALCACHE > 0
|
|
float2 MaterialCacheUV = Vertex.RawAttributeData.TexCoords[0].xy;
|
|
#endif // NUM_MATERIAL_OUTPUTS_GETMATERIALCACHE > 0
|
|
|
|
return GetMaterialCacheUnwrapClipPosition(MaterialCacheUV, NaniteView.MaterialCacheUnwrapMinAndInvSize);
|
|
#else // MATERIAL_CACHE
|
|
return mul(float4(PointWorld, 1), Transforms.TranslatedWorldToClip);
|
|
#endif // MATERIAL_CACHE
|
|
}
|
|
|
|
FNaniteTransformedTri TransformNaniteTriangle(in FNaniteView NaniteView, FPrimitiveSceneData PrimitiveData, FInstanceSceneData InstanceData, FNaniteVertTransforms Transforms, FNanitePostDeformVertex InVerts[3], bool bEvaluateWPO)
|
|
{
|
|
FNaniteTransformedTri Tri = (FNaniteTransformedTri)0;
|
|
|
|
#if USES_WORLD_POSITION_OFFSET
|
|
#if ALWAYS_EVALUATE_WORLD_POSITION_OFFSET
|
|
bEvaluateWPO = true;
|
|
#else
|
|
bEvaluateWPO &= (PrimitiveData.Flags & PRIMITIVE_SCENE_DATA_FLAG_EVALUATE_WORLD_POSITION_OFFSET) != 0u;
|
|
#endif
|
|
BRANCH
|
|
if (bEvaluateWPO)
|
|
{
|
|
UNROLL_N(3)
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
FMaterialVertexParameters VertexParameters = MakeInitializedMaterialVertexParameters();
|
|
SetVertexParameterInstanceData(VertexParameters, InstanceData, PrimitiveData, true /* WPO */);
|
|
SetVertexParameterAttributeData(VertexParameters, InVerts[i], Transforms.LocalToTranslatedWorld, Transforms.LocalToWorldNoScale);
|
|
|
|
FMaterialVertexParameters PrevVertexParameters = MakeInitializedMaterialVertexParameters();
|
|
SetVertexParameterInstanceData(PrevVertexParameters, InstanceData, PrimitiveData, true /* WPO */);
|
|
SetVertexParameterAttributeData(PrevVertexParameters, InVerts[i], Transforms.PrevLocalToTranslatedWorld, Transforms.PrevLocalToWorldNoScale);
|
|
|
|
#if ENABLE_NEW_HLSL_GENERATOR
|
|
EvaluateVertexMaterialAttributes(VertexParameters);
|
|
EvaluateVertexMaterialAttributes(PrevVertexParameters);
|
|
#endif
|
|
const float3 WorldPositionOffset = GetMaterialWorldPositionOffset(VertexParameters);
|
|
const float3 PrevWorldPositionOffset = GetMaterialPreviousWorldPositionOffset(PrevVertexParameters);
|
|
const float3 LocalOffset = mul(WorldPositionOffset, Transforms.WorldToLocalVector);
|
|
const float3 PrevLocalOffset = mul(PrevWorldPositionOffset, Transforms.PrevWorldToLocalVector);
|
|
const float3 NormalWorld = mul(float4(InVerts[i].TangentBasis.TangentZ, 0), Transforms.LocalToTranslatedWorld).xyz;
|
|
|
|
Tri.Verts[i].VertIndex = InVerts[i].VertIndex;
|
|
Tri.Verts[i].RawAttributeData = InVerts[i].RawAttributeData;
|
|
Tri.Verts[i].SplineDist = InVerts[i].SplineDist;
|
|
Tri.Verts[i].NormalClip = mul(float4(NormalWorld, 0), Transforms.TranslatedWorldToClip);
|
|
Tri.Verts[i].TangentBasis = InVerts[i].TangentBasis;
|
|
Tri.Verts[i].PointLocal = InVerts[i].PointLocal;
|
|
Tri.Verts[i].PointPostDeform = InVerts[i].Position + LocalOffset;
|
|
Tri.Verts[i].PrevPointPostDeform = InVerts[i].Position + PrevLocalOffset;
|
|
Tri.Verts[i].PointWorld = VertexParameters.WorldPosition + WorldPositionOffset;
|
|
Tri.Verts[i].PointWorld_NoOffset = VertexParameters.WorldPosition;
|
|
Tri.Verts[i].PointClip = GetNaniteClipPosition(NaniteView, VertexParameters, Transforms, InVerts[i], Tri.Verts[i].PointWorld);
|
|
|
|
#if NUM_TEX_COORD_INTERPOLATORS
|
|
GetMaterialCustomizedUVs(VertexParameters, Tri.Verts[i].CustomizedUVs);
|
|
GetCustomInterpolators(VertexParameters, Tri.Verts[i].CustomizedUVs);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
#endif // USES WORLD_POSITION_OFFSET
|
|
{
|
|
UNROLL_N(3)
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
const float3 NormalWorld = mul(float4(InVerts[i].TangentBasis.TangentZ, 0), Transforms.LocalToTranslatedWorld).xyz;
|
|
|
|
FMaterialVertexParameters VertexParameters = MakeInitializedMaterialVertexParameters();
|
|
SetVertexParameterInstanceData(VertexParameters, InstanceData, PrimitiveData, false /* WPO */);
|
|
SetVertexParameterAttributeData(VertexParameters, InVerts[i], Transforms.LocalToTranslatedWorld, Transforms.LocalToWorldNoScale);
|
|
|
|
Tri.Verts[i].VertIndex = InVerts[i].VertIndex;
|
|
Tri.Verts[i].RawAttributeData = InVerts[i].RawAttributeData;
|
|
Tri.Verts[i].SplineDist = InVerts[i].SplineDist;
|
|
Tri.Verts[i].NormalClip = mul(float4(NormalWorld, 0), Transforms.TranslatedWorldToClip);
|
|
Tri.Verts[i].TangentBasis = InVerts[i].TangentBasis;
|
|
Tri.Verts[i].PointLocal = InVerts[i].PointLocal;
|
|
Tri.Verts[i].PointPostDeform = InVerts[i].Position;
|
|
Tri.Verts[i].PrevPointPostDeform = InVerts[i].Position;
|
|
Tri.Verts[i].PointWorld = mul(float4(Tri.Verts[i].PointPostDeform, 1), Transforms.LocalToTranslatedWorld).xyz;
|
|
Tri.Verts[i].PointWorld_NoOffset = Tri.Verts[i].PointWorld;
|
|
Tri.Verts[i].PointClip = GetNaniteClipPosition(NaniteView, VertexParameters, Transforms, InVerts[i], Tri.Verts[i].PointWorld);
|
|
|
|
#if NUM_TEX_COORD_INTERPOLATORS
|
|
#if ENABLE_NEW_HLSL_GENERATOR
|
|
EvaluateVertexMaterialAttributes(VertexParameters);
|
|
#endif
|
|
GetMaterialCustomizedUVs(VertexParameters, Tri.Verts[i].CustomizedUVs);
|
|
GetCustomInterpolators(VertexParameters, Tri.Verts[i].CustomizedUVs);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return Tri;
|
|
}
|
|
|
|
FNaniteTransformedTri FetchTransformedNaniteTriangle(
|
|
in FNaniteView NaniteView,
|
|
FPrimitiveSceneData PrimitiveData,
|
|
FInstanceSceneData InstanceData,
|
|
FInstanceViewData InstanceViewData,
|
|
FNaniteVertTransforms Transforms,
|
|
FCluster Cluster,
|
|
FVisibleCluster VisibleCluster,
|
|
uint3 VertIndexes,
|
|
bool bEvaluateWPO)
|
|
{
|
|
FNanitePostDeformVertex Verts[3];
|
|
FetchAndDeformLocalNaniteTriangle(PrimitiveData, InstanceData, InstanceViewData, Cluster, VisibleCluster, VertIndexes, NANITE_NUM_TEXCOORDS_TO_DECODE, Verts);
|
|
|
|
return TransformNaniteTriangle(NaniteView, PrimitiveData, InstanceData, Transforms, Verts, bEvaluateWPO);
|
|
}
|
|
|
|
FNaniteTransformedVert TransformNaniteVertex(FPrimitiveSceneData PrimitiveData, FInstanceSceneData InstanceData, FNaniteVertTransforms Transforms, FNanitePostDeformVertex InVert, bool bEvaluateWPO)
|
|
{
|
|
FNaniteTransformedVert Vert = (FNaniteTransformedVert)0;
|
|
|
|
Vert.VertIndex = InVert.VertIndex;
|
|
Vert.RawAttributeData = InVert.RawAttributeData;
|
|
Vert.TangentBasis = InVert.TangentBasis;
|
|
Vert.PointLocal = InVert.PointLocal;
|
|
Vert.SplineDist = InVert.SplineDist;
|
|
|
|
const float3 NormalWorld = mul(float4(InVert.TangentBasis.TangentZ, 0), Transforms.LocalToTranslatedWorld).xyz;
|
|
Vert.NormalClip = mul(float4(NormalWorld, 0), Transforms.TranslatedWorldToClip);
|
|
|
|
#if USES_WORLD_POSITION_OFFSET
|
|
#if ALWAYS_EVALUATE_WORLD_POSITION_OFFSET
|
|
bEvaluateWPO = true;
|
|
#else
|
|
bEvaluateWPO &= (PrimitiveData.Flags & PRIMITIVE_SCENE_DATA_FLAG_EVALUATE_WORLD_POSITION_OFFSET) != 0u;
|
|
#endif
|
|
BRANCH
|
|
if (bEvaluateWPO)
|
|
{
|
|
FMaterialVertexParameters VertexParameters = MakeInitializedMaterialVertexParameters();
|
|
SetVertexParameterInstanceData(VertexParameters, InstanceData, PrimitiveData, true /* WPO */);
|
|
SetVertexParameterAttributeData(VertexParameters, InVert, Transforms.LocalToTranslatedWorld, Transforms.LocalToWorldNoScale);
|
|
|
|
FMaterialVertexParameters PrevVertexParameters = MakeInitializedMaterialVertexParameters();
|
|
SetVertexParameterInstanceData(PrevVertexParameters, InstanceData, PrimitiveData, true /* WPO */);
|
|
SetVertexParameterAttributeData(PrevVertexParameters, InVert, Transforms.PrevLocalToTranslatedWorld, Transforms.PrevLocalToWorldNoScale);
|
|
|
|
#if ENABLE_NEW_HLSL_GENERATOR
|
|
EvaluateVertexMaterialAttributes(VertexParameters);
|
|
EvaluateVertexMaterialAttributes(PrevVertexParameters);
|
|
#endif
|
|
const float3 WorldPositionOffset = GetMaterialWorldPositionOffset(VertexParameters);
|
|
const float3 PrevWorldPositionOffset = GetMaterialPreviousWorldPositionOffset(PrevVertexParameters);
|
|
const float3 LocalOffset = mul(WorldPositionOffset, Transforms.WorldToLocalVector);
|
|
const float3 PrevLocalOffset = mul(PrevWorldPositionOffset, Transforms.PrevWorldToLocalVector);
|
|
|
|
Vert.PointPostDeform = InVert.Position + LocalOffset;
|
|
Vert.PrevPointPostDeform = InVert.Position + PrevLocalOffset;
|
|
Vert.PointWorld = VertexParameters.WorldPosition + WorldPositionOffset;
|
|
Vert.PointWorld_NoOffset = VertexParameters.WorldPosition;
|
|
Vert.PointClip = mul(float4(Vert.PointWorld, 1), Transforms.TranslatedWorldToClip);
|
|
|
|
#if NUM_TEX_COORD_INTERPOLATORS
|
|
GetMaterialCustomizedUVs(VertexParameters, Vert.CustomizedUVs);
|
|
GetCustomInterpolators(VertexParameters, Vert.CustomizedUVs);
|
|
#endif
|
|
}
|
|
else
|
|
#endif // USES WORLD_POSITION_OFFSET
|
|
{
|
|
Vert.PointPostDeform = InVert.Position;
|
|
Vert.PrevPointPostDeform = InVert.Position;
|
|
Vert.PointWorld = mul(float4(Vert.PointPostDeform, 1), Transforms.LocalToTranslatedWorld).xyz;
|
|
Vert.PointWorld_NoOffset = Vert.PointWorld;
|
|
Vert.PointClip = mul(float4(Vert.PointWorld, 1), Transforms.TranslatedWorldToClip);
|
|
|
|
#if NUM_TEX_COORD_INTERPOLATORS
|
|
FMaterialVertexParameters VertexParameters = MakeInitializedMaterialVertexParameters();
|
|
SetVertexParameterInstanceData(VertexParameters, InstanceData, PrimitiveData, false /* WPO */);
|
|
SetVertexParameterAttributeData(VertexParameters, InVert, Transforms.LocalToTranslatedWorld, Transforms.LocalToWorldNoScale);
|
|
|
|
#if ENABLE_NEW_HLSL_GENERATOR
|
|
EvaluateVertexMaterialAttributes(VertexParameters);
|
|
#endif
|
|
GetMaterialCustomizedUVs(VertexParameters, Vert.CustomizedUVs);
|
|
GetCustomInterpolators(VertexParameters, Vert.CustomizedUVs);
|
|
#endif
|
|
}
|
|
|
|
return Vert;
|
|
}
|
|
|
|
FNaniteTransformedVert FetchTransformedNaniteVertex(
|
|
FPrimitiveSceneData PrimitiveData,
|
|
FInstanceSceneData InstanceData,
|
|
FInstanceViewData InstanceViewData,
|
|
FNaniteVertTransforms Transforms,
|
|
FCluster Cluster,
|
|
FVisibleCluster VisibleCluster,
|
|
uint VertIndex,
|
|
bool bEvaluateWPO)
|
|
{
|
|
FNanitePostDeformVertex Vert = FetchAndDeformLocalNaniteVertex(PrimitiveData, InstanceData, InstanceViewData, Cluster, VisibleCluster, VertIndex, NANITE_NUM_TEXCOORDS_TO_DECODE);
|
|
return TransformNaniteVertex(PrimitiveData, InstanceData, Transforms, Vert, bEvaluateWPO);
|
|
}
|
|
|
|
HLSL_STATIC_ASSERT(sizeof(FNaniteTransformedVert) == (128 + sizeof(FNaniteRawAttributeData) + 8 * NUM_TEX_COORD_INTERPOLATORS), "Unexpected size of FNaniteTransformedVert. WaveReadLaneAt implementation needs to be updated.");
|
|
FNaniteTransformedVert WaveReadLaneAt(FNaniteTransformedVert Vert, uint SrcIndex)
|
|
{
|
|
FNaniteTransformedVert Result;
|
|
|
|
Result.VertIndex = WaveReadLaneAt( Vert.VertIndex, SrcIndex );
|
|
Result.RawAttributeData = WaveReadLaneAt( Vert.RawAttributeData, SrcIndex );
|
|
Result.PointLocal = WaveReadLaneAt( Vert.PointLocal, SrcIndex );
|
|
Result.PointPostDeform = WaveReadLaneAt( Vert.PointPostDeform, SrcIndex );
|
|
Result.PrevPointPostDeform = WaveReadLaneAt( Vert.PrevPointPostDeform, SrcIndex );
|
|
Result.PointWorld = WaveReadLaneAt( Vert.PointWorld, SrcIndex );
|
|
Result.PointWorld_NoOffset = WaveReadLaneAt( Vert.PointWorld_NoOffset, SrcIndex );
|
|
Result.PointClip = WaveReadLaneAt( Vert.PointClip, SrcIndex );
|
|
Result.SplineDist = WaveReadLaneAt( Vert.SplineDist, SrcIndex );
|
|
Result.TangentBasis = WaveReadLaneAt( Vert.TangentBasis, SrcIndex );
|
|
Result.NormalClip = WaveReadLaneAt( Vert.NormalClip, SrcIndex );
|
|
#if NUM_TEX_COORD_INTERPOLATORS
|
|
UNROLL
|
|
for (uint i = 0; i < NUM_TEX_COORD_INTERPOLATORS; ++i)
|
|
{
|
|
Result.CustomizedUVs[i] = WaveReadLaneAt(Vert.CustomizedUVs[i], SrcIndex);
|
|
}
|
|
#endif
|
|
|
|
return Result;
|
|
}
|
|
|
|
FNaniteTransformedTri MakeTransformedNaniteTriangle(FNaniteTransformedVert Vert, uint3 SrcLaneIndices)
|
|
{
|
|
FNaniteTransformedTri Tri;
|
|
|
|
UNROLL
|
|
for (uint Corner = 0; Corner < 3; ++Corner)
|
|
{
|
|
Tri.Verts[Corner] = WaveReadLaneAt(Vert, SrcLaneIndices[Corner]);
|
|
}
|
|
|
|
return Tri;
|
|
}
|
|
|
|
FMaterialPixelParameters FetchNaniteMaterialPixelParameters(FPrimitiveSceneData PrimitiveData, FInstanceSceneData InstanceData, FInstanceDynamicData InstanceDynamicData, FNaniteView NaniteView, FNaniteTransformedTri Tri, FCluster Cluster, FBarycentrics Barycentrics, inout FVertexFactoryInterpolantsVSToPS Interpolants, inout float4 SvPosition)
|
|
{
|
|
FMaterialPixelParameters Result = MakeInitializedMaterialPixelParameters();
|
|
|
|
// TODO Couldn't this be derived from the barycentric derivatives?
|
|
const float SignTest = dot(cross(Tri.Verts[1].PointClip.xyw - Tri.Verts[0].PointClip.xyw, Tri.Verts[2].PointClip.xyw - Tri.Verts[0].PointClip.xyw), Tri.Verts[0].PointClip.xyw);
|
|
Result.TwoSidedSign = CondMask(SignTest < 0.0f, -1.0f, 1.0f);
|
|
|
|
// VOXELTODO
|
|
// Hack to determine TwoSidedSign from normals for voxel. Doesn't work well with trees that bend normals for shading
|
|
if (Cluster.bVoxel)
|
|
{
|
|
const float3 WorldNormal = mul(Tri.Verts[0].RawAttributeData.TangentZ, DFToFloat3x3(InstanceData.LocalToWorld));
|
|
float Dot = dot(WorldNormal, NaniteView.ViewForward);
|
|
|
|
Result.TwoSidedSign = CondMask(Dot < 0.0f, -1.0f, 1.0f);
|
|
Result.TwoSidedSign = 1.0;
|
|
}
|
|
|
|
// Only need the first UV from cluster data (used to solve the tangent frame in GetAttributeData).
|
|
// But we don't use any for the pixel parameters because we interpolate the UVs manually below, in case they were customized.
|
|
const uint NumAttributeDataCoords = 1;
|
|
const FNaniteAttributeData AttributeData = GetAttributeData(
|
|
Cluster,
|
|
Tri.Verts[0].PointLocal,
|
|
Tri.Verts[1].PointLocal,
|
|
Tri.Verts[2].PointLocal,
|
|
Tri.Verts[0].RawAttributeData,
|
|
Tri.Verts[1].RawAttributeData,
|
|
Tri.Verts[2].RawAttributeData,
|
|
Tri.Verts[0].TangentBasis,
|
|
Tri.Verts[1].TangentBasis,
|
|
Tri.Verts[2].TangentBasis,
|
|
Barycentrics,
|
|
InstanceData,
|
|
NumAttributeDataCoords
|
|
);
|
|
|
|
#if INTERPOLATE_VERTEX_COLOR
|
|
Result.VertexColor = AttributeData.VertexColor.Value;
|
|
Result.VertexColor_DDX = AttributeData.VertexColor.Value_dx;
|
|
Result.VertexColor_DDY = AttributeData.VertexColor.Value_dy;
|
|
#else
|
|
// Coerce compiler into DCE as much code as possible.
|
|
Result.VertexColor = float4(1, 1, 1, 1);
|
|
Result.VertexColor_DDX = 0.0f;
|
|
Result.VertexColor_DDY = 0.0f;
|
|
#endif
|
|
|
|
Result.TangentToWorld = AttributeData.TangentToWorld;
|
|
Result.UnMirrored = AttributeData.UnMirrored;
|
|
|
|
#if NUM_TEX_COORD_INTERPOLATORS > 0
|
|
UNROLL
|
|
for (uint TexCoordIndex = 0; TexCoordIndex < NUM_TEX_COORD_INTERPOLATORS; TexCoordIndex++)
|
|
{
|
|
TDual< float2 > TexCoord = Lerp( Tri.Verts[0].CustomizedUVs[TexCoordIndex], Tri.Verts[1].CustomizedUVs[TexCoordIndex], Tri.Verts[2].CustomizedUVs[TexCoordIndex], Barycentrics );
|
|
Result.TexCoords[TexCoordIndex] = TexCoord.Value;
|
|
Result.TexCoords_DDX[TexCoordIndex] = TexCoord.Value_dx;
|
|
Result.TexCoords_DDY[TexCoordIndex] = TexCoord.Value_dy;
|
|
}
|
|
#endif
|
|
|
|
const TDual< float3 > PointWorld = Lerp( Tri.Verts[0].PointWorld, Tri.Verts[1].PointWorld, Tri.Verts[2].PointWorld, Barycentrics );
|
|
Result.WorldPosition_CamRelative = PointWorld.Value;
|
|
Result.WorldPosition_DDX = PointWorld.Value_dx;
|
|
Result.WorldPosition_DDY = PointWorld.Value_dy;
|
|
|
|
// Should be Pow2(InvScale) but that requires renormalization
|
|
float3x3 LocalToWorldNoScale = DFToFloat3x3(InstanceData.LocalToWorld);
|
|
float3 InvScale = InstanceData.InvNonUniformScale;
|
|
LocalToWorldNoScale[0] *= InvScale.x;
|
|
LocalToWorldNoScale[1] *= InvScale.y;
|
|
LocalToWorldNoScale[2] *= InvScale.z;
|
|
const TDual< float3 > WorldGeoNormal = Lerp(mul(Tri.Verts[0].TangentBasis.TangentZ, LocalToWorldNoScale), mul(Tri.Verts[1].TangentBasis.TangentZ, LocalToWorldNoScale), mul(Tri.Verts[2].TangentBasis.TangentZ, LocalToWorldNoScale), Barycentrics );
|
|
Result.WorldGeoNormal_DDX = WorldGeoNormal.Value_dx;
|
|
Result.WorldGeoNormal_DDY = WorldGeoNormal.Value_dy;
|
|
|
|
Result.WorldPosition_NoOffsets_CamRelative = Lerp( Tri.Verts[0].PointWorld_NoOffset, Tri.Verts[1].PointWorld_NoOffset, Tri.Verts[2].PointWorld_NoOffset, Barycentrics ).Value;
|
|
|
|
const float3 PrevPointPostDeform = Lerp( Tri.Verts[0].PrevPointPostDeform, Tri.Verts[1].PrevPointPostDeform, Tri.Verts[2].PrevPointPostDeform, Barycentrics ).Value;
|
|
float3 PrevPointWorld = mul(float4(PrevPointPostDeform.xyz, 1), InstanceDynamicData.PrevLocalToTranslatedWorld).xyz;
|
|
#if USES_DISPLACEMENT
|
|
{
|
|
// TODO PixelTranslatedWorld is already calculated outside this function.
|
|
// TODO GetMaterialPreviousDisplacementScaled so that dynamic displacement gets velocities.
|
|
const float4 PixelTranslatedWorld = mul( SvPosition, NaniteView.SVPositionToTranslatedWorld );
|
|
const float3 Displacement = PixelTranslatedWorld.xyz / PixelTranslatedWorld.w - PointWorld.Value;
|
|
PrevPointWorld += Displacement;
|
|
}
|
|
#endif
|
|
|
|
Result.PrevScreenPosition = mul(float4(PrevPointWorld, 1), NaniteView.PrevTranslatedWorldToClip);
|
|
|
|
if( Cluster.bVoxel )
|
|
{
|
|
float4 ThisClip = SvPositionToScreenPosition( SvPosition );
|
|
float4 PrevClip = mul( ThisClip, View.ClipToPrevClipWithAA );
|
|
Result.PrevScreenPosition = PrevClip;
|
|
|
|
const float3 V = -normalize( Result.WorldPosition_CamRelative );
|
|
#if 1
|
|
//const float Alpha = View.GeneralPurposeTweak;
|
|
//const float Alpha = tan( 0.5 * PI * min( AttributeData.VertexColor.Value.a, 0.999 ) );
|
|
float3 Alpha = 1;
|
|
if( AttributeData.VertexColor.Value.a > 0.5 )
|
|
Alpha.z = 2 - 2 * AttributeData.VertexColor.Value.a;
|
|
else
|
|
Alpha.xy = 2 * AttributeData.VertexColor.Value.a;
|
|
|
|
const float2 Noise = Rand3DPCG16( int3( SvPosition.xy, View.StateFrameIndexMod8 ) ).xy / 65535.0;
|
|
|
|
// world to sphere
|
|
float3 TangentV = mul( AttributeData.TangentToWorld, V );
|
|
TangentV *= Alpha;
|
|
TangentV = normalize( TangentV );
|
|
|
|
// visible sample on sphere
|
|
float3 VisibleNormal = CosineSampleHemisphere( Noise, TangentV ).xyz;
|
|
|
|
// sphere to world
|
|
VisibleNormal *= Alpha;
|
|
VisibleNormal = normalize( VisibleNormal );
|
|
float3 WorldNormal = mul( VisibleNormal, AttributeData.TangentToWorld );
|
|
|
|
Result.TangentToWorld = GetTangentBasis( WorldNormal );
|
|
#else
|
|
Result.TangentToWorld[2] *= dot( Result.TangentToWorld[2], V ) > 0 ? 1 : -1;
|
|
#endif
|
|
}
|
|
|
|
// Update screen W and all screen derivatives. This is rarely used and will be dead code eliminated most of the time.
|
|
{
|
|
const TDual< float4 > PointClip = Lerp( Tri.Verts[0].PointClip, Tri.Verts[1].PointClip, Tri.Verts[2].PointClip, Barycentrics );
|
|
SvPosition.w = PointClip.Value.w;
|
|
|
|
float2 Z_DDX_DDY = float2( PointClip.Value_dx.z, PointClip.Value_dy.z );
|
|
float2 W_DDX_DDY = float2( PointClip.Value_dx.w, PointClip.Value_dy.w );
|
|
|
|
// PPZ = Z / W
|
|
// PPZ' = (Z'W - ZW')/W^2
|
|
float2 PPZ_DDX_DDY = (Z_DDX_DDY * PointClip.Value.w - PointClip.Value.z * W_DDX_DDY) / (PointClip.Value.w * PointClip.Value.w);
|
|
SvPositionToResolvedScreenPositionDeriv(SvPosition, PPZ_DDX_DDY, W_DDX_DDY, Result.ScreenPosition, Result.ScreenPosition_DDX, Result.ScreenPosition_DDY);
|
|
}
|
|
|
|
#if USE_PARTICLE_SUBUVS && NUM_TEX_COORD_INTERPOLATORS > 0
|
|
// Output TexCoord0 for when previewing materials that use ParticleSubUV.
|
|
Result.Particle.SubUVCoords[0] = Result.TexCoords[0];
|
|
Result.Particle.SubUVCoords[1] = Result.TexCoords[0];
|
|
#endif
|
|
|
|
// Required for previewing materials that use ParticleColor
|
|
Result.Particle.Color = half4(1, 1, 1, 1);
|
|
|
|
Result.PerInstanceRandom = InstanceData.RandomID;
|
|
|
|
#if NEEDS_LIGHTMAP_COORDINATE
|
|
const uint LightMapDataIndex = PrimitiveData.LightmapDataIndex;
|
|
const uint LightMapUVIndex = PrimitiveData.LightmapUVIndex;
|
|
|
|
TDual< float2 > LightMapCoordinateInput;
|
|
if (LightMapUVIndex < NumAttributeDataCoords)
|
|
{
|
|
LightMapCoordinateInput = AttributeData.TexCoords[LightMapUVIndex];
|
|
}
|
|
else
|
|
{
|
|
// We don't already have the UV in the attribute data, so retrieve it
|
|
LightMapCoordinateInput = GetTexCoord(Cluster, uint3(Tri.Verts[0].VertIndex, Tri.Verts[1].VertIndex, Tri.Verts[2].VertIndex), Barycentrics, LightMapUVIndex);
|
|
}
|
|
|
|
const bool bHasPerInstanceCoordinateScaleBias = (InstanceData.Flags & INSTANCE_SCENE_DATA_FLAG_HAS_LIGHTSHADOW_UV_BIAS);
|
|
|
|
const float4 LightMapCoordinateScaleBias = GetLightmapData(LightMapDataIndex).LightMapCoordinateScaleBias;
|
|
const float2 InstanceLightMapScaleBias = CondMask(bHasPerInstanceCoordinateScaleBias, InstanceData.LightMapAndShadowMapUVBias.xy, LightMapCoordinateScaleBias.zw);
|
|
|
|
// TODO: Figure out why LightMapCoordinateInput * LightMapCoordinateScaleBias.xy + InstanceLightMapScaleBias fails to compile
|
|
TDual< float2 > LightMapCoordinate = LightMapCoordinateInput;
|
|
LightMapCoordinate.Value *= LightMapCoordinateScaleBias.xy;
|
|
LightMapCoordinate.Value_dx *= LightMapCoordinateScaleBias.xy;
|
|
LightMapCoordinate.Value_dy *= LightMapCoordinateScaleBias.xy;
|
|
LightMapCoordinate.Value += InstanceLightMapScaleBias;
|
|
|
|
TDual< float2 > ShadowMapCoordinate = (TDual< float2 >)0;
|
|
#if STATICLIGHTING_TEXTUREMASK
|
|
const float4 ShadowMapCoordinateScaleBias = GetLightmapData(LightMapDataIndex).ShadowMapCoordinateScaleBias;
|
|
const float2 InstanceShadowMapScaleBias = CondMask(bHasPerInstanceCoordinateScaleBias, InstanceData.LightMapAndShadowMapUVBias.zw, ShadowMapCoordinateScaleBias.zw);
|
|
|
|
// TODO: Figure out why LightMapCoordinateInput * ShadowMapCoordinateScaleBias.xy + InstanceShadowMapScaleBias fails to compile
|
|
ShadowMapCoordinate = LightMapCoordinateInput;
|
|
ShadowMapCoordinate.Value *= ShadowMapCoordinateScaleBias.xy;
|
|
ShadowMapCoordinate.Value_dx *= ShadowMapCoordinateScaleBias.xy;
|
|
ShadowMapCoordinate.Value_dy *= ShadowMapCoordinateScaleBias.xy;
|
|
ShadowMapCoordinate.Value += InstanceShadowMapScaleBias;
|
|
#endif
|
|
|
|
#if LIGHTMAP_UV_ACCESS
|
|
// Store unscaled/unbiased lightmap UVs
|
|
Result.LightmapUVs = LightMapCoordinateInput.Value;
|
|
Result.LightmapUVs_DDX = LightMapCoordinateInput.Value_dx;
|
|
Result.LightmapUVs_DDY = LightMapCoordinateInput.Value_dy;
|
|
#endif
|
|
|
|
SetLightMapCoordinate(Interpolants, LightMapCoordinate, ShadowMapCoordinate);
|
|
SetLightMapDataIndex(Interpolants, LightMapDataIndex);
|
|
|
|
#endif // NEEDS_LIGHTMAP_COORDINATE
|
|
|
|
#if USES_PER_INSTANCE_CUSTOM_DATA
|
|
Result.CustomDataOffset = InstanceData.CustomDataOffset;
|
|
Result.CustomDataCount = InstanceData.CustomDataCount;
|
|
#endif
|
|
|
|
#if HAS_INSTANCE_LOCAL_TO_WORLD_PS
|
|
Result.InstanceLocalToWorld = InstanceData.LocalToWorld;
|
|
#endif
|
|
#if HAS_INSTANCE_WORLD_TO_LOCAL_PS
|
|
Result.InstanceWorldToLocal = InstanceData.WorldToLocal;
|
|
#endif
|
|
|
|
Result.PrimitiveId = InstanceData.PrimitiveId;
|
|
Result.InstanceId = InstanceData.RelativeId;
|
|
|
|
return Result;
|
|
}
|
|
|
|
// Shared function (for Nanite raster and shading passes) to fetch a valid FMaterialPixelParameters struct, which is used by material inputs.
|
|
FMaterialPixelParameters FetchNaniteMaterialPixelParameters(FNaniteView NaniteView, UlongType PackedPixel, bool bHasPageData, FBarycentrics Barycentrics, bool bCalcBarycentrics, uint3 TriIndices, bool bCalcTriIndices, inout FVertexFactoryInterpolantsVSToPS Interpolants, inout float4 SvPosition)
|
|
{
|
|
FMaterialPixelParameters Result = MakeInitializedMaterialPixelParameters();
|
|
|
|
uint DepthInt = 0;
|
|
uint VisibleClusterIndex = 0;
|
|
uint TriIndex = 0;
|
|
bool bIsImposter = false;
|
|
UnpackVisPixel(PackedPixel, DepthInt, VisibleClusterIndex, TriIndex, bIsImposter);
|
|
|
|
// Update to real depth from VisBuffer
|
|
SvPosition.z = asfloat(DepthInt);
|
|
|
|
if (VisibleClusterIndex != 0xFFFFFFFF)
|
|
{
|
|
#if VIRTUAL_TEXTURE_TARGET
|
|
FVisibleCluster VisibleCluster = GetVisibleCluster( VisibleClusterIndex, VIRTUAL_TEXTURE_TARGET );
|
|
#else
|
|
FVisibleCluster VisibleCluster = GetVisibleCluster( VisibleClusterIndex );
|
|
#endif
|
|
FPrimitiveSceneData PrimitiveData;
|
|
FInstanceSceneData InstanceData;
|
|
GetNaniteMaterialSceneData(VisibleCluster, PrimitiveData, InstanceData);
|
|
|
|
FInstanceDynamicData InstanceDynamicData = CalculateInstanceDynamicData(NaniteView, InstanceData);
|
|
FCluster Cluster = GetCluster(VisibleCluster.PageIndex, VisibleCluster.ClusterIndex);
|
|
|
|
if (bCalcTriIndices)
|
|
{
|
|
TriIndices = DecodeTriangleIndices(Cluster, TriIndex);
|
|
|
|
BRANCH
|
|
if( Cluster.bVoxel )
|
|
{
|
|
// TODO Share with USES_DISPLACEMENT
|
|
float4x4 TranslatedWorldToLocal = DFFastToTranslatedWorld( InstanceData.WorldToLocal, NaniteView.PreViewTranslation );
|
|
|
|
float4 PixelTranslatedWorld = mul( SvPosition, NaniteView.SVPositionToTranslatedWorld );
|
|
float4 PixelLocal = mul( PixelTranslatedWorld, TranslatedWorldToLocal );
|
|
float3 LocalPos = PixelLocal.xyz / PixelLocal.w;
|
|
|
|
FBrick Brick = DecodeBrick(Cluster, TriIndex);
|
|
|
|
BRANCH
|
|
if (Cluster.bSkinning)
|
|
{
|
|
const FNaniteSkinningHeader SkinningHeader = LoadNaniteSkinningHeader(InstanceData.PrimitiveId);
|
|
const FBoneInfluenceHeader BoneInfluenceHeader = GetBoneInfluenceHeader(Cluster);
|
|
|
|
#if NANITE_PER_VOXEL_BRICK_SKINNING
|
|
const float4x3 SkinningTransform4x3 = SampleSkinningTransform(InstanceData, SkinningHeader, BoneInfluenceHeader, Brick.VertOffset);
|
|
#else
|
|
const float4x3 SkinningTransform4x3 = SampleVoxelSkinningTransform(InstanceData, Cluster, SkinningHeader);
|
|
#endif
|
|
|
|
const float3x3 InvSkinningTransform3x3 = Inverse(float3x3(SkinningTransform4x3[0], SkinningTransform4x3[1], SkinningTransform4x3[2]));
|
|
LocalPos = mul(LocalPos - SkinningTransform4x3[3], InvSkinningTransform3x3);
|
|
}
|
|
|
|
float3 VoxelPos = LocalPos.xyz / ( Cluster.LODError );
|
|
|
|
VoxelPos -= Brick.StartPos.xyz;
|
|
|
|
uint3 Voxel = (uint3)floor( VoxelPos );
|
|
uint VoxelIndex = Voxel.x + Voxel.y * 4 + Voxel.z * 16;
|
|
uint Mask = 1u << ( VoxelIndex & 31 );
|
|
Mask -= 1;
|
|
|
|
const uint2 BrickBits = reversebits( Brick.ReverseBrickBits.yx ); //TODO: Fix up logic to work on reversed bits directly
|
|
|
|
uint VertIndex = Brick.VertOffset;
|
|
VertIndex += countbits( BrickBits.x & ( VoxelIndex < 32 ? Mask : ~0u ) );
|
|
VertIndex += countbits( BrickBits.y & ( VoxelIndex < 32 ? 0 : Mask ) );
|
|
|
|
TriIndices = VertIndex;
|
|
}
|
|
}
|
|
|
|
// Don't evaluate WPO for imposter pixels or for clusters that don't have WPO enabled
|
|
bool bEvaluateWPO = !bIsImposter;
|
|
#if !ALWAYS_EVALUATE_WORLD_POSITION_OFFSET
|
|
bEvaluateWPO &= (VisibleCluster.Flags & NANITE_CULLING_FLAG_ENABLE_WPO) != 0;
|
|
#endif
|
|
const FNaniteVertTransforms Transforms = CalculateNaniteVertexTransforms(InstanceData, InstanceDynamicData, NaniteView);
|
|
const FNaniteTransformedTri Tri = FetchTransformedNaniteTriangle(NaniteView, PrimitiveData, InstanceData, GetInstanceViewData(InstanceData.InstanceId, NaniteView.SceneRendererPrimaryViewId), Transforms, Cluster, VisibleCluster, TriIndices, bEvaluateWPO);
|
|
|
|
if (bCalcBarycentrics)
|
|
{
|
|
// Calculate perspective correct barycentric coordinates with screen derivatives
|
|
const float2 PixelClip = (SvPosition.xy - NaniteView.ViewRect.xy) * NaniteView.ViewSizeAndInvSize.zw * float2(2, -2) + float2(-1, 1);
|
|
|
|
#if USES_DISPLACEMENT
|
|
float4x4 TranslatedWorldToLocal = DFFastToTranslatedWorld( InstanceData.WorldToLocal, NaniteView.PreViewTranslation );
|
|
float3 CameraLocal = TranslatedWorldToLocal[3].xyz;
|
|
|
|
float4 PixelTranslatedWorld = mul( SvPosition, NaniteView.SVPositionToTranslatedWorld );
|
|
float4 PixelTranslatedWorld_dx = mul( float4(1,0,0,0), NaniteView.SVPositionToTranslatedWorld );
|
|
float4 PixelTranslatedWorld_dy = mul( float4(0,1,0,0), NaniteView.SVPositionToTranslatedWorld );
|
|
|
|
float4 PixelLocal = mul( PixelTranslatedWorld, TranslatedWorldToLocal );
|
|
float4 PixelLocal_dx = mul( PixelTranslatedWorld_dx, TranslatedWorldToLocal );
|
|
float4 PixelLocal_dy = mul( PixelTranslatedWorld_dy, TranslatedWorldToLocal );
|
|
|
|
Barycentrics = CalculateTriangleBarycentrics(
|
|
CameraLocal,
|
|
PixelLocal.xyz / PixelLocal.w,
|
|
( PixelLocal.xyz + PixelLocal_dx.xyz ) / PixelLocal.w,
|
|
( PixelLocal.xyz + PixelLocal_dy.xyz ) / PixelLocal.w,
|
|
Tri.Verts[0].PointPostDeform,
|
|
Tri.Verts[1].PointPostDeform,
|
|
Tri.Verts[2].PointPostDeform,
|
|
Tri.Verts[0].TangentBasis.TangentZ,
|
|
Tri.Verts[1].TangentBasis.TangentZ,
|
|
Tri.Verts[2].TangentBasis.TangentZ );
|
|
#else
|
|
Barycentrics = CalculateTriangleBarycentrics(PixelClip, Tri.Verts[0].PointClip, Tri.Verts[1].PointClip, Tri.Verts[2].PointClip, NaniteView.ViewSizeAndInvSize.zw);
|
|
#endif
|
|
|
|
if( Cluster.bVoxel )
|
|
{
|
|
Barycentrics.Value = float3(1,0,0);
|
|
Barycentrics.Value_dx = 0;
|
|
Barycentrics.Value_dy = 0;
|
|
}
|
|
}
|
|
|
|
Result = FetchNaniteMaterialPixelParameters(PrimitiveData, InstanceData, InstanceDynamicData, NaniteView, Tri, Cluster, Barycentrics, Interpolants, SvPosition);
|
|
|
|
#if NUM_TEX_COORD_INTERPOLATORS > 0
|
|
if( Cluster.bVoxel )
|
|
{
|
|
float Depth = NaniteView.ViewToClip[3][2] / ( SvPosition.z - NaniteView.ViewToClip[2][2] );
|
|
float4 UVDensities = GetMaterialUVDensities(Cluster, InstanceData.PrimitiveId, TriIndex);
|
|
|
|
UNROLL
|
|
for (uint TexCoordIndex = 0; TexCoordIndex < NUM_TEX_COORD_INTERPOLATORS; TexCoordIndex++)
|
|
{
|
|
// TODO Don't use NaniteView.LODScale
|
|
float dUV_dXY = rcp( GetProjectedEdgeLengthAtDepth( UVDensities[TexCoordIndex] * InstanceData.NonUniformScale.w, Depth, NaniteView ) );
|
|
Result.TexCoords_DDX[TexCoordIndex] = dUV_dXY;
|
|
Result.TexCoords_DDY[TexCoordIndex] = dUV_dXY;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
#if IS_NANITE_SHADING_PASS
|
|
|
|
#if NANITE_USE_HW_BARYCENTRICS
|
|
#error NOT_SUPPORTED
|
|
#endif
|
|
|
|
/** Converts from vertex factory specific interpolants to a FMaterialPixelParameters, which is used by material inputs. */
|
|
FMaterialPixelParameters GetMaterialPixelParameters(FNaniteView NaniteView, inout FVertexFactoryInterpolantsVSToPS Interpolants, inout float4 SvPosition)
|
|
{
|
|
UlongType PackedPixel = (UlongType)0;
|
|
// Note: because of quad shading the CS shading can produce OOB pixels that need to return a safe value (0 translates into an invalid visible cluster ID which will skip most of the work)
|
|
if(all(Interpolants.PixelPos >= NaniteView.ViewRect.xy) && all(Interpolants.PixelPos < NaniteView.ViewRect.zw))
|
|
{
|
|
PackedPixel = NaniteShading.VisBuffer64[Interpolants.PixelPos];
|
|
}
|
|
|
|
const FBarycentrics Barycentrics = (FBarycentrics)0; // Unused for shading pass (barycentrics are invalid here for full screen tile grid)
|
|
return FetchNaniteMaterialPixelParameters(NaniteView, PackedPixel, VIRTUAL_TEXTURE_TARGET, Barycentrics, true, uint3(0,0,0), true, Interpolants, SvPosition);
|
|
}
|
|
|
|
FMaterialPixelParameters GetMaterialPixelParameters(inout FVertexFactoryInterpolantsVSToPS Interpolants, inout float4 SvPosition)
|
|
{
|
|
#if INSTANCED_STEREO
|
|
const FNaniteView NaniteView = GetNaniteView(Interpolants.EyeIndex);
|
|
#else
|
|
const FNaniteView NaniteView = GetNaniteView(0);
|
|
#endif
|
|
return GetMaterialPixelParameters(NaniteView, Interpolants, SvPosition);
|
|
}
|
|
|
|
#endif // IS_NANITE_SHADING_PASS
|
|
|
|
#if RAYHITGROUPSHADER
|
|
|
|
struct FVertexFactoryInput
|
|
{
|
|
// Dynamic instancing related attributes with InstanceIdOffset : ATTRIBUTE13
|
|
VF_GPUSCENE_DECLARE_INPUT_BLOCK(13)
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Material evaluation for raytracing
|
|
|
|
// define this to let shaders know this alternative method is available
|
|
#define VF_SUPPORTS_RAYTRACING_PREPARE_MATERIAL_PIXEL_PARAMETERS 1
|
|
|
|
FMaterialPixelParameters GetMaterialPixelParameters(float3 RayOrigin, float3 RayDirection, float HitT, uint HitPrimitiveIndex, FRayTracingIntersectionAttributes HitAttributes, uint HitKind, float4 SvPosition, out float3 WorldGeoNormal)
|
|
{
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
const uint GPUSceneInstanceId = GetInstanceUserData();
|
|
const FInstanceSceneData InstanceSceneData = GetInstanceSceneData(GPUSceneInstanceId);
|
|
|
|
FVertexFactoryInput Input = (FVertexFactoryInput)0;
|
|
VF_GPUSCENE_SET_INPUT_FOR_RT(Input, GPUSceneInstanceId, InstanceSceneData.RelativeId);
|
|
#else
|
|
#error "HGS requires GPU Scene support"
|
|
#endif // VF_USE_PRIMITIVE_SCENE_DATA
|
|
|
|
FSceneDataIntermediates SceneData = VF_GPUSCENE_GET_INTERMEDIATES(Input); // NOTE: Input is not used when VF_USE_PRIMITIVE_SCENE_DATA == 0
|
|
FInstanceSceneData InstanceData = SceneData.InstanceData;
|
|
FPrimitiveSceneData PrimitiveData = SceneData.Primitive;
|
|
|
|
const uint InstanceId = SceneData.InstanceId;
|
|
|
|
const uint FirstTriangle = HitGroupSystemRootConstants.FirstPrimitive;
|
|
const uint PackedTriangleData = RayTracingDataBuffer[PrimitiveData.NaniteRayTracingDataOffset + FirstTriangle + HitPrimitiveIndex];
|
|
|
|
const uint PageIndex = PackedTriangleData & NANITE_MAX_GPU_PAGES_MASK;
|
|
const uint ClusterIndex = (PackedTriangleData >> NANITE_MAX_GPU_PAGES_BITS) & NANITE_MAX_CLUSTERS_PER_PAGE_MASK;
|
|
const uint TriIndex = (PackedTriangleData >> (NANITE_MAX_GPU_PAGES_BITS + NANITE_MAX_CLUSTERS_PER_PAGE_BITS)) & NANITE_MAX_CLUSTER_TRIANGLES_MASK;
|
|
|
|
const FNaniteView NaniteView = GetNaniteView(0);
|
|
|
|
FInstanceDynamicData InstanceDynamicData = CalculateInstanceDynamicData(NaniteView, InstanceData);
|
|
FCluster Cluster = GetCluster(PageIndex, ClusterIndex);
|
|
|
|
// TODO: Nanite-Assemblies: No assembly support here for RT
|
|
FVisibleCluster VisibleCluster = (FVisibleCluster)0;
|
|
VisibleCluster.AssemblyTransformIndex = 0xFFFFFFFFu;
|
|
|
|
const uint3 TriIndices = DecodeTriangleIndices(Cluster, TriIndex);
|
|
const FNaniteVertTransforms Transforms = CalculateNaniteVertexTransforms(InstanceData, InstanceDynamicData, NaniteView);
|
|
const bool bEvaluateWPO = false;
|
|
const FNaniteTransformedTri Tri = FetchTransformedNaniteTriangle(NaniteView, PrimitiveData, InstanceData, GetInstanceViewData(InstanceData.InstanceId, NaniteView.SceneRendererPrimaryViewId), Transforms, Cluster, VisibleCluster, TriIndices, bEvaluateWPO);
|
|
const float2 HitBarycentrics = HitAttributes.GetBarycentrics();
|
|
|
|
#if USE_ANALYTIC_DERIVATIVES
|
|
const float2 PixelClip = (SvPosition.xy - View.ViewRectMin.xy) * View.ViewSizeAndInvSize.zw * float2(2, -2) + float2(-1, 1);
|
|
FBarycentrics Barycentrics = CalculateTriangleBarycentrics(PixelClip, Tri.Verts[0].PointClip, Tri.Verts[1].PointClip, Tri.Verts[2].PointClip, View.ViewSizeAndInvSize.zw);
|
|
#else
|
|
FBarycentrics Barycentrics = (FBarycentrics)0;
|
|
#endif
|
|
// Replace value with barycentrics from the raytracer, the function above is to make sure derivatives are populated
|
|
Barycentrics.Value = float3(1 - HitBarycentrics.x - HitBarycentrics.y, HitBarycentrics.x, HitBarycentrics.y);
|
|
|
|
|
|
FVertexFactoryInterpolantsVSToPS Interpolants;
|
|
FMaterialPixelParameters Result = FetchNaniteMaterialPixelParameters(PrimitiveData, InstanceData, InstanceDynamicData, NaniteView, Tri, Cluster, Barycentrics, Interpolants, SvPosition);
|
|
|
|
WorldGeoNormal = Result.TangentToWorld[2];
|
|
|
|
Result.TwoSidedSign = -sign(dot(RayDirection, WorldGeoNormal));
|
|
|
|
return Result;
|
|
}
|
|
|
|
#endif // RAYHITGROUPSHADER
|
|
|
|
struct FVertexFactoryRayTracingInterpolants
|
|
{
|
|
FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS;
|
|
};
|
|
|
|
float2 VertexFactoryGetRayTracingTextureCoordinate( FVertexFactoryRayTracingInterpolants Interpolants )
|
|
{
|
|
return float2(0,0);
|
|
}
|
|
|
|
FVertexFactoryInterpolantsVSToPS VertexFactoryAssignInterpolants(FVertexFactoryRayTracingInterpolants Input)
|
|
{
|
|
return Input.InterpolantsVSToPS;
|
|
}
|
|
|
|
FVertexFactoryRayTracingInterpolants VertexFactoryInterpolate(FVertexFactoryRayTracingInterpolants a, float aInterp, FVertexFactoryRayTracingInterpolants b, float bInterp)
|
|
{
|
|
return a;
|
|
}
|
|
|
|
#if RAYHITGROUPSHADER
|
|
|
|
// Fake structs / functions required to compile RayTracingHitShaders.usf
|
|
|
|
struct FVertexFactoryIntermediates
|
|
{
|
|
half3x3 TangentToLocal;
|
|
};
|
|
|
|
FVertexFactoryInput LoadVertexFactoryInputForHGS(uint TriangleIndex, int VertexIndex)
|
|
{
|
|
FVertexFactoryInput Input = (FVertexFactoryInput)0;
|
|
return Input;
|
|
}
|
|
|
|
FVertexFactoryIntermediates GetVertexFactoryIntermediates(FVertexFactoryInput Input)
|
|
{
|
|
FVertexFactoryIntermediates Intermediates = (FVertexFactoryIntermediates)0;
|
|
return Intermediates;
|
|
}
|
|
|
|
half3x3 VertexFactoryGetTangentToLocal(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
return Intermediates.TangentToLocal;
|
|
}
|
|
|
|
float4 VertexFactoryGetWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
float3 VertexFactoryGetWorldNormal(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
float3 VertexFactoryGetInstanceSpacePosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
float3 VertexFactoryGetPreviousInstanceSpacePosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
FMaterialVertexParameters GetMaterialVertexParameters(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float3 WorldPosition, half3x3 TangentToLocal, bool bIsPreviousFrame = false)
|
|
{
|
|
FMaterialVertexParameters Result = MakeInitializedMaterialVertexParameters();
|
|
return Result;
|
|
}
|
|
|
|
FVertexFactoryRayTracingInterpolants VertexFactoryGetRayTracingInterpolants(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, FMaterialVertexParameters VertexParameters)
|
|
{
|
|
FVertexFactoryRayTracingInterpolants Interpolants = (FVertexFactoryRayTracingInterpolants)0;
|
|
return Interpolants;
|
|
}
|
|
|
|
#endif |