1171 lines
36 KiB
HLSL
1171 lines
36 KiB
HLSL
|
|
// Upgrade NOTE: excluded shader from OpenGL ES 2.0 because it uses non-square matrices
|
|
#pragma exclude_renderers gles
|
|
|
|
|
|
#define MaterialFloat float
|
|
#define MaterialFloat2 float2
|
|
#define MaterialFloat3 float3
|
|
#define MaterialFloat4 float4
|
|
#define MaterialFloat3x3 float3x3
|
|
#define MaterialFloat4x4 float4x4
|
|
#define MaterialFloat4x3 float4x3
|
|
|
|
#define LOOP UNITY_LOOP
|
|
#define UNROLL UNITY_UNROLL
|
|
|
|
/*struct FTexCoordScalesParams
|
|
{
|
|
|
|
int2 PixelPosition;
|
|
|
|
|
|
float4 OneOverDDU;
|
|
float4 OneOverDDV;
|
|
|
|
|
|
float MinScale;
|
|
float MaxScale;
|
|
|
|
float TexSample;
|
|
|
|
|
|
float4 ScalesPerIndex;
|
|
};*/
|
|
#define FTexCoordScalesParams float2
|
|
|
|
struct FMaterialParticleParameters
|
|
{
|
|
/** Relative time [0-1]. */
|
|
half RelativeTime;
|
|
/** Fade amount due to motion blur. */
|
|
half MotionBlurFade;
|
|
/** Random value per particle [0-1]. */
|
|
half Random;
|
|
/** XYZ: Direction, W: Speed. */
|
|
half4 Velocity;
|
|
/** Per-particle color. */
|
|
half4 Color;
|
|
/** Particle translated world space position and size(radius). */
|
|
float4 TranslatedWorldPositionAndSize;
|
|
/** Macro UV scale and bias. */
|
|
half4 MacroUV;
|
|
/** Dynamic parameter used by particle systems. */
|
|
half4 DynamicParameter;
|
|
/** mesh particle orientation */
|
|
float4x4 LocalToWorld;
|
|
|
|
#if USE_PARTICLE_SUBUVS
|
|
/** SubUV texture coordinates*/
|
|
MaterialFloat2 SubUVCoords[ 2 ];
|
|
/** SubUV interpolation value*/
|
|
MaterialFloat SubUVLerp;
|
|
#endif
|
|
|
|
/** The size of the particle. */
|
|
float2 Size;
|
|
};
|
|
|
|
struct FPixelMaterialInputs
|
|
{
|
|
MaterialFloat3 EmissiveColor;
|
|
MaterialFloat Opacity;
|
|
MaterialFloat OpacityMask;
|
|
MaterialFloat3 BaseColor;
|
|
MaterialFloat Metallic;
|
|
MaterialFloat Specular;
|
|
MaterialFloat Roughness;
|
|
MaterialFloat3 Normal;
|
|
MaterialFloat AmbientOcclusion;
|
|
MaterialFloat2 Refraction;
|
|
MaterialFloat PixelDepthOffset;
|
|
MaterialFloat Subsurface;
|
|
MaterialFloat ShadingModel;
|
|
//4.25
|
|
MaterialFloat Anisotropy;
|
|
MaterialFloat3 Tangent;
|
|
};
|
|
|
|
struct FMaterialVertexParameters
|
|
{
|
|
// Position in the translated world (VertexFactoryGetWorldPosition).
|
|
// Previous position in the translated world (VertexFactoryGetPreviousWorldPosition) if
|
|
// computing material's output for previous frame (See {BasePassVertex,Velocity}Shader.usf).
|
|
float3 WorldPosition;
|
|
// TangentToWorld[2] is WorldVertexNormal
|
|
half3x3 TangentToWorld;
|
|
#if USE_INSTANCING
|
|
/** Per-instance properties. */
|
|
float4x4 InstanceLocalToWorld;
|
|
float3 InstanceLocalPosition;
|
|
float4 PerInstanceParams;
|
|
uint InstanceId;
|
|
uint InstanceOffset;
|
|
|
|
#elif IS_MESHPARTICLE_FACTORY
|
|
/** Per-particle properties. */
|
|
float4x4 InstanceLocalToWorld;
|
|
#endif
|
|
// If either USE_INSTANCING or (IS_MESHPARTICLE_FACTORY && FEATURE_LEVEL >= FEATURE_LEVEL_SM4)
|
|
// is true, PrevFrameLocalToWorld is a per-instance transform
|
|
float4x4 PrevFrameLocalToWorld;
|
|
|
|
float3 PreSkinnedPosition;
|
|
float3 PreSkinnedNormal;
|
|
|
|
#if GPU_SKINNED_MESH_FACTORY
|
|
float3 PreSkinOffset;
|
|
float3 PostSkinOffset;
|
|
#endif
|
|
|
|
half4 VertexColor;
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX
|
|
float2 TexCoords[ NUM_MATERIAL_TEXCOORDS_VERTEX ];
|
|
#if ES3_1_PROFILE
|
|
float2 TexCoordOffset; // Offset for UV localization for large UV values
|
|
#endif
|
|
#endif
|
|
|
|
/** Per-particle properties. Only valid for particle vertex factories. */
|
|
FMaterialParticleParameters Particle;
|
|
|
|
// Index into View.PrimitiveSceneData
|
|
uint PrimitiveId;
|
|
|
|
#if WATER_MESH_FACTORY
|
|
uint WaterWaveParamIndex;
|
|
#endif
|
|
};
|
|
|
|
struct FMaterialPixelParameters
|
|
{
|
|
#if NUM_TEX_COORD_INTERPOLATORS
|
|
float2 TexCoords[ NUM_TEX_COORD_INTERPOLATORS ];
|
|
#endif
|
|
|
|
/** Interpolated vertex color, in linear color space. */
|
|
half4 VertexColor;//TBD
|
|
|
|
/** Normalized world space normal. */
|
|
half3 WorldNormal;
|
|
|
|
/** Normalized world space reflected camera vector. */
|
|
half3 ReflectionVector;
|
|
|
|
/** Normalized world space camera vector, which is the vector from the point being shaded to the camera position. */
|
|
half3 CameraVector;
|
|
|
|
/** World space light vector, only valid when rendering a light function. */
|
|
half3 LightVector;
|
|
|
|
/**
|
|
* Like SV_Position (.xy is pixel position at pixel center, z:DeviceZ, .w:SceneDepth)
|
|
* using shader generated value SV_POSITION
|
|
* Note: this is not relative to the current viewport. RelativePixelPosition = MaterialParameters.SvPosition.xy - View.ViewRectMin.xy;
|
|
*/
|
|
float4 SvPosition;
|
|
|
|
/** Post projection position reconstructed from SvPosition, before the divide by W. left..top -1..1, bottom..top -1..1 within the viewport, W is the SceneDepth */
|
|
float4 ScreenPosition;
|
|
|
|
half UnMirrored;
|
|
|
|
half TwoSidedSign;
|
|
|
|
/**
|
|
* Orthonormal rotation-only transform from tangent space to world space
|
|
* The transpose(TangentToWorld) is WorldToTangent, and TangentToWorld[2] is WorldVertexNormal
|
|
*/
|
|
half3x3 TangentToWorld;
|
|
|
|
/**
|
|
* Interpolated worldspace position of this pixel
|
|
* todo: Make this TranslatedWorldPosition and also rename the VS/DS/HS WorldPosition to be TranslatedWorldPosition
|
|
*/
|
|
float3 AbsoluteWorldPosition;
|
|
|
|
/**
|
|
* Interpolated worldspace position of this pixel, centered around the camera
|
|
*/
|
|
float3 WorldPosition_CamRelative;
|
|
|
|
/**
|
|
* Interpolated worldspace position of this pixel, not including any world position offset or displacement.
|
|
* Only valid if shader is compiled with NEEDS_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS, otherwise just contains 0
|
|
*/
|
|
float3 WorldPosition_NoOffsets;
|
|
|
|
/**
|
|
* Interpolated worldspace position of this pixel, not including any world position offset or displacement.
|
|
* Only valid if shader is compiled with NEEDS_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS, otherwise just contains 0
|
|
*/
|
|
float3 WorldPosition_NoOffsets_CamRelative;
|
|
|
|
/** Offset applied to the lighting position for translucency, used to break up aliasing artifacts. */
|
|
half3 LightingPositionOffset;
|
|
|
|
float AOMaterialMask;
|
|
|
|
#if LIGHTMAP_UV_ACCESS
|
|
float2 LightmapUVs;
|
|
#endif
|
|
|
|
#if USE_INSTANCING
|
|
half4 PerInstanceParams;
|
|
#endif
|
|
|
|
// Index into View.PrimitiveSceneData
|
|
uint PrimitiveId;
|
|
|
|
/** Per-particle properties. Only valid for particle vertex factories. */
|
|
FMaterialParticleParameters Particle;
|
|
|
|
#if (ES2_PROFILE || ES3_1_PROFILE)
|
|
float4 LayerWeights;
|
|
#endif
|
|
|
|
#if TEX_COORD_SCALE_ANALYSIS
|
|
/** Parameters used by the MaterialTexCoordScales shader. */
|
|
FTexCoordScalesParams TexCoordScalesParams;
|
|
#endif
|
|
|
|
#if POST_PROCESS_MATERIAL && (FEATURE_LEVEL <= FEATURE_LEVEL_ES3_1)
|
|
/** Used in mobile custom pp material to preserve original SceneColor Alpha */
|
|
half BackupSceneColorAlpha;
|
|
#endif
|
|
|
|
#if COMPILER_HLSL
|
|
// Workaround for "error X3067: 'GetObjectWorldPosition': ambiguous function call"
|
|
// Which happens when FMaterialPixelParameters and FMaterialVertexParameters have the same number of floats with the HLSL compiler ver 9.29.952.3111
|
|
// Function overload resolution appears to identify types based on how many floats / ints / etc they contain
|
|
uint Dummy;
|
|
#endif
|
|
|
|
FTexCoordScalesParams TexCoordScalesParams;
|
|
|
|
float3 WorldTangent;
|
|
};
|
|
|
|
float4 View_TemporalAAParams;
|
|
|
|
//To be moved into InitializeExpressions
|
|
float UE_Material_PerFrameScalarExpression0;
|
|
float UE_Material_PerFrameScalarExpression1;
|
|
|
|
MaterialFloat3 ReflectionAboutCustomWorldNormal( FMaterialPixelParameters Parameters, MaterialFloat3 WorldNormal, bool bNormalizeInputNormal )
|
|
{
|
|
if( bNormalizeInputNormal )
|
|
{
|
|
WorldNormal = normalize( WorldNormal );
|
|
}
|
|
|
|
return -Parameters.CameraVector + WorldNormal * dot( WorldNormal, Parameters.CameraVector ) * 2.0;
|
|
}
|
|
MaterialFloat4 ProcessMaterialColorTextureLookup(MaterialFloat4 TextureValue)
|
|
{
|
|
#if (ES2_PROFILE || ES3_1_PROFILE) && !METAL_PROFILE // Metal supports sRGB textures
|
|
#if MOBILE_EMULATION
|
|
if( View.MobilePreviewMode > 0.5f)
|
|
{
|
|
// undo HW srgb->lin
|
|
TextureValue.rgb = pow(TextureValue.rgb, 1.0f / 2.2f); // TODO: replace with a more accurate lin -> sRGB conversion.
|
|
}
|
|
#endif
|
|
|
|
// sRGB read approximation
|
|
TextureValue.rgb *= TextureValue.rgb;
|
|
#endif
|
|
return TextureValue;
|
|
}
|
|
float ProcessMaterialLinearGreyscaleTextureLookup( float TextureValue )
|
|
{
|
|
return TextureValue;
|
|
}
|
|
|
|
#if DECAL_PRIMITIVE
|
|
|
|
float3 TransformTangentNormalToWorld( in FMaterialPixelParameters Parameters, float3 TangentNormal )
|
|
{
|
|
// To transform the normals use tranpose(Inverse(DecalToWorld)) = transpose(WorldToDecal)
|
|
// But we want to only rotate the normals (we don't want to non-uniformaly scale them).
|
|
// We assume the matrix is only a scale and rotation, and we remove non-uniform scale:
|
|
float3 lengthSqr = { length2( DecalToWorld._m00_m01_m02 ),
|
|
length2( DecalToWorld._m10_m11_m12 ),
|
|
length2( DecalToWorld._m20_m21_m22 ) };
|
|
|
|
float3 scale = rsqrt( lengthSqr );
|
|
|
|
// Pre-multiply by the inverse of the non-uniform scale in DecalToWorld
|
|
float4 ScaledNormal = float4( -TangentNormal.z * scale.x, TangentNormal.y * scale.y, TangentNormal.x * scale.z, 0.f );
|
|
|
|
// Compute the normal
|
|
return normalize( mul( ScaledNormal, DecalToWorld ).xyz );
|
|
}
|
|
|
|
#else //DECAL_PRIMITIVE
|
|
|
|
float3 TransformTangentNormalToWorld( in FMaterialPixelParameters Parameters, float3 TangentNormal )
|
|
{
|
|
return TangentNormal;// normalize( float3( TransformTangentVectorToWorld( Parameters.TangentToWorld, TangentNormal ) ) );
|
|
}
|
|
|
|
#endif //DECAL_PRIMITIVE
|
|
|
|
//These 2 are the Unity Normal unpacking functions
|
|
/*fixed3 UnpackNormalmapRGorAG( fixed4 packednormal )
|
|
{
|
|
// This do the trick
|
|
packednormal.x *= packednormal.w;
|
|
|
|
fixed3 normal;
|
|
normal.xy = packednormal.xy * 2 - 1;
|
|
normal.z = sqrt( 1 - saturate( dot( normal.xy, normal.xy ) ) );
|
|
return normal;
|
|
}
|
|
inline fixed3 UnpackNormal( fixed4 packednormal )
|
|
{
|
|
#if defined(UNITY_NO_DXT5nm)
|
|
return packednormal.xyz * 2 - 1;
|
|
#else
|
|
return UnpackNormalmapRGorAG( packednormal );
|
|
#endif
|
|
}*/
|
|
void swap( inout float x, inout float y )
|
|
{
|
|
float temp = x;
|
|
x = y;
|
|
y = temp;
|
|
}
|
|
MaterialFloat4 UnpackNormalMap( MaterialFloat4 TextureSample )
|
|
{
|
|
float3 Unpacked = UnpackNormal( TextureSample );
|
|
//This is needed for textures that don't have flip Green channel on
|
|
Unpacked.x *= -1;
|
|
swap( Unpacked.x, Unpacked.y );
|
|
return MaterialFloat4( Unpacked.xy, Unpacked.z, 1.0f );
|
|
}
|
|
SamplerState GetMaterialSharedSampler(SamplerState TextureSampler, SamplerState SharedSampler)
|
|
{
|
|
return TextureSampler;
|
|
}
|
|
float3 GetActorWorldPosition()
|
|
{
|
|
return UNITY_MATRIX_M[ 3 ];
|
|
}
|
|
float3 GetActorWorldPosition( uint PrimitiveId )
|
|
{
|
|
return UNITY_MATRIX_M[ 3 ];
|
|
}
|
|
MaterialFloat4 Texture2DSample(Texture2D Tex, SamplerState Sampler, float2 UV)
|
|
{
|
|
#if COMPUTESHADER
|
|
return tex2D( Tex, UV, 0);
|
|
#else
|
|
#if HDRP
|
|
return SAMPLE_TEXTURE2D(Tex, Sampler, UV);
|
|
#else
|
|
return tex2D(Tex, UV);
|
|
#endif
|
|
#endif
|
|
}
|
|
MaterialFloat4 Texture2DSampleGrad( Texture2D Tex, SamplerState Sampler, float2 UV, MaterialFloat2 DDX, MaterialFloat2 DDY )
|
|
{
|
|
#if HDRP
|
|
return SAMPLE_TEXTURE2D( Tex, Sampler, UV );// , DDX, DDY );
|
|
#else
|
|
return tex2Dgrad( Tex, UV, DDX, DDY );
|
|
#endif
|
|
}
|
|
MaterialFloat4 Texture2DSampleLevel( Texture2D Tex, SamplerState Sampler, float2 UV, MaterialFloat Mip )
|
|
{
|
|
#if HDRP
|
|
return SAMPLE_TEXTURE2D_LOD( Tex, Sampler, UV, Mip );
|
|
#else
|
|
//tex2Dlod( Tex, float3( UV, Mip ) );
|
|
return tex2D( Tex, float3( UV, Mip ) );
|
|
#endif
|
|
}
|
|
MaterialFloat4 TextureCubeSample( TextureCube Tex, SamplerState Sampler, float3 UV)
|
|
{
|
|
//#if COMPUTESHADER
|
|
// return Tex.SampleLevel(Sampler, UV, 0);
|
|
//#else
|
|
#if HDRP
|
|
return SAMPLE_TEXTURECUBE(Tex, Sampler, UV);
|
|
#else
|
|
return texCUBE(Tex, UV);
|
|
#endif
|
|
//#endif
|
|
}
|
|
MaterialFloat4 TextureCubeSampleBias( TextureCube Tex, SamplerState Sampler, float3 UV, MaterialFloat MipBias )
|
|
{
|
|
#if USE_FORCE_TEXTURE_MIP
|
|
return texCUBEbias( Tex, float4( UV, 0 ) );
|
|
#else
|
|
#if HDRP
|
|
return SAMPLE_TEXTURECUBE_BIAS( Tex, Sampler, UV, MipBias );
|
|
#else
|
|
return texCUBEbias( Tex, float4( UV, MipBias ) );
|
|
#endif
|
|
#endif
|
|
}
|
|
MaterialFloat4 TextureCubeSampleLevel( TextureCube Tex, SamplerState Sampler, float3 UV, MaterialFloat Mip )
|
|
{
|
|
#if HDRP
|
|
return SAMPLE_TEXTURECUBE_LOD( Tex, Sampler, UV, Mip );
|
|
#else
|
|
return texCUBElod( Tex, float4(UV, Mip) );
|
|
#endif
|
|
}
|
|
float4 Texture2DSampleBias( Texture2D Tex, SamplerState Sampler, float2 UV, float MipBias )
|
|
{
|
|
#if HDRP
|
|
return SAMPLE_TEXTURE2D_BIAS( Tex, Sampler, UV, MipBias );
|
|
#else
|
|
return tex2Dbias( Tex, float4( UV, 0, MipBias ) );
|
|
#endif
|
|
}
|
|
half3 GetMaterialNormalRaw(FPixelMaterialInputs PixelMaterialInputs)
|
|
{
|
|
return PixelMaterialInputs.Normal;
|
|
}
|
|
|
|
half3 GetMaterialNormal(FMaterialPixelParameters Parameters, FPixelMaterialInputs PixelMaterialInputs)
|
|
{
|
|
half3 RetNormal;
|
|
|
|
RetNormal = GetMaterialNormalRaw(PixelMaterialInputs);
|
|
|
|
#if (USE_EDITOR_SHADERS && !(ES2_PROFILE || ES3_1_PROFILE || ESDEFERRED_PROFILE)) || MOBILE_EMULATION
|
|
{
|
|
// this feature is only needed for development/editor - we can compile it out for a shipping build (see r.CompileShadersForDevelopment cvar help)
|
|
half3 OverrideNormal = View.NormalOverrideParameter.xyz;
|
|
|
|
#if !MATERIAL_TANGENTSPACENORMAL
|
|
OverrideNormal = Parameters.TangentToWorld[2] * (1 - View.NormalOverrideParameter.w);
|
|
#endif
|
|
|
|
RetNormal = RetNormal * View.NormalOverrideParameter.w + OverrideNormal;
|
|
}
|
|
#endif
|
|
|
|
return RetNormal;
|
|
}
|
|
MaterialFloat PositiveClampedPow( MaterialFloat X, MaterialFloat Y )
|
|
{
|
|
return pow( max( X, 0.0f ), Y );
|
|
}
|
|
MaterialFloat2 PositiveClampedPow( MaterialFloat2 X, MaterialFloat2 Y )
|
|
{
|
|
return pow( max( X, MaterialFloat2( 0.0f, 0.0f ) ), Y );
|
|
}
|
|
MaterialFloat3 PositiveClampedPow( MaterialFloat3 X, MaterialFloat3 Y )
|
|
{
|
|
return pow( max( X, MaterialFloat3( 0.0f, 0.0f, 0.0f ) ), Y );
|
|
}
|
|
MaterialFloat4 PositiveClampedPow( MaterialFloat4 X, MaterialFloat4 Y )
|
|
{
|
|
return pow( max( X, MaterialFloat4( 0.0f, 0.0f, 0.0f, 0.0f ) ), Y );
|
|
}
|
|
|
|
/** Get the per-instance random value when instancing */
|
|
float GetPerInstanceRandom(FMaterialPixelParameters Parameters)
|
|
{
|
|
#if USE_INSTANCING
|
|
return Parameters.PerInstanceParams.x;
|
|
#else
|
|
return 0.5;
|
|
#endif
|
|
}
|
|
float3 GetObjectWorldPosition( FMaterialPixelParameters Parameters )
|
|
{
|
|
//TODO
|
|
//return Primitive.ObjectWorldPositionAndRadius.xyz;
|
|
return float3( 0, 0, 0 );
|
|
}
|
|
|
|
MaterialFloat ProcessMaterialGreyscaleTextureLookup( MaterialFloat TextureValue )
|
|
{
|
|
#if (ES2_PROFILE || ES3_1_PROFILE) && !METAL_PROFILE // Metal supports R8 sRGB
|
|
#if MOBILE_EMULATION
|
|
if ( View.MobilePreviewMode > 0.5f )
|
|
{
|
|
// undo HW srgb->lin
|
|
TextureValue = pow( TextureValue, 1.0f / 2.2f ); // TODO: replace with a more accurate lin -> sRGB conversion.
|
|
}
|
|
#endif
|
|
// sRGB read approximation
|
|
TextureValue *= TextureValue;
|
|
#endif
|
|
return TextureValue;
|
|
}
|
|
float3 GetWorldPosition_NoMaterialOffsets( FMaterialPixelParameters Parameters )
|
|
{
|
|
return Parameters.WorldPosition_NoOffsets;
|
|
}
|
|
float3 GetWorldPosition( FMaterialPixelParameters Parameters )
|
|
{
|
|
return Parameters.AbsoluteWorldPosition;
|
|
}
|
|
MaterialFloat4 ProcessMaterialLinearColorTextureLookup( MaterialFloat4 TextureValue )
|
|
{
|
|
return TextureValue;
|
|
}
|
|
float StoreTexCoordScale( in out FTexCoordScalesParams Params, float2 UV, int TextureReferenceIndex )
|
|
{
|
|
/*float GPUScaleX = length( ddx( UV ) );
|
|
float GPUScaleY = length( ddy( UV ) );
|
|
|
|
if ( TextureReferenceIndex >= 0 && TextureReferenceIndex < 32 )
|
|
{
|
|
float OneOverCPUScale = OneOverCPUTexCoordScales[ TextureReferenceIndex / 4 ][ TextureReferenceIndex % 4 ];
|
|
|
|
int TexCoordIndex = TexCoordIndices[ TextureReferenceIndex / 4 ][ TextureReferenceIndex % 4 ];
|
|
|
|
float GPUScale = min( GPUScaleX * GetComponent( Params.OneOverDDU, TexCoordIndex ), GPUScaleY * GetComponent( Params.OneOverDDV, TexCoordIndex ) );
|
|
|
|
|
|
const bool bUpdateMinMax = ( OneOverCPUScale > 0 && ( AnalysisParams.x == -1 || AnalysisParams.x == TextureReferenceIndex ) );
|
|
Params.MinScale = bUpdateMinMax ? min( Params.MinScale, GPUScale * OneOverCPUScale ) : Params.MinScale;
|
|
Params.MaxScale = bUpdateMinMax ? max( Params.MaxScale, GPUScale * OneOverCPUScale ) : Params.MaxScale;
|
|
|
|
|
|
const bool bUpdateScale = ( AnalysisParams.y && Params.PixelPosition.x / 32 == TextureReferenceIndex / 4 );
|
|
Params.ScalesPerIndex[ TextureReferenceIndex % 4 ] = bUpdateScale ? min( Params.ScalesPerIndex[ TextureReferenceIndex % 4 ], GPUScale ) : Params.ScalesPerIndex[ TextureReferenceIndex % 4 ];
|
|
}*/
|
|
return 1.f;
|
|
}
|
|
float StoreTexSample( in out FTexCoordScalesParams Params, float4 C, int TextureReferenceIndex )
|
|
{
|
|
//Params.TexSample = AnalysisParams.x == TextureReferenceIndex ? lerp( .4f, 1.f, saturate( Luminance( C.rgb ) ) ) : Params.TexSample;
|
|
|
|
return 1.f;
|
|
}
|
|
float3 RotateAboutAxis( float4 NormalizedRotationAxisAndAngle, float3 PositionOnAxis, float3 Position )
|
|
{
|
|
|
|
float3 ClosestPointOnAxis = PositionOnAxis + NormalizedRotationAxisAndAngle.xyz * dot( NormalizedRotationAxisAndAngle.xyz, Position - PositionOnAxis );
|
|
|
|
float3 UAxis = Position - ClosestPointOnAxis;
|
|
float3 VAxis = cross( NormalizedRotationAxisAndAngle.xyz, UAxis );
|
|
float CosAngle;
|
|
float SinAngle;
|
|
sincos( NormalizedRotationAxisAndAngle.w, SinAngle, CosAngle );
|
|
|
|
float3 R = UAxis * CosAngle + VAxis * SinAngle;
|
|
|
|
float3 RotatedPosition = ClosestPointOnAxis + R;
|
|
|
|
return RotatedPosition - Position;
|
|
}
|
|
float2 SvPositionToBufferUV( float4 SvPosition )
|
|
{
|
|
return SvPosition.xy * View_BufferSizeAndInvSize.zw;
|
|
}
|
|
float2 GetSceneTextureUV( FMaterialPixelParameters Parameters )
|
|
{
|
|
return SvPositionToBufferUV( Parameters.SvPosition );
|
|
}
|
|
MaterialFloat UnMirror( MaterialFloat Coordinate, FMaterialPixelParameters Parameters )
|
|
{
|
|
return ( ( Coordinate )*( Parameters.UnMirrored )*0.5 + 0.5 );
|
|
}
|
|
MaterialFloat2 UnMirrorU( MaterialFloat2 UV, FMaterialPixelParameters Parameters )
|
|
{
|
|
return MaterialFloat2( UnMirror( UV.x, Parameters ), UV.y );
|
|
}
|
|
MaterialFloat2 UnMirrorV( MaterialFloat2 UV, FMaterialPixelParameters Parameters )
|
|
{
|
|
return MaterialFloat2( UV.x, UnMirror( UV.y, Parameters ) );
|
|
}
|
|
MaterialFloat2 UnMirrorUV( MaterialFloat2 UV, FMaterialPixelParameters Parameters )
|
|
{
|
|
return MaterialFloat2( UnMirror( UV.x, Parameters ), UnMirror( UV.y, Parameters ) );
|
|
}
|
|
float4 GetScreenPosition( FMaterialPixelParameters Parameters )
|
|
{
|
|
return Parameters.ScreenPosition;
|
|
}
|
|
float GetPixelDepth(FMaterialPixelParameters Parameters)
|
|
{
|
|
//FLATTEN
|
|
//if (View.ViewToClip[3][3] < 1.0f)
|
|
//{
|
|
// Perspective
|
|
return GetScreenPosition(Parameters).w;
|
|
//}
|
|
//else
|
|
//{
|
|
// // Ortho
|
|
// return ConvertFromDeviceZ(GetScreenPosition(Parameters).z);
|
|
//}
|
|
}
|
|
uint Mod( uint a, uint b )
|
|
{
|
|
|
|
return a % b;
|
|
}
|
|
|
|
uint2 Mod( uint2 a, uint2 b )
|
|
{
|
|
|
|
return a % b;
|
|
}
|
|
|
|
uint3 Mod( uint3 a, uint3 b )
|
|
{
|
|
|
|
return a % b;
|
|
}
|
|
float CalcSceneDepth( float2 ScreenUV )
|
|
{
|
|
return 0.0f;
|
|
}
|
|
float CalcSceneDepth( uint2 PixelPos )
|
|
{
|
|
return 0.0f;
|
|
}
|
|
float2 ScreenPositionToBufferUV( float4 ScreenPosition )
|
|
{
|
|
float4 View_ScreenPositionScaleBias = float4( 1, 1, 0, 0 );//TODO
|
|
|
|
return float2( ScreenPosition.xy / ScreenPosition.w * View_ScreenPositionScaleBias.xy + View_ScreenPositionScaleBias.wz );
|
|
}
|
|
float2 ScreenAlignedPosition( float4 ScreenPosition )
|
|
{
|
|
return float2 ( ScreenPositionToBufferUV( ScreenPosition ) );
|
|
}
|
|
float4 VoronoiCompare(float4 minval, float3 candidate, float3 offset, bool bDistanceOnly)
|
|
{
|
|
if (bDistanceOnly)
|
|
{
|
|
return float4( 0, 0, 0, min(minval.w, dot(offset, offset)) );
|
|
}
|
|
else
|
|
{
|
|
float newdist = dot(offset, offset);
|
|
return newdist > minval.w ? minval : float4( candidate, newdist );
|
|
}
|
|
}
|
|
|
|
uint3 Rand3DPCG16(int3 p)
|
|
{
|
|
// taking a signed int then reinterpreting as unsigned gives good behavior for negatives
|
|
uint3 v = uint3( p );
|
|
|
|
// Linear congruential step. These LCG constants are from Numerical Recipies
|
|
// For additional #'s, PCG would do multiple LCG steps and scramble each on output
|
|
// So v here is the RNG state
|
|
v = v * 1664525u + 1013904223u;
|
|
|
|
// PCG uses xorshift for the final shuffle, but it is expensive (and cheap
|
|
// versions of xorshift have visible artifacts). Instead, use simple MAD Feistel steps
|
|
//
|
|
// Feistel ciphers divide the state into separate parts (usually by bits)
|
|
// then apply a series of permutation steps one part at a time. The permutations
|
|
// use a reversible operation (usually ^) to part being updated with the result of
|
|
// a permutation function on the other parts and the key.
|
|
//
|
|
// In this case, I'm using v.x, v.y and v.z as the parts, using + instead of ^ for
|
|
// the combination function, and just multiplying the other two parts (no key) for
|
|
// the permutation function.
|
|
//
|
|
// That gives a simple mad per round.
|
|
v.x += v.y*v.z;
|
|
v.y += v.z*v.x;
|
|
v.z += v.x*v.y;
|
|
v.x += v.y*v.z;
|
|
v.y += v.z*v.x;
|
|
v.z += v.x*v.y;
|
|
|
|
// only top 16 bits are well shuffled
|
|
return v >> 16u;
|
|
}
|
|
float3 VoronoiCornerSample(float3 pos, int Quality)
|
|
{
|
|
// random values in [-0.5, 0.5]
|
|
float3 noise = float3( Rand3DPCG16(int3( pos )) ) / 0xffff - 0.5;
|
|
|
|
// quality level 1 or 2: searches a 2x2x2 neighborhood with points distributed on a sphere
|
|
// scale factor to guarantee jittered points will be found within a 2x2x2 search
|
|
if (Quality <= 2)
|
|
{
|
|
return normalize(noise) * 0.2588;
|
|
}
|
|
|
|
// quality level 3: searches a 3x3x3 neighborhood with points distributed on a sphere
|
|
// scale factor to guarantee jittered points will be found within a 3x3x3 search
|
|
if (Quality == 3)
|
|
{
|
|
return normalize(noise) * 0.3090;
|
|
}
|
|
|
|
// quality level 4: jitter to anywhere in the cell, needs 4x4x4 search
|
|
return noise;
|
|
}
|
|
float3 NoiseTileWrap(float3 v, bool bTiling, float RepeatSize)
|
|
{
|
|
return bTiling ? ( frac(v / RepeatSize) * RepeatSize ) : v;
|
|
}
|
|
// 220 instruction Worley noise
|
|
float4 VoronoiNoise3D_ALU(float3 v, int Quality, bool bTiling, float RepeatSize, bool bDistanceOnly)
|
|
{
|
|
float3 fv = frac(v), fv2 = frac(v + 0.5);
|
|
float3 iv = floor(v), iv2 = floor(v + 0.5);
|
|
|
|
// with initial minimum distance = infinity (or at least bigger than 4), first min is optimized away
|
|
float4 mindist = float4( 0, 0, 0, 100 );
|
|
float3 p, offset;
|
|
|
|
// quality level 3: do a 3x3x3 search
|
|
if (Quality == 3)
|
|
{
|
|
UNROLL for (offset.x = -1; offset.x <= 1; ++offset.x)
|
|
{
|
|
UNROLL for (offset.y = -1; offset.y <= 1; ++offset.y)
|
|
{
|
|
UNROLL for (offset.z = -1; offset.z <= 1; ++offset.z)
|
|
{
|
|
p = offset + VoronoiCornerSample(NoiseTileWrap(iv2 + offset, bTiling, RepeatSize), Quality);
|
|
mindist = VoronoiCompare(mindist, iv2 + p, fv2 - p, bDistanceOnly);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// everybody else searches a base 2x2x2 neighborhood
|
|
else
|
|
{
|
|
UNROLL for (offset.x = 0; offset.x <= 1; ++offset.x)
|
|
{
|
|
UNROLL for (offset.y = 0; offset.y <= 1; ++offset.y)
|
|
{
|
|
UNROLL for (offset.z = 0; offset.z <= 1; ++offset.z)
|
|
{
|
|
p = offset + VoronoiCornerSample(NoiseTileWrap(iv + offset, bTiling, RepeatSize), Quality);
|
|
mindist = VoronoiCompare(mindist, iv + p, fv - p, bDistanceOnly);
|
|
|
|
// quality level 2, do extra set of points, offset by half a cell
|
|
if (Quality == 2)
|
|
{
|
|
// 467 is just an offset to a different area in the random number field to avoid similar neighbor artifacts
|
|
p = offset + VoronoiCornerSample(NoiseTileWrap(iv2 + offset, bTiling, RepeatSize) + 467, Quality);
|
|
mindist = VoronoiCompare(mindist, iv2 + p, fv2 - p, bDistanceOnly);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// quality level 4: add extra sets of four cells in each direction
|
|
if (Quality >= 4)
|
|
{
|
|
UNROLL for (offset.x = -1; offset.x <= 2; offset.x += 3)
|
|
{
|
|
UNROLL for (offset.y = 0; offset.y <= 1; ++offset.y)
|
|
{
|
|
UNROLL for (offset.z = 0; offset.z <= 1; ++offset.z)
|
|
{
|
|
// along x axis
|
|
p = offset.xyz + VoronoiCornerSample(NoiseTileWrap(iv + offset.xyz, bTiling, RepeatSize), Quality);
|
|
mindist = VoronoiCompare(mindist, iv + p, fv - p, bDistanceOnly);
|
|
|
|
// along y axis
|
|
p = offset.yzx + VoronoiCornerSample(NoiseTileWrap(iv + offset.yzx, bTiling, RepeatSize), Quality);
|
|
mindist = VoronoiCompare(mindist, iv + p, fv - p, bDistanceOnly);
|
|
|
|
// along z axis
|
|
p = offset.zxy + VoronoiCornerSample(NoiseTileWrap(iv + offset.zxy, bTiling, RepeatSize), Quality);
|
|
mindist = VoronoiCompare(mindist, iv + p, fv - p, bDistanceOnly);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// transform squared distance to real distance
|
|
return float4( mindist.xyz, sqrt(mindist.w) );
|
|
}
|
|
float Noise3D_Multiplexer(int Function, float3 Position, int Quality, bool bTiling, uint RepeatSize)
|
|
{
|
|
// verified, HLSL compiled out the switch if Function is a constant
|
|
//switch (Function)
|
|
//{
|
|
// case 0:
|
|
// return SimplexNoise3D_TEX(Position);
|
|
// case 1:
|
|
// return GradientNoise3D_TEX(Position, bTiling, RepeatSize);
|
|
// case 2:
|
|
// return FastGradientPerlinNoise3D_TEX(Position);
|
|
// case 3:
|
|
// return GradientNoise3D_ALU(Position, bTiling, RepeatSize);
|
|
// case 4:
|
|
// return ValueNoise3D_ALU(Position, bTiling, RepeatSize);
|
|
//default:
|
|
return VoronoiNoise3D_ALU(Position, Quality, bTiling, RepeatSize, true).w * 2. - 1.;
|
|
//}
|
|
//return 0;
|
|
}
|
|
|
|
// @param LevelScale usually 2 but higher values allow efficient use of few levels
|
|
// @return in user defined range (OutputMin..OutputMax)
|
|
MaterialFloat MaterialExpressionNoise(float3 Position, float Scale, int Quality, int Function, bool bTurbulence, uint Levels, float OutputMin, float OutputMax, float LevelScale, float FilterWidth, bool bTiling, float RepeatSize)
|
|
{
|
|
Position *= Scale;
|
|
FilterWidth *= Scale;
|
|
|
|
float Out = 0.0f;
|
|
float OutScale = 1.0f;
|
|
float InvLevelScale = 1.0f / LevelScale;
|
|
|
|
LOOP for (uint i = 0; i < Levels; ++i)
|
|
{
|
|
// fade out noise level that are too high frequent (not done through dynamic branching as it usually requires gradient instructions)
|
|
OutScale *= saturate(1.0 - FilterWidth);
|
|
|
|
if (bTurbulence)
|
|
{
|
|
Out += abs(Noise3D_Multiplexer(Function, Position, Quality, bTiling, RepeatSize)) * OutScale;
|
|
}
|
|
else
|
|
{
|
|
Out += Noise3D_Multiplexer(Function, Position, Quality, bTiling, RepeatSize) * OutScale;
|
|
}
|
|
|
|
Position *= LevelScale;
|
|
RepeatSize *= LevelScale;
|
|
OutScale *= InvLevelScale;
|
|
FilterWidth *= LevelScale;
|
|
}
|
|
|
|
if (!bTurbulence)
|
|
{
|
|
// bring -1..1 to 0..1 range
|
|
Out = Out * 0.5f + 0.5f;
|
|
}
|
|
|
|
// Out is in 0..1 range
|
|
return lerp(OutputMin, OutputMax, Out);
|
|
}
|
|
|
|
#define NUM_CUSTOM_PRIMITIVE_DATA 8 // Num float4s used for custom data. Must match FCustomPrimitiveData::NumCustomPrimitiveDataFloat4s in SceneTypes.h
|
|
|
|
struct FPrimitiveSceneData
|
|
{
|
|
float4x4 LocalToWorld;
|
|
float4 InvNonUniformScaleAndDeterminantSign;
|
|
float4 ObjectWorldPositionAndRadius;
|
|
float4x4 WorldToLocal;
|
|
float4x4 PreviousLocalToWorld;
|
|
float4x4 PreviousWorldToLocal;
|
|
float3 ActorWorldPosition;
|
|
float UseSingleSampleShadowFromStationaryLights;
|
|
float3 ObjectBounds;
|
|
float LpvBiasMultiplier;
|
|
float DecalReceiverMask;
|
|
float PerObjectGBufferData;
|
|
float UseVolumetricLightmapShadowFromStationaryLights;
|
|
float DrawsVelocity;
|
|
float4 ObjectOrientation;
|
|
float4 NonUniformScale;
|
|
float3 LocalObjectBoundsMin;
|
|
uint LightingChannelMask;
|
|
float3 LocalObjectBoundsMax;
|
|
uint LightmapDataIndex;
|
|
float3 PreSkinnedLocalBoundsMin;
|
|
int SingleCaptureIndex;
|
|
float3 PreSkinnedLocalBoundsMax;
|
|
uint OutputVelocity;
|
|
float4 CustomPrimitiveData[ NUM_CUSTOM_PRIMITIVE_DATA ];
|
|
};
|
|
|
|
// Stride of a single primitive's data in float4's, must match C++
|
|
#define PRIMITIVE_SCENE_DATA_STRIDE 35
|
|
|
|
// Fetch from scene primitive buffer
|
|
FPrimitiveSceneData GetPrimitiveData( uint PrimitiveId )
|
|
{
|
|
// Note: layout must match FPrimitiveSceneShaderData in C++
|
|
// Relying on optimizer to remove unused loads
|
|
|
|
FPrimitiveSceneData PrimitiveData;
|
|
uint PrimitiveBaseOffset = PrimitiveId * PRIMITIVE_SCENE_DATA_STRIDE;
|
|
PrimitiveData.LocalToWorld[ 0 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 0 ];
|
|
PrimitiveData.LocalToWorld[ 1 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 1 ];
|
|
PrimitiveData.LocalToWorld[ 2 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 2 ];
|
|
PrimitiveData.LocalToWorld[ 3 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 3 ];
|
|
|
|
PrimitiveData.InvNonUniformScaleAndDeterminantSign = View.PrimitiveSceneData[ PrimitiveBaseOffset + 4 ];
|
|
PrimitiveData.ObjectWorldPositionAndRadius = View.PrimitiveSceneData[ PrimitiveBaseOffset + 5 ];
|
|
|
|
PrimitiveData.WorldToLocal[ 0 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 6 ];
|
|
PrimitiveData.WorldToLocal[ 1 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 7 ];
|
|
PrimitiveData.WorldToLocal[ 2 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 8 ];
|
|
PrimitiveData.WorldToLocal[ 3 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 9 ];
|
|
|
|
PrimitiveData.PreviousLocalToWorld[ 0 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 10 ];
|
|
PrimitiveData.PreviousLocalToWorld[ 1 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 11 ];
|
|
PrimitiveData.PreviousLocalToWorld[ 2 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 12 ];
|
|
PrimitiveData.PreviousLocalToWorld[ 3 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 13 ];
|
|
|
|
PrimitiveData.PreviousWorldToLocal[ 0 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 14 ];
|
|
PrimitiveData.PreviousWorldToLocal[ 1 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 15 ];
|
|
PrimitiveData.PreviousWorldToLocal[ 2 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 16 ];
|
|
PrimitiveData.PreviousWorldToLocal[ 3 ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 17 ];
|
|
|
|
PrimitiveData.ActorWorldPosition = View.PrimitiveSceneData[ PrimitiveBaseOffset + 18 ].xyz;
|
|
PrimitiveData.UseSingleSampleShadowFromStationaryLights = View.PrimitiveSceneData[ PrimitiveBaseOffset + 18 ].w;
|
|
|
|
PrimitiveData.ObjectBounds = View.PrimitiveSceneData[ PrimitiveBaseOffset + 19 ].xyz;
|
|
PrimitiveData.LpvBiasMultiplier = View.PrimitiveSceneData[ PrimitiveBaseOffset + 19 ].w;
|
|
|
|
PrimitiveData.DecalReceiverMask = View.PrimitiveSceneData[ PrimitiveBaseOffset + 20 ].x;
|
|
PrimitiveData.PerObjectGBufferData = View.PrimitiveSceneData[ PrimitiveBaseOffset + 20 ].y;
|
|
PrimitiveData.UseVolumetricLightmapShadowFromStationaryLights = View.PrimitiveSceneData[ PrimitiveBaseOffset + 20 ].z;
|
|
PrimitiveData.DrawsVelocity = View.PrimitiveSceneData[ PrimitiveBaseOffset + 20 ].w;
|
|
|
|
PrimitiveData.ObjectOrientation = View.PrimitiveSceneData[ PrimitiveBaseOffset + 21 ];
|
|
PrimitiveData.NonUniformScale = View.PrimitiveSceneData[ PrimitiveBaseOffset + 22 ];
|
|
|
|
PrimitiveData.LocalObjectBoundsMin = View.PrimitiveSceneData[ PrimitiveBaseOffset + 23 ].xyz;
|
|
PrimitiveData.LightingChannelMask = asuint( View.PrimitiveSceneData[ PrimitiveBaseOffset + 23 ].w );
|
|
|
|
PrimitiveData.LocalObjectBoundsMax = View.PrimitiveSceneData[ PrimitiveBaseOffset + 24 ].xyz;
|
|
PrimitiveData.LightmapDataIndex = asuint( View.PrimitiveSceneData[ PrimitiveBaseOffset + 24 ].w );
|
|
|
|
PrimitiveData.PreSkinnedLocalBoundsMin = View.PrimitiveSceneData[ PrimitiveBaseOffset + 25 ].xyz;
|
|
PrimitiveData.SingleCaptureIndex = asuint( View.PrimitiveSceneData[ PrimitiveBaseOffset + 25 ].w );
|
|
|
|
PrimitiveData.PreSkinnedLocalBoundsMax = View.PrimitiveSceneData[ PrimitiveBaseOffset + 26 ].xyz;
|
|
PrimitiveData.OutputVelocity = asuint( View.PrimitiveSceneData[ PrimitiveBaseOffset + 26 ].w );
|
|
|
|
UNROLL
|
|
for( int i = 0; i < NUM_CUSTOM_PRIMITIVE_DATA; i++ )
|
|
{
|
|
PrimitiveData.CustomPrimitiveData[ i ] = View.PrimitiveSceneData[ PrimitiveBaseOffset + 27 + i ];
|
|
}
|
|
|
|
return PrimitiveData;
|
|
}
|
|
float2 SvPositionToViewportUV( float4 SvPosition )
|
|
{
|
|
// can be optimized from 2SUB+2MUL to 2MAD
|
|
float2 PixelPos = SvPosition.xy - View.ViewRectMin.xy;
|
|
|
|
return PixelPos.xy * View.ViewSizeAndInvSize.zw;
|
|
}
|
|
|
|
#if POST_PROCESS_MATERIAL
|
|
|
|
float2 GetPixelPosition( FMaterialPixelParameters Parameters )
|
|
{
|
|
return Parameters.SvPosition.xy - float2( PostProcessOutput_ViewportMin );
|
|
}
|
|
|
|
float2 GetViewportUV( FMaterialPixelParameters Parameters )
|
|
{
|
|
return GetPixelPosition( Parameters ) * PostProcessOutput_ViewportSizeInverse;
|
|
}
|
|
|
|
#else
|
|
|
|
float2 GetPixelPosition( FMaterialPixelParameters Parameters )
|
|
{
|
|
return Parameters.SvPosition.xy - float2( View.ViewRectMin.xy );
|
|
}
|
|
|
|
float2 GetViewportUV( FMaterialPixelParameters Parameters )
|
|
{
|
|
return SvPositionToViewportUV( Parameters.SvPosition );
|
|
}
|
|
|
|
#endif
|
|
float2 CalcScreenUVFromOffsetFraction( float4 ScreenPosition, float2 OffsetFraction )
|
|
{
|
|
float2 NDC = ScreenPosition.xy / ScreenPosition.w;
|
|
// Apply the offset in NDC space so that it is consistent regardless of scene color buffer size
|
|
// Clamp to valid area of the screen to avoid reading garbage
|
|
//@todo - soft clamp
|
|
float2 OffsetNDC = clamp( NDC + OffsetFraction * float2( 2, -2 ), -.999f, .999f );
|
|
return float2( OffsetNDC * ResolvedView.ScreenPositionScaleBias.xy + ResolvedView.ScreenPositionScaleBias.wz );
|
|
}
|
|
float3 DecodeSceneColorForMaterialNode( float2 ScreenUV )
|
|
{
|
|
#if !defined(SceneColorCopyTexture)
|
|
// Hit proxies rendering pass doesn't have access to valid render buffers
|
|
return float3( 0.0f, 0.0f, 0.0f );
|
|
#else
|
|
float4 EncodedSceneColor = Texture2DSample( SceneColorCopyTexture, SceneColorCopySampler, ScreenUV );
|
|
|
|
// Undo the function in EncodeSceneColorForMaterialNode
|
|
float3 SampledColor = pow( EncodedSceneColor.rgb, 4 ) * 10;
|
|
|
|
#if USE_PREEXPOSURE
|
|
SampledColor *= View.OneOverPreExposure.xxx;
|
|
#endif
|
|
|
|
return SampledColor;
|
|
#endif
|
|
}
|
|
|
|
float3 MaterialExpressionBlackBody( float Temp )
|
|
{
|
|
float u = ( 0.860117757f + 1.54118254e-4f * Temp + 1.28641212e-7f * Temp * Temp ) / ( 1.0f + 8.42420235e-4f * Temp + 7.08145163e-7f * Temp * Temp );
|
|
float v = ( 0.317398726f + 4.22806245e-5f * Temp + 4.20481691e-8f * Temp * Temp ) / ( 1.0f - 2.89741816e-5f * Temp + 1.61456053e-7f * Temp * Temp );
|
|
|
|
float x = 3 * u / ( 2 * u - 8 * v + 4 );
|
|
float y = 2 * v / ( 2 * u - 8 * v + 4 );
|
|
float z = 1 - x - y;
|
|
|
|
float Y = 1;
|
|
float X = Y / y * x;
|
|
float Z = Y / y * z;
|
|
|
|
float3x3 XYZtoRGB =
|
|
{
|
|
3.2404542, -1.5371385, -0.4985314,
|
|
-0.9692660, 1.8760108, 0.0415560,
|
|
0.0556434, -0.2040259, 1.0572252
|
|
};
|
|
|
|
return mul( XYZtoRGB, float3( X, Y, Z ) ) * pow( 0.0004 * Temp, 4 );
|
|
}
|
|
|
|
#define DDX ddx
|
|
#define DDY ddy
|
|
|
|
float GetPerInstanceFadeAmount( FMaterialPixelParameters Parameters )
|
|
{
|
|
#if USE_INSTANCING
|
|
return float( Parameters.PerInstanceParams.y );
|
|
#else
|
|
return float( 1.0 );
|
|
#endif
|
|
}
|
|
|
|
MaterialFloat3x3 GetLocalToWorld3x3( uint PrimitiveId )
|
|
{
|
|
//return (MaterialFloat3x3)GetPrimitiveData( PrimitiveId ).LocalToWorld;
|
|
return (MaterialFloat3x3)Primitive.LocalToWorld;
|
|
}
|
|
|
|
MaterialFloat3x3 GetLocalToWorld3x3()
|
|
{
|
|
return (MaterialFloat3x3)Primitive.LocalToWorld;
|
|
}
|
|
|
|
MaterialFloat3 TransformLocalVectorToWorld( FMaterialPixelParameters Parameters, MaterialFloat3 InLocalVector )
|
|
{
|
|
return mul( InLocalVector, GetLocalToWorld3x3( Parameters.PrimitiveId ) );
|
|
}
|
|
float3 TransformLocalPositionToWorld( FMaterialPixelParameters Parameters, float3 InLocalPosition )
|
|
{
|
|
//return mul( float4( InLocalPosition, 1 ), GetPrimitiveData( Parameters.PrimitiveId ).LocalToWorld ).xyz;
|
|
return mul( float4( InLocalPosition, 1 ), Primitive.LocalToWorld ).xyz;
|
|
}
|
|
|
|
bool GetShadowReplaceState()
|
|
{
|
|
#ifdef SHADOW_DEPTH_SHADER
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
float IsShadowDepthShader()
|
|
{
|
|
return GetShadowReplaceState() ? 1.0f : 0.0f;
|
|
}
|
|
|
|
float3 GetTranslatedWorldPosition( FMaterialPixelParameters Parameters )
|
|
{
|
|
return Parameters.WorldPosition_CamRelative;
|
|
}
|
|
float GetDistanceToNearestSurfaceGlobal( float3 Position )
|
|
{
|
|
//Distance to nearest DistanceField voxel I think ?
|
|
return 1000.0f;
|
|
}
|
|
float2 RotateScaleOffsetTexCoords( float2 InTexCoords, float4 InRotationScale, float2 InOffset )
|
|
{
|
|
return float2( dot( InTexCoords, InRotationScale.xy ), dot( InTexCoords, InRotationScale.zw ) ) + InOffset;
|
|
}
|
|
float2 GetTanHalfFieldOfView()
|
|
{
|
|
//@return tan(View.FieldOfViewWideAngles * .5)
|
|
//return float2( View.ClipToView[ 0 ][ 0 ], View.ClipToView[ 1 ][ 1 ] );
|
|
float EmulatedFOV = 3.14f / 2.0f;
|
|
return float2( EmulatedFOV, EmulatedFOV );
|
|
}
|
|
float Pow2( float x )
|
|
{
|
|
return x * x;
|
|
}
|
|
float3 HairAbsorptionToColor( float3 A, float B = 0.3f )
|
|
{
|
|
const float b2 = B * B;
|
|
const float b3 = B * b2;
|
|
const float b4 = b2 * b2;
|
|
const float b5 = B * b4;
|
|
const float D = ( 5.969f - 0.215f * B + 2.532f * b2 - 10.73f * b3 + 5.574f * b4 + 0.245f * b5 );
|
|
return exp( -sqrt( A ) * D );
|
|
}
|
|
float3 HairColorToAbsorption( float3 C, float B = 0.3f )
|
|
{
|
|
const float b2 = B * B;
|
|
const float b3 = B * b2;
|
|
const float b4 = b2 * b2;
|
|
const float b5 = B * b4;
|
|
const float D = ( 5.969f - 0.215f * B + 2.532f * b2 - 10.73f * b3 + 5.574f * b4 + 0.245f * b5 );
|
|
return Pow2( log( C ) / D );
|
|
}
|
|
float3 GetHairColorFromMelanin( float InMelanin, float InRedness, float3 InDyeColor )
|
|
{
|
|
InMelanin = saturate( InMelanin );
|
|
InRedness = saturate( InRedness );
|
|
const float Melanin = -log( max( 1 - InMelanin, 0.0001f ) );
|
|
const float Eumelanin = Melanin * ( 1 - InRedness );
|
|
const float Pheomelanin = Melanin * InRedness;
|
|
|
|
const float3 DyeAbsorption = HairColorToAbsorption( saturate( InDyeColor ) );
|
|
const float3 Absorption = Eumelanin * float3( 0.506f, 0.841f, 1.653f ) + Pheomelanin * float3( 0.343f, 0.733f, 1.924f );
|
|
|
|
return HairAbsorptionToColor( Absorption + DyeAbsorption );
|
|
}
|
|
|
|
float3 MaterialExpressionGetHairColorFromMelanin( float Melanin, float Redness, float3 DyeColor )
|
|
{
|
|
return GetHairColorFromMelanin( Melanin, Redness, DyeColor );
|
|
}
|
|
bool GetRayTracingQualitySwitch()
|
|
{
|
|
#if RAYHITGROUPSHADER
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
MaterialFloat2 GetDefaultSceneTextureUV( FMaterialPixelParameters Parameters, uint SceneTextureId )
|
|
{
|
|
return float2( 0, 0 );
|
|
}
|
|
float4 SceneTextureLookup( float2 UV, int SceneTextureIndex, bool bFiltered )
|
|
{
|
|
return float4( 0, 0, 0, 0 );
|
|
}
|
|
float3 MaterialExpressionAtmosphericLightVector( FMaterialPixelParameters Parameters )
|
|
{
|
|
#if MATERIAL_ATMOSPHERIC_FOG
|
|
return ResolvedView.AtmosphereLightDirection[ 0 ].xyz;
|
|
#else
|
|
return float3( 0.f, 0.f, 0.f );
|
|
#endif
|
|
}
|
|
|
|
#if TEX_COORD_SCALE_ANALYSIS
|
|
#define MaterialStoreTexCoordScale(Parameters, UV, TextureReferenceIndex) StoreTexCoordScale(Parameters.TexCoordScalesParams, UV, TextureReferenceIndex)
|
|
#define MaterialStoreTexSample(Parameters, UV, TextureReferenceIndex) StoreTexSample(Parameters.TexCoordScalesParams, UV, TextureReferenceIndex)
|
|
#else
|
|
#define MaterialStoreTexCoordScale(Parameters, UV, TextureReferenceIndex) 1.0f
|
|
#define MaterialStoreTexSample(Parameters, UV, TextureReferenceIndex) 1.0f
|
|
#endif |