shadow map


Shadow mapping 的原理: 

一个物体之所以会处在阴影当中,是由于在它和光源之间存在着遮蔽物,或者说遮蔽物离光源的距离比物体要近,这就是 shadow mapping 算法的基本原理.


Pass1: 以光源为视点,或者说在光源坐标系下面对整个场景进行渲染,目的是要得到一副所有物体相对于光源的 depth map (也就是我们所说的shadow map),也就是这副图像中每个象素的值代表着场景里面离光源最近的 fragment 的深度值。由于这个pass中我们感兴趣的只是象素的深度值,所以可以把所有的光照计算关掉,打开 z-test 和 z-write 的 render state 。

Pass2: 将视点恢复到原来的正常位置,渲染整个场景,对每个象素计算它和光源的距离,然后将这个值和 depth map中相应的值比较,以确定这个象素点是否处在阴影当中。然后根据比较的结果,对 shadowed fragment 和 lighted fragment 分别进行不同的光照计算,这样就可以得到阴影的效果了。 


实现一:固定管线

纹理:

在实现过程中,需要指定纹理坐标,而opengl中有两种为顶点指定坐标的方法:

第一种是人工为每个顶点指定坐标,可以通过函数glTexCord*()来完成

第二种是自动生成纹理坐标,由函数glTexGen*()来完成。

//Set up texture coordinate generation.
	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
	glTexGenfv(GL_S, GL_EYE_PLANE, textureMatrix.GetRow(0));
	glEnable(GL_TEXTURE_GEN_S);

	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
	glTexGenfv(GL_T, GL_EYE_PLANE, textureMatrix.GetRow(1));
	glEnable(GL_TEXTURE_GEN_T);

	glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
	glTexGenfv(GL_R, GL_EYE_PLANE, textureMatrix.GetRow(2));
	glEnable(GL_TEXTURE_GEN_R);

	glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
	glTexGenfv(GL_Q, GL_EYE_PLANE, textureMatrix.GetRow(3));
	glEnable(GL_TEXTURE_GEN_Q);




实现二:可编程管线

void display()
{
	//1.render to framebuffer with fixed pipeline
	glBindFramebuffer(GL_FRAMEBUFFER,fboId);

	//Use viewport the same size as the shadow map
	glViewport(0, 0, windowWidth, windowHeight);

	// Clear previous frame values
	glClear(GL_DEPTH_BUFFER_BIT);

	//Disable color rendering, we only want to write to the Z-Buffer
	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 

	// Culling switching, rendering only backface, this is done to avoid self-shadowing
	glCullFace(GL_FRONT); 

	glMatrixMode(GL_PROJECTION);
	glLoadMatrixf(&lightProjectionMatrix[0][0]);

	glMatrixMode(GL_MODELVIEW);
	glLoadMatrixf(&lightViewMatrix[0][0]);

	drawScene();

	glBindFramebuffer(GL_FRAMEBUFFER, 0);


	//2.render to screen with programmable pipeline

	glViewport(0, 0, windowWidth, windowHeight);

	//Enabling color write (previously disabled for light POV z-buffer rendering)
	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 

	// Clear the screen
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glCullFace(GL_BACK); // Cull back-facing triangles -> draw only front-facing triangles

	glMatrixMode(GL_PROJECTION);
	glLoadMatrixf(&cameraProjectionMatrix[0][0]);

	glMatrixMode(GL_MODELVIEW);
	glLoadMatrixf(&cameraViewMatrix[0][0]);

	glm::mat4 biasMatrix(
		0.5, 0.0, 0.0, 0.0, 
		0.0, 0.5, 0.0, 0.0,
		0.0, 0.0, 0.5, 0.0,
		0.5, 0.5, 0.5, 1.0
		);

	glm::mat4 depthBiasMVP = biasMatrix*cameraProjectionMatrix*cameraViewMatrix;

	// Use  shader
	glUseProgram(shadowProgramID);
	glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &depthBiasMVP[0][0]);
	
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, shadowMapTexture);
	glUniform1i(shadowMapUniform, 0);
	
	drawScene();


	// DEBUG only. this piece of code draw the depth buffer onscreen
	
	glUseProgram(0);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-windowWidth/2,windowWidth/2,-windowHeight/2,windowHeight/2,1,20);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glColor4f(1,1,1,1);
	glActiveTextureARB(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D,shadowMapTexture);
	glEnable(GL_TEXTURE_2D);
	glTranslated(0,0,-1);
	glBegin(GL_QUADS);
	glTexCoord2d(1,1);glVertex3f(-1,-1,0);
	glTexCoord2d(0,1);glVertex3f(-windowWidth/2,-1,0);
	glTexCoord2d(0,0);glVertex3f(-windowWidth/2,-windowHeight/2,0);
	glTexCoord2d(1,0);glVertex3f(-1,-windowHeight/2,0);
	glEnd();
	glDisable(GL_TEXTURE_2D);
	
	glutSwapBuffers();
}

//shadowmap.vert
#version 120

uniform mat4 DepthBiasMVP;

varying vec4 ShadowCoord;

void main()
{
	gl_Position = ftransform();
	
	gl_FrontColor = gl_Color;
	
	ShadowCoord = DepthBiasMVP * gl_Vertex;

}

//shadowmap.frag
#version 120

uniform sampler2D ShadowMap;

varying vec4 ShadowCoord;


void main()
{
	vec4 shadowCoordinateWdivide = ShadowCoord / ShadowCoord.w;
	
	shadowCoordinateWdivide.z += 0.0005;
	
	float distanceFromLight = texture2D(ShadowMap, shadowCoordinateWdivide.st).z;
	
	float shadow = 1.0;
	
	if(ShadowCoord.w > 0.0)
		shadow = distanceFromLight < shadowCoordinateWdivide.z ? 0.5 : 0.99;
		
	
	gl_FragColor = shadow * gl_Color;

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值