I've been working on putting GG's shadow mapping and Evo's normal mapping shaders together (based mainly on GG's with evo's normal mapping bit) and I've got it working! Well, almost. I'm trying to add a third light to the shader:
// Simple cubic shadow mapping shader for two lights
// Created 22 March 2012, edited 25 March 2012.
float4x4 wvp : WorldViewProjection;
float4x4 mw : World;
float shadowMapSize = 1024.0;
float defeatZFighting = 0.005;
float4 ambientColour = {0.1, 0.1, 0.1, 1.0};
float4 lightColour1 = {1.0, 1.0, 1.0, 1.0};
float4 lightPosition1 = {0.0, 500.0, 0.0, 0.001}; // 4th entry is reciprocal of light range
float lightProjScale1 = 0.002; // reciprocal of max likely distance of shadow from light (default 500)
float4 lightColour2 = {0.0, 1.0, 1.0, 1.0};
float4 lightPosition2 = {0.0, 500.0, 0.0, 0.001}; // 4th entry is reciprocal of light range
float lightProjScale2 = 0.002; // reciprocal of max likely distance of shadow from light (default 500)
float4 lightColour3 = {0.0, 1.0, 1.0, 1.0};
float4 lightPosition3 = {0.0, 500.0, 0.0, 0.001}; // 4th entry is reciprocal of light range
float lightProjScale3 = 0.002; // reciprocal of max likely distance of shadow from light (default 500)
texture baseTexture < string ResourceName=""; >;
sampler baseSample = sampler_state
{ texture = <baseTexture>;
minFilter = linear;
magFilter = linear;
mipFilter = linear;
addressU = wrap;
addressV = wrap;
};
texture cubeTexture1
< string ResourceName = "";
string Type = "CUBE";
>;
samplerCUBE cubeSample1 = sampler_state
{ texture = <cubeTexture1>;
mipFilter = linear;
magFilter = linear;
minFilter = linear;
};
texture cubeTexture2
< string ResourceName = "";
string Type = "CUBE";
>;
samplerCUBE cubeSample2 = sampler_state
{ texture = <cubeTexture2>;
mipFilter = linear;
magFilter = linear;
minFilter = linear;
};
texture normalTexture < string ResourceName=""; >;
sampler normalSample = sampler_state
{ texture = <normalTexture>;
minFilter = linear;
magFilter = linear;
mipFilter = linear;
addressU = wrap;
addressV = wrap;
};
//Light 3
texture cubeTexture3
< string ResourceName = "";
string Type = "CUBE";
>;
samplerCUBE cubeSample3 = sampler_state
{ texture = <cubeTexture3>;
mipFilter = linear;
magFilter = linear;
minFilter = linear;
};
struct VSInput
{ float4 pos : position;
float3 normal : normal;
float2 UV : texcoord0;
};
struct VSOutDepth
{ float4 pos : position;
float3 depth : texcoord0;
float2 UV : texcoord1;
};
struct VSOutScene
{ float4 pos : position;
float2 UV : texcoord0;
float3 normal : texcoord1;
float3 lightView1 : texcoord2;
float3 depth1 : texcoord3;
float3 lightView2 : texcoord4;
float3 depth2 : texcoord5;
float3 lightView3 : texcoord6;
float3 depth3 : texcoord7;
};
struct PSOutput { float4 col : color; };
VSOutDepth VSDepth1( VSInput In, VSOutDepth Out )
{ Out.pos = mul(In.pos, wvp);
float3 view = mul(In.pos, mw).xyz - lightPosition1.xyz;
Out.depth = view * lightProjScale1; // try to aim for values with length in range 0.0 to 1.0
return Out;
}
VSOutDepth VSDepth2( VSInput In, VSOutDepth Out )
{ Out.pos = mul(In.pos, wvp);
float3 view = mul(In.pos, mw).xyz - lightPosition2.xyz;
Out.depth = view * lightProjScale2; // try to aim for values with length in range 0.0 to 1.0
return Out;
}
VSOutDepth VSDepth3( VSInput In, VSOutDepth Out )
{ Out.pos = mul(In.pos, wvp);
float3 view = mul(In.pos, mw).xyz - lightPosition3.xyz;
Out.depth = view * lightProjScale3; // try to aim for values with length in range 0.0 to 1.0
return Out;
}
VSOutScene VSScene( VSInput In, VSOutScene Out )
{ Out.pos = mul(In.pos, wvp);
Out.UV = In.UV;
float4 wPos = mul(In.pos, mw);
Out.normal = mul(In.normal, (float3x3) mw );
Out.lightView1 = wPos.xyz - lightPosition1.xyz; // direction vector for cube map lookup for light 1
Out.depth1 = Out.lightView1 * lightProjScale1; // scaled light view for depth comparison for light 1
Out.lightView2 = wPos.xyz - lightPosition2.xyz;
Out.depth2 = Out.lightView2 * lightProjScale2;
Out.lightView3 = wPos.xyz - lightPosition3.xyz;
Out.depth3 = Out.lightView3 * lightProjScale3;
return Out;
}
PSOutput PSDepth( VSOutDepth In, PSOutput Out)
{ Out.col = float4 (length(In.depth), 0.0, 0.0, 1.0);
return Out;
}
PSOutput PSScene0( VSOutScene In, PSOutput Out)
{ // no filtering of shadow edges
float4 base = tex2D(baseSample, In.UV);
//Normal mapping
float3 NormalMap=tex2D(normalSample,In.UV)*2-1;
float3 LightV=normalize(In.lightView1);
float3 ViewV =normalize(In.lightView1);
NormalMap=normalize(NormalMap);
float Normal=saturate(dot(reflect(-ViewV,NormalMap),LightV));
Normal=pow(Normal,16)+saturate(dot(NormalMap,LightV));
// lighting for first light - depth test uses red component
float shadow1 = texCUBE(cubeSample1, In.lightView1).r < length(In.depth1) - defeatZFighting ? 0.0 : 1.0;
float attenuation1 = saturate(1.0 - length(In.lightView1) * lightPosition1.w);
float diffuse1 = saturate(dot(normalize(-In.lightView1), normalize(In.normal))) * attenuation1;
float4 light = lightColour1 * diffuse1 * shadow1 + ambientColour;
// lighting for second light - depth test uses red component
float shadow2 = texCUBE(cubeSample2, In.lightView2).r < length(In.depth2) - defeatZFighting ? 0.0 : 1.0;
float attenuation2 = saturate(1.0 - length(In.lightView2) * lightPosition2.w);
float diffuse2 = saturate(dot(normalize(-In.lightView2), normalize(In.normal))) * attenuation2;
light += lightColour2 * diffuse2 * shadow2;
Out.col = base * light * Normal;
return Out;
}
PSOutput PSScene1( VSOutScene In, PSOutput Out)
{ // no filtering of shadow edges
float4 base = tex2D(baseSample, In.UV);
//Normal mapping
float3 NormalMap=tex2D(normalSample,In.UV)*2-1;
float3 LightV=normalize(In.lightView1);
float3 ViewV =normalize(In.lightView1);
NormalMap=normalize(NormalMap);
float Normal=saturate(dot(reflect(-ViewV,NormalMap),LightV));
Normal=pow(Normal,16)+saturate(dot(NormalMap,LightV));
// lighting for first light - depth test uses red component
float shadow1 = texCUBE(cubeSample1, In.lightView1).r < length(In.depth1) - defeatZFighting ? 0.0 : 1.0;
float attenuation1 = saturate(1.0 - length(In.lightView1) * lightPosition1.w);
float diffuse1 = saturate(dot(normalize(-In.lightView1), normalize(In.normal))) * attenuation1;
float4 light = lightColour1 * diffuse1 * shadow1 + ambientColour;
// lighting for second light - depth test uses red component
float shadow2 = texCUBE(cubeSample2, In.lightView2).r < length(In.depth2) - defeatZFighting ? 0.0 : 1.0;
float attenuation2 = saturate(1.0 - length(In.lightView2) * lightPosition2.w);
float diffuse2 = saturate(dot(normalize(-In.lightView2), normalize(In.normal))) * attenuation2;
light += lightColour2 * diffuse2 * shadow2;
// lighting for third light - depth test uses red component
float shadow3 = texCUBE(cubeSample3, In.lightView3).r < length(In.depth3) - defeatZFighting ? 0.0 : 1.0;
float attenuation3 = saturate(1.0 - length(In.lightView3) * lightPosition3.w);
float diffuse3 = saturate(dot(normalize(-In.lightView3), normalize(In.normal))) * attenuation3;
light += lightColour3 * diffuse3 * shadow3;
Out.col = base * light * Normal;
return Out;
}
technique shadow1
{ pass p1
{ vertexShader = compile vs_2_0 VSDepth1();
pixelShader = compile ps_2_0 PSDepth();
}
}
technique shadow2
{ pass p1
{ vertexShader = compile vs_2_0 VSDepth2();
pixelShader = compile ps_2_0 PSDepth();
}
}
technique shadow3
{ pass p1
{ vertexShader = compile vs_2_0 VSDepth3();
pixelShader = compile ps_2_0 PSDepth();
}
}
technique scene0
// unfiltered shadow map lookup
{ pass p1
{ vertexShader = compile vs_2_0 VSScene();
pixelShader = compile ps_2_0 PSScene0();
}
}
technique scene1
{ pass p1
{ vertexShader = compile vs_2_0 VSScene();
pixelShader = compile ps_2_0 PSScene1();
}
}
DBP:
` Simple demo of cubic shadow mapping with two lights.
` This version uses Dark Shader commands and two cube maps.
` A useful reference: http://http.developer.nvidia.com/GPUGems/gpugems_ch12.html
` Created 25 March 2012, edited 14 April 2012.
//Aim: add a static shadow map image to the shader and thereby increase performance
//Method:
// Set an object camera mask on dynamic objects & static objects
//
set display mode 800,600, 32
sync on : sync rate 60 : sync
shadowMapSize = 256
` setup main camera
backdrop on
autocam off
position camera -100, 20, -50
point camera 50, 20, 50
global cx#
global cy#
cx# = camera angle x()
cy# = camera angle y()
null = make vector4(10)
` load textures
load image "Media/rockwall.dds", 200
load image "Media/stripes.png", 201
load image "Media/light1.png", 202
load image "Media/light2.png", 203
load image "Media/light3.png", 205
nMap = 204
load image "Media/rockwall_n.dds", nMap
` load effect
load effect "Media/CubicShadowMappingV2.fx", 1, 0
set vector4 10, 0.2, 0.2, 0.2, 0.0
set effect constant vector 1, "ambientColour", 10
set effect constant float 1, "shadowMapSize", shadowMapSize
` create point light objects
type position
x as float
y as float
z as float
w as float
endtype
dim lightPosition(6) as position
make object sphere 1, 5 ` this is the first light
texture object 1, 202
set object light 1, 0
lightX# = 50.0 : lightY# = 50.0 : lightZ# = 50.0
invLightRange# = 0.004
position object 1, lightX#, lightY#, lightZ#
lightPosition(1).x = lightX#
lightPosition(1).y = lightY#
lightPosition(1).z = lightZ#
lightPosition(1).w = invLightRange#
lightProjScale1# = 0.001 ` this value needs to be defined more clearly
make object sphere 31, 5 ` this is the second light - this will be moved around the scene
texture object 31, 203
set object light 31, 0
lightX# = 50.0 : lightY# = 50.0 : lightZ# = 50.0
position object 31, lightX#, lightY#, lightZ#
lightPosition(2).x = lightX#
lightPosition(2).y = lightY#
lightPosition(2).z = lightZ#
lightPosition(2).w = invLightRange#
lightProjScale2# = 0.001 ` this value needs to be defined more clearly
//light 3
make object sphere 99, 5 ` this is the second light - this will be moved around the scene
texture object 99, 205
set object light 99, 0
lightX# = 150.0 : lightY# = 150.0 : lightZ# = 150.0
position object 99, lightX#, lightY#, lightZ#
lightPosition(3).x = lightX#
lightPosition(3).y = lightY#
lightPosition(3).z = lightZ#
lightPosition(3).w = invLightRange#
lightProjScale3# = 0.001 ` this value needs to be defined more clearly
make object cylinder 11, 48
scale object 11, 5, 100, 5
position object 11, lightPosition(1).x, 24, lightPosition(1).z
texture object 11, 0, 201
set vector4 10, lightPosition(1).x, lightPosition(1).y, lightPosition(1).z, lightPosition(1).w ` 4th entry is reciprocal of light range
set effect constant vector 1, "lightPosition1", 10
set effect constant float 1, "lightProjScale1", lightProjScale1#
set vector4 10, 1.0, 0.5, 0.5, 1.0
set effect constant vector 1, "lightColour1", 10
set vector4 10, lightPosition(2).x, lightPosition(2).y, lightPosition(2).z, lightPosition(2).w
set effect constant vector 1, "lightPosition2", 10
set effect constant float 1, "lightProjScale2", lightProjScale2#
set vector4 10, 0.0, 0.5, 0.5, 1.0
set effect constant vector 1, "lightColour2", 10
set vector4 10, 0.1, 0.1, 0.1, 1.0
// set effect constant vector 1, "ambientColour", 10
//Lights 3
set vector4 10, lightPosition(3).x, lightPosition(3).y, lightPosition(3).z, lightPosition(3).w
set effect constant vector 1, "lightPosition3", 10
set effect constant float 1, "lightProjScale3", lightProjScale3#
set vector4 10, 0.5, 0.5, 0.0, 1.0
set effect constant vector 1, "lightColour3", 10
set vector4 10, 0.1, 0.1, 0.1, 1.0
set effect constant vector 1, "ambientColour", 10
` test camera to check part of cube map
make camera 1
color backdrop 1, 0
set camera to image 1, 1, shadowMapSize, shadowMapSize
set camera fov 1, 90.0
set camera aspect 1, 1.0
set camera range 1, 1.0, 2001.0
position camera 1, lightPosition(1).x, lightPosition(1).y, lightPosition(1).z
rotate camera 1, 0, 270, 0
testImage = 0
//Make additional cameras
LightCam_S = 2
LightCam_D = 3
Make Camera LightCam_S
Make Camera LightCam_D
global CamMsk_S as word =%0101
//0x00000004
//2^0 || 2^LightCam_S
global CamMsk_D as word =%1001
//0x00000008
//2^0 || 2^LightCam_D
` Dark Shader version - no explicit extra cameras needed
make dynamic cube map 1, shadowMapSize
make dynamic cube map 2, shadowMapSize
make dynamic cube map 3, shadowMapSize
` create room
make object cube 2, -500.0
position object 2, 0.0, 250.0, 0.0
texture object 2, 0, 200 ` put the main texture on texture stage 0
set object effect 2, 1
apply cube map to object 2, 1, 1 ` obj id, stage id, cube map id
apply cube map to object 2, 2, 2 ` obj id, stage id, cube map id
scale object texture 2, 0, 8, 8 ` scales the stage 0 UV coordinates
Texture Object 2,3,nMap
apply cube map to object 2, 4, 3 ` obj id, stage id, cube map id
` the room ceiling
make object plain 12, 500, 500
xrotate object 12, 90
position object 12, 0.0, 200.0, 0.0
texture object 12, 0, 200 ` put the main texture on texture stage 0
set object effect 12, 1
apply cube map to object 12, 1, 1 ` obj id, stage id, cube map id
apply cube map to object 12, 2, 2 ` obj id, stage id, cube map id
scale object texture 12, 0, 8, 8 ` scales the stage 0 UV coordinates
Texture Object 12,3,nMap
apply cube map to object 12, 4, 3 ` obj id, stage id, cube map id
` create moving objects
for obj = 3 to 8
make object sphere obj, 8.0, 100, 100
texture object obj, 0, 200
set object effect obj, 1
apply cube map to object obj, 1, 1 ` obj id, stage id, cube map id
apply cube map to object obj, 2, 2 ` obj id, stage id, cube map id
Texture Object obj,3,nMap
apply cube map to object obj, 4, 3 ` obj id, stage id, cube map id
next obj
rotate = 1
` place some fixed objects
make object cone 20, 50
position object 20, 100.0, 0.0, 100.0
texture object 20, 0, 200
set object effect 20, 1
apply cube map to object 20, 1, 1 ` obj id, stage id, cube map id
apply cube map to object 20, 2, 2 ` obj id, stage id, cube map id
Texture Object 20,3,nMap
apply cube map to object 20, 4, 3 ` obj id, stage id, cube map id
make object cube 21, 40
position object 21, 0.0, 0.0, 0.0
texture object 21, 0, 200
set object effect 21, 1
apply cube map to object 21, 1, 1 ` obj id, stage id, cube map id
apply cube map to object 21, 2, 2 ` obj id, stage id, cube map id
Texture Object 21,3,nMap
apply cube map to object 21, 4, 3 ` obj id, stage id, cube map id
make object sphere 22, 70
position object 22, 0.0, 0.0, 100.0
texture object 22, 0, 200
set object effect 22, 1
apply cube map to object 22, 1, 1 ` obj id, stage id, cube map id
apply cube map to object 22, 2, 2 ` obj id, stage id, cube map id
Texture Object 22,3,nMap
apply cube map to object 22, 4, 3 ` obj id, stage id, cube map id
make object cube 23, 50
rotate object 23, 45, 45, 0
position object 23, 100.0, 0.0, 0.0
texture object 23, 0, 200
set object effect 23, 1
apply cube map to object 23, 1, 1 ` obj id, stage id, cube map id
apply cube map to object 23, 2, 2 ` obj id, stage id, cube map id
Texture Object 23,3,nMap
apply cube map to object 23, 4, 3 ` obj id, stage id, cube map id
load object "Media/tiny.x", 25
scale object 25, 10.0, 10.0, 10.0
position object 25, -50.0, 25, -50.0
set object effect 25, 1
apply cube map to object 25, 1, 1 ` obj id, stage id, cube map id
apply cube map to object 25, 2, 2 ` obj id, stage id, cube map id
loop object 25
set object speed 25, 4000
set object effect 11, 1
apply cube map to object 11, 1, 1 ` obj id, stage id, cube map id
apply cube map to object 11, 2, 2 ` obj id, stage id, cube map id
Texture Object 11,3,nMap
apply cube map to object 11, 4, 3 ` obj id, stage id, cube map id
` main program loop
move = 1
repeat
center text screen width()/2, 40, "Press 1 for sample Shadow Map, m to toggle light and sphere movement"
center text screen width()/2, 70, "FPS "+str$(screen fps())
move object 25, -0.45
if object position z(25) < -240 then yrotate object 25, 180
if object position z(25) > 240 then yrotate object 25, 0
`check input
key$ = inkey$()
select key$
case "m"
if keyNow = 0
keyNow = 1
move = 1 - move
endif
endcase
case default
keyNow = 0
endcase
endselect
if move = 1
` move objects and second light
inc angle#, 1.0
for obj = 3 to 8
position object obj, sin(angle# * obj + 30.0 * obj) * 80.0 + lightPosition(1).x, sin(angle# + 20.0 * obj) * 20.0 + lightPosition(1).y, sin(angle# * obj + 35.0 * obj) * 80.0 + lightPosition(1).z
next obj
lightPosition(2).x = sin(angle#) * 200.0
lightPosition(2).y = 60.0
lightPosition(2).z = cos(angle#) * 200.0
position object 31, lightPosition(2).x, lightPosition(2).y, lightPosition(2).z
set vector4 10, lightPosition(2).x, lightPosition(2).y, lightPosition(2).z, lightPosition(2).w
set effect constant vector 1, "lightPosition2", 10
angle2#=wrapvalue(angle#+180)
lightPosition(3).x = sin(angle2#) * 200.0
lightPosition(3).y = 60.0
lightPosition(3).z = cos(angle2#) * 200.0
position object 99, lightPosition(3).x, lightPosition(3).y, lightPosition(3).z
set vector4 10, lightPosition(3).x, lightPosition(3).y, lightPosition(3).z, lightPosition(3).w
set effect constant vector 1, "lightPosition3", 10
endif
`update cameras
positionCamera()
` render shadow map for first light
set effect technique 1, "shadow1"
hide object 1 ` light camera is inside this so it shouldn't be rendered
show object 31
show object 99
//Use dynamic camera instead of -1
render dynamic cube map 1, LightCam_D, lightPosition(1).x, lightPosition(1).y, lightPosition(1).z ` cube map id, temporary camera id, camX, camY, camZ
` render shadow map for second light using another cube map
set effect technique 1, "shadow2"
show object 1
show object 99
hide object 31
render dynamic cube map 2, LightCam_D, lightPosition(2).x, lightPosition(2).y, lightPosition(2).z ` cube map id, temporary camera id, camX, camY, camZ
` render shadow map for third light using another cube map
set effect technique 1, "shadow3"
show object 1
show object 31
hide object 99
render dynamic cube map 3, LightCam_D, lightPosition(3).x, lightPosition(3).y, lightPosition(3).z ` cube map id, temporary camera id, camX, camY, camZ
show object 99
` show test image component of cube map
if key$ = "1"
` render test image
set effect technique 1, "shadow1"
position camera 1, lightPosition(1).x, lightPosition(1).y, lightPosition(1).z
sync camera 1
paste image 1, 0, 0
testImage = 1
endif
if key$ = "s" and testImage then save image "test.png", 1 : end ` for testing only
` main scene
set effect technique 1, "scene1"
sync mask 1
show object 2
show object 1
show object 31
sync
until spacekey()
end
function positionCamera()
control camera using arrowkeys 0, 3, 0
cx# = cx# + mousemovey(): cy# = cy# + mousemovex()
if cx# < -45.0
cx# = -45.0
else
if cx# > 45.0 then cx# = 45.0
endif
rotate camera cx#, cy#, 0
endfunction
This shader fails, but if you remove or comment out the line:
light += lightColour3 * diffuse3 * shadow3;
from the shader file then it works fine with two lights. This is very confusing, no matter what I do I can't get it to output anything when the third light is included!
Can anyone help?
Thanks,