OpenGL:如何根据相机距离对点进行排序?

Daz*_*zid 3 c++ opengl shader glsl cinder

我有一个使用 OpenGL 的由 100.000 个球体作为点精灵组成的结构。当我绕中心轴旋转结构时遇到问题。点精灵根据其数组按顺序渲染,这意味着最后一个点精灵与创建的第一个点精灵重叠,而不考虑三维空间中的深度。

如何实时排序和重新排列点精灵的顺序以始终保持三维视角?我想这个想法是读取相机相对于粒子的位置,然后对数组进行排序以始终首先显示更接近的粒子。是否可以使用着色器来修复?

这是我的着色器:shader.frag

#version 120
uniform sampler2D tex;
varying vec4 inColor;
//uniform vec3 lightDir;

void main (void) {
gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * inColor;
}
Run Code Online (Sandbox Code Playgroud)

着色器垂直

#version 120
// define a few constants here, for faster rendering
attribute float particleRadius;
attribute vec4 myColor;
varying vec4 inColor;

void main(void)
{
vec4 eyeCoord = vec4(gl_ModelViewMatrix * gl_Vertex);
gl_Position = gl_ProjectionMatrix * eyeCoord;
float distance = length(eyeCoord);
float attenuation = 700.0 / distance;
gl_PointSize = particleRadius * attenuation;
//gl_PointSize = 1.0 / distance * SIZE;
//gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_FrontColor = gl_Color;
inColor = myColor;
}
Run Code Online (Sandbox Code Playgroud)

绘制方法:

void MyApp::draw(){
//gl::clear( ColorA( 0.0f, 0.0f, 0.0f, 0.0f ), true );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// SET MATRICES TO WINDOW
gl::setMatricesWindow( getWindowSize(), false );
gl::setViewport( getWindowBounds() );
gl::enableAlphaBlending();

gl::enable( GL_TEXTURE_2D );
gl::enable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST);
gl::color( ColorA( 1.0f, 1.0f, 1.0f, 1.0f ) );

mShader.bind();
// store current OpenGL state
glPushAttrib( GL_POINT_BIT | GL_ENABLE_BIT );

// enable point sprites and initialize it
gl::enable( GL_POINT_SPRITE_ARB );
glPointParameterfARB( GL_POINT_FADE_THRESHOLD_SIZE_ARB, -1.0f );
glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, 0.1f );
glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, 200.0f );

// allow vertex shader to change point size
gl::enable( GL_VERTEX_PROGRAM_POINT_SIZE );

GLint thisColor = mShader.getAttribLocation( "myColor" );
glEnableVertexAttribArray(thisColor);
glVertexAttribPointer(thisColor,4,GL_FLOAT,true,0,theColors);

GLint particleRadiusLocation = mShader.getAttribLocation( "particleRadius" );
glEnableVertexAttribArray(particleRadiusLocation);
glVertexAttribPointer(particleRadiusLocation, 1, GL_FLOAT, true, 0, mRadiuses);

glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glEnableClientState(GL_VERTEX_ARRAY);

glVertexPointer(3, GL_FLOAT, 0, mPositions);

mTexture.enableAndBind();
glDrawArrays( GL_POINTS, 0, mNumParticles );
mTexture.unbind();

glDisableClientState(GL_VERTEX_ARRAY);
glDisableVertexAttribArrayARB(thisColor);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableVertexAttribArrayARB(particleRadiusLocation);
// unbind shader
mShader.unbind();

// restore OpenGL state
glPopAttrib();

}
Run Code Online (Sandbox Code Playgroud)

And*_*man 5

你有两种不同的混合情况void MyApp::draw()

  1. 添加剂-(src + dst)

    • 独立于订单

  2. α -(src * src.a + (dst * (1.0 - src.a))

    • 订单相关

第一个混合函数不会导致您正在讨论的问题,因此我假设mRoom.isPowerOn() == false我们正在处理 alpha 混合。

要解决后一种情况的顺序依赖性问题,您需要将点转换为眼睛空间并使用它们的z坐标进行排序。这里的问题是,这不是可以在 GLSL 中轻松解决的问题 - 您需要在顶点着色器运行之前对数据进行排序(因此最直接的方法是在 CPU 上执行此操作)。鉴于涉及大量数据点,基于 GPU 的解决方案是可能的,并且可能有必要实时执行此操作,但您应该首先在 CPU 上执行此操作,然后弄清楚从哪里开始。

实现排序时,请记住点精灵始终是屏幕对齐的(z眼睛空间中的统一值),因此您不必担心交叉(点精灵将完全在前面、后面或平行)到它重叠的任何其他点精灵)。这使得对它们进行排序比其他类型的几何图形简单得多,其他类型的几何图形可能必须在交叉点处分割并绘制两次才能正确排序。