2

OpenGL を使用して、ポイント スプライトとして 100.000 個の球体で構成された構造を持っています。構造を中心軸で回転すると問題が発生します。ポイント スプライトは、その配列に応じて順番にレンダリングされます。つまり、最後のものは、作成された最初のポイント スプライトと重なり、3 次元空間の深さは考慮されません。

ポイントスプライトの順序をリアルタイムでソートおよび再配置して、常に 3 次元の視点を維持するにはどうすればよいですか? アイデアは、粒子に対するカメラの位置を読み取り、配列を並べ替えて、常により近い粒子を最初に表示することだと思います。シェーダーを使用して修正することは可能ですか?

これが私のシェーダーです: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;
}

シェーダー頂点

#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;
}

描画方法:

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();

}
4

1 に答える 1

3

に 2 つの異なるブレンド ケースがあります。void MyApp::draw()

  1. 添加剤 -(src + dst)

    • 独立した注文

  2. アルファ -(src * src.a + (dst * (1.0 - src.a))

    • オーダー依存

mRoom.isPowerOn() == false最初のブレンディング関数は、あなたが議論している問題を引き起こさないので、アルファ ブレンディングを扱っていると仮定しています。

後者の場合の順序依存性の問題を解決するには、ポイントを目の空間に変換し、それらのz座標を使用して並べ替える必要があります。ここでの問題は、これが GLSL で簡単に解決できるものではないということです。頂点シェーダーを実行するにデータを並べ替える必要があります (したがって、最も簡単な方法では、CPU でこれを行う必要があります)。GPU ベースのソリューションは可能であり、関連する膨大な数のデータ ポイントを考えるとリアルタイムでこれを行う必要があるかもしれませんが、CPU でこれを行うことから始めて、そこからどこへ行くべきかを理解する必要があります。

並べ替えを実装するときは、ポイント スプライトが常に画面に揃えられる (zアイ スペースで均一な値) ことに注意してください。したがって、交差について心配する必要はありません (ポイント スプライトは、完全に前、後ろ、または平行のいずれかになります)。オーバーラップする他のポイントスプライトに)。これにより、適切な順序付けのために交点で分割して 2 回描画する必要がある場合がある他のタイプのジオメトリよりも、並べ替えがはるかに簡単になります。

于 2014-12-16T20:12:22.797 に答える