I am trying to use Shadow mapping (from this thread) and I have strange texture lookup problem.
Basically, the displayed textured are not what they should be.
Note that I am no shader expert, but It looked quite solid. I am puzzled.
Ideas are welcome.
Here follows screenshots with and without the shader.
First the python code :
class CameraShadow(CameraQuake):
def __init__(self, *args, **kw):
CameraQuake.__init__(self, *args, **kw)
self.firsttime = True
def start(self):
if self.firsttime :
self.firstactivation()
self.firsttime = False
#==
CameraQuake.start(self)
self.activate_shader()
def stop(self):
CameraQuake.stop(self)
self.deactivate_shader()
def firstactivation(self):
self.cutout = CutoutMgr()
# creating dummy nodes to hold the light
spotDum=render.attachNewNode('spot')
spotholder=spotDum.attachNewNode('holder')
spotholder.setPos(100,100,100)
spotholder.lookAt(0,0,0)
mapsize=1024 # depth map size
mapscale=1.0/mapsize;
self.Ldepthmap = Texture()
# IMPORTANT !
self.Ldepthmap.setFormat(Texture.FDepthComponent) # to store depth value instead of color
self.Ldepthmap.setMinfilter(Texture.FTShadow) # to use OpenGL SGIX_shadow extension
self.Ldepthmap.setMagfilter(Texture.FTShadow)
LBuffer=base.win.makeTextureBuffer('depthmap', mapsize, mapsize,self.Ldepthmap)
self.LCam=base.makeCamera(LBuffer)
self.LCam.reparentTo(spotholder)
self.LCam.node().setScene(render)
# self.LCam.node().getLens().setFov(40)
# self.LCam.node().getLens().setNearFar(.1,1000)
self.LCam.node().showFrustum()
ratio = 4/3.0
size = 2
# self.ortho_lens = OrthographicLens()
# self.ortho_lens.setFilmSize(size*ratio,size)
# self.LCam.node().setLens(self.ortho_lens)
# WARNING ! scale the camera accordingly to match your scene size
self.LCam.setScale(8)
# default values
self.lightIntensity=1.8
self.Xoffset=0.0009765
self.Yoffset=0.0009765
self.Doffset=-0.0000239
# set the shadow weight according to the light intensity, change the contrast here
self.shadowWeight=.25
def deactivate_shader(self):
render.clearShader()
def activate_shader(self):
if not self.shaderSupport():
OnscreenText(text = 'Shadow does not supported by your graphics hardware.', fg=(1,1,1,1),scale=.1)
return
#==
self.base.setFrameRateMeter(1)# pour voir les fps
# shader setup
shadowshader = Shader.load('HW shadow 2Lights_mine.sha')
render.setShader(shadowshader)
render.setShaderInput('light',self.LCam)
render.setShaderInput('Ldepthmap',self.Ldepthmap)
render.setShaderInput('cutout',self.cutout.images[0])
render.setShaderInput('offset',Vec4(self.Xoffset,self.Yoffset,self.Doffset,0))
render.setShaderInput('lightIntensity',Vec4(self.lightIntensity,0,0,0))
render.setShaderInput('shadowWeight',Vec4(self.lightIntensity*self.shadowWeight,0,0,0))
render.setShaderInput('texScale',Vec4(1,1,0,0))
RGB = changelight(self.lightIntensity)
lightcolor=Vec4(*RGB)
render.setShaderInput('lightcolor',lightcolor)
def shaderSupport(self):
return self.base.win.getGsg().getSupportsDepthTexture() and self.base.win.getGsg().getSupportsShadowFilter()
And the Shader :
//Cg
void vshader(float4 vtx_position : POSITION,
float2 vtx_texcoord0: TEXCOORD0,
float3 vtx_normal: NORMAL,
uniform float4x4 trans_model_to_clip_of_light,
uniform float4x4 mat_modelproj,
uniform float4 mspos_light,
uniform float4 k_offset,
uniform float4 k_lightIntensity,
uniform float4 k_shadowWeight,
uniform float4 k_texScale,
out float4 l_position : POSITION,
out float2 l_texcoord0 : TEXCOORD0,
out float4 l_texcoord1 : TEXCOORD1,
out float l_downScaledSmooth,
out float l_side_Self_Shadowing_Artifact_Removal
)
{
float4x4 scaleBiasMatrix = {
0.5f,0.0f,0.0f, .5+k_offset.x,
0.0f,0.5f,0.0f, .5+k_offset.y,
0.0f,0.0f,0.5f, .5+k_offset.z,
0.0f,0.0f,0.0f, 1.0f};
// vertex position
l_position = mul(mat_modelproj, vtx_position);
// transformation to the light's clip space
float4x4 textureMat = mul(scaleBiasMatrix, trans_model_to_clip_of_light);
// apply texture transform on particular nodes, if changed on-the-fly
l_texcoord0 = vtx_texcoord0*k_texScale.xy;
l_texcoord1 = mul(textureMat, vtx_position);
/* ------preserving smooth shading---------
smooth = (vtx normal) dot (vector from vertex to the light) */
float smooth = dot(vtx_normal, normalize(mspos_light - vtx_position));
/* scale down the smooth shading result and add shadowWeight,
to maintain visual rasionality against the lightweight shadows */
l_downScaledSmooth = (k_shadowWeight.x + (k_lightIntensity.x-k_shadowWeight.x)*.5*(smooth+1.0));
// uncomment the next line and comment the next one to see the difference
//l_side_Self_Shadowing_Artifact_Removal=smooth;
l_side_Self_Shadowing_Artifact_Removal = abs(smooth)*(smooth+.2); // however, this is experimental, but the result is quite acceptable to cover self-shadowing artifact on objects' side
}
void fshader(float2 l_texcoord0 : TEXCOORD0,
float4 l_texcoord1 : TEXCOORD1,
in float l_downScaledSmooth,
in float l_side_Self_Shadowing_Artifact_Removal,
uniform sampler2D tex_0 : TEXUNIT0,
uniform sampler2D k_Ldepthmap,
uniform sampler2D k_cutout,
uniform float4 k_shadowWeight,
uniform float4 k_lightcolor,
out float4 o_color:COLOR)
{
float4 baseColor = tex2D(tex_0, l_texcoord0)* l_downScaledSmooth;
// perspective divide, or switch from 4D to 3D
float3 shadowUV = l_texcoord1.xyz / l_texcoord1.w;
// only apply shadow & light inside light's frustum --> UV ranges 0..1
if(shadowUV.x>0.0 && shadowUV.x<1.0 && shadowUV.y>0.0 && shadowUV.y<1.0)
{
float4 cutout=tex2D(k_cutout,shadowUV)*k_lightcolor; //// the light texture
// hardware depth compare
// float shade = tex2Dproj(k_Ldepthmap, l_texcoord1);//shadowUV.xy);
float shade = tex2D(k_Ldepthmap,shadowUV.xy);
// if shade=0 (fully shadowed), shadowWeight is added to achieve lightweight shadows,
// or else it would end up purely black
o_color.rgb = baseColor.rgb * ( cutout*shade*l_side_Self_Shadowing_Artifact_Removal + k_shadowWeight.x );
}
// outside the light's frustum
else
o_color.rgb = baseColor.rgb * k_shadowWeight.x;
// preserving textures' alpha channel
o_color.a = baseColor.a;