最简单的shadow volume

看了简单shadow volume  主要参考:http://www.zwqxin.com/archives/opengl/shadow-volume-1.html 和http://bbs.pfan.cn/post-252901.html

实现:一个方形 的阴影体产生

效果:,蓝色为产生阴影体的正方形, 黄色代表点光源(其实没开光源),红色为阴影。

主要运用:简单的z_pass。  没有进行边缘检测等,直接用正方形四个点产生阴影体。

疑问和缺点:没有用vector<> 直接用的数组,但是用的很不好,感觉很麻烦。

                      刚用vbo,不熟悉,在绘制黑色屏幕时, 是不是每一次都要指定相应的vertex buffer ??但是前面指定过了,难道没用? 

                     两个缺点:第一个视点在阴影体内的话可以用z_fail解决,

                                          从图中看出,其实球体的底部也被阴影绘制了,这个怎么解决,恐怕通过volume没法解决????还是进行麻烦的检测是不是第一个接收阴影照射的面???

 

zwq:这是因为我们生成阴影锥体的时候用的是模型的本地坐标来进行计算;但是实际上你一般会经过坐标系变换,把物体“移动”到一个位置,譬如右移3单位,那么你的阴影锥计算就会出错。所以一般两个选择:把物体的所有顶点x坐标都+3,再计算阴影锥;把光源位置x坐标-3(转换到模型坐标系),计算阴影锥。哪一种计算量少点很明显。

附完整代码:

 

#include "GLee.h"
#include <gl/glut.h>
#include <stdlib.h>
#include <gl/GL.h>



static GLfloat  LightPos[] = { 0.0f, 3.0f,  0.0f, 1.0f};			// Light Position
static GLfloat	LightAmb[] = {0.7f, 0.7f, 0.7f, 1.0f};				// 环境光
static GLfloat	LightDif[] = {1.0f, 1.0f, 1.0f, 1.0f};				// 漫射光

//float LightSpc[] = {1.0f, 1.0f, 1.0f, .0f};			// Specular Light Values
const float light_r= 0.3;//假设正方形为光源


void init(void )
{
	glClearColor(0.0,0.0,0.0,0.0);
	
	//glLightfv(GL_LIGHT0, GL_POSITION, LightPos);		// Set Light1 Position
	//glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmb);			// Set Light1 Ambience
	//glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDif);			// Set Light1 Diffuse
	//glLightfv(GL_LIGHT1, GL_SPECULAR, LightSpc);		// Set Light1 Specular
	//glEnable(GL_LIGHT0);								// Enable Light1
	//glEnable(GL_LIGHTING);	
	
    glCullFace(GL_BACK);
	glEnable(GL_CULL_FACE);	
	glEnable(GL_DEPTH_TEST);
}


void reshap(int width,int height )
{
	glViewport(0,0,(GLsizei)width,(GLsizei)height);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45,(GLfloat)width/(GLfloat)height,0.1,200);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.0,1.0,15.0,0.0,0.0,-10.0,0.0,1.0,0.0);

	//glLoadIdentity();
}



void shadow_volume(GLfloat vetex_dest[4][3],GLfloat light_position[3])
{
   GLfloat  volume_vertex[8][3]=
   {
	   vetex_dest[0][0],vetex_dest[0][1],vetex_dest[0][2],  //0 
	
	   vetex_dest[1][0],vetex_dest[1][1],vetex_dest[1][2],  //1

	   vetex_dest[2][0],vetex_dest[2][1],vetex_dest[2][2],  //2

	   vetex_dest[3][0],vetex_dest[3][1],vetex_dest[3][2], //3


(vetex_dest[0][0]-light_position[0])*100+vetex_dest[0][0], //4
(vetex_dest[0][1]-light_position[1])*100+vetex_dest[0][1],
(vetex_dest[0][2]-light_position[2])*100+vetex_dest[0][2],


(vetex_dest[1][0]-light_position[0])*100+vetex_dest[1][0],//5
(vetex_dest[1][1]-light_position[1])*100+vetex_dest[1][1],
(vetex_dest[1][2]-light_position[2])*100+vetex_dest[1][2],

(vetex_dest[2][0]-light_position[0])*100+vetex_dest[2][0],//6
(vetex_dest[2][1]-light_position[1])*100+vetex_dest[2][1],
(vetex_dest[2][2]-light_position[2])*100+vetex_dest[2][2],

(vetex_dest[3][0]-light_position[0])*100+vetex_dest[3][0],//7
(vetex_dest[3][1]-light_position[1])*100+vetex_dest[3][1],
(vetex_dest[3][2]-light_position[2])*100+vetex_dest[3][2],

  };


   GLint volume_index[4][4]=             //must保证逆时针顺序
   {
       0,3,7,4,  //front
	   0,4,5,1, //right
	   1,5,6,2,
	   2,6,7,3,

   };


   GLuint vol_v_buffer=0,
          vol_i_buffer=0;

   glGenBuffers(1,&vol_v_buffer);
   glGenBuffers(1,&vol_i_buffer);

   glBindBuffer(GL_ARRAY_BUFFER,vol_v_buffer);
   glBufferData(GL_ARRAY_BUFFER,sizeof(volume_vertex),volume_vertex,GL_STATIC_DRAW);
   glEnableClientState(GL_VERTEX_ARRAY);

   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,vol_i_buffer);
   glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(volume_index),volume_index,GL_STATIC_DRAW);

   glInterleavedArrays(GL_V3F,0,0);
   glDrawElements(GL_QUADS,24,GL_UNSIGNED_INT,NULL);


}




void keyboard(unsigned char key,int x,int y);
void display(void )
{
	glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);


	//open light



	 GLfloat vertex_list[][6]=
	{
		{ 0.8, 0.8, 0.8,     4.0,  -4.0,  -4.0}, //四边形里端
		{0.8, 0.8, 0.8,	   4.0,   4.0,  -4.0},
		{0.8, 0.8, 0.8,	    -4.0,  4.0,  -4.0},
		{0.8, 0.8, 0.8,   -4.0,  -4.0,  -4.0},

		{0.8, 0.8, 0.8,  4.0, -4.0,  4.0},     //底端 
		{0.8, 0.8, 0.8,  4.0, -4.0, -4.0},
		{0.8, 0.8, 0.8,  -4.0, -4.0,  -4.0},
		{0.8, 0.8, 0.8,  -4.0,  -4.0,  4.0},

		{0.8, 0.8, 0.8,  -4.0, -4.0,  4.0},   //左侧
		{0.8, 0.8, 0.8,	    -4.0,  -4.0,  -4.0},
		{0.8, 0.8, 0.8,  -4.0,  4.0,  -4.0},
		{0.8, 0.8, 0.8,  -4.0,  4.0,  4.0},

	 0.0 , 0.0,  0.8,     2.0, -2.0,  2.0,     //阴影产生者 12 13 14 15
	0.0 , 0.0,  0.8,   2.0,  -2.0,  -2.0,
	 0.0 , 0.0,  0.8,  -2.0, -2.0,  -2.0,
	0.0 , 0.0,  0.8,   -2.0,  -2.0,  2.0,


	0.8, 0.8, 0.0,        LightPos[0]+light_r,  LightPos[1]-light_r, LightPos[2]-light_r, //假定为光源
	0.8, 0.8, 0.0,  	 LightPos[0]+light_r,  LightPos[1]+light_r, LightPos[2]-light_r,
	0.8, 0.8, 0.0,	    LightPos[0]-light_r,  LightPos[1]+light_r, LightPos[2]-light_r,
	0.8, 0.8, 0.0,      LightPos[0]-light_r,  LightPos[1]-light_r, LightPos[2]-light_r,


	0.8,0.0,0.0,    20,-20,10,   //直接在投影矩阵里绘制大型quad,没有转换到二维视图了
   0.8,0.0,0.0,    -20,-20,10,
   0.8,0.0,0.0,    -20,20,10,
    0.8,0.0,0.0,    20,20,10,

	};


	static const GLint index_list[][4]=
	{
       0,  1,  2,   3,
       4,   5,  6,  7,
	   8,  9,   10,  11,
	   12,  13,  14,  15,
	   16,   17,  18,  19,
	   20,  21,   22,   23,

	};
	static const GLint shadow_buffer_index_list[][4]=
	{
         20,  21,   22,   23,
	};

	GLuint vbuffer=0,
		   ibuffer=0,		     
	       shadow_buffer=0;//涂黑用的buffer

	//GLeeInit();
	glGenBuffers(1,&vbuffer);
    glGenBuffers(1,&ibuffer);
	glGenBuffers(1,&shadow_buffer);

	glBindBuffer(GL_ARRAY_BUFFER,vbuffer);
	glBufferData(GL_ARRAY_BUFFER,sizeof(vertex_list),vertex_list,GL_STATIC_DRAW);

	
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ibuffer);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(index_list),index_list,GL_STATIC_DRAW);

	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_VERTEX_ARRAY);

	glInterleavedArrays(GL_C3F_V3F,0,0);

	glDrawElements(GL_QUADS,20,GL_UNSIGNED_INT,NULL);


	glPushMatrix();
	glTranslatef(0.0,-3.5,3.0);
	glutSolidSphere(1,20,20);

	glPopMatrix();
/test//检测阴影体
	//GLfloat temp_vertex[4][3]=
	//{

	//	vertex_list[12][3], vertex_list[12][4],vertex_list[12][5],
	//	vertex_list[13][3], vertex_list[13][4],vertex_list[13][5],
	//	vertex_list[14][3], vertex_list[14][4],vertex_list[14][5],
	//	vertex_list[15][3], vertex_list[15][4],vertex_list[15][5],


	//};
	//glColor4f(1,1,0,1);
	//shadow_volume(temp_vertex,LightPos);
///test//
	
	glPushAttrib(GL_ALL_ATTRIB_BITS);

	glEnable(GL_CULL_FACE);
	glDisable(GL_LIGHTING);
	glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
	glDepthMask(GL_FALSE);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_STENCIL_TEST);
	glClearStencil(0);

	glDepthFunc(GL_LESS);
	glStencilFunc(GL_ALWAYS,1,1);
	glStencilOp(GL_KEEP,GL_KEEP,GL_INCR);
	glFrontFace(GL_CCW);



	GLfloat temp_vertex[4][3]=
	{

		vertex_list[12][3], vertex_list[12][4],vertex_list[12][5],
		vertex_list[13][3], vertex_list[13][4],vertex_list[13][5],
		vertex_list[14][3], vertex_list[14][4],vertex_list[14][5],
		vertex_list[15][3], vertex_list[15][4],vertex_list[15][5],


	};
	shadow_volume(temp_vertex,LightPos);

	glStencilOp(GL_KEEP,GL_KEEP,GL_DECR);
	glFrontFace(GL_CW);
	shadow_volume(temp_vertex,LightPos);



	//draw shadow
	glStencilFunc(GL_NOTEQUAL,0,1);
	glStencilFunc(GL_KEEP,GL_KEEP,GL_KEEP);


	glDisable(GL_CULL_FACE);
	glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC0_ALPHA,GL_ONE_MINUS_SRC_ALPHA);


//是不是每一次都要指定相应的vertex buffer ??但是前面指定过了,难道没用?

	 glBindBuffer(GL_ARRAY_BUFFER,vbuffer);
	 glBufferData(GL_ARRAY_BUFFER,sizeof(vertex_list),vertex_list,GL_STATIC_DRAW);


	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ibuffer);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER,24*sizeof(GLint),index_list+5,GL_STATIC_DRAW);

	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_VERTEX_ARRAY);

	glInterleavedArrays(GL_C3F_V3F,0,0);

	glDrawElements(GL_QUADS,4,GL_UNSIGNED_INT,NULL);





	//glColor4f(0.8,0.0,0.0,0.9);
	//glBegin(GL_QUADS);
	//glVertex3f(20,-20,10);
	//glVertex3f(-20,-20,10);
	//glVertex3f(-20,20,10);
	//glVertex3f(20,20,10);
	//glEnd();

       

	glDisable(GL_BLEND);
	glDisable(GL_CULL_FACE);
	glEnable(GL_LIGHTING);
	glDepthFunc(GL_LEQUAL);
	glDepthMask(GL_TRUE);
	glDisable(GL_STENCIL_TEST);

	glPopAttrib();



  
	glutSwapBuffers();
}


void keyboard(unsigned char key,int x,int y)
{
	switch(key)
	{

	case 'w':

		LightPos[2]=LightPos[2]-0.4;
		glutPostRedisplay();
		break;

	case  's':
		LightPos[2]=LightPos[2]+0.4;
		glutPostRedisplay();
		break;

	case  'd':
		LightPos[0]=LightPos[0]+0.4;
		glutPostRedisplay();	
		break;

	case  'a':
		LightPos[0]=LightPos[0]-0.4;
		glutPostRedisplay();
		break;

	case 27:
		exit(0);
		break;
	default:
		break;

	}
}


int main(int argc,char** argv )
{
	glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_RGBA| GLUT_DOUBLE |GLUT_DEPTH |GLUT_STENCIL);
	glutInitWindowSize(800,600);
	glutInitWindowPosition(100,100);
	glutCreateWindow("Shadow Volume");


	init();
	glutDisplayFunc(&display);
	glutReshapeFunc(reshap);
	glutKeyboardFunc(&keyboard);
	//glutIdleFunc(keyboard);

	glutMainLoop();

	return 0;
}


 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值