我想要“面对水晶球”效果,我有一个模型(面部)在半透明模型(水晶球)内做事。我觉得我正在服用疯狂的药片,因为我只是不能让这个内脸被球部分遮挡。我的目标是改变球(和/或脸)的alpha值,使脸部出现并消失。
以下是相关位代码。正如你所看到的,我不是使用着色器,而是使用旧的GL / GLES1。如果有人能告诉我我做错了什么,我将非常感激。
设置代码......
//-- CONFIGURATION ---------------
// Create The Depth Buffer Object
glGenRenderbuffersOES(1, &depth_renderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depth_renderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES,
GL_DEPTH_COMPONENT16_OES,
width,
height);
// Create The FrameBuffer Object
glGenFramebuffersOES(1, &framebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
GL_COLOR_ATTACHMENT0_OES,
GL_RENDERBUFFER_OES,
color_renderbuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
GL_DEPTH_ATTACHMENT_OES,
GL_RENDERBUFFER_OES,
depth_renderbuffer);
// Bind Color Buffer
glBindRenderbufferOES(GL_RENDERBUFFER_OES, color_renderbuffer);
glViewport(0, 0, width, height);
//-- LIGHTING ----------------------
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//-- PROJECTION ---------------------
glMatrixMode(GL_PROJECTION);
viewport_size = vec2((float) width,(float) height);
//Orthographic Projection
float max_x,max_y;
if(width>height){
max_y = 1;
max_x = (float)width/(float)height;
}
else{
max_x = 1;
max_y = (float)height/(float) width;
}
const float MAX_X = max_x;
const float MAX_Y = max_y;
const float Z_0 = 0;
const float MAX_Z = 1;
glOrthof(-MAX_X, MAX_X, -MAX_Y, MAX_Y, Z_0-MAX_Z, Z_0+MAX_Z);
world_size = vec3(2*MAX_X,2*MAX_Y,2*MAX_Z);
//Color Depth
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE); //Dissapears if False
glDepthFunc(GL_LEQUAL);
glEnable(GL_BLEND);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //doesn't do it
glBlendFunc(GL_ONE, GL_ONE); //better
这是渲染调用
glClearColor(world->background_color.x,
world->background_color.y,
world->background_color.z,
world->background_color.w);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for(int s=0;s<surfaces.size();s++){
Surface* surface = surface[s];
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, surface->getMatAmbient().Pointer());
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, surface->getMatDiffuse().Pointer());
glMatrixMode(GL_MODELVIEW);
//If I don't put this code in here (as opposed to above), the light gets all crazy! WHY!?
glPushMatrix();
glLoadIdentity();
vec4 light_position = vec4(world->light->position,1);
glLightfv(GL_LIGHT0,GL_POSITION,light_position.Pointer());
glPopMatrix();
glPushMatrix();
glMultMatrixf(surface->transform.Pointer());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_buffer);
glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_buffer);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, VERTEX_STRIDE, 0);
glNormalPointer(GL_FLOAT, VERTEX_STRIDE, (GLvoid*) VERTEX_NORMAL_OFFSET);
glDrawElements(GL_TRIANGLES, surface->indices.size(), GL_UNSIGNED_SHORT, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glPopMatrix();
}
答案 0 :(得分:3)
听起来你可能会遇到一个深度缓冲概念的简单案例,并不适用于你的场景。深度缓冲区为屏幕上的每个像素存储一个深度,在具有完全不透明对象的场景中,该深度将是该像素处最近对象的深度。
问题在于,当您想要将部分透明的对象添加到场景中时,您最终会处于多个对象对单个像素的颜色有贡献的位置。但是你仍然只能存储其中一个的深度。
所以在你的情况下可能发生的事情是你首先绘制水晶球,然后将各种水晶球像素的深度放入深度缓冲区。然后你试图绘制面部,OpenGL看到它比缓冲区中的值更远,所以跳过那些像素。
因此,快速修复解决方案只是手动重新排序场景几何体,使得面部始终在水晶球之前绘制,始终在内部。
在一个理想的解决方案中,您可以在一个步骤中绘制所有不透明几何体(传统上以接近前后顺序的东西,虽然在PowerVR上并不重要)来建立不透明的深度值,然后是所有透明几何体回到前面,以便按正确的顺序合成。
在OpenGL中,您确实希望某些事物的顺序相对固定,以便您可以将相关值推送到GPU而不会产生通信成本。人们仍倾向于划分为不透明和透明的几何体,并首先绘制不透明的但通常它们只会在绘制透明几何体时禁用z缓冲区写入,努力做到有点像后向前的顺序但是不要在问题上投入太多时间。
如果您乐意使用纯添加剂混合,那么一旦深度缓冲区设置了不透明的东西,透明胶片的任何订单图纸都是正确的。
答案 1 :(得分:2)
您渲染对象的顺序是什么?如果你在脸前画球,那么整个脸都会被拒绝,因为它在z缓冲区的球后面。如果要进行正确的透明度,则必须从后向前渲染对象。
关于你的内联问题:
//If I don't put this code in here (as opposed to above), the light gets all crazy! WHY!?
当您使用位置调用glLightfv时,位置将根据当前在模型视图矩阵堆栈中的内容进行转换。你必须把它放在相对于你定义坐标的参考框架的正确位置(它是相对于视图坐标,还是世界坐标,还是对象坐标?)。