0

半透明のモデル (クリスタル ボール) の中でモデル (顔) が何かをしている「Face In a Crystal Ball」エフェクトが必要です。この内側の顔がボールによって部分的に遮られているように見せることができないので、私は狂った薬を服用しているように感じます. 私の目標は、ボール (および/または面) のアルファを変化させて、面を表示および非表示にすることです。

以下は、関連するビット コードです。ご覧のとおり、私はシェーダーを使用しておらず、古き良き 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

シーンに実際には適用されないデプスバッファの概念の単純なケースに苦しんでいるように思われます。デプスバッファは、画面上のピクセルごとに1つのデプスを格納します。これは、完全に不透明なオブジェクトがあるシーンでは、そのピクセルで最も近いオブジェクトのデプスになります。

問題は、部分的に透明なオブジェクトをシーンに追加したい場合、複数のオブジェクトが個々のピクセルの色に寄与する位置になってしまうことです。ただし、そのうちの1つだけの深さを保存できます。

したがって、おそらくあなたのケースで起こっていることは、最初に水晶玉を描画していることであり、それはさまざまな水晶玉ピクセルの深度を深度バッファに入れています。次に、顔を描画しようとしていますが、OpenGLは、すでにバッファにある値よりも遠くにあることを確認しているため、これらのピクセルをスキップします。

したがって、クイックフィックスの解決策は、顔が常に水晶玉の前に描かれ、常に内側になるように、シーンのジオメトリを手動で並べ替えることです。

理想的なソリューションでは、すべての不透明なジオメトリを1つのステップで(従来は前後の順序に近い順序で描画しますが、PowerVRではそれほど重要ではありません)、不透明な深度値を確立してから、すべての透明なジオメトリを後ろから前に描画します。正しい順序で合成されるようにします。

OpenGLでは、特定のものの順序を比較的固定して、関連する値をGPUにプッシュし、通信コストを発生させないようにする必要があります。人々は依然として不透明と透明のジオメトリに分割し、最初に不透明を描画する傾向がありますが、多くの場合、透明なジオメトリを描画するときにzバッファ書き込みを無効にして、後ろから前の順序のようなものにするように努力しますが、問題にあまり時間をかけないでください。

純粋にアディティブブレンディングを使用することに満足している場合は、デプスバッファに不透明なものが設定されていれば、透明度の順序図は明らかに正しいです。

于 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 に答える