2012-03-14 62 views
0

我想要一个模型(面部)在半透明模型(水晶球)内部做事的“面对水晶球”效果。我感觉我正在服用疯狂的药丸,因为我无法让这个内心的面孔出现在球的部分遮挡下。我的目标是改变球(和/或脸)的阿尔法,使脸部出现和消失。OpenGL(ES)半透明模型内的模型

下面是相关的位代码。你会看到,我不使用着色器,只是很好的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(); 

} 

回答

2

为了什么你渲染的对象?如果您在面前画球,那么整个面部会被拒绝,因为它位于z缓冲区内的球后面。如果你想做正确的透明度,你必须从后到前渲染对象。

和关于你的网线的问题: //If I don't put this code in here (as opposed to above), the light gets all crazy! WHY!?

当你调用glLightfv一个位置,该位置是由目前什么在模型视图矩阵堆栈转化。你必须把它放在正确的地方,相对于你定义坐标的参考框架(它是相对于视图坐标,还是世界坐标,还是对象坐标?)。

+0

谢谢!基本上我试图修复世界坐标中的光线。有关最佳做法的任何提示? – Brooks 2012-05-31 22:49:04

3

听起来好像您可能正在遭受深度缓冲区概念的简单情况,而这种情况并不适用于您的场景。深度缓冲区为屏幕上的每个像素存储一个深度,在具有完全不透明对象的场景中,该深度将是该像素处最近对象的深度。

问题是,当您想要将部分透明的对象添加到场景中时,最终会出现多个对象对单个像素的颜色起作用的位置。但是,您仍然可以存储其中一个的深度。

那么是什么在你的情况很可能发生的事情是你第一次画水晶球,而这把各种水晶球像素的深度进入深度缓冲。然后你试图绘制脸部,OpenGL发现它比缓冲区中的值更远,因此跳过这些像素。

所以快速修复解决方案就是用手重新排序场景几何图形,以便始终在水晶球之前绘制面部,始终在面板内部。

在一个理想的解决方案中,您可以在一个步骤中绘制所有不透明的几何图形(传统上以接近前后顺序的方式绘制,尽管这对于PowerVR并不重要)建立不透明的深度值,几何回到正面,以便它按正确的顺序合成。

在OpenGL中你真的想某些事情的顺序是相对固定的,这样就可以转移到GPU推动相关的值,且不会产生通信费用。人们仍倾向于分为透明和不透明的几何形状和绘制不透明第一,但往往他们就会再禁用时,他们绘制透明几何Z缓冲写道,在努力做到这一点的东西有点像背到前面的命令,但不要在这个问题上投入太多时间。

如果您很乐意使用纯粹的添加混合,那么一旦深度缓冲区设置了不透明的东西,显然任何透明度顺序图都是正确的。

+0

谢谢!重新排列GPU上的几何图形听起来很痛苦。我其实没有不透明的物体,所以它们不是真正的问题。由于透明模型始终在旋转,因此除了添加剂混合之外,听起来并不像我有任何其他选择? – Brooks 2012-05-31 22:53:09

+0

将所有东西推到树叶上的BSP树将允许几何重新排序的次数比您预期的要少(在计算方面,无论如何) - 特别是如果很多对象都是凸起的(比如球)。否则,你可能会想要添加剂。 – Tommy 2012-05-31 23:51:19