Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fully transparent OpenGL model

Tags:

c++

opengl

Explain me what i'm doing wrong. I have loaded 3d model to self-coded opengl render (v 3.3) and try to make it transparent like xray effect using vertex shader:

#version 330

attribute vec3 coord3d;
attribute vec2 texcoord;
varying vec2 f_texcoord;

uniform mat4 projectionMatrix; 
uniform mat4 modelViewMatrix; 

layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec4 inColor;

smooth out vec4 theColor;

void main()
{
    gl_Position = projectionMatrix*modelViewMatrix*vec4(inPosition, 1.0);
    theColor = vec4(0.0,0.2,0.4,0.4);
    f_texcoord = texcoord;

}

The model was triangulated in editor and draw with:

glDrawArrays(GL_TRIANGLE_FAN, 0, (vertices.at(i)->size()/3));

If i use

glEnable(GL_ALPHA_TEST);
glEnable( GL_BLEND );
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glEnable(GL_DEPTH_TEST);
glClearDepth(1.0); 

I see some unwanted triangles or lines:

If i do it without depth test i see multiple triangless inside faces (which i don't want):

How can i rid of unwanted effects and implement x-ray effect like Google Sketchup did it

Should i implement depth sorting if i want all model transparent?

How can i implement this:

GS

like image 696
xcix Avatar asked Sep 19 '13 13:09

xcix


1 Answers

Problem 1:

First of all, don't disable the depth test. The depth test is performed before blending to ensure fragments are correctly dropped, even when blending is enabled. For more information on per-fragment operations and the order in which they are performed, see section 17.3 of the core OpenGL 4.4 specification.

When you disable depth testing, you will get unexpected results unless the order of draw calls is absolutely correct, thus defying the very purpose of depth buffering. And even if you get the order right you cannot expect all side effects to be gone and trying to order every command just the way you need it doesn't work for anything but the simplest programs.

Consider the following, very simple example:

enter image description here

You can see 3 quads, the farthest visualizing the usual tex coordinate space (s,t E [0, 1]), a blue quad which blends with the latter, and an opaque red quad which is supposed to be in the front. Obviously, the red quad isn't in front, although the depth values indicate otherwise. Also obvious, the intent is to not blend the blue quad with the red quad. Rendering the red quad after the blue quad seemingly fixes the problem, but if you draw another quad which is supposed to be behind both the blue and the red quad, it would simply appear on top with disabled depth testing. This is all wrong.

enter image description here

The yellow quad obscures everything, although it's supposed to go behind the red and blue quad. The correct image is the following, which is obtained purely by enabling depth testing:

enter image description here

My general suggestion would be: unless you have a very good reason to disable the depth test, for instance when rendering overlays and not wanting to hassle with the depth buffer, leave depth testing enabled.

Note: Depth buffering will not solve your problem of usually having to arrange non-opaque geometry back-to-front to get a correct result! If you want to be completely independent of ordering when trying to simulate transparency, look for the usual suspects among the many papers on order independent transparency.

Problem 2:

From the looks of it, I assume your using the following blend function:

gl::BlendFunc (gl::ONE, gl::ONE);

or anythin that leads to a steady, successive accumulation of values like

gl::BlendFunc (gl::SRC_ALPHA, gl::ONE);

and the default blend-equation for RGB and alpha components:

gl::BlendEquation (gl::FUNC_ADD);

If this isn't the case, please add a comment stating the actual values so I can re-recheck and possibly edit my advice. The following still applies because colors just don't lie. ;)

Your second problem is due to z-fighting under projection. Some fragments are correctly discarded, others aren't. Since you obviously have duplicate faces that exactly coincide in some places, it may be possible that for one fragment a slightly higher depth value is generated for the first face. When the second face is rendered, a slightly lower depth value is generated and the fragment passes, leading to overdraw where there should actually be none.

The first fragment has already done all the magic and a blended value was written into the frame buffer and the depth value was written to the depth buffer, i.e. you have one fragment of the face that passed all tests and has blended with the background. Now comes the second fragment which is not discarded because the depth value is slightly lower and again blends with the already blended color in the framebuffer. Due to additive blending, you get the results you observed. I reproduced this case in the following example with the same color and alpha values you used:

enter image description here

Problem 3: Your model seems to have a lot of duplicate faces and in general, the triangulation looks horrible. You should really redo it. Understanding and using blending is hard enough as it is. Don't complicate it with sub-optimal data.

like image 166
thokra Avatar answered Sep 25 '22 15:09

thokra