summaryrefslogtreecommitdiff
path: root/tests/hlsl/dxsdk/MultithreadedRendering11/MultithreadedRendering11_PS.hlsl
blob: dbeb87f338c2efef25f16dcb676bb3c33215822a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
//TEST_IGNORE_FILE: Currently failing due to Spire compiler issues.
//TEST:COMPARE_HLSL: -target dxbc-assembly -profile ps_4_0 -entry PSMain
//--------------------------------------------------------------------------------------
// File: MultithreadedRendering11_PS.hlsl
//
// The pixel shader file for the MultithreadedRendering11 sample.  
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------

// Various debug options
//#define NO_DIFFUSE_MAP
//#define NO_NORMAL_MAP
//#define NO_AMBIENT
//#define NO_DYNAMIC_LIGHTING
//#define NO_SHADOW_MAP

#define SHADOW_DEPTH_BIAS 0.0005f

//--------------------------------------------------------------------------------------
// Globals
//--------------------------------------------------------------------------------------
static const int g_iNumLights = 4;
static const int g_iNumShadows = 1; // by convention, the first n lights cast shadows

cbuffer cbPerObject : register( b0 )
{
	float4		g_vObjectColor			: packoffset( c0 );
};

cbuffer cbPerLight : register( b1 )
{
    struct LightDataStruct
    {
	    matrix		m_mLightViewProj;
	    float4		m_vLightPos;
	    float4		m_vLightDir;
	    float4		m_vLightColor;
	    float4		m_vFalloffs;    // x = dist end, y = dist range, z = cos angle end, w = cos range
	} g_LightData[g_iNumLights]         : packoffset( c0 );
};

cbuffer cbPerScene : register( b2 )
{
	float4		g_vMirrorPlane			: packoffset( c0 );
	float4  	g_vAmbientColor			: packoffset( c1 );
	float4		g_vTintColor			: packoffset( c2 );
};

//--------------------------------------------------------------------------------------
// Textures and Samplers
//--------------------------------------------------------------------------------------
Texture2D	        g_txDiffuse                : register( t0 );
Texture2D	        g_txNormal                 : register( t1 );
Texture2D           g_txShadow[g_iNumShadows]  : register( t2 );

SamplerState        g_samPointClamp : register( s0 );
SamplerState        g_samLinearWrap : register( s1 );

//--------------------------------------------------------------------------------------
// Input / Output structures
//--------------------------------------------------------------------------------------
struct PS_INPUT
{
	float3 vNormal		: NORMAL;
	float3 vTangent		: TANGENT;
	float2 vTexcoord	: TEXCOORD0;
	float4 vPosWorld	: TEXCOORD1;
};

//--------------------------------------------------------------------------------------
// Sample normal map, convert to signed, apply tangent-to-world space transform
//--------------------------------------------------------------------------------------
float3 CalcPerPixelNormal( float2 vTexcoord, float3 vVertNormal, float3 vVertTangent )
{
	// Compute tangent frame
	vVertNormal =   normalize( vVertNormal );	
	vVertTangent =  normalize( vVertTangent );	
	float3 vVertBinormal = normalize( cross( vVertTangent, vVertNormal ) );	
	float3x3 mTangentSpaceToWorldSpace = float3x3( vVertTangent, vVertBinormal, vVertNormal ); 
	
	// Compute per-pixel normal
	float3 vBumpNormal = g_txNormal.Sample( g_samLinearWrap, vTexcoord );
	vBumpNormal = 2.0f * vBumpNormal - 1.0f;
	
	return mul( vBumpNormal, mTangentSpaceToWorldSpace );
}

//--------------------------------------------------------------------------------------
// Test how much pixel is in shadow, using 2x2 percentage-closer filtering
//--------------------------------------------------------------------------------------
float4 CalcUnshadowedAmountPCF2x2( int iShadow, float4 vPosWorld )
{
    matrix mLightViewProj = g_LightData[iShadow].m_mLightViewProj;
    Texture2D txShadow =    g_txShadow[iShadow]; 

    // Compute pixel position in light space
    float4 vLightSpacePos = mul( vPosWorld, mLightViewProj ); 
    vLightSpacePos.xyz /= vLightSpacePos.w;
    
    // Translate from surface coords to texture coords
    // Could fold these into the matrix
    float2 vShadowTexCoord = 0.5f * vLightSpacePos + 0.5f;
    vShadowTexCoord.y = 1.0f - vShadowTexCoord.y;
    
    // Depth bias to avoid pixel self-shadowing
    float vLightSpaceDepth = vLightSpacePos.z - SHADOW_DEPTH_BIAS;
    
    // Find sub-pixel weights
    float2 vShadowMapDims = float2( 2048.0f, 2048.0f ); // need to keep in sync with .cpp file
    float4 vSubPixelCoords;
    vSubPixelCoords.xy = frac( vShadowMapDims * vShadowTexCoord );
    vSubPixelCoords.zw = 1.0f - vSubPixelCoords;
    float4 vBilinearWeights = vSubPixelCoords.zxzx * vSubPixelCoords.wwyy;

    // 2x2 percentage closer filtering
    float2 vTexelUnits = 1.0f / vShadowMapDims;
    float4 vShadowDepths;
    vShadowDepths.x = txShadow.Sample( g_samPointClamp, vShadowTexCoord );
    vShadowDepths.y = txShadow.Sample( g_samPointClamp, vShadowTexCoord + float2( vTexelUnits.x, 0.0f ) );
    vShadowDepths.z = txShadow.Sample( g_samPointClamp, vShadowTexCoord + float2( 0.0f, vTexelUnits.y ) );
    vShadowDepths.w = txShadow.Sample( g_samPointClamp, vShadowTexCoord + vTexelUnits );
    
    // What weighted fraction of the 4 samples are nearer to the light than this pixel?
    float4 vShadowTests = ( vShadowDepths >= vLightSpaceDepth ) ? 1.0f : 0.0f;
    return dot( vBilinearWeights, vShadowTests );
}

//--------------------------------------------------------------------------------------
// Diffuse lighting calculation, with angle and distance falloff
//--------------------------------------------------------------------------------------
float4 CalcLightingColor( int iLight, float3 vPosWorld, float3 vPerPixelNormal )
{
    float3 vLightPos =      g_LightData[iLight].m_vLightPos.xyz; 
    float3 vLightDir =      g_LightData[iLight].m_vLightDir.xyz;
    float4 vLightColor =    g_LightData[iLight].m_vLightColor; 
    float4 vFalloffs =      g_LightData[iLight].m_vFalloffs; 
    
    float3 vLightToPixelUnNormalized = vPosWorld - vLightPos;
    
    // Dist falloff = 0 at vFalloffs.x, 1 at vFalloffs.x - vFalloffs.y
    float fDist = length( vLightToPixelUnNormalized );
    float fDistFalloff = saturate( ( vFalloffs.x - fDist ) / vFalloffs.y );
    
    // Normalize from here on
    float3 vLightToPixelNormalized = vLightToPixelUnNormalized / fDist;
    
    // Angle falloff = 0 at vFalloffs.z, 1 at vFalloffs.z - vFalloffs.w
    float fCosAngle = dot( vLightToPixelNormalized, vLightDir );
    float fAngleFalloff = saturate( ( fCosAngle - vFalloffs.z ) / vFalloffs.w );
    
    // Diffuse contribution
    float fNDotL = saturate( -dot( vLightToPixelNormalized, vPerPixelNormal ) );
    
	return vLightColor * fNDotL * fDistFalloff * fAngleFalloff;
}

//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PSMain( PS_INPUT Input ) : SV_TARGET
{
    // Manual clip test, so that objects which are behind the mirror 
    // don't show up in the mirror.
    clip( dot( g_vMirrorPlane.xyz, Input.vPosWorld.xyz ) + g_vMirrorPlane.w );

#ifdef NO_DIFFUSE_MAP
	float4 vDiffuse = 0.5f;
#else   // #ifdef NO_DIFFUSE_MAP
	float4 vDiffuse = g_txDiffuse.Sample( g_samLinearWrap, Input.vTexcoord );
#endif  // #ifdef NO_DIFFUSE_MAP #else
	
	// Compute per-pixel normal
#ifdef NO_NORMAL_MAP
	float3 vPerPixelNormal = Input.vNormal;
#else   // #ifdef NO_NORMAL_MAP
	float3 vPerPixelNormal = CalcPerPixelNormal( Input.vTexcoord, Input.vNormal, Input.vTangent );
#endif  // #ifdef NO_NORMAL_MAP #else

    // Compute lighting contribution
#ifdef NO_AMBIENT
	float4 vTotalLightingColor = 0.0f;
#else   // #ifdef NO_AMBIENT
	float4 vTotalLightingColor = g_vAmbientColor;
#endif  // #ifdef NO_AMBIENT #else

#ifndef NO_DYNAMIC_LIGHTING
	for ( int iLight = 0; iLight < g_iNumLights; ++iLight )
	{
        float4 vLightingColor = CalcLightingColor( iLight, Input.vPosWorld, vPerPixelNormal );
#ifndef NO_SHADOW_MAP
	    if ( iLight < g_iNumShadows && any( vLightingColor.xyz ) > 0.0f ) // Don't bother checking shadow map if the pixel is unlit
	    {
            vLightingColor *= CalcUnshadowedAmountPCF2x2( iLight, Input.vPosWorld );
	    }
#endif  // #ifndef NO_SHADOW_MAP
	    vTotalLightingColor += vLightingColor;
	}
#endif  // #ifndef NO_DYNAMIC_LIGHTING

	return vDiffuse * g_vTintColor * g_vObjectColor * vTotalLightingColor;
}