879 lines
34 KiB
HLSL
879 lines
34 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
LandscapeVertexFactory.usf: Landscape vertex factory.
|
|
=============================================================================*/
|
|
|
|
// Compile Version 2
|
|
|
|
#include "VertexFactoryCommon.ush"
|
|
|
|
#define VERTEX_FACTORY_MODIFIES_INTERPOLATION 1
|
|
|
|
#define VF_SUPPORTS_RAYTRACING_VERTEX_MASK 1
|
|
|
|
// Set by FLightMapTexturePolicy
|
|
#include "/Engine/Generated/UniformBuffers/PrecomputedLightingBuffer.ush"
|
|
#include "LightmapData.ush"
|
|
|
|
#if LANDSCAPE_XYOFFSET
|
|
#define XYOFFSET_SCALE (1.0f/256.f)
|
|
#endif
|
|
|
|
/* Return index into buffers for this section instance. */
|
|
int GetComponentLinearIndex()
|
|
{
|
|
#if FIXED_GRID
|
|
// Fixed grid doesn't use LandscapeContinuousLODParameters buffers
|
|
return 0;
|
|
#else
|
|
return (LandscapeParameters.ComponentBaseY - LandscapeContinuousLODParameters.Min.y) * LandscapeContinuousLODParameters.Size.x + (LandscapeParameters.ComponentBaseX - LandscapeContinuousLODParameters.Min.x);
|
|
#endif
|
|
}
|
|
|
|
float GetViewLODData(uint ComponentIndex)
|
|
{
|
|
#if FIXED_GRID
|
|
// Fixed grid doesn't use LandscapeContinuousLODParameters buffers
|
|
return 0;
|
|
#else
|
|
const int AbsoluteSectionLODIndex = View.LandscapeIndirection[LandscapeContinuousLODParameters.LandscapeIndex] + ComponentIndex;
|
|
return View.LandscapePerComponentData[AbsoluteSectionLODIndex];
|
|
#endif
|
|
}
|
|
|
|
/* Get current Lod for this section instance. */
|
|
float GetSectionLod(uint ComponentIndex)
|
|
{
|
|
#if FIXED_GRID
|
|
// Fixed grid has fixed Lod
|
|
return LandscapeFixedGrid.LodValues.x;
|
|
#else
|
|
#if RAYTRACING_DYNAMIC_GEOMETRY_CONVERTER
|
|
int LODBias = LandscapeParameters.RayTracingLODBias;
|
|
#else
|
|
int LODBias = View.FarShadowStaticMeshLODBias;
|
|
#endif
|
|
return min(GetViewLODData(ComponentIndex) + LODBias, LandscapeParameters.LastLOD);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* x = Current mesh LOD
|
|
* y = Unused
|
|
* z = SectionSizeQuads in current mesh LOD
|
|
* w = 1/SectionSizeQuads in current mesh LOD
|
|
**/
|
|
float4 GetLodValues(uint ComponentIndex)
|
|
{
|
|
#if FIXED_GRID
|
|
// Fixed grid has fixed Lod
|
|
return LandscapeFixedGrid.LodValues;
|
|
#else
|
|
// Get Lod for the current section and infer the values
|
|
uint Lod = (uint)floor(GetSectionLod(ComponentIndex));
|
|
float LodSubSectionSizeQuads = (float)((LandscapeParameters.SubsectionSizeVerts >> Lod) - 1);
|
|
return float4(Lod, 0, LodSubSectionSizeQuads, rcp(LodSubSectionSizeQuads));
|
|
#endif
|
|
}
|
|
|
|
uint GetRayTracingSectionVertCountForLOD(uint ComponentIndex)
|
|
{
|
|
uint Lod = (uint)floor(GetSectionLod(ComponentIndex));
|
|
return ((LandscapeParameters.RayTracingSectionSizeVerts >> Lod) + 1);
|
|
}
|
|
|
|
/**
|
|
* x = Heightmap texture LOD difference from current LOD to highest LOD
|
|
* y = todo: XYOffset texture LOD difference from current LOD to highest LOD
|
|
*/
|
|
float2 GetLodBias(uint ComponentIndex)
|
|
{
|
|
#if FIXED_GRID
|
|
// Fixed grid doesn't use LodBias
|
|
return 0;
|
|
#else
|
|
float LodBias = LandscapeContinuousLODParameters.SectionLODBias[ComponentIndex];
|
|
return float2(LodBias, 0.f);
|
|
#endif
|
|
}
|
|
|
|
|
|
float GetNeighborSectionLodFromOffset(int2 NeighborOffset, float CenterLOD)
|
|
{
|
|
#if FIXED_GRID
|
|
// Fixed grid has fixed Lod
|
|
return LandscapeFixedGrid.LodValues.x;
|
|
#else // !FIXED_GRID
|
|
// Calculate neighbor position, and clamp to valid range
|
|
int2 NeighborPos = NeighborOffset + int2(LandscapeParameters.ComponentBaseX, LandscapeParameters.ComponentBaseY);
|
|
NeighborPos = max(LandscapeContinuousLODParameters.Min , NeighborPos);
|
|
NeighborPos = min(LandscapeContinuousLODParameters.Min + LandscapeContinuousLODParameters.Size - int2(1, 1), NeighborPos);
|
|
|
|
// lookup neighbor LOD
|
|
uint NeighborComponentIndex = (NeighborPos.y - LandscapeContinuousLODParameters.Min.y) * LandscapeContinuousLODParameters.Size.x + (NeighborPos.x - LandscapeContinuousLODParameters.Min.x);
|
|
float NeighborLOD = GetSectionLod(NeighborComponentIndex);
|
|
|
|
// the Edge LOD is the max of Our LOD and the Neighbor LOD (both sides will agree on EdgeLOD this way)
|
|
float EdgeLOD = max(CenterLOD, NeighborLOD);
|
|
|
|
return EdgeLOD;
|
|
#endif // !FIXED_GRID
|
|
}
|
|
|
|
/** Calculate fractional render LOD for a vertex within a subsection. */
|
|
float CalcLOD(uint ComponentIndex, float2 xyLocalToSubsection, float2 Subsection)
|
|
{
|
|
#if FIXED_GRID
|
|
// Fixed grid has fixed Lod
|
|
return LandscapeFixedGrid.LodValues.x;
|
|
#else
|
|
float2 xy = (xyLocalToSubsection + Subsection) / LandscapeParameters.NumSubsections;
|
|
|
|
// calculate blend value (normalized distance from section border: 1 at the border, 0 at the center)
|
|
float2 Delta = xy * 2 - 1;
|
|
float2 AbsDelta = abs(Delta);
|
|
float LB = max(AbsDelta.x, AbsDelta.y);
|
|
|
|
// shift the blend towards 0 to reduce the lod blend range
|
|
float k = LandscapeParameters.InvLODBlendRange;
|
|
LB = saturate(1 - (1-LB) * k);
|
|
|
|
// determine which neighbor is closest
|
|
int2 NeighborOffset = (AbsDelta.x > AbsDelta.y) ? int2(sign(Delta.x), 0) : int2(0, sign(Delta.y));
|
|
|
|
// calculate lod for this section, and the closest neighbor
|
|
float CenterLod = GetSectionLod(ComponentIndex);
|
|
float NeighborLod = GetNeighborSectionLodFromOffset(NeighborOffset, CenterLod);
|
|
|
|
// blend from center lod to the neighbor lod, based on distance from the border
|
|
float LODCalculated = (1-LB) * CenterLod + LB * NeighborLod;
|
|
|
|
return LODCalculated;
|
|
#endif
|
|
}
|
|
|
|
struct FVertexFactoryInput
|
|
{
|
|
// UByte4
|
|
uint4 Position : ATTRIBUTE0;
|
|
|
|
#if LANDSCAPE_TILE
|
|
#undef GetInstanceIdFromVF
|
|
// UByte4
|
|
uint4 TileData : ATTRIBUTE1;
|
|
#if INSTANCED_STEREO
|
|
#define GetInstanceIdFromVF(VFInput) (VFInput.InstanceId)
|
|
uint InstanceId : SV_InstanceID;
|
|
#else
|
|
#define GetInstanceIdFromVF(VFInput) (0)
|
|
#endif // INSTANCED_STEREO
|
|
#else
|
|
// Dynamic instancing related attributes with InstanceIdOffset : ATTRIBUTE1
|
|
VF_GPUSCENE_DECLARE_INPUT_BLOCK(1)
|
|
VF_INSTANCED_STEREO_DECLARE_INPUT_BLOCK()
|
|
#endif
|
|
VF_MOBILE_MULTI_VIEW_DECLARE_INPUT_BLOCK()
|
|
};
|
|
|
|
// RHI_RAYTRACING
|
|
#if RAYHITGROUPSHADER
|
|
FVertexFactoryInput LoadVertexFactoryInputForHGS(uint TriangleIndex, int VertexIndex)
|
|
{
|
|
FVertexFactoryInput Input;
|
|
|
|
uint RTSectionSizeVertsCurrentLOD = GetRayTracingSectionVertCountForLOD(GetComponentLinearIndex());
|
|
uint RTSectionSizeQuadsCurrentLOD = RTSectionSizeVertsCurrentLOD - 1;
|
|
uint NumRayTracingSections = LandscapeParameters.NumRayTracingSections;
|
|
|
|
float RTSectionSizeScaler = (RTSectionSizeQuadsCurrentLOD - 1.0f / NumRayTracingSections) / RTSectionSizeQuadsCurrentLOD ;
|
|
|
|
#if 1
|
|
FTriangleBaseAttributes Tri = LoadTriangleBaseAttributes(TriangleIndex);
|
|
uint VertexId = Tri.Indices[VertexIndex];
|
|
#else
|
|
uint QuadId = TriangleIndex / 2;
|
|
uint QuadX = QuadId % RTSectionSizeQuadsCurrentLOD;
|
|
uint QuadY = QuadId / RTSectionSizeQuadsCurrentLOD;
|
|
uint i00 = (QuadX + 0) + (QuadY + 0) * RTSectionSizeVertsCurrentLOD;
|
|
uint i10 = (QuadX + 1) + (QuadY + 0) * RTSectionSizeVertsCurrentLOD;
|
|
uint i11 = (QuadX + 1) + (QuadY + 1) * RTSectionSizeVertsCurrentLOD;
|
|
uint i01 = (QuadX + 0) + (QuadY + 1) * RTSectionSizeVertsCurrentLOD;
|
|
uint Indices[6] = {i00, i11, i10, i00, i01, i10};
|
|
uint VertexId = Indices[TriangleIndex % 2 * 3 + VertexIndex];
|
|
#endif
|
|
|
|
// Note: GetInstanceUserData() stores the GPU-Scene instance ID
|
|
VF_GPUSCENE_SET_INPUT_FOR_RT(Input, GetInstanceUserData(), 0U);
|
|
|
|
Input.Position.x = (VertexId % RTSectionSizeVertsCurrentLOD + LandscapeMVF.RayTracingSectionXY.x * RTSectionSizeQuadsCurrentLOD) * RTSectionSizeScaler;
|
|
Input.Position.y = (VertexId / RTSectionSizeVertsCurrentLOD + LandscapeMVF.RayTracingSectionXY.y * RTSectionSizeQuadsCurrentLOD) * RTSectionSizeScaler;
|
|
Input.Position.z = LandscapeMVF.SubXY.x;
|
|
Input.Position.w = LandscapeMVF.SubXY.y;
|
|
|
|
return Input;
|
|
}
|
|
#endif
|
|
|
|
#if COMPUTESHADER
|
|
FVertexFactoryInput LoadVertexFactoryInputForDynamicUpdate(uint TriangleIndex, int VertexIndex, uint PrimitiveId, uint DrawInstanceId)
|
|
{
|
|
FVertexFactoryInput Input = (FVertexFactoryInput)0;
|
|
|
|
uint RTSectionSizeVertsCurrentLOD = GetRayTracingSectionVertCountForLOD(GetComponentLinearIndex());
|
|
uint RTSectionSizeQuadsCurrentLOD = RTSectionSizeVertsCurrentLOD - 1;
|
|
uint NumRayTracingSections = LandscapeParameters.NumRayTracingSections;
|
|
|
|
float RTSectionSizeScaler = (RTSectionSizeQuadsCurrentLOD - 1.0f / NumRayTracingSections) / RTSectionSizeQuadsCurrentLOD ;
|
|
|
|
uint VertexId = TriangleIndex * 3 + VertexIndex;
|
|
|
|
Input.Position.x = (VertexId % RTSectionSizeVertsCurrentLOD + LandscapeMVF.RayTracingSectionXY.x * RTSectionSizeQuadsCurrentLOD) * RTSectionSizeScaler;
|
|
Input.Position.y = (VertexId / RTSectionSizeVertsCurrentLOD + LandscapeMVF.RayTracingSectionXY.y * RTSectionSizeQuadsCurrentLOD) * RTSectionSizeScaler;
|
|
Input.Position.z = LandscapeMVF.SubXY.x;
|
|
Input.Position.w = LandscapeMVF.SubXY.y;
|
|
|
|
FPrimitiveSceneData PrimitiveData = GetPrimitiveData(PrimitiveId);
|
|
VF_GPUSCENE_SET_INPUT_FOR_RT(Input, PrimitiveData.InstanceSceneDataOffset + DrawInstanceId, DrawInstanceId);
|
|
|
|
return Input;
|
|
}
|
|
|
|
uint GetNumRayTracingDynamicMeshVerticesIndirect()
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
struct FVertexFactoryInterpolantsVSToPS
|
|
{
|
|
float2 LayerTexCoord : TEXCOORD0; // xy == texcoord
|
|
float4 WeightHeightMapTexCoord : TEXCOORD1;
|
|
float4 TransformedTexCoords : TEXCOORD2;
|
|
#if NEEDS_LIGHTMAP_COORDINATE
|
|
#if FEATURE_LEVEL == FEATURE_LEVEL_ES3_1
|
|
float2 LightMapCoordinate[2] : TEXCOORD4;
|
|
float2 ShadowMapCoordinate : TEXCOORD6;
|
|
#else
|
|
float2 LightMapCoordinate : TEXCOORD3;
|
|
float2 ShadowMapCoordinate : TEXCOORD4;
|
|
#endif
|
|
#endif
|
|
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
nointerpolation uint PrimitiveId : PRIMITIVE_ID;
|
|
#endif
|
|
};
|
|
|
|
#if NUM_TEX_COORD_INTERPOLATORS
|
|
float2 GetUV(FVertexFactoryInterpolantsVSToPS Interpolants, int UVIndex)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
struct FLandscapeTexCoords
|
|
{
|
|
float2 LayerTexCoord : TEXCOORD0; // xy == texcoord
|
|
float2 WeightMapTexCoord;
|
|
float2 HeightMapTexCoord;
|
|
#if NEEDS_LIGHTMAP_COORDINATE
|
|
float2 LightMapCoordinate;
|
|
#endif
|
|
};
|
|
|
|
struct FVertexFactoryRayTracingInterpolants
|
|
{
|
|
FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS;
|
|
|
|
#if NEEDS_VERTEX_FACTORY_INTERPOLATION
|
|
// First row of the tangent to world matrix
|
|
float3 TangentToWorld0 : VS_To_DS_TangentToWorld0;
|
|
// Last row of the tangent to world matrix in xyz
|
|
float4 TangentToWorld2 : VS_To_DS_TangentToWorld2;
|
|
// LOD of the vertex, used for fading out tessellation
|
|
float CalculatedLOD : VS_To_DS_CalculatedLOD;
|
|
#endif
|
|
};
|
|
|
|
#if NEEDS_VERTEX_FACTORY_INTERPOLATION
|
|
float2 VertexFactoryGetRayTracingTextureCoordinate( FVertexFactoryRayTracingInterpolants Interpolants )
|
|
{
|
|
return Interpolants.InterpolantsVSToPS.WeightHeightMapTexCoord.zw;
|
|
}
|
|
#endif // #if NEEDS_VERTEX_FACTORY_INTERPOLATION
|
|
|
|
FVertexFactoryInterpolantsVSToPS VertexFactoryAssignInterpolants(FVertexFactoryRayTracingInterpolants Input)
|
|
{
|
|
return Input.InterpolantsVSToPS;
|
|
}
|
|
|
|
struct FVertexFactoryIntermediates
|
|
{
|
|
float4 InputPosition;
|
|
float3 LocalPosition;
|
|
float3 WorldNormal;
|
|
uint ComponentIndex;
|
|
float4 LodValues;
|
|
float2 LodBias;
|
|
/** Cached primitive and instance data */
|
|
FSceneDataIntermediates SceneData;
|
|
};
|
|
|
|
FPrimitiveSceneData GetPrimitiveData(FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
return Intermediates.SceneData.Primitive;
|
|
}
|
|
|
|
FInstanceSceneData GetInstanceData(FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
return Intermediates.SceneData.InstanceData;
|
|
}
|
|
|
|
float3 GetLocalPosition(FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
return Intermediates.LocalPosition+float3(Intermediates.InputPosition.zw * LandscapeParameters.SubsectionOffsetParams.ww,0);
|
|
}
|
|
|
|
float4 VertexFactoryGetWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
FDFMatrix LocalToWorld = GetInstanceData(Intermediates).LocalToWorld;
|
|
return TransformLocalToTranslatedWorld(GetLocalPosition(Intermediates), LocalToWorld);
|
|
}
|
|
|
|
float3 VertexFactoryGetInstanceSpacePosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
return GetLocalPosition(Intermediates);
|
|
}
|
|
|
|
float3 VertexFactoryGetWorldNormal(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
return Intermediates.WorldNormal;
|
|
}
|
|
|
|
float4 VertexFactoryGetPreviousWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
// Note we still use LocalToWorld. Landscape's transform never changes.
|
|
float3 LocalPosition = GetLocalPosition(Intermediates);
|
|
FDFMatrix LocalToWorld = GetInstanceData(Intermediates).LocalToWorld;
|
|
return TransformPreviousLocalPositionToTranslatedWorld(LocalPosition, LocalToWorld);
|
|
}
|
|
|
|
// local position relative to instance
|
|
float3 VertexFactoryGetPreviousInstanceSpacePosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
return GetLocalPosition(Intermediates);
|
|
}
|
|
|
|
/** Calculate the texture coordinates generated by Landscape */
|
|
FLandscapeTexCoords GetLandscapeTexCoords(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
|
|
{
|
|
FLandscapeTexCoords Result;
|
|
|
|
Result.LayerTexCoord.xy = Intermediates.LocalPosition.xy + LandscapeParameters.SubsectionSizeVertsLayerUVPan.zw + Intermediates.InputPosition.zw * LandscapeParameters.SubsectionOffsetParams.ww;
|
|
|
|
Result.WeightMapTexCoord = Intermediates.LocalPosition.xy * LandscapeParameters.WeightmapUVScaleBias.xy + LandscapeParameters.WeightmapUVScaleBias.zw + Intermediates.InputPosition.zw * LandscapeParameters.SubsectionOffsetParams.zz;
|
|
Result.HeightMapTexCoord = Intermediates.LocalPosition.xy * LandscapeParameters.HeightmapUVScaleBias.xy + LandscapeParameters.HeightmapUVScaleBias.zw + 0.5*LandscapeParameters.HeightmapUVScaleBias.xy + Intermediates.InputPosition.zw * LandscapeParameters.SubsectionOffsetParams.xy;
|
|
|
|
#if NEEDS_LIGHTMAP_COORDINATE
|
|
Result.LightMapCoordinate = (Intermediates.LocalPosition.xy * LandscapeParameters.LandscapeLightmapScaleBias.xy + LandscapeParameters.LandscapeLightmapScaleBias.wz + Intermediates.InputPosition.zw * LandscapeParameters.LightmapSubsectionOffsetParams.xy);
|
|
#endif
|
|
|
|
return Result;
|
|
}
|
|
|
|
float3x3 CalcTangentBasisFromWorldNormal(float3 Normal)
|
|
{
|
|
float3 LocalTangentX = normalize(float3(Normal.z, 0.0f, -Normal.x));
|
|
float3 LocalTangentY = cross(Normal, LocalTangentX);
|
|
|
|
float3x3 LocalToTangent = float3x3(LocalTangentX,LocalTangentY,Normal);
|
|
|
|
return LocalToTangent;
|
|
}
|
|
|
|
/** Lookup per-pixel tangent basis from heightmap texture */
|
|
float3x3 VertexFactoryGetPerPixelTangentBasis(FVertexFactoryInterpolantsVSToPS Interpolants)
|
|
{
|
|
float3x3 Result;
|
|
#if PIXELSHADER || RAYHITGROUPSHADER || COMPUTESHADER
|
|
float4 SampleValue = Texture2DSample(LandscapeParameters.NormalmapTexture, LandscapeParameters.NormalmapTextureSampler, Interpolants.WeightHeightMapTexCoord.zw);
|
|
float2 SampleNormal = float2(SampleValue.b, SampleValue.a) * float2(2.0,2.0) - float2(1.0,1.0);
|
|
float3 WorldNormal = float3( SampleNormal, sqrt(max(1.0-dot(SampleNormal,SampleNormal),0.0)) );
|
|
|
|
Result = CalcTangentBasisFromWorldNormal(WorldNormal);
|
|
#endif
|
|
return Result;
|
|
}
|
|
|
|
/** Lookup per-pixel height from heightmap texture. */
|
|
#define VF_PER_PIXEL_HEIGHTMAP 1
|
|
/** Use high quality barycentric version of interpolation. */
|
|
#ifndef PER_PIXEL_HEIGHTMAP_HQ
|
|
#define PER_PIXEL_HEIGHTMAP_HQ 0
|
|
#endif
|
|
|
|
bool HasVertexFactoryPerPixelHeight()
|
|
{
|
|
return LandscapeParameters.VirtualTexturePerPixelHeight != 0;
|
|
}
|
|
|
|
float GetVertexFactoryPerPixelHeight(FVertexFactoryInterpolantsVSToPS Interpolants)
|
|
{
|
|
float2 UV = Interpolants.WeightHeightMapTexCoord.zw;
|
|
|
|
#if PER_PIXEL_HEIGHTMAP_HQ
|
|
if (LandscapeParameters.VirtualTexturePerPixelHeight > 1)
|
|
{
|
|
// It only makes sense to use barycentric sampling when sampling resolution is sufficiently above heightmap resolution.
|
|
float2 TextureSize = LandscapeParameters.HeightmapTextureSize.xy;
|
|
float2 dUVdx = ddx(UV * TextureSize);
|
|
float2 dUVdy = ddy(UV * TextureSize);
|
|
float T = max(dot(dUVdx, dUVdx), dot(dUVdy, dUVdy));
|
|
if (T < 0.125f)
|
|
{
|
|
// Fake barycentric interpolation to try and match same result that we would get from vertex interpolation with a vertex located at each texel.
|
|
float2 PixelCoord = UV * TextureSize - 0.5f;
|
|
float2 FloorPixelCoord = floor(PixelCoord);
|
|
float2 SubPixelPos = PixelCoord - FloorPixelCoord;
|
|
|
|
float B1 = min(SubPixelPos.x, SubPixelPos.y);
|
|
float B2 = abs(SubPixelPos.y - SubPixelPos.x);
|
|
float B0 = 1.0f - B1 - B2;
|
|
|
|
// Which is the third sample/triangle vertex depends on if we are upper or lower triangle in the quad.
|
|
bool bLowerTriangle = (SubPixelPos.x > SubPixelPos.y);
|
|
|
|
float2 InvTextureSize = LandscapeParameters.HeightmapTextureSize.zw;
|
|
float2 BaseUV = (FloorPixelCoord + 0.5f) * InvTextureSize;
|
|
float2 UV1 = InvTextureSize;
|
|
float2 UV2 = bLowerTriangle ? float2(InvTextureSize.x, 0) : float2(0, InvTextureSize.y);
|
|
|
|
float2 S0 = LandscapeParameters.HeightmapTexture.SampleLevel(LandscapeParameters.HeightmapTextureSampler, BaseUV, 0).xy;
|
|
float2 S1 = LandscapeParameters.HeightmapTexture.SampleLevel(LandscapeParameters.HeightmapTextureSampler, BaseUV + UV1, 0).xy;
|
|
float2 S2 = LandscapeParameters.HeightmapTexture.SampleLevel(LandscapeParameters.HeightmapTextureSampler, BaseUV + UV2, 0).xy;
|
|
|
|
float H0 = DecodePackedHeight(S0);
|
|
float H1 = DecodePackedHeight(S1);
|
|
float H2 = DecodePackedHeight(S2);
|
|
|
|
return B0 * H0 + B1 * H1 + B2 * H2;
|
|
}
|
|
}
|
|
#endif // PER_PIXEL_HEIGHTMAP_HQ
|
|
|
|
// Use simple bilinear interpolation of heightmap.
|
|
// Ideally we want to reuse this sample from VertexFactoryGetPerPixelTangentBasis().
|
|
float4 SampleValue = LandscapeParameters.NormalmapTexture.Sample(LandscapeParameters.NormalmapTextureSampler, UV);
|
|
return DecodePackedHeight(SampleValue.xy);
|
|
}
|
|
|
|
/** Converts from vertex factory specific interpolants to a FMaterialPixelParameters, which is used by material inputs. */
|
|
FMaterialPixelParameters GetMaterialPixelParameters(FVertexFactoryInterpolantsVSToPS Interpolants, float4 SvPosition)
|
|
{
|
|
// GetMaterialPixelParameters is responsible for fully initializing the result
|
|
FMaterialPixelParameters Result = MakeInitializedMaterialPixelParameters();
|
|
|
|
#if NEEDS_LIGHTMAP_COORDINATE
|
|
#if FEATURE_LEVEL == FEATURE_LEVEL_ES3_1
|
|
// Not supported in pixel shader
|
|
float2 LightmapUVs = float2(0, 0);
|
|
#else
|
|
float2 LightmapUVs = Interpolants.LightMapCoordinate.xy;
|
|
#endif
|
|
#else
|
|
float2 LightmapUVs = float2(0, 0);
|
|
#endif
|
|
|
|
#if NUM_MATERIAL_TEXCOORDS // XY layer
|
|
Result.TexCoords[0] = Interpolants.LayerTexCoord.xy;
|
|
#if NUM_MATERIAL_TEXCOORDS > 1 // VS calcualted TexCoord 1, default is XZ layer
|
|
Result.TexCoords[1] = Interpolants.TransformedTexCoords.xy;
|
|
#if NUM_MATERIAL_TEXCOORDS > 2 // VS calcualted TexCoord 2, default is YZ layer
|
|
Result.TexCoords[2] = Interpolants.TransformedTexCoords.zw;
|
|
#if NUM_MATERIAL_TEXCOORDS > 3 // Weightmap
|
|
Result.TexCoords[3] = Interpolants.WeightHeightMapTexCoord.xy;
|
|
#if NUM_MATERIAL_TEXCOORDS > 4 // Lightmap
|
|
#if NEEDS_LIGHTMAP_COORDINATE
|
|
Result.TexCoords[4] = LightmapUVs;
|
|
#else
|
|
Result.TexCoords[4] = float2(0,0);
|
|
#endif
|
|
#if NUM_MATERIAL_TEXCOORDS > 5 // Height map
|
|
Result.TexCoords[5] = Interpolants.WeightHeightMapTexCoord.zw;
|
|
#if NUM_MATERIAL_TEXCOORDS > 6
|
|
for (uint CoordinateIndex = 6; CoordinateIndex < NUM_MATERIAL_TEXCOORDS; CoordinateIndex++)
|
|
{
|
|
Result.TexCoords[CoordinateIndex] = float2(0,0);
|
|
}
|
|
#endif // 6
|
|
#endif // 5
|
|
#endif // 4
|
|
#endif // 3
|
|
#endif // 2
|
|
#endif // 1
|
|
#endif // 0
|
|
|
|
// Calculate LocalToTangent directly from normal map texture.
|
|
float3x3 TangentToLocal = VertexFactoryGetPerPixelTangentBasis(Interpolants);
|
|
Result.TangentToWorld = mul(TangentToLocal, (float3x3)LandscapeParameters.LocalToWorldNoScaling);
|
|
Result.UnMirrored = 1;
|
|
|
|
Result.VertexColor = 1;
|
|
|
|
#if LIGHTMAP_UV_ACCESS
|
|
Result.LightmapUVs = LightmapUVs;
|
|
#endif
|
|
|
|
Result.TwoSidedSign = 1;
|
|
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
Result.PrimitiveId = Interpolants.PrimitiveId;
|
|
#endif
|
|
|
|
return Result;
|
|
}
|
|
|
|
float3 VertexFactoryGetPreviousInstanceSpacePosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates);
|
|
float3 VertexFactoryGetInstanceSpacePosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates);
|
|
|
|
/** 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,
|
|
bool bIsPreviousFrame = false)
|
|
{
|
|
FMaterialVertexParameters Result = MakeInitializedMaterialVertexParameters();
|
|
Result.SceneData = Intermediates.SceneData;
|
|
|
|
Result.WorldPosition = WorldPosition;
|
|
if (bIsPreviousFrame)
|
|
{
|
|
Result.PositionInstanceSpace = VertexFactoryGetPreviousInstanceSpacePosition(Input, Intermediates);
|
|
}
|
|
else
|
|
{
|
|
Result.PositionInstanceSpace = VertexFactoryGetInstanceSpacePosition(Input, Intermediates);
|
|
}
|
|
Result.PositionPrimitiveSpace = Result.PositionInstanceSpace; // No support for instancing, so instance == primitive
|
|
|
|
Result.VertexColor = float4(1,1,1,1);
|
|
Result.TangentToWorld = mul(TangentToLocal, (float3x3)LandscapeParameters.LocalToWorldNoScaling);
|
|
Result.PreSkinnedPosition = Intermediates.LocalPosition.xyz;
|
|
Result.PreSkinnedNormal = TangentToLocal[2].xyz;
|
|
|
|
// Assumes no instancing and landscape's transform never change
|
|
Result.PrevFrameLocalToWorld = GetInstanceData(Intermediates).LocalToWorld;
|
|
|
|
FLandscapeTexCoords LandscapeTexCoords = GetLandscapeTexCoords(Input, Intermediates);
|
|
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX // XY layer
|
|
Result.TexCoords[0] = LandscapeTexCoords.LayerTexCoord.xy;
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX > 1 // XZ layer
|
|
Result.TexCoords[1] = float2(LandscapeTexCoords.LayerTexCoord.x, Intermediates.LocalPosition.z);
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX > 2 // YZ layer
|
|
Result.TexCoords[2] = float2(LandscapeTexCoords.LayerTexCoord.y, Intermediates.LocalPosition.z);
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX > 3 // Weightmap
|
|
Result.TexCoords[3] = LandscapeTexCoords.WeightMapTexCoord;
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX > 4 // Lightmap
|
|
#if NEEDS_LIGHTMAP_COORDINATE
|
|
Result.TexCoords[4] = LandscapeTexCoords.LightMapCoordinate.xy;
|
|
#else
|
|
Result.TexCoords[4] = float2(0,0);
|
|
#endif
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX > 5 // Height map
|
|
Result.TexCoords[5] = LandscapeTexCoords.HeightMapTexCoord;
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX > 6
|
|
UNROLL
|
|
for (uint CoordinateIndex = 6; CoordinateIndex < NUM_MATERIAL_TEXCOORDS_VERTEX; CoordinateIndex++)
|
|
{
|
|
Result.TexCoords[CoordinateIndex] = float2(0,0);
|
|
}
|
|
#endif // 6
|
|
#endif // 5
|
|
#endif // 4
|
|
#endif // 3
|
|
#endif // 2
|
|
#endif // 1
|
|
#endif // 0
|
|
|
|
#if ENABLE_NEW_HLSL_GENERATOR
|
|
EvaluateVertexMaterialAttributes(Result);
|
|
#endif
|
|
Result.LWCData = MakeMaterialLWCData(Result);
|
|
|
|
return Result;
|
|
}
|
|
|
|
#if NEEDS_LIGHTMAP_COORDINATE
|
|
void GetLightMapCoordinates(FVertexFactoryInterpolantsVSToPS Interpolants, out float2 LightmapUV0, out float2 LightmapUV1, out uint LightmapDataIndex)
|
|
{
|
|
#if FEATURE_LEVEL == FEATURE_LEVEL_ES3_1
|
|
LightmapUV0 = Interpolants.LightMapCoordinate[0];
|
|
LightmapUV1 = Interpolants.LightMapCoordinate[1];
|
|
#else
|
|
LightmapUV0 = Interpolants.LightMapCoordinate * float2( 1, 0.5 );
|
|
LightmapUV1 = LightmapUV0 + float2( 0, 0.5 );
|
|
#endif
|
|
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
LightmapDataIndex = GetPrimitiveData(Interpolants.PrimitiveId).LightmapDataIndex;
|
|
#else
|
|
LightmapDataIndex = 0;
|
|
#endif
|
|
}
|
|
|
|
void GetShadowMapCoordinate(FVertexFactoryInterpolantsVSToPS Interpolants, out float2 ShadowMapCoordinate, out uint LightmapDataIndex)
|
|
{
|
|
ShadowMapCoordinate = Interpolants.ShadowMapCoordinate;
|
|
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
LightmapDataIndex = GetPrimitiveData(Interpolants.PrimitiveId).LightmapDataIndex;
|
|
#else
|
|
LightmapDataIndex = 0;
|
|
#endif
|
|
|
|
}
|
|
#endif
|
|
|
|
FVertexFactoryIntermediates GetVertexFactoryIntermediates(FVertexFactoryInput Input)
|
|
{
|
|
FVertexFactoryIntermediates Intermediates;
|
|
Intermediates.SceneData = VF_GPUSCENE_GET_INTERMEDIATES(Input);
|
|
Intermediates.ComponentIndex = GetComponentLinearIndex();
|
|
Intermediates.LodValues = GetLodValues(Intermediates.ComponentIndex);
|
|
Intermediates.LodBias = GetLodBias(Intermediates.ComponentIndex);
|
|
Intermediates.InputPosition = Input.Position;
|
|
|
|
#if LANDSCAPE_TILE
|
|
Intermediates.InputPosition = Intermediates.InputPosition + Input.TileData;
|
|
Intermediates.InputPosition.xy = min(Intermediates.InputPosition.xy, float2(Intermediates.LodValues.z, Intermediates.LodValues.z));
|
|
#endif
|
|
|
|
float2 xy = Intermediates.InputPosition.xy * Intermediates.LodValues.w;
|
|
|
|
float LODCalculated = CalcLOD(Intermediates.ComponentIndex, xy, Intermediates.InputPosition.zw);
|
|
float LodValue = floor(LODCalculated);
|
|
float MorphAlpha = LODCalculated - LodValue;
|
|
|
|
// InputPositionLODAdjusted : Position for actual LOD in base LOD units
|
|
float2 ActualLODCoordsInt = floor(Intermediates.InputPosition.xy * pow(2, -(LodValue - Intermediates.LodValues.x)));
|
|
float InvLODScaleFactor = pow(2, -LodValue);
|
|
|
|
// Base to Actual LOD, Base to Next LOD
|
|
float2 CoordTranslate = float2( LandscapeParameters.SubsectionSizeVertsLayerUVPan.x * InvLODScaleFactor - 1, max(LandscapeParameters.SubsectionSizeVertsLayerUVPan.x * 0.5f * InvLODScaleFactor, 2) - 1 ) * LandscapeParameters.SubsectionSizeVertsLayerUVPan.y;
|
|
float2 InputPositionLODAdjusted = ActualLODCoordsInt / CoordTranslate.x;
|
|
|
|
// InputPositionNextLOD : Position for next LOD in base LOD units
|
|
float2 NextLODCoordsInt = floor(ActualLODCoordsInt * 0.5);
|
|
float2 InputPositionNextLOD = NextLODCoordsInt / CoordTranslate.y;
|
|
|
|
// Get the height and normal XY for current and next LOD out of the textures
|
|
float2 SampleCoords = InputPositionLODAdjusted * LandscapeParameters.HeightmapUVScaleBias.xy + LandscapeParameters.HeightmapUVScaleBias.zw + 0.5*LandscapeParameters.HeightmapUVScaleBias.xy + Intermediates.InputPosition.zw * LandscapeParameters.SubsectionOffsetParams.xy;
|
|
float4 SampleValue = Texture2DSampleLevel(LandscapeParameters.HeightmapTexture, LandscapeParameters.HeightmapTextureSampler, SampleCoords, LodValue-Intermediates.LodBias.x);
|
|
float Height = DecodePackedHeight(SampleValue.xy);
|
|
|
|
float2 SampleCoordsNextLOD = InputPositionNextLOD * LandscapeParameters.HeightmapUVScaleBias.xy + LandscapeParameters.HeightmapUVScaleBias.zw + 0.5*LandscapeParameters.HeightmapUVScaleBias.xy + Intermediates.InputPosition.zw * LandscapeParameters.SubsectionOffsetParams.xy;
|
|
float4 SampleValueNextLOD = Texture2DSampleLevel(LandscapeParameters.HeightmapTexture, LandscapeParameters.HeightmapTextureSampler, SampleCoordsNextLOD, LodValue+1-Intermediates.LodBias.x);
|
|
float HeightNextLOD = DecodePackedHeight(SampleValueNextLOD.xy);
|
|
|
|
#if LANDSCAPE_XYOFFSET // FEATURE_LEVEL >= FEATURE_LEVEL_SM4 only
|
|
float2 SampleCoords2 = float2(InputPositionLODAdjusted * LandscapeParameters.WeightmapUVScaleBias.xy + LandscapeParameters.WeightmapUVScaleBias.zw + Intermediates.InputPosition.zw * LandscapeParameters.SubsectionOffsetParams.zz);
|
|
float4 OffsetValue = Texture2DSampleLevel( LandscapeParameters.XYOffsetmapTexture, LandscapeParameters.XYOffsetmapTextureSampler, SampleCoords2, LodValue- Intermediates.LodBias.y );
|
|
float2 SampleCoordsNextLOD2 = float2(InputPositionNextLOD * LandscapeParameters.WeightmapUVScaleBias.xy + LandscapeParameters.WeightmapUVScaleBias.zw + Intermediates.InputPosition.zw * LandscapeParameters.SubsectionOffsetParams.zz);
|
|
float4 OffsetValueNextLOD = Texture2DSampleLevel( LandscapeParameters.XYOffsetmapTexture, LandscapeParameters.XYOffsetmapTextureSampler, SampleCoordsNextLOD2, LodValue+1-Intermediates.LodBias.y );
|
|
float2 XYOffset = float2(((OffsetValue.r * 255.0 * 256.0 + OffsetValue.g * 255.0) - 32768.0) * XYOFFSET_SCALE, ((OffsetValue.b * 255.0 * 256.0 + OffsetValue.a * 255.0) - 32768.0) * XYOFFSET_SCALE );
|
|
float2 XYOffsetNextLOD = float2(((OffsetValueNextLOD.r * 255.0 * 256.0 + OffsetValueNextLOD.g * 255.0) - 32768.0) * XYOFFSET_SCALE, ((OffsetValueNextLOD.b * 255.0 * 256.0 + OffsetValueNextLOD.a * 255.0) - 32768.0) * XYOFFSET_SCALE );
|
|
|
|
InputPositionLODAdjusted = InputPositionLODAdjusted + XYOffset;
|
|
InputPositionNextLOD = InputPositionNextLOD + XYOffsetNextLOD;
|
|
#endif
|
|
|
|
Intermediates.LocalPosition = lerp( float3(InputPositionLODAdjusted, Height), float3(InputPositionNextLOD, HeightNextLOD), MorphAlpha );
|
|
|
|
float2 Normal = float2(SampleValue.b, SampleValue.a);
|
|
float2 NormalNextLOD = float2(SampleValueNextLOD.b, SampleValueNextLOD.a);
|
|
float2 InterpNormal = lerp( Normal, NormalNextLOD, MorphAlpha ) * float2(2.0,2.0) - float2(1.0,1.0);
|
|
Intermediates.WorldNormal = float3( InterpNormal, sqrt(max(1.0-dot(InterpNormal,InterpNormal),0.0)) );
|
|
|
|
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 = CalcTangentBasisFromWorldNormal(Intermediates.WorldNormal);
|
|
return Result;
|
|
}
|
|
|
|
float4 VertexFactoryGetRasterizedWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float4 InWorldPosition)
|
|
{
|
|
return InWorldPosition;
|
|
}
|
|
|
|
float3 VertexFactoryGetPositionForVertexLighting(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float3 TranslatedWorldPosition)
|
|
{
|
|
return TranslatedWorldPosition;
|
|
}
|
|
|
|
FVertexFactoryInterpolantsVSToPS VertexFactoryGetInterpolantsVSToPS(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, FMaterialVertexParameters VertexParameters)
|
|
{
|
|
FVertexFactoryInterpolantsVSToPS Interpolants;
|
|
|
|
Interpolants = (FVertexFactoryInterpolantsVSToPS)0;
|
|
FLandscapeTexCoords LandscapeTexCoords = GetLandscapeTexCoords(Input, Intermediates);
|
|
|
|
Interpolants.LayerTexCoord = LandscapeTexCoords.LayerTexCoord;
|
|
Interpolants.WeightHeightMapTexCoord.xy = LandscapeTexCoords.WeightMapTexCoord;
|
|
Interpolants.WeightHeightMapTexCoord.zw = LandscapeTexCoords.HeightMapTexCoord;
|
|
|
|
// Landscape material doesn't support custom vertex interpolators for now but GetMaterialCustomizedUVs is declared using NUM_TEX_COORD_INTERPOLATORS
|
|
#if NUM_TEX_COORD_INTERPOLATORS
|
|
float2 CustomizedUVs[NUM_TEX_COORD_INTERPOLATORS];
|
|
GetMaterialCustomizedUVs(VertexParameters, CustomizedUVs);
|
|
#endif // NUM_TEX_COORD_INTERPOLATORS
|
|
|
|
// Landscape material only supports up to NUM_MATERIAL_TEXCOORDS 5 (0-3 are reserved for landscape-specific stuff: see UMaterialExpressionLandscapeLayerCoords, 4 is for lightmaps and 5 for heightmap coordinates,
|
|
// anything above is not supported : see GetMaterialPixelParameters) :
|
|
#if NUM_MATERIAL_TEXCOORDS
|
|
Interpolants.LayerTexCoord.xy = CustomizedUVs[0];
|
|
Interpolants.TransformedTexCoords = 0;
|
|
|
|
#if NUM_MATERIAL_TEXCOORDS > 1
|
|
Interpolants.TransformedTexCoords.xy = CustomizedUVs[1];
|
|
#if NUM_MATERIAL_TEXCOORDS > 2
|
|
Interpolants.TransformedTexCoords.zw = CustomizedUVs[2];
|
|
#endif // NUM_MATERIAL_TEXCOORDS > 2
|
|
#endif // NUM_MATERIAL_TEXCOORDS > 1
|
|
#endif // NUM_MATERIAL_TEXCOORDS
|
|
|
|
#if NEEDS_LIGHTMAP_COORDINATE
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
const uint LightmapDataIndex = GetPrimitiveData(Intermediates).LightmapDataIndex;
|
|
#else
|
|
const uint LightmapDataIndex = 0;
|
|
#endif
|
|
|
|
#if FEATURE_LEVEL == FEATURE_LEVEL_ES3_1
|
|
Interpolants.LightMapCoordinate[0] = LandscapeTexCoords.LightMapCoordinate * VF_GPUSCENE_GET_LIGHTMAP_UV_SCALE_BIAS(Input, LightmapDataIndex).xy + VF_GPUSCENE_GET_LIGHTMAP_UV_SCALE_BIAS(Input, LightmapDataIndex).zw;
|
|
Interpolants.LightMapCoordinate[0].y *= 0.5;
|
|
Interpolants.LightMapCoordinate[1] = Interpolants.LightMapCoordinate[0].xy;
|
|
Interpolants.LightMapCoordinate[1].y += 0.5;
|
|
#else
|
|
Interpolants.LightMapCoordinate = LandscapeTexCoords.LightMapCoordinate * VF_GPUSCENE_GET_LIGHTMAP_UV_SCALE_BIAS(Input, LightmapDataIndex).xy + VF_GPUSCENE_GET_LIGHTMAP_UV_SCALE_BIAS(Input, LightmapDataIndex).zw;
|
|
#endif
|
|
|
|
#if STATICLIGHTING_TEXTUREMASK
|
|
Interpolants.ShadowMapCoordinate = LandscapeTexCoords.LightMapCoordinate * VF_GPUSCENE_GET_SHADOWMAP_UV_SCALE_BIAS(Input, LightmapDataIndex).xy + VF_GPUSCENE_GET_SHADOWMAP_UV_SCALE_BIAS(Input, LightmapDataIndex).zw;
|
|
#else
|
|
Interpolants.ShadowMapCoordinate = 0;
|
|
#endif
|
|
#endif
|
|
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
Interpolants.PrimitiveId = Intermediates.SceneData.PrimitiveId;
|
|
#endif
|
|
|
|
return Interpolants;
|
|
}
|
|
|
|
FVertexFactoryRayTracingInterpolants VertexFactoryGetRayTracingInterpolants(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, FMaterialVertexParameters VertexParameters)
|
|
{
|
|
FVertexFactoryRayTracingInterpolants Interpolants;
|
|
|
|
Interpolants.InterpolantsVSToPS = VertexFactoryGetInterpolantsVSToPS(Input, Intermediates, VertexParameters);
|
|
|
|
#if NEEDS_VERTEX_FACTORY_INTERPOLATION
|
|
// Calculate LocalToTangent directly from normal map texture.
|
|
float3x3 TangentToLocal = CalcTangentBasisFromWorldNormal(Intermediates.WorldNormal);
|
|
float3x3 TangentToWorld = mul(TangentToLocal, (float3x3)LandscapeParameters.LocalToWorldNoScaling);
|
|
|
|
Interpolants.TangentToWorld0 = TangentToWorld[0];
|
|
Interpolants.TangentToWorld2 = float4(TangentToWorld[2], 1);
|
|
|
|
float2 xy = Intermediates.InputPosition.xy * Intermediates.LodValues.w;
|
|
Interpolants.CalculatedLOD = CalcLOD(Intermediates.ComponentIndex, xy, Intermediates.InputPosition.zw);
|
|
#endif
|
|
|
|
return Interpolants;
|
|
}
|
|
|
|
FVertexFactoryRayTracingInterpolants VertexFactoryInterpolate(FVertexFactoryRayTracingInterpolants a, float aInterp, FVertexFactoryRayTracingInterpolants b, float bInterp)
|
|
{
|
|
FVertexFactoryRayTracingInterpolants O;
|
|
|
|
#if NEEDS_LIGHTMAP_COORDINATE && FEATURE_LEVEL > FEATURE_LEVEL_ES3_1
|
|
INTERPOLATE_MEMBER(InterpolantsVSToPS.LightMapCoordinate);
|
|
#endif
|
|
|
|
INTERPOLATE_MEMBER(InterpolantsVSToPS.LayerTexCoord);
|
|
INTERPOLATE_MEMBER(InterpolantsVSToPS.WeightHeightMapTexCoord);
|
|
INTERPOLATE_MEMBER(InterpolantsVSToPS.TransformedTexCoords);
|
|
|
|
#if NEEDS_VERTEX_FACTORY_INTERPOLATION
|
|
INTERPOLATE_MEMBER(TangentToWorld0);
|
|
INTERPOLATE_MEMBER(TangentToWorld2);
|
|
INTERPOLATE_MEMBER(CalculatedLOD);
|
|
#endif
|
|
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
O.InterpolantsVSToPS.PrimitiveId = a.InterpolantsVSToPS.PrimitiveId;
|
|
#endif
|
|
|
|
return O;
|
|
}
|
|
|
|
#if NUM_VF_PACKED_INTERPOLANTS > 0
|
|
void VertexFactoryPackInterpolants(inout FVertexFactoryInterpolantsVSToPS Interpolants, float4 PackedInterpolants[NUM_VF_PACKED_INTERPOLANTS])
|
|
{
|
|
Interpolants.TransformedTexCoord0.zw = PackedInterpolants[0].xy;
|
|
Interpolants.TransformedTexCoord1.zw = PackedInterpolants[0].zw;
|
|
}
|
|
|
|
void VertexFactoryUnpackInterpolants(FVertexFactoryInterpolantsVSToPS Interpolants, out float4 PackedInterpolants[NUM_VF_PACKED_INTERPOLANTS])
|
|
{
|
|
PackedInterpolants[0].xy = Interpolants.TransformedTexCoord0.zw;
|
|
PackedInterpolants[0].zw = Interpolants.TransformedTexCoord1.zw;
|
|
#if NUM_VF_PACKED_INTERPOLANTS > 1
|
|
UNROLL
|
|
for (int i = 1; i < NUM_VF_PACKED_INTERPOLANTS; ++i)
|
|
{
|
|
PackedInterpolants[i] = 0;
|
|
}
|
|
#endif
|
|
}
|
|
#endif // NUM_VF_PACKED_INTERPOLANTS > 0
|
|
|
|
float4 VertexFactoryGetTranslatedPrimitiveVolumeBounds(FVertexFactoryInterpolantsVSToPS Interpolants)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
uint VertexFactoryGetPrimitiveId(FVertexFactoryInterpolantsVSToPS Interpolants)
|
|
{
|
|
#if VF_USE_PRIMITIVE_SCENE_DATA
|
|
return Interpolants.PrimitiveId;
|
|
#else // VF_USE_PRIMITIVE_SCENE_DATA
|
|
return 0;
|
|
#endif // VF_USE_PRIMITIVE_SCENE_DATA
|
|
}
|
|
|
|
// Tell the VSM depth shader that we are supplying a constant bias
|
|
#define VF_USE_VSM_CONSTANT_BIAS 1
|
|
|
|
float VertexFactoryGetNonNaniteVirtualShadowMapConstantDepthBias()
|
|
{
|
|
return LandscapeParameters.NonNaniteVirtualShadowMapConstantDepthBias;
|
|
}
|
|
|
|
#include "VertexFactoryDefaultInterface.ush"
|