0

我想要“水晶球中的脸”效果,其中我有一个模型(脸)在半透明模型(水晶球)内部做事。我觉得我正在服用疯狂的药丸,因为我无法让这张内脸出现部分被球遮挡。我的目标是改变球(和/或脸)的 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();

}
4

2 回答 2

3

听起来您可能遇到了一个简单的深度缓冲区概念并没有真正应用于您的场景的案例。深度缓冲区为屏幕上的每个像素存储一个深度,在具有完全不透明对象的场景中,该深度将是该像素处最近对象的深度。

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

所以在你的情况下可能发生的事情是你首先绘制水晶球,然后将各种水晶球像素的深度放入深度缓冲区。然后您尝试绘制脸部,OpenGL 发现它比缓冲区中已有的值更远,因此跳过这些像素。

因此,快速修复的解决方案就是手动重新排列场景几何体,使脸部始终绘制在水晶球之前,始终在内部。

在一个理想的解决方案中,您将一步绘制所有不透明几何体(传统上以接近从前到后的顺序,尽管这在 PowerVR 上不那么重要)以建立不透明深度值,然后所有透明几何体回到前面以便它以正确的顺序合成。

在 OpenGL 中,您确实希望某些事物的顺序相对固定,以便您可以将相关值推送到 GPU 而不会产生通信成本。人们仍然倾向于划分为不透明几何和透明几何并首先绘制不透明,但通常他们会在绘制透明几何时禁用 z-buffer 写入,努力做到有点像从后到前的顺序但不要在问题上投入太多时间。

如果您乐于使用纯加法混合,那么一旦深度缓冲区设置了不透明的东西,显然任何用于透明胶片的顺序绘制都是正确的。

于 2012-03-14T23:34:42.673 回答
2

你渲染对象的顺序是什么?如果你在脸之前画球,那么整个脸都会被拒绝,因为它在 z 缓冲区中的球后面。如果你想做正确的透明度,你必须从后到前渲染对象。

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

当您使用位置调用 glLightfv 时,该位置将由模型视图矩阵堆栈中的当前内容进行转换。你必须把它放在相对于你定义坐标的参考框架的正确位置(它是相对于视图坐标,还是相对于世界坐标,还是相对于对象坐标?)。

于 2012-03-14T23:32:29.373 回答