I'm using glReadPixels to get depth value of select pixel, but i always get 1, how can i solve it? here is the code:
glEnable(GL_DEPTH_TEST);
..
glReadPixels(x, viewport[3] - y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, z);
Do I miss anything? And my rendering part is shown below. I use different shaders to draw different part of scene, so how should i make it correct to read depth value from buffer?
void onDisplay(void)
{
// Clear the window and the depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// calculate the view matrix.
GLFrame eyeFrame;
eyeFrame.MoveUp(gb_eye_height);
eyeFrame.RotateWorld(gb_eye_theta * 3.1415926 / 180.0, 1.0, 0.0, 0.0);
eyeFrame.RotateWorld(gb_eye_phi * 3.1415926 / 180.0, 0.0, 1.0, 0.0);
eyeFrame.MoveForward(-gb_eye_radius);
eyeFrame.GetCameraMatrix(gb_hit_modelview);
gb_modelViewMatrix.PushMatrix(gb_hit_modelview);
// draw coordinate system
if(gb_bCoord)
{
DrawCoordinateAxis();
}
if(gb_bTexture)
{
GLfloat vEyeLight[] = { -100.0f, 100.0f, 150.0f };
GLfloat vAmbientColor[] = { 0.2f, 0.2f, 0.2f, 1.0f };
GLfloat vDiffuseColor[] = { 1.0f, 1.0f, 1.0f, 1.0f};
glUseProgram(normalMapShader);
glUniform4fv(locAmbient, 1, vAmbientColor);
glUniform4fv(locDiffuse, 1, vDiffuseColor);
glUniform3fv(locLight, 1, vEyeLight);
glUniform1i(locColorMap, 0);
glUniform1i(locNormalMap, 1);
gb_treeskl.Display(SetGeneralColor, SetSelectedColor, 0);
}
else
{
if(!gb_bOnlyVoxel)
{
if(gb_bPoints)
{
//GLfloat vPointColor[] = { 1.0, 1.0, 0.0, 0.6 };
GLfloat vPointColor[] = { 0.2, 0.0, 0.0, 0.9 };
gb_shaderManager.UseStockShader(GLT_SHADER_FLAT, gb_transformPipeline.GetModelViewProjectionMatrix(), vPointColor);
gb_treeskl.Display(NULL, NULL, 1);
}
if(gb_bSkeleton)
{
GLfloat vEyeLight[] = { -100.0f, 100.0f, 150.0f };
glUseProgram(adsPhongShader);
glUniform3fv(locLight, 1, vEyeLight);
gb_treeskl.Display(SetGeneralColor, SetSelectedColor, 0);
}
}
if(gb_bVoxel)
{
GLfloat vEyeLight[] = { -100.0f, 100.0f, 150.0f };
glUseProgram(adsPhongShader);
glUniform3fv(locLight, 1, vEyeLight);
SetVoxelColor();
glPolygonMode(GL_FRONT, GL_LINE);
glLineWidth(1.0f);
gb_treeskl.DisplayVoxel();
glPolygonMode(GL_FRONT, GL_FILL);
}
}
//glUniformMatrix4fv(locMVP, 1, GL_FALSE, gb_transformPipeline.GetModelViewProjectionMatrix());
//glUniformMatrix4fv(locMV, 1, GL_FALSE, gb_transformPipeline.GetModelViewMatrix());
//glUniformMatrix3fv(locNM, 1, GL_FALSE, gb_transformPipeline.GetNormalMatrix());
//gb_sphereBatch.Draw();
gb_modelViewMatrix.PopMatrix();
glutSwapBuffers();
}
I think you are reading correctly the only problem is that you are not linearize the depth from buffer back to <znear...zfar> range hence the ~1 value for whole screen due to logarithmic dependence of depth (almost all the values are very close to 1).
I am doing this like this:
double glReadDepth(double x,double y,double *per=NULL) // x,y [pixels], per[16]
{
GLfloat _z=0.0; double m[16],z,zFar,zNear;
if (per==NULL){ per=m; glGetDoublev(GL_PROJECTION_MATRIX,per); } // use actual perspective matrix if not passed
zFar =0.5*per[14]*(1.0-((per[10]-1.0)/(per[10]+1.0))); // compute zFar from perspective matrix
zNear=zFar*(per[10]+1.0)/(per[10]-1.0); // compute zNear from perspective matrix
glReadPixels(x,y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&_z); // read depth value
z=_z; // logarithmic
z=(2.0*z)-1.0; // logarithmic NDC
z=(2.0*zNear*zFar)/(zFar+zNear-(z*(zFar-zNear))); // linear <zNear,zFar>
return -z;
}
Do not forget that x,y is in pixels and (0,0) is bottom left corner !!! The returned depth is in range <zNear,zFar>. The function is assuming you are using perspective transform like this:
void glPerspective(double fovy,double aspect,double zNear,double zFar)
{
double per[16],f;
for (int i=0;i<16;i++) per[i]=0.0;
// original gluProjection
// f=divide(1.0,tan(0.5*fovy*deg))
// per[ 0]=f/aspect;
// per[ 5]=f;
// corrected gluProjection
f=divide(1.0,tan(0.5*fovy*deg*aspect));
per[ 0]=f;
per[ 5]=f*aspect;
// z range
per[10]=divide(zFar+zNear,zNear-zFar);
per[11]=-1.0;
per[14]=divide(2.0*zFar*zNear,zNear-zFar);
glLoadMatrixd(per);
}
Beware the depth accuracy will be good only for close to camera object without linear depth buffer. For more info see:
How to correctly linearize depth in OpenGL ES in iOS?
If the problem persist there might be also another reason for this. Do you have Depth buffer in your pixel format? In windows You can check like this:
Getting a window's pixel format
Missing depth buffer could explain why the value is always 1 (not like ~0.997). In such case you need to change the init of your window enabling some bits for depth buffer (16/24/32). See:
What is the proper OpenGL initialisation on Intel HD 3000?
For more detailed info about using this technique (with C++ example) see:
OpenGL 3D-raypicking with high poly meshes
Well, you missed to past the really relevent parts of the code. Also the status of the depth testing unit has no influence on what glReadPixels delivers. How about you post your rendering code as well.
Update
After a buffer swap SwapBuffers the contents of the back buffer are undefined and the default state for frame buffer reads is to read from the back buffer. Technically double buffering happens on only the color component, not the depth and stencil component. But you might run into a driver issue with that.
I suggest two tests to rule out those:
Do a read of the depth buffer with glReadBuffer(GL_BACK); right before the SwapBuffers.
Select the front buffer with glReadBuffer(GL_FRONT); for reading after SwapBuffers
Also please specify in which context (program, not OpenGL, well the later, too) you did your glReadPixels when this problem occours. Also check if you can read color value correctly.
Related
For practice I am setting up a 2d/orthographic rendering pipeline in openGL to be used for a simple game, but I am having issues related to the coordinate system.
In short, rotations distort 2d shapes, and I cannot seem to figure why. I am also not entirely sure that my coordinate system is sound.
First I looked for previous answers, but the following (the most relevant 2D opengl rotation causes sprite distortion) indicates that the problem was an incorrect ordering of transformations, but for now I am using just a view matrix and projection matrix, multiplied in the correct order in the vertex shader:
gl_Position = projection * view * model vec4(1.0); //(The model is just the identity matrix.)
To summarize my setup so far:
- I am successfully uploading a quad that should stretch across the whole screen:
GLfloat vertices[] = {
-wf, hf, 0.0f, 0.0, 0.0, 1.0, 1.0, // top left
-wf, -hf, 0.0f, 0.0, 0.0, 1.0, 1.0, // bottom left
wf, -hf, 0.0f, 0.0, 0.0, 1.0, 1.0, // bottom right
wf, hf, 0.0f, 0.0, 0.0, 1.0, 1.0, // top right
};
GLuint indices[] = {
0, 1, 2, // first Triangle
2, 3, 0, // second Triangle
};
wf and hf are 1, and I am trying to use a -1 to 1 coordinate system so I don't need to scale by the resolution in shaders (though I am not sure that this is correct to do.)
My viewport and orthographic matrix:
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
...
glm::mat4 mat_ident(1.0f);
glm::mat4 mat_projection = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
... though this clearly does not factor in the screen width and height. I have seen others use width and height instead of 1s, but this seems to break the system or display nothing.
I rotate with a static method that modifies a struct containing a glm::quaternion (time / 1000) to get seconds:
main_cam.rotate((GLfloat)curr_time / TIME_UNIT_TO_SECONDS, 0.0f, 0.0f, 1.0f);
// which does: glm::angleAxis(angle, glm::vec3(x, y, z) * orientation)
Lastly, I pass the matrix as a uniform:
glUniformMatrix4fv(MAT_LOC, 1, GL_FALSE, glm::value_ptr(mat_projection * FreeCamera_calc_view_matrix(&main_cam) * mat_ident));
...and multiply in the vertex shader
gl_Position = u_matrix * vec4(a_position, 1.0);
v_position = a_position.xyz;
The full-screen quad rotates on its center (0, 0 as I wanted), but its length and width distort, which means that I didn't set something correctly.
My best guess is that I haven't created the right ortho matrix, but admittedly I have had trouble finding anything else on stack overflow or elsewhere that might help debug. Most answers suggest that the matrix multiplication order is wrong, but that is not the case here.
A secondary question is--should I not set my coordinates to 1/-1 in the context of a 2d game? I did so in order to make writing shaders easier. I am also concerned about character/object movement once I add model matrices.
What might be causing the issue? If I need to multiply the arguments to gl::ortho by width and height, then how do I transform coordinates so v_position (my "in"/"varying" interpolated version of the position attribute) works in -1 to 1 as it should in a shader? What are the implications of choosing a particular coordinates system when it comes to ease of placing entities? The game will use sprites and textures, so I was considering a pixel coordinate system, but that quickly became very challenging to reason about on the shader side. I would much rather have THIS working.
Thank you for your help.
EDIT: Is it possible that my varying/interpolated v_position should be set to the calculated gl_Position value instead of the attribute position?
Try accounting for the aspect ratio of the window you are displaying on in the first two parameters of glm::ortho to reflect the aspect ratio of your display.
GLfloat aspectRatio = SCREEN_WIDTH / SCREEN_HEIGHT;
glm::mat4 mat_projection = glm::ortho(-aspectRatio, aspectRatio, -1.0f, 1.0f, -1.0f, 1.0f);
Here's the vertex buffer information of the quad I'm drawing:
static const GLfloat pv_quad[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
This quad is used to draw 2D frames on the screen as part of the graphical user interface. The class I use to do this is Mage::Interface::Frame. I'll spare you the header definition and instead give you the class's implementation, as it's small. There's some test code in here, so ignore the fact the shader is part of the class. I know it shouldn't be there.
#include <Mage/Root.h>
#include <Mage/Interface/Frame.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
using Mage::Interface::Frame;
Frame::Frame()
: width(300), height(200), position(0, 0), color(1.0, 1.0, 1.0), model(1.0), rotation(0) {
prog.compileFile("Data/Shaders/FrameVertex.glsl", Mage::ShaderType::VERTEX);
prog.compileFile("Data/Shaders/FrameFragment.glsl", Mage::ShaderType::FRAGMENT);
prog.link();
this->calcTransform();
}
void Frame::setSize(int w, int h) {
this->width = w;
this->height = h;
this->calcTransform();
}
void Frame::setColor(int r, int g, int b) {
this->color = glm::vec3(float(r) / 256, float(g) / 256, float(b) / 256);
}
void Frame::setRotation(float degrees) {
this->rotation = glm::radians(degrees);
this->calcTransform();
}
void Frame::calcTransform() {
this->model = glm::mat4(1.0f); // reset model to origin.
// 1280 and 720 are the viewport's size. This is only hard coded for tests.
this->model = glm::scale(this->model, glm::vec3(float(width) / 1280, float(height) / 720, 1.0f));
this->model = glm::rotate(this->model, this->rotation, glm::vec3(0.0f, 0.0f, 1.0f));
this->model = glm::translate(this->model, glm::vec3(position.x, position.y, 0.0f));
}
void Frame::draw() {
Mage::VertexObject obj = ROOT.getRenderWindow()->getVertexBufferObject()->getObject("PrimitiveQuad");
prog.use();
prog.setUniform("mvp", this->model);
prog.setUniform("fColor", this->color);
glEnableVertexAttribArray(0);
ROOT.getRenderWindow()->getVertexBufferObject()->bind();
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)obj.begin);
glDrawArrays(GL_TRIANGLE_STRIP, 0, obj.size);
glDisableVertexAttribArray(0);
}
Here's the drawing function that's called every frame:
void RenderWindow::render() {
Mage::Interface::Frame F;
F.setSize(400, 200);
F.setRotation(0);
while (glfwWindowShouldClose(this->win) == 0) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
F.draw();
glfwSwapBuffers(this->win);
glfwPollEvents();
}
}
When I have setRotation(0), the resulting quad is indeed, 400 pixels wide and 200 pixels high, right in the centre of my screen as you would expect.
However, if I set the rotation to (90), well, this happens:
As you can see, that's not at all close to a 90 degrees turn. It should be 400px high and 200px wide.
Anyone care to explain what's going on here?
EDIT: Some playing around has shown me that the problem is with the scale, not the rotation. When I comment out the scale, the rotation appears to be correct.
The angle argument to glm::rotate() is in radians, not degrees:
m: Input matrix multiplied by this rotation matrix.
angle: Rotation angle expressed in radians.
axis: Rotation axis, recommanded [sic] to be normalized.
Use this:
void Frame::setRotation(float degrees) {
this->rotation = glm::radians( degrees );
this->calcTransform();
}
I am assuming that this game is supposed to be a 3D game with a 2D GUI, although this was not specified in the question, though not entirely necessary, as my answer will be the same.
When rendering with a 3D matrix, using a perspective view (Field of View taken into account), as opposed to using an orthographic view, the shapes will bend to their position depending on the fov.
So with that, I propose that you use a simple solution, and initialize a 2D viewing matrix (or orthographic matrix) for your 2D interface. If you are just looking for a simple way to render a 2D quad onto the screen freeGLUT(free Graphics Library Utility Toolkit) is there for you. There are plenty of docs out there to help install freeglut, so once you finish that, initialize a 2D rendering matrix, then render the quad using glVertex2i/f or glVertex3i/f, like so:
void setView2d()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, *SCREEN_WIDTH, *SCREEN_HEIGHT, 0);
glMatrixMode( GL_MODELVIEW );
glDisable(GL_DEPTH_TEST);
glLoadIdentity();
}
void setView3d()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70, (GL_FLOAT)*SCREEN_WIDTH / *SCREEN_HEIGHT, 0.1, 100);
glEnable(GL_DEPTH_TEST);
glLoadIdentity();
}
void render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_TEST);
setView2d(); //Render 2D objects
glPushMatrix();
{
//glTranslatef() and glRotatef() still work for 2D
//if using rotate, rotate on z axis, like so:
glRotatef(90, 0, 0, 1);
glBegin(GL_TRIANGLES);
{
glVertex2i(0, 0);
glVertex2i(100, 0);
glVertex2i(0, 100);
/*
glVertex2i is replacable with glVertex2f, glVertex3i, and glVertex3f
if using a glVertex3, set the z value to 0
*/
}
glEnd();
}
glPopMatrix();
setView3d(); //Render 3D objects
glPushMatrix();
{
//render 3D stuff
}
glPopMatrix();
glutSwapBuffers();
}
I should also mention that when using the gluOrtho2D, coordinates used in vertex x,y are based on pixels, instead of the 3D blocks.
Hope this helped,
-Nick
I followed a guide to draw a Lorenz system in 2D.
I want now to extend my project and switch from 2D to 3D. As far as I know I have to substitute the gluOrtho2D call with either gluPerspective or glFrustum. Unfortunately whatever I try is useless.
This is my initialization code:
// set the background color
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
/// set the foreground (pen) color
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);*/
// set the foreground (pen) color
glColor4f(1.0f, 1.0f, 1.0f, 0.02f);
// enable blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// enable point smoothing
glEnable(GL_POINT_SMOOTH);
glPointSize(1.0f);
// set up the viewport
glViewport(0, 0, 400, 400);
// set up the projection matrix (the camera)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//gluOrtho2D(-2.0f, 2.0f, -2.0f, 2.0f);
gluPerspective(45.0f, 1.0f, 0.1f, 100.0f); //Sets the frustum to perspective mode
// set up the modelview matrix (the objects)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
while to draw I do this:
glClear(GL_COLOR_BUFFER_BIT);
// draw some points
glBegin(GL_POINTS);
// go through the equations many times, drawing a point for each iteration
for (int i = 0; i < iterations; i++) {
// compute a new point using the strange attractor equations
float xnew=z*sin(a*x)+cos(b*y);
float ynew=x*sin(c*y)+cos(d*z);
float znew=y*sin(e*z)+cos(f*x);
// save the new point
x = xnew;
y = ynew;
z = znew;
// draw the new point
glVertex3f(x, y, z);
}
glEnd();
// swap the buffers
glutSwapBuffers();
the problem is that I don't visualize anything in my window. It's all black. What am I doing wrong?
The name "gluOrtho2D" is a bit misleading. In fact gluOrtho2D is probably the most useless function ever. The definition of gluOrtho2D is
void gluOrtho2D(
GLdouble left,
GLdouble right,
GLdouble bottom,
GLdouble top )
{
glOrtho(left, right, bottom, top, -1, 1);
}
i.e. the only thing it does it calling glOrtho with default values for near and far. Wow, how complicated and ingenious </sarcasm>.
Anyway, even if it's called ...2D, there's nothing 2-dimensional about it. The projection volume still has a depth range of [-1 ; 1] which is perfectly 3-dimensional.
Most likely the points generated lie outside the projection volume, which has a Z value range of [0.1 ; 100] in your case, but your points are confined to the range [-1 ; 1] in either axis (and IIRC the Z range of the strange attractor is entirely positive). So you have to apply some translation to see something. I suggest you choose
near = 1
far = 10
and apply a translation of Z: -5.5 to move things into the center of the viewing volume.
I code as the NeHe tutors Lesson27 told me,but it's a z-pass algorithm.when i'm in the shadow,the shadow is gone.somebody told me I can use z-fail algorithm to solve this problem.
so I spend two days to research z-fail algorithm.At last ,I can't figure it out.My program never run as what i think.
The z-fail algorithm as the wiki listed:
Depth fail
Around the year 2000, several people discovered that Heidmann's method can be made to work for all camera positions by reversing the depth. Instead of counting the shadow surfaces in front of the object's surface, the surfaces behind it can be counted just as easily, with the same end result. This solves the problem of the eye being in shadow, since shadow volumes between the eye and the object are not counted, but introduces the condition that the rear end of the shadow volume must be capped, or shadows will end up missing where the volume points backward to infinity.
Disable writes to the depth and color buffers.
Use front-face culling.
Set the stencil operation to increment on depth fail (only count shadows behind the object).
Render the shadow volumes.
Use back-face culling.
Set the stencil operation to decrement on depth fail.
Render the shadow volumes.
The Main question I think is the depth test. At step 3 and 6,the stencil operation is based on depth fail.Although it can show out the shadow,but it maybe shadowed on the object before it(i.e:the object which depth buffer value is less than it).so all the shadow effect looks mess.
But in z-pass algorithm,the stencil operation is based on depth pass,that means it not only can show out the shadow,but also shadowed only on the object behind it,that accords with eye system.
so how to solve this problem to make my depth fail algorithm show out the shadow on the right objects.
here is my z-fail algorithm code(somewhere may be where,please help me find out,the shadow effect is awful)
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);
}
the VECTOR class is like this:
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;
}
};
the SECTOR class and others is like this:
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;
};
the DrawGLScene function in my main.cpp is like this:
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
}
Since my reputation is under 10,I can't capture the shadow effect to show u how badly it looks like! pls help me,I would thx u for ur attention and ur time!!!
thx Najzero for giving me 5 reputation,now i can capture the screen to show the effect.I will append a detail description follow.
the z-pass algorithm effect:
when i'm not in the effect,it's ok!(the orange pot represent the light)
but when i'm in the wall_shadow,it's not ok!the wall_shadow is gone,although the brick_shadow is still there.
so I need z-fail algorithm to solve this problem.but the last effect my code realized is like this:
the tick represent the shadow effect is right,the cross represent the shadow shouldn't appear on the object.
another screenshot,
a ha,At last,I find the problem in my code.I am so happy ,lol!!!!!!!!!
the problem is gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.001f,100.0f);
as the GuentherKrass said in the http://www.opengl.org/discussion_boards/showthread.php/146157-Z-Fail-Stencil-Shadow-Volumes
If you do it this way, be sure to use a perspective projection matrix with an infinite far plane or use GL_DEPTH_CLAMP to avoid the back cap being culled by the far clipping plane.
so I just change the code above to
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.001f,1000000.0f);
alright,It looks like perfect!!!!!!!!!!!!!!!!!111 hahahahaaa
two days, stay up, instant noodles..it's god damn so worth!!
ok,, I will put the last effct picture out.If anyone want my code just email me(nomorefancy#gmail.com)
attention:
the brick shadow is independent of the wall shadow.
I'm trying to rotate a 2D image using OGL ES. After load it I can move it through the screen but when trying to rotate the image through its center, it has an odd behavior as the rotation center is the lower-left screen corner, not the center of the image itself.
Googling around I've read that I could push the current matrix, change whatever I need (translate the coords, rotate the image, etc) and then pop the matrix coming back to the previous matrix status... I did it but still not working as I'm looking for (but at least now seems that the original coords where it does the rotation are not the lower-left corner...)
Any thoughts? Anyone could spot where my problem is?
Any help would be much appreciated! Thanks!!
void drawImage(Image *img)
{
GLfloat fX = (GLfloat)img->x;
GLfloat fY = (GLfloat)(flipY(img->m_height+img->y));
GLfloat coordinates[] = { 0, img->m_textureHeight, img->m_textureWidth, img->m_textureHeight, 0, 0, img->m_textureWidth, 0 };
GLfloat vertices[] =
{
fX, fY, 0.0,
img->m_width+fX, fY, 0.0,
fX, img->m_height+fY, 0.0,
img->m_width+fX, img->m_height+fY, 0.0
};
//Push and change de matrix, translate coords, rotate and scale image and then pop the matrix
glPushMatrix(); //push texture matrix
glTranslatef((int)fX, (int)fY, 0.0); //translate texture matrix
// rotate
if (img->rotation != 0.0f )
glRotatef( -img->rotation, 0.0f, 0.0f, 1.0f );
// scale
if (img->scaleX != 1.0f || img->scaleY != 1.0f)
glScalef( img->scaleX, img->scaleY, 1.0f );
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glColor4f(1.0, 0.0, 0.0, 1.0);
glBindTexture(GL_TEXTURE_2D, img->m_name);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
}
Most importantly, you need to understand how to do this operation.
before doing a rotation you have to translate your self in the rotation origin and only then apply to rotation.
Check out this article which explains it well.
The simple breakdown is:
move object to origin.
Rotate.
Move object back.