OpenGLでプリミティブをワイヤフレームとしてレンダリングするにはどうすればよいですか?
10 に答える
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
スイッチを入れ、
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
通常に戻るために。
テクスチャ マッピングやライティングなどは、ワイヤフレーム ラインが有効になっている場合でも適用されるため、奇妙に見える可能性があることに注意してください。
http://cone3d.gamedev.net/cgi-bin/index.pl?page=tutorials/ogladv/tut5から
// Turn on wireframe mode
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);
// Draw the box
DrawBox();
// Turn off wireframe mode
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_FILL);
OpenGL 3 以降で前方互換性のあるコンテキストを想定すると、前述のように使用できますがglPolygonMode
、1px を超える太さの線は非推奨になっていることに注意してください。したがって、三角形をワイヤーフレームとして描くことはできますが、非常に細くする必要があります。GL_LINES
OpenGL ES では、同じ制限で使用できます。
OpenGL では、ジオメトリ シェーダーを使用して着信三角形を取得し、それらを分解して、太い線をエミュレートする四角形 (実際には三角形のペア) としてラスタライズするために送信できます。非常に単純ですが、ジオメトリ シェーダーはスケーリングのパフォーマンスが低いことで有名です。
代わりにできること、および OpenGL ES でも機能することは、フラグメントシェーダーを使用することです。三角形にワイヤーフレームの三角形のテクスチャを適用することを考えてください。テクスチャが不要であることを除けば、プロシージャルに生成できます。話は十分ですが、コーディングしましょう。フラグメント シェーダー:
in vec3 v_barycentric; // barycentric coordinate inside the triangle
uniform float f_thickness; // thickness of the rendered lines
void main()
{
float f_closest_edge = min(v_barycentric.x,
min(v_barycentric.y, v_barycentric.z)); // see to which edge this pixel is the closest
float f_width = fwidth(f_closest_edge); // calculate derivative (divide f_thickness by this to have the line width constant in screen-space)
float f_alpha = smoothstep(f_thickness, f_thickness + f_width, f_closest_edge); // calculate alpha
gl_FragColor = vec4(vec3(.0), f_alpha);
}
そして頂点シェーダー:
in vec4 v_pos; // position of the vertices
in vec3 v_bc; // barycentric coordinate inside the triangle
out vec3 v_barycentric; // barycentric coordinate inside the triangle
uniform mat4 t_mvp; // modeview-projection matrix
void main()
{
gl_Position = t_mvp * v_pos;
v_barycentric = v_bc; // just pass it on
}
ここで、重心座標は単純(1, 0, 0)
に で(0, 1, 0)
あり(0, 0, 1)
、3 つの三角形の頂点に対して (順序は実際には重要ではないため、三角形のストリップへのパッキングが潜在的に容易になります)。
このアプローチの明らかな欠点は、いくつかのテクスチャ座標を消費し、頂点配列を変更する必要があることです。非常に単純なジオメトリ シェーダーで解決できますが、GPU により多くのデータを供給するよりも遅くなると思います。
Modern OpenGL (OpenGL 3.2 以降) では、これに Geometry Shader を使用できます。
#version 330
layout (triangles) in;
layout (line_strip /*for lines, use "points" for points*/, max_vertices=3) out;
in vec2 texcoords_pass[]; //Texcoords from Vertex Shader
in vec3 normals_pass[]; //Normals from Vertex Shader
out vec3 normals; //Normals for Fragment Shader
out vec2 texcoords; //Texcoords for Fragment Shader
void main(void)
{
int i;
for (i = 0; i < gl_in.length(); i++)
{
texcoords=texcoords_pass[i]; //Pass through
normals=normals_pass[i]; //Pass through
gl_Position = gl_in[i].gl_Position; //Pass through
EmitVertex();
}
EndPrimitive();
}
特記事項:
- ポイントの場合は、に変更
layout (line_strip, max_vertices=3) out;
しますlayout (points, max_vertices=3) out;
- ジオメトリ シェーダーの詳細を読む
最も簡単な方法は、プリミティブを として描画することGL_LINE_STRIP
です。
glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();