Implementacje w języku C++
Poniżej znajdują się wybrane ciekawsze fragmenty shaderów z dwóch ostatnich prywatnych projektów (Nvidia Cg)
Realizacja oświetlenia zgodnie z modelem Phonga dla światła pointlight + renderowanie cieni metodą VSM (Deffered Shading)
struct FragIn_fsquad { float2 uv : TEXCOORD0; float3 ray: TEXCOORD1; float4 vp : TEXCOORD2; }; float4 deferredPointLShadow(FragIn_fsquad IN, uniform sampler2D dif: TEXUNIT0, uniform sampler2D nor_dep: TEXUNIT1, uniform samplerCUBE shad: TEXUNIT2, uniform float4 lightPos, uniform float lightAtt, uniform float4 lightDif, uniform float4 lightPosWS, uniform float4x4 ivM):COLOR { float4 normals_depth=tex2D(nor_dep, IN.uv); //get normals+depth from texture float _d=tex2D(nor_dep, IN.uv).a; //depth from texture float3 p=normalize(IN.ray)*normals_depth.a; //calculate possition float3 lightVec=lightPos.xyz - p; float dist=length(lightVec); if (dist>lightAtt) discard; float3 n=normals_depth.xyz* 2 - 1; //unpacked normal float3 ld = normalize(lightVec); float3 LdotN = saturate(dot(ld, n)); if (LdotN<=0) discard; // standard variance shadow mapping code float3 ld2=mul((float3x3)ivM, -ld); ld2.z=-ld2.z; float2 moments = texCUBE(shad, ld2).rg; float litFactor = (dist <= moments.x ? 1 : 0); float E_x2 = moments.y; float Ex_2 = moments.x * moments.x; float vsmEpsilon = 0.025; float variance = min(max(E_x2 - Ex_2, 0.0) + vsmEpsilon, 1.0); float m_d = moments.x - dist; float _p = variance / (variance + m_d * m_d); float compareDistance=smoothstep(0.4, 1, max(litFactor, _p)); if (compareDistance==0) discard; float specular = pow(saturate(dot(reflect(-normalize(-p.xyz), n), ld)), 64.0)*lightDif; float4 d=tex2D(dif, IN.uv); //color float att = saturate( 1.0f - saturate( ( dist * dist ) / ( lightAtt * lightAtt ) ) ); float4 ret=float4(LdotN * lightDif*d+specular,0)*dot(att, att)*compareDistance; return ret; }
Texture Splatting + renderowanie cieni metoda PSSM (wersja WIP)
void shadow_receiver_splatting_vs( float4 position : POSITION, float3 normal : NORMAL, float3 tangent : TANGENT, float2 uv : TEXCOORD0, float2 uv2 : TEXCOORD1, out float4 oPosition : POSITION, out float3 oUv : TEXCOORD0, out float3 oUv2 : TEXCOORD1, out float3 oTSLightDir : TEXCOORD2, out float3 oTSHalfAngle : TEXCOORD3, out float4 oLightPosition0 : TEXCOORD4, out float4 oLightPosition1 : TEXCOORD5, out float4 oLightPosition2 : TEXCOORD6, uniform float4 lightPosition, // object space uniform float3 eyePosition, // object space uniform float4x4 worldViewProjMatrix, uniform float4x4 texWorldViewProjMatrix0, uniform float4x4 texWorldViewProjMatrix1, uniform float4x4 texWorldViewProjMatrix2) { // calculate output position oPosition = mul(worldViewProjMatrix, position); // pass the main uvs straight through unchanged oUv.xy = uv; oUv.z = oPosition.z; oUv2.xy = uv2; float3 LightDir = normalize(lightPosition.xyz - (position * lightPosition.w).xyz); float3 eyeDir = normalize(eyePosition - position.xyz); float3 HalfAngle = normalize(eyeDir + LightDir); //Create binormal float3 binormal = cross(tangent, normal); // Form a rotation matrix out of the vectors float3x3 rotation = float3x3(tangent, binormal, normal); // Transform vectors according to this matrix oTSLightDir = mul(rotation, LightDir); oTSHalfAngle = mul(rotation, HalfAngle); // Calculate the position of vertex in light space oLightPosition0 = mul(texWorldViewProjMatrix0, position); oLightPosition1 = mul(texWorldViewProjMatrix1, position); oLightPosition2 = mul(texWorldViewProjMatrix2, position); } void shadow_receiver_splatting_ps( float3 uv : TEXCOORD0, float3 uv2 : TEXCOORD1, float3 OSlightDir : TEXCOORD2, float3 OShalfAngle : TEXCOORD3, float4 LightPosition0 : TEXCOORD4, float4 LightPosition1 : TEXCOORD5, float4 LightPosition2 : TEXCOORD6, out float4 oColour : COLOR, uniform float4 invShadowMapSize0, uniform float4 invShadowMapSize1, uniform float4 invShadowMapSize2, uniform float4 pssmSplitPoints, uniform sampler2D shadowMap0 :TEXUNIT0, uniform sampler2D shadowMap1 :TEXUNIT1, uniform sampler2D shadowMap2 :TEXUNIT2, uniform sampler2D diffuse : TEXUNIT3, uniform sampler2D diffuse2 : TEXUNIT4, uniform sampler2D splat_mask : TEXUNIT5, uniform sampler2D specular: TEXUNIT6, uniform sampler2D normalMap : TEXUNIT7, uniform sampler2D normalMap2 : TEXUNIT8, uniform float4 lightDiffuse, uniform float4 lightSpecular, uniform float4 ambient ) { // calculate shadow float shadowing = 1.0f; float4 splitColour; if (uv.z <= pssmSplitPoints.y) { splitColour = float4(0.1, 0, 0, 1); shadowing = shadowPCF(shadowMap0, LightPosition0, invShadowMapSize0.xy); } else if (uv.z <= pssmSplitPoints.z) { splitColour = float4(0, 0.1, 0, 1); shadowing = shadowPCF(shadowMap1, LightPosition1, invShadowMapSize1.xy); } else { splitColour = float4(0.1, 0.1, 0, 1); shadowing = shadowPCF(shadowMap2, LightPosition2, invShadowMapSize2.xy); } float3 lightVec = normalize(OSlightDir); float3 halfAngle = normalize(OShalfAngle); // get diffuse colour float4 diffuseColour1 = tex2D(diffuse, uv.xy); float4 diffuseColour2 = tex2D(diffuse2, uv.xy); float4 mask = tex2D(splat_mask, uv2.xy); float4 diffuseColour = diffuseColour1*(float4(1,1,1,1)-mask) + diffuseColour2*mask; // get bump map vector, expand from range-compressed float3 bumpVec1 = expand(tex2D(normalMap, uv).xyz); float3 bumpVec2 = expand(tex2D(normalMap2, uv).xyz); float3 bumpVec = bumpVec1*(float3(1,1,1)-mask.xyz) + bumpVec2*mask.xyz; // specular float4 specularColour = tex2D(specular, uv.xy); float shininess = specularColour.w; specularColour.w = 1; // calculate lit value. float4 lighting = lit(dot(bumpVec, lightVec), dot(bumpVec, halfAngle), shininess * 128) * shadowing; // final lighting with diffuse and spec oColour = (diffuseColour * (ambient + lightDiffuse * lighting.y)) + (lightSpecular * specularColour * lighting.z); oColour.w = diffuseColour.w; }