Files
2026-07-13 13:13:17 +08:00

318 lines
8.6 KiB
HLSL

#include "shared/point.hlsl"
#include "shared/quat-functions.hlsl"
#include "shared/point-light.hlsl"
#include "shared/pbr.hlsl"
#include "shared/bias-functions.hlsl"
cbuffer Transforms : register(b0)
{
float4x4 CameraToClipSpace;
float4x4 ClipSpaceToCamera;
float4x4 WorldToCamera;
float4x4 CameraToWorld;
float4x4 WorldToClipSpace;
float4x4 ClipSpaceToWorld;
float4x4 ObjectToWorld;
float4x4 WorldToObject;
float4x4 ObjectToCamera;
float4x4 ObjectToClipSpace;
};
cbuffer Params : register(b1)
{
float4 Color;
float AlphaCutOff;
float UseFlatShading;
float SpecularAA;
float Scale;
float UsePointScale; //8
float ScaleFactorMode; //9
};
cbuffer FogParams : register(b2)
{
float4 FogColor;
float FogDistance;
float FogBias;
}
cbuffer PointLights : register(b3)
{
PointLight Lights[8];
int ActiveLightCount;
}
cbuffer PbrParams : register(b4)
{
float4 BaseColor;
float4 EmissiveColor;
float Roughness;
float Specular;
float Metal;
}
cbuffer CustomParams : register(b5)
{
float A;
float B;
float C;
float D;
float3 Offset;
float __padding;
float2 GainAndBias;
}
cbuffer Params : register(b6)
{
/*{FLOAT_PARAMS}*/
}
struct psInput
{
float2 texCoord : TEXCOORD;
float4 pixelPosition : SV_POSITION;
float3 worldPosition : POSITION;
float3x3 tbnToWorld : TBASIS;
float3 colorRGB : COLOR;
float fog : VPOS;
int pointIndex: Extra1;
};
struct psOutput
{
float4 Color : SV_Target0;
float4 Normal : SV_Target1;
};
sampler WrappedSampler : register(s0);
//sampler LinearSampler : register(s1);
sampler ClampedSampler : register(s1);
StructuredBuffer<PbrVertex> PbrVertices : register(t0);
StructuredBuffer<int3> FaceIndices : register(t1);
Texture2D<float4> BaseColorMap : register(t2);
Texture2D<float4> EmissiveColorMap : register(t3);
Texture2D<float4> RSMOMap : register(t4);
Texture2D<float4> NormalMap : register(t5);
TextureCube<float4> PrefilteredSpecular : register(t6);
Texture2D<float4> BRDFLookup : register(t7);
Texture2D<float4> Gradient : register(t8);
StructuredBuffer<Point> Points : register(t9);
psInput vsMain(uint id
: SV_VertexID)
{
psInput output;
uint faceCount, meshStride;
FaceIndices.GetDimensions(faceCount, meshStride);
int verticesPerInstance = faceCount * 3;
int faceIndex = (id % verticesPerInstance) / 3;
int faceVertexIndex = id % 3;
uint instanceCount, instanceStride;
Points.GetDimensions(instanceCount, instanceStride);
int instanceIndex = id / verticesPerInstance;
output.pointIndex = instanceIndex;
PbrVertex vertex = PbrVertices[FaceIndices[faceIndex][faceVertexIndex]];
float4 posInObject = float4(vertex.Position, 1);
// float resizeFromW = UseWForSize ? Points[instanceIndex].W : 1;
// float3 resizeFromStretch = UseStretch ? Points[instanceIndex].Stretch : 1;
float sizeFactor = ScaleFactorMode == 0
? 1
: (ScaleFactorMode == 1) ? Points[instanceIndex].FX1
: Points[instanceIndex].FX2;
float3 s = Scale * sizeFactor * (UsePointScale ? Points[instanceIndex].Scale : 1);
posInObject.xyz *= s; //(0, resizeFromW) * Scale * resizeFromStretch;
float4x4 orientationMatrix = transpose(qToMatrix(normalize(Points[instanceIndex].Rotation)));
posInObject = mul(float4(posInObject.xyz, 1), orientationMatrix);
posInObject += float4(Points[instanceIndex].Position, 0);
output.colorRGB = Points[instanceIndex].Color.rgb;
output.colorRGB = 1;
float4 posInClipSpace = mul(posInObject, ObjectToClipSpace);
output.pixelPosition = posInClipSpace;
// Texture Coordinates
float2 uv = vertex.TexCoord;
output.texCoord = float2(uv.x, 1 - uv.y);
// Pass tangent space basis vectors (for normal mapping).
float3x3 TBN = float3x3(vertex.Tangent, vertex.Bitangent, vertex.Normal);
TBN = mul(TBN, (float3x3)orientationMatrix);
TBN = mul(TBN, (float3x3)ObjectToWorld);
output.tbnToWorld = float3x3(
normalize(TBN._m00_m01_m02),
normalize(TBN._m10_m11_m12),
normalize(TBN._m20_m21_m22));
output.worldPosition = mul(posInObject, ObjectToWorld);
// Fog
if (FogDistance > 0)
{
float4 posInCamera = mul(posInObject, ObjectToCamera);
float fog = pow(saturate(-posInCamera.z / FogDistance), FogBias);
output.fog = fog;
}
return output;
}
//=== Global functions ==============================================
/*{GLOBALS}*/
//=== Additional Resources ==========================================
/*{RESOURCES(t10)}*/
//=== Field functions ===============================================
/*{FIELD_FUNCTIONS}*/
//-------------------------------------------------------------------
//-------------------------------------------------------------------
inline float4 GetField(float4 p) //.w:0 => distance :1 => Color
{
#ifndef USE_WORLDSPACE
//p.xyz = mul(float4(p.xyz, 1), WorldToObject).xyz;
#endif
float4 f = 1;
/*{FIELD_CALL}*/
return f;
}
float GetDistance(float3 p3)
{
return GetField(float4(p3.xyz, 0)).w;
}
//===================================================================
#include "shared/pbr-render.hlsl"
float3 ComputeNormal(psInput pin, float3x3 tbnToWorld)
{
float3 N;
if (UseFlatShading > 0.5)
{
// Flat shading: calculate geometric normal from world position derivatives
float3 dpdx = ddx(pin.worldPosition);
float3 dpdy = ddy(pin.worldPosition);
float3 geometricNormal = normalize(cross(dpdy, dpdx));
// Apply normal map details on top of flat normal
float4 normalMap = NormalMap.Sample(WrappedSampler, pin.texCoord);
float3 normalDetail = normalize(2.0 * normalMap.rgb - 1.0);
// Create TBN basis using geometric normal and derivatives
float3 T = normalize(dpdx);
float3 B = normalize(cross(geometricNormal, T));
T = cross(B, geometricNormal); // Reorthogonalize
float3x3 flatTBN = float3x3(T, B, geometricNormal);
// Apply normal map in flat shading tangent space
N = normalize(mul(normalDetail, flatTBN));
}
else
{
// Standard shading: use interpolated normals with normal mapping
float4 normalMap = NormalMap.Sample(WrappedSampler, pin.texCoord);
N = normalize(2.0 * normalMap.rgb - 1.0);
N = normalize(mul(N, tbnToWorld));
}
return N;
}
inline float3 AdjustRoughnessForSpecularAA(float baseRoughness)
{
// --- Specular anti-aliasing ---
// Compute normal variance using screen-space derivatives and increase roughness accordingly.
// This reduces specular aliasing on silhouettes and high-frequency normalmap regions.
float3 Nx = ddx(frag.N);
float3 Ny = ddy(frag.N);
float normalVar = max(0.0, max(dot(Nx, Nx), dot(Ny, Ny)));
normalVar *= SpecularAA;
// convert roughness -> alpha (energy-preserving), combine variance, then convert back
float baseR = saturate(baseRoughness);
float baseR2 = baseR * baseR;
float adjustedR = sqrt(baseR2 + normalVar);
return saturate(adjustedR);
}
float Biased(float f){return ApplyGainAndBias(f, GainAndBias);}
float4 SampleGradient(float f){return Gradient.SampleLevel(ClampedSampler, float2(f, 0.5), 0);}
//- DEFINES ------------------------------------
/*{defines}*/
//----------------------------------------------
void SetupFrag(psInput pin) {
float4 roughnessMetallicOcclusion = RSMOMap.Sample(WrappedSampler, pin.texCoord);
frag.Metalness = saturate(roughnessMetallicOcclusion.y + Metal);
frag.Occlusion = roughnessMetallicOcclusion.z;
frag.albedo = BaseColorMap.Sample(WrappedSampler, pin.texCoord);
frag.albedo.rgb *= pin.colorRGB;
frag.uv = pin.texCoord;
frag.N = ComputeNormal(pin, pin.tbnToWorld);
frag.Roughness = AdjustRoughnessForSpecularAA(roughnessMetallicOcclusion.x + Roughness, SpecularAA);
frag.fog = pin.fog;
frag.worldPosition = pin.worldPosition;
float4 eyePosition = mul(float4(0, 0, 0, 1), CameraToWorld);
frag.Lo = normalize(eyePosition.xyz - frag.worldPosition);
}
psOutput psMain(psInput pin) : SV_TARGET
{
psOutput output;
float4 c=float4(1,1,1,1);
{
//- METHOD -------------------------------------
/*{method}*/
//----------------------------------------------
}
// Alpha testing
if (AlphaCutOff > 0 && c.a < AlphaCutOff)
{
discard;
}
float3 worldNormal = frag.N;
// Output to color buffer (SV_Target0)
output.Color = c;
// Output to normal buffer (SV_Target1)
output.Normal = float4(worldNormal, 1.0);
return output;
}