我作爲NeHe導師Lesson27告訴我的代碼,但它是一個z-pass算法。當我在陰影中時,陰影消失了。有人告訴我,我可以使用z-fail算法來解決這個問題。所以我花了兩天的時間研究z-fail算法。最後,我無法弄清楚。我的程序從未如我所想的那樣運行。如何在opengl中實現z-fail算法?
的z失敗算法作爲維基上市:
深度失敗 大約在2000年,幾個人發現,可製成Heidmann的方法,通過扭轉深度爲所有相機位置的工作。而不是計算物體表面前面的陰影表面,它後面的表面可以很容易計數,最終結果相同。這解決了眼睛處於陰影中的問題,因爲眼睛和物體之間的陰影體積不計算在內,但是會引入陰影體積的後端必須被遮蓋的情況,或者陰影將最終丟失在體積點的位置回到無限。
禁止寫入深度和顏色緩衝區。
使用正面剔除。
將模板操作設置爲在深度失敗時遞增(僅計算對象後面的陰影)。
渲染陰影卷。
使用背面剔除。
將模板操作設置爲減少深度失敗。
渲染陰影卷。
我認爲的主要問題是深度測試。在第3步和第6步,模板操作基於深度失敗。儘管它可以顯示陰影,但它可能會隱藏在它之前的對象上(即:深度緩衝值小於它的對象)。所有陰影效果看起來很亂。
但是在z-pass算法中,模板操作是基於深度通過的,這意味着它不僅能夠顯示出陰影,而且還能夠隱藏它後面的對象,符合眼睛系統。
那麼如何解決這個問題使我的深度失效算法顯示出正確物體上的陰影。
這裏是我的Z-失敗算法代碼(某處可能是在哪裏,請幫我找出來,陰影效果是可怕的)
VECTOR vec;
void shadowvolume(SECTOR &sec,float *lp)
{
unsigned int p1, p2;
VECTOR v1, v2;
int i, j, k, jj;
for (i=0; i<sec.numplanes;i++)
{
if (sec.planes[i].visible)
{
for (j=0;j<3;j++)
{
k = sec.planes[i].neigh[j];
if ((!k) || (!sec.planes[k-1].visible))//如果以第k個點開始的鄰邊沒有相鄰平面或者相鄰平面不可見
{
// here we have an edge, we must draw a polygon
p1 = sec.planes[i].p[j]-1;//鄰邊的起點
jj = (j+1)%3;
p2 = sec.planes[i].p[jj]-1;//鄰邊的終點
//calculate the length of the vector
v1.x = (sec.points[p1].vec.x - lp[0])*100;
v1.y = (sec.points[p1].vec.y - lp[1])*100;
v1.z = (sec.points[p1].vec.z - lp[2])*100;
v2.x = (sec.points[p2].vec.x - lp[0])*100;
v2.y = (sec.points[p2].vec.y - lp[1])*100;
v2.z = (sec.points[p2].vec.z - lp[2])*100;
glBegin(GL_TRIANGLE_STRIP);//將光源連到鄰邊的起點並延長,將光源連到鄰邊的終點的並延長,最後延長出來的梯形,畫了過後模板緩衝區的值加1
glVertex3f(sec.points[p1].vec.x,sec.points[p1].vec.y,sec.points[p1].vec.z);
glVertex3f(sec.points[p1].vec.x + v1.x,sec.points[p1].vec.y + v1.y,sec.points[p1].vec.z + v1.z);
glVertex3f(sec.points[p2].vec.x,sec.points[p2].vec.y,sec.points[p2].vec.z);
glVertex3f(sec.points[p2].vec.x + v2.x,sec.points[p2].vec.y + v2.y,sec.points[p2].vec.z + v2.z);
glEnd();
}
}
// caps
glBegin(GL_TRIANGLES);
for(k=0;k<3;k++)
glVertex3fv((float*)&sec.points[sec.planes[i].p[k]-1].vec);
glEnd();
glBegin(GL_TRIANGLES);
for(k=2;k>=0;k--)
{
vec.x=sec.points[sec.planes[i].p[k]-1].vec.x+(sec.points[sec.planes[i].p[k]-1].vec.x-lp[0])*100;
vec.y=sec.points[sec.planes[i].p[k]-1].vec.y+(sec.points[sec.planes[i].p[k]-1].vec.y-lp[1])*100;
vec.z=sec.points[sec.planes[i].p[k]-1].vec.z+(sec.points[sec.planes[i].p[k]-1].vec.z-lp[2])*100;
glVertex3fv((float*)&vec);
}
glEnd();
}
}
}
void CastShadow(SECTOR &sec, float *lp)
{//lp是光源相對於物體的位置
float side;
glEnable(GL_CULL_FACE);
int i;
for (i=0;i<sec.numplanes;i++)
{
side =sec.planes[i].planeeq.a*lp[0]+sec.planes[i].planeeq.b*lp[1]+sec.planes[i].planeeq.c*lp[2]+sec.planes[i].planeeq.d*lp[3];
if (side>0)
sec.planes[i].visible = TRUE;
else
sec.planes[i].visible = FALSE;
}
glDisable(GL_LIGHTING);
glDepthMask(GL_FALSE);
glDepthFunc(GL_LEQUAL);
glEnable(GL_STENCIL_TEST);
glColorMask(0, 0, 0, 0);
glStencilFunc(GL_ALWAYS, 0, 0xffffffff);
glCullFace(GL_FRONT);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
//glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
shadowvolume(sec,lp);
glCullFace(GL_BACK);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
//glStencilOp(GL_KEEP,GL_KEEP, GL_INCR);
shadowvolume(sec,lp);
glColorMask(1, 1, 1, 1);
//draw a shadowing rectangle covering the entire screen
glColor4f(0.0f, 0.0f, 0.0f,0.4f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glStencilFunc(GL_NOTEQUAL, 0, 0xffffffff);
//glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glPushMatrix();
glLoadIdentity();
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(-0.1f, 0.1f,-0.0010f);
glVertex3f(-0.1f,-0.1f,-0.0010f);
glVertex3f(0.1f, 0.1f,-0.0010f);
glVertex3f(0.1f,-0.1f,-0.0010f);
glEnd();
glPopMatrix();
glDisable(GL_BLEND);
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
glEnable(GL_LIGHTING);
glDisable(GL_STENCIL_TEST);
glShadeModel(GL_SMOOTH);
glDisable(GL_CULL_FACE);
}
Vector類是這樣的:
class VECTOR
{
public:
float x,y,z;
bool operator==(VECTOR vec)
{
if(x==vec.x && y==vec.y && z==vec.z)
return true;
return false;
}
};
SECTOR類和其他是這樣的:
class PLANEEQ
{
public:
float a,b,c,d;
};
class PLANE
{
public:
unsigned int p[3];//點的序號
VECTOR normal[3];
unsigned int neigh[3];//平面3個相依平面的序號
PLANEEQ planeeq;
bool visible;
PLANE()
{
neigh[0]=0;
neigh[1]=0;
neigh[2]=0;
planeeq.a=0;
planeeq.b=0;
planeeq.c=0;
planeeq.d=0;
visible=false;
}
};
class SECTOR
{
public:
int numpoints;
int numplanes;
vector<VERTEX> points;
vector<PLANE> planes;
MATERIAL material;
bool read();
bool loadtexture();
bool build();
bool plane_calc();
void SetConnectivity();
SECTOR& SECTOR::subdivide(long depth);
SECTOR(string str1,string str2):modelfilename(str1),texturefilename(str2)
{
numpoints=0;
numplanes=0;
}
SECTOR()
{
numpoints=0;
numplanes=0;
}
private:
FILE *modelfilein,*texturefilein;
string modelfilename,texturefilename;
char oneline[255];
UINT texturename;
AUX_RGBImageRec *TextureImage;
};
class POSITION
{
public:
float x,y,z,w;
};
DrawGLScene函數在我的主。CPP是這樣的:
int DrawGLScene(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |GL_STENCIL_BUFFER_BIT);
glLoadIdentity();
DrawGLRoom();
glLoadIdentity();
GLfloat xtrans = -xpos;
GLfloat ztrans = -zpos;
GLfloat ytrans = -ypos-1.2f;
GLfloat sceneroty = 360.0f - yrot;
glRotatef(lookupdown,1.0f,0,0);
glRotatef(sceneroty,0,1.0f,0);
glTranslatef(xtrans, ytrans, ztrans);
brick_sec.build();
floor_sec.build();
//wall_sec.build();
//CastShadow(wall_sec,(float *)&lightgroup.lights[0].pos);
CastShadow(brick_sec,(float*)&lightgroup.lights[0].pos);
CastShadow(floor_sec,(float*)&lightgroup.lights[0].pos);
lightgroup.build();
glColor4f(0.7f, 0.4f, 0.0f, 1.0f);
glDisable(GL_LIGHTING);
glDepthMask(GL_FALSE);
glTranslatef(lightgroup.lights[0].pos.x, lightgroup.lights[0].pos.y, lightgroup.lights[0].pos.z);
gluSphere(q, 0.2f, 16, 8);
glEnable(GL_LIGHTING);
glDepthMask(GL_TRUE);
if(space_time>0)
{
ypos=sin(space_time*3.1415926/180);
space_time-=4;
}
else
{
sp=false;
}
//glFlush();
return TRUE; // Everything Went OK
}
由於我的名聲是10歲以下的,我無法捕捉陰影效果,以顯示它ü多麼嚴重的樣子!請幫助我,我會告訴你我的注意力和你的時間!
thx Najzero給了我5個聲望,現在我可以捕捉屏幕來顯示效果。我會追加一個細節描述。
的Z-pass算法效果: 當我在效果又不是,這是確定(橙色壺代表光)
,但是當我在wall_shadow我,這是不正常!wall_shadow消失了,雖然brick_shadow仍然存在。
,所以我需要的z失敗算法來解決這個問題。但最後的效果我的代碼實現的是這樣的: 刻度代表陰影效果是正確的,十字代表的影子不該不會出現在對象上。
另一張截圖,
哦,這應該是有趣的。我們遇到了類似問題。你的近平面設置爲?沒有看到gluPerspective()調用來猜測。當近平面爲0時,對於涉及Z渲染的所有事物都得到一些瘋狂的結果 – Najzero
這裏是我的gluPerspective函數:我的近平面設置爲0.001f gluPerspective(45.0f,(GLfloat)width /(GLfloat)height,0.001f,100.0 F); 近平面不能爲0,你可以使用0.00001來代替。 – nomorefancy
此代碼被極度廢棄。 –