Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

383 lines
13 KiB

//========== Copyright (c) Valve Corporation, All rights reserved. ==========//
//
// Purpose: Common code for tessellation
//
// $NoKeywords: $
//
//===========================================================================//
#ifndef TESSELLATION_VS_FXC_H_
#define TESSELLATION_VS_FXC_H_
#ifdef SHADER_MODEL_VS_3_0
#define TESSELLATION_MODE_ACC_PATCHES_EXTRA 1
#define TESSELLATION_MODE_ACC_PATCHES_REG 2
struct VS_INPUT
{
float2 UV : POSITION0; // Cartesian UV coordinates
float4 BasisU : TEXCOORD0; // BasisU ( precalculated Bernstein basis functions for U )
float4 BasisV : TEXCOORD1; // BasisV ( precalculated Bernstein basis functions for V )
float4 V0_TanU : POSITION1; // Superprim vertex 0
float4 V0_tc01 : TEXCOORD2;
float4 V0_tc23 : TEXCOORD3;
float4 V1_TanU : POSITION2; // Superprim vertex 1
float4 V1_tc01 : TEXCOORD4;
float4 V1_tc23 : TEXCOORD5;
float4 V2_TanU : POSITION3; // Superprim vertex 2
float4 V2_tc01 : TEXCOORD6;
float4 V2_tc23 : TEXCOORD7;
float4 V3_TanU : POSITION4; // Superprim vertex 3
float4 V3_tc01 : TEXCOORD8;
float4 V3_tc23 : TEXCOORD9;
float PatchID : TEXCOORD10; // ID for this patch
};
void LoadACCPatchPos( float patchIndex, out float3 Bez[16],
float flOneOverSubDHeight, sampler2D sampSubD )
{
float idx = ( patchIndex + 0.5 ) * flOneOverSubDHeight;
[unroll]
for (int i = 0; i < 4; i++)
{
float4 tmp[3];
tmp[0] = tex2Dlod( sampSubD, float4((i * 3 + 0.5) / 30, idx, 0, 0) );
tmp[1] = tex2Dlod( sampSubD, float4((i * 3 + 1.5) / 30, idx, 0, 0) );
tmp[2] = tex2Dlod( sampSubD, float4((i * 3 + 2.5) / 30, idx, 0, 0) );
Bez[4 * i + 0] = tmp[0].xyz;
Bez[4 * i + 1] = float3( tmp[0].w, tmp[1].xy );
Bez[4 * i + 2] = float3( tmp[1].zw, tmp[2].x );
Bez[4 * i + 3] = tmp[2].yzw;
}
}
void LoadACCPatchTan( float patchIndex, out float3 TanU[12], out float3 TanV[12],
float flOneOverSubDHeight, sampler2D sampSubD )
{
float idx = ( patchIndex + 0.5 ) * flOneOverSubDHeight;
// Tangents
[unroll]
for (int i = 0; i < 3; i++)
{
float4 tmp[3];
tmp[0] = tex2Dlod(sampSubD, float4((i * 3 + 0.5 + 12) / 30, idx, 0, 0));
tmp[1] = tex2Dlod(sampSubD, float4((i * 3 + 1.5 + 12) / 30, idx, 0, 0));
tmp[2] = tex2Dlod(sampSubD, float4((i * 3 + 2.5 + 12) / 30, idx, 0, 0));
TanU[4 * i + 0] = tmp[0].xyz;
TanU[4 * i + 1] = float3( tmp[0].w, tmp[1].xy );
TanU[4 * i + 2] = float3( tmp[1].zw, tmp[2].x );
TanU[4 * i + 3] = tmp[2].yzw;
}
// Tangents
[unroll]
for (int i = 0; i < 3; i++)
{
float4 tmp[3];
tmp[0] = tex2Dlod(sampSubD, float4((i * 3 + 0.5 + 21) / 30, idx, 0, 0));
tmp[1] = tex2Dlod(sampSubD, float4((i * 3 + 1.5 + 21) / 30, idx, 0, 0));
tmp[2] = tex2Dlod(sampSubD, float4((i * 3 + 2.5 + 21) / 30, idx, 0, 0));
TanV[4 * i + 0] = tmp[0].xyz;
TanV[4 * i + 1] = float3( tmp[0].w, tmp[1].xy );
TanV[4 * i + 2] = float3( tmp[1].zw, tmp[2].x );
TanV[4 * i + 3] = tmp[2].yzw;
}
}
void EvaluateCubicACCPosPatch( in float4 BasisU, in float4 BasisV, float2 UV, float3 cpP[16], out float3 pos )
{
pos = (BasisU.x * cpP[ 0] + BasisU.y * cpP[ 1] + BasisU.z * cpP[ 2] + BasisU.w * cpP[ 3]) * BasisV.x +
(BasisU.x * cpP[ 4] + BasisU.y * cpP[ 5] + BasisU.z * cpP[ 6] + BasisU.w * cpP[ 7]) * BasisV.y +
(BasisU.x * cpP[ 8] + BasisU.y * cpP[ 9] + BasisU.z * cpP[10] + BasisU.w * cpP[11]) * BasisV.z +
(BasisU.x * cpP[12] + BasisU.y * cpP[13] + BasisU.z * cpP[14] + BasisU.w * cpP[15]) * BasisV.w;
}
//--------------------------------------------------------------------------------------
// Cubic Bernstein basis functions
// http://mathworld.wolfram.com/BernsteinPolynomial.html
//--------------------------------------------------------------------------------------
float4 BernsteinBasis( float t )
{
float invT = 1.0f-t;
return float4( invT*invT*invT, 3.0*t*invT*invT, 3.0*t*t*invT, t*t*t );
}
float3 BersteinBasisQuad( float t )
{
float invT = 1.0f-t;
return float3( invT * invT, 2 * invT * t, t * t );
}
void EvaluateCubicACCTanPatches( in float4 BasisU, in float4 BasisV, float2 UV, float3 cpU[12], float3 cpV[12],
out float3 tanU, out float3 tanV )
{
// quadratic bernstein basis functions
float3 qBasisU = BersteinBasisQuad( UV.x );
float3 qBasisV = BersteinBasisQuad( UV.y );
tanU = (qBasisU.x * cpU[ 0] + qBasisU.y * cpU[ 1] + qBasisU.z * cpU[ 2]) * BasisV.x +
(qBasisU.x * cpU[ 3] + qBasisU.y * cpU[ 4] + qBasisU.z * cpU[ 5]) * BasisV.y +
(qBasisU.x * cpU[ 6] + qBasisU.y * cpU[ 7] + qBasisU.z * cpU[ 8]) * BasisV.z +
(qBasisU.x * cpU[ 9] + qBasisU.y * cpU[10] + qBasisU.z * cpU[11]) * BasisV.w;
tanV = (BasisU.x * cpV[ 0] + BasisU.y * cpV[ 1] + BasisU.z * cpV[ 2] + BasisU.w * cpV[ 3]) * qBasisV.x +
(BasisU.x * cpV[ 4] + BasisU.y * cpV[ 5] + BasisU.z * cpV[ 6] + BasisU.w * cpV[ 7]) * qBasisV.y +
(BasisU.x * cpV[ 8] + BasisU.y * cpV[ 9] + BasisU.z * cpV[10] + BasisU.w * cpV[11]) * qBasisV.z;
}
// We define a patch owner for each edge and vertex of the mesh.
// When sampling a displacement map on the boundaries and corners, owner coords are used
//
// Each patch stores: The superprim verts can store
// all of this data like so:
// -- patch U -->
// | X Y Z W
// p t3|t2 t1|t3 +-----------------------------------+
// a --0-----1-- | tanX | tanY | tanZ | sBWrnk | <- Binormal sign flip bit and wrinkle weight
// t t1|t0 t0|t2 +-----------------------------------+
// c | | | innerU | innerV | edgeVU | edgeVV |
// h t2|t0 t0|t1 +-----------------------------------+
// | --3-----2-- | edgeUU | edgeUV | cornerU| cornerV|
// V t3|t1 t2|t3 +-----------------------------------+
//
float2 ComputeConsistentDisplacementUVs( float2 UV,
float4 V0_tc01, float4 V0_tc23,
float4 V1_tc01, float4 V1_tc23,
float4 V2_tc01, float4 V2_tc23,
float4 V3_tc01, float4 V3_tc23 )
{
// Use the tie-breaking scheme for sampling texture coordinates to avoid cracking
float2 t0[4], t1[4], t2[4], t3[4];
t0[0] = V0_tc01.xy;
t0[1] = V0_tc01.zw;
t0[2] = V0_tc23.xy;
t0[3] = V0_tc23.zw;
t1[0] = V1_tc01.xy;
t1[1] = V1_tc01.zw;
t1[2] = V1_tc23.xy;
t1[3] = V1_tc23.zw;
t2[0] = V2_tc01.xy;
t2[1] = V2_tc01.zw;
t2[2] = V2_tc23.xy;
t2[3] = V2_tc23.zw;
t3[0] = V3_tc01.xy;
t3[1] = V3_tc01.zw;
t3[2] = V3_tc23.xy;
t3[3] = V3_tc23.zw;
float flMaxUV = 0.99;
float flMinUV = 0.01;
int i0 = 2 * (UV.x < flMinUV) + (UV.y < flMinUV);
int i1 = (UV.x > flMaxUV) + 2 * (UV.y < flMinUV);
int i2 = 2 * (UV.x > flMaxUV) + (UV.y > flMaxUV);
int i3 = (UV.x < flMinUV) + 2 * (UV.y > flMaxUV);
float2 bottom = lerp( t0[i0], t1[i1], UV.x );
float2 top = lerp( t3[i3], t2[i2], UV.x );
return lerp( bottom, top, UV.y );
}
void DeCasteljau(float u, float3 p0, float3 p1, float3 p2, float3 p3, out float3 p)
{
float3 q0, q1, q2;
float3 r0, r1;
[isolate]
{
q0 = lerp( p0, p1, u );
q1 = lerp( p1, p2, u );
q2 = lerp( p2, p3, u );
r0 = lerp( q0, q1, u );
r1 = lerp( q1, q2, u );
p = lerp( r0, r1, u );
}
}
void DeCasteljau(float u, float3 p0, float3 p1, float3 p2, float3 p3, out float3 p, out float3 dp)
{
float3 q0, q1, q2;
float3 r0, r1;
[isolate]
{
q0 = lerp( p0, p1, u );
q1 = lerp( p1, p2, u );
q2 = lerp( p2, p3, u );
r0 = lerp( q0, q1, u );
r1 = lerp( q1, q2, u );
p = lerp( r0, r1, u );
}
dp = r0 - r1;
}
void EvaluateBezierRegular( float2 uv, float3 p[16], out float3 pos, out float3 nor )
{
float3 t0, t1, t2, t3;
float3 p0, p1, p2, p3;
[isolate]
{
DeCasteljau( uv.x, p[ 0], p[ 1], p[ 2], p[ 3], p0, t0 );
DeCasteljau( uv.x, p[ 4], p[ 5], p[ 6], p[ 7], p1, t1 );
DeCasteljau( uv.x, p[ 8], p[ 9], p[10], p[11], p2, t2 );
DeCasteljau( uv.x, p[12], p[13], p[14], p[15], p3, t3 );
}
float3 du, dv;
DeCasteljau( uv.y, p0, p1, p2, p3, pos, dv );
DeCasteljau( uv.y, t0, t1, t2, t3, du );
nor = normalize( cross(3 * dv, 3 * du) );
}
void EvaluateBezierPosition( float2 uv, float3 p[16], out float3 pos )
{
float3 t0, t1, t2, t3;
float3 p0, p1, p2, p3;
[isolate]
{
DeCasteljau( uv.x, p[ 0], p[ 1], p[ 2], p[ 3], p0, t0 );
DeCasteljau( uv.x, p[ 4], p[ 5], p[ 6], p[ 7], p1, t1 );
DeCasteljau( uv.x, p[ 8], p[ 9], p[10], p[11], p2, t2 );
DeCasteljau( uv.x, p[12], p[13], p[14], p[15], p3, t3 );
}
DeCasteljau( uv.y, p0, p1, p2, p3, pos );
}
void EvaluateSubdivisionSurface( const VS_INPUT v, float flOneOverSubDHeight, float flDoDisplacement, float flDoWrinkledDisplacements,
sampler2D BezierSampler, sampler2D sampDisplacement,
// Outputs
out float3 vWorldNormal, out float3 vWorldPos,
out float3 vWorldTangentS, out float3 vWorldTangentT, out float flBiTangentSign,
out float flWrinkleWeight,
out float2 vTexUV, out float2 vPatchUV,
bool bTangentFrame = true )
{
float4 vInTan;
float2 vDispUV;
float3 vPatchTangent;
float3 vPatchBiTangent;
float4 vBasisU;
float4 vBasisV;
float flPatchLoadIndex;
// PatchUV is passed in for us
vPatchUV = v.UV;
// compute values for tangent based on patchUV
float4 TanUbottom = lerp( v.V0_TanU, v.V1_TanU, vPatchUV.x );
float4 TanUtop = lerp( v.V3_TanU, v.V2_TanU, vPatchUV.x );
vInTan = lerp( TanUbottom, TanUtop, vPatchUV.y );
// compute values for texcoord based on patchUV
float2 bottom = lerp( v.V0_tc01.xy, v.V1_tc01.xy, vPatchUV.x );
float2 top = lerp( v.V3_tc01.xy, v.V2_tc01.xy, vPatchUV.x );
vTexUV = lerp( bottom, top, vPatchUV.y );
// Compute consistent displacement UVs for crack-free displacement mapping
vDispUV = ComputeConsistentDisplacementUVs( vPatchUV,
v.V0_tc01, v.V0_tc23,
v.V1_tc01, v.V1_tc23,
v.V2_tc01, v.V2_tc23,
v.V3_tc01, v.V3_tc23 );
// Cubic Bernstein basis coefficients are passed in for us
vBasisU = v.BasisU;
vBasisV = v.BasisV;
// Patch load index is passed in for us
flPatchLoadIndex = v.PatchID;
float3 ControlPoints[16];
LoadACCPatchPos( flPatchLoadIndex, ControlPoints, flOneOverSubDHeight, BezierSampler );
#if ( TESSELLATION == TESSELLATION_MODE_ACC_PATCHES_REG )
EvaluateBezierRegular( vPatchUV, ControlPoints, vWorldPos, vWorldNormal );
#else
// We split the loading and evaluation of Position patches and Tangent patches to reduce temp register pressure.
// Load and evaluation position
// EvaluateCubicACCPosPatch( vBasisU, vBasisV, vPatchUV, ControlPoints, vWorldPos );
EvaluateBezierPosition( vPatchUV, ControlPoints, vWorldPos );
// Load and evaluate tangent patches
float3 ControlPointsU[12], ControlPointsV[12];
LoadACCPatchTan( flPatchLoadIndex, ControlPointsU, ControlPointsV, flOneOverSubDHeight, BezierSampler );
EvaluateCubicACCTanPatches( vBasisU, vBasisV, vPatchUV, ControlPointsU, ControlPointsV, vPatchTangent, vPatchBiTangent );
vWorldNormal = normalize( cross( vPatchBiTangent, vPatchTangent ) ); // Compute world normal
#endif
// Up to three scalar displacements for { Neutral, Compress, Stretch }
float3 vDisplacement = tex2Dlod( sampDisplacement, float4( vDispUV, 0, 0 ) );
flBiTangentSign = sign( vInTan.w );
if ( bTangentFrame )
{
vWorldTangentS = normalize( vInTan.xyz - ( vWorldNormal * dot( vInTan.xyz, vWorldNormal ) ) ); // Orthonormalize superprim tangent
vWorldTangentT = cross( vWorldNormal, vWorldTangentS.xyz ) * flBiTangentSign; // Sign encodes Binormal flip
}
else
{
vWorldTangentS = vWorldTangentT = vWorldNormal;
}
flWrinkleWeight = abs( vInTan.w ) - 2.0f; // Convert wrinkle weight to -1 to 1 range for pixel shader to use
float3 vDispCoeff = float3(0,0,0); // { Neutral, Compress, Stretch } Displacement Coefficients
vDispCoeff.y = saturate( -flWrinkleWeight ); // One of these two is zero
vDispCoeff.z = saturate( flWrinkleWeight ); // while the other is in the 0..1 range
vDispCoeff *= flDoWrinkledDisplacements; // Separate control for presence of wrinkled displacements (just multiplying by 0 or 1 here)
vDispCoeff.x = 1.0f - vDispCoeff.y - vDispCoeff.z; // Derive neutral weight since these all sum to one
// Displace along normal, using wrinkle displacement map coefficients
vWorldPos += vWorldNormal * ( flDoDisplacement * dot( vDisplacement, vDispCoeff ) );
}
// Wrapper for no-tangent-frame, no-wrinkle version
void EvaluateSubdivisionSurface( VS_INPUT v, float flOneOverSubDHeight, float flDoDisplacement, float flDoWrinkledDisplacements,
sampler2D BezierSampler, sampler2D DispSampler,
// Outputs
out float3 vWorldNormal, out float3 vWorldPos,
out float2 vUV, out float2 vPatchUV )
{
float3 vDummyA, vDummyB;
float flDummyWrinkle;
float flDummyBinormalFlip;
EvaluateSubdivisionSurface( v, flOneOverSubDHeight, flDoDisplacement, flDoWrinkledDisplacements,
BezierSampler, DispSampler, vWorldNormal, vWorldPos, vDummyA, vDummyB,
flDummyBinormalFlip, flDummyWrinkle, vUV, vPatchUV, false );
}
#endif // SHADER_MODEL_VS_3_0
#endif //#ifndef TESSELLATION_VS_FXC_H_