GLSLによるジオメトリシェーダ - ディスプレースメントマッピング
をテンプレートにして作成
[
トップ
|
新規
|
一覧
|
検索
|
最終更新
|
ヘルプ
]
開始行:
----
#contents
----
*ディスプレースメントマッピング [#h56092c6]
レンダリング時にフラグメントシェーダにおいてテクスチャに...
バンプマッピングでは表面の細かな凸凹を少ないポリゴン数で...
一方,実際にジオメトリが凸凹になっているわけではないので...
これに対して,テクスチャに格納されたハイトフィールドを用...
ディスプレースメントマッピング(displacement mapping)であ...
*テッセレーション [#r01e7ebe]
ディスプレースメントマッピングを行う場合,まず,描画する...
生成された新しい頂点をテクスチャの値に応じてポリゴン法線...
これをテッセレーション(tessellation)と呼ぶ.
テッセレーションはCPU側でやってもよいのだが,
ここではジオメトリシェーダを用いてやってみる.
ただし,前述([[GLSLによるジオメトリシェーダ#qb36625f]]参...
(各頂点が8要素を持つとして最大頂点数が128,この頂点数で三...
CPUである程度分割した後,GPUで再度分割するという風にして...
ジオメトリシェーダでテッセレーションを行うために,三角形...
三角形ポリゴンの分割には様々な方法が考えられるが,まず,...
#ref(tri_parameterize.gif)
頂点v0を原点として,v1を(s,t)=(1,0),v2を(0,1)となるよう...
任意の(s,t)における座標値v(s,t)=v0+s(v1-v0)+t(v2-v0)が計...
三角形の細分割方法として,ここでは元の三角形ポリゴンと同...
元の三角形ポリゴンのエッジの中点を結ぶ形で新しいポリゴン...
#ref(tri_subdiv1.gif)
上の図で数値は(s,t)のパラメータ値を表す.これをさらに分割...
#ref(tri_subdiv2.gif)
となる.1回分割した状態をレベル1, 2回分割した状態をレベル...
レベル1の時の辺の分割数は2,レベル2で4,レベルLで2^Lとなる.
また,生成される三角形の数はn=4^Lとなる.ジオメトリシェー...
生成できる三角形は42以下なので,レベル2が最大となる.
また,色情報がなければレベル3までは分割可能である.
上の図において赤く塗りつぶした領域に注目すると,
-s=0のエッジとs=0.25の頂点で構成される三角形が4個
-s=0の頂点とs=0.25のエッジで構成される三角形が3個
で構成されていることが分かる.緑,青の領域についても同様に...
-s=i/nのエッジとs=(i+1)/nの頂点で構成される三角形が(n-i)個
-s=i/nの頂点とs=(i+1)/nのエッジで構成される三角形が(n-i-1...
となる.ここで,i=0,1,...,n-1であり,n=4^Lである.
これをコードにすると,
#code(C){{
int layer = 1 << level; // 三角形の各辺の分割数
float s0, s1, t0, t1;
float ds = 1.0/float(layer);
float dt = 1.0/float(layer);
s0 = 0.0; s1 = s0+ds;
t0 = 0.0; t1 = t0+dt;
int n = layer;
for(int i = 0; i < layer; ++i){ // s方向
t0 = 0.0; t1 = t0+dt;
for(int j = 0; j < n; ++j){ // t方向
// (s0, t0),(s1, t0),(s0, t1)で三角形を生成
...
if(j != n-1){
// (s0, t1),(s1, t0),(s1, t1)で三角形を生成
...
}
t0 += dt; t1 += dt;
}
s0 += ds; s1 += ds;
n--;
}
}}
となる.
*シェーダコード [#f1c4a0b5]
頂点シェーダ,フラグメントシェーダは頂点座標や色をパスス...
-頂点シェーダ
#code(C){{
#version 120
void main(void)
{
gl_FrontColor = gl_Color;
gl_Position = gl_Vertex;
gl_TexCoord[0] = gl_TextureMatrix[0]*gl_MultiTexCoord0;
}
}}
-フラグメントシェーダ
#code(C){{
#version 120
void main(void)
{
gl_FragColor = gl_Color;
}
}}
ジオメトリシェーダでは新しい三角形ポリゴンを生成して,テ...
#code(C){{
#version 120
#extension GL_EXT_geometry_shader4 : enable
uniform sampler2D HeightMap;
uniform int SubLevel;
uniform float Height;
/*!
* 三角形上のパラメータ座標値から新しい頂点を生成
* @param[in] s,t パラメータ座標値(v0を(0,0),v1を(1.0),v2...
*/
void SetVertex(float s, float t)
{
gl_TexCoord[0] = gl_TexCoordIn[0][0]+s*(gl_TexCoordIn[1]...
// gl_FrontColor = gl_FrontColorIn[0]+s*(gl_FrontColorIn...
vec4 pos = gl_PositionIn[0]+s*(gl_PositionIn[1]-gl_Posit...
pos.y = length(texture2D(HeightMap, gl_TexCoord[0].xy).x...
gl_Position = gl_ModelViewProjectionMatrix*pos;
EmitVertex();
}
void main(void)
{
int level = SubLevel;
int layer = 1 << level; // 三角形の各辺の分割数
// v0を(0,0),v1を(1.0),v2を(0,1)として三角形を(s,t)でパ...
float s0, s1, t0, t1;
float ds = 1.0/float(layer);
float dt = 1.0/float(layer);
s0 = 0.0;
s1 = s0+ds;
t0 = 0.0;
t1 = t0+dt;
int n;
n = layer-1;
for(int i = 0; i < layer; ++i){ // s方向のレイヤー
t0 = 0.0;
t1 = t0+dt;
for(int j = 0; j < n; ++j){ // t方向のレイヤー
SetVertex(s0, t0);
SetVertex(s1, t0);
SetVertex(s0, t1);
EndPrimitive();
SetVertex(s0, t1);
SetVertex(s1, t0);
SetVertex(s1, t1);
EndPrimitive();
t0 += dt;
t1 += dt;
}
SetVertex(s0, t0);
SetVertex(s1, t0);
SetVertex(s0, t1);
EndPrimitive();
s0 += ds;
s1 += ds;
n--;
}
}
}}
元の三角形はx-z平面上にあり,高さ方向(法線方向)はy軸と平...
SetVertex関数内のgl_FrontColorの行をコメントアウトしなけ...
生成できるポリゴン数は42に制限される.
*シェーダのビルドと呼び出し [#h849d980]
CPU側でもテッセレーションのコードを実装して,CPUである程...
ディスプレースメントマッピングをしている.
CPU側のテッセレーションのコードは以下.
#code(C){{
/*!
* 三角形上のパラメータ座標値から新しい頂点を生成して描画
* @param[in] s,t パラメータ座標値(v0を(0,0),v1を(1.0),v2...
* @param[in] v0,v1,v2 三角形頂点座標
* @param[in] tc1,tc2,tc3 三角形頂点でのテクスチャ座標値
*/
void SetVertex(float s, float t, Vec3 v0, Vec3 v1, Vec3 v...
{
Vec3 v = v0+s*(v1-v0)+t*(v2-v0);
Vec2 tc = tc0+s*(tc1-tc0)+t*(tc2-tc0);
glTexCoord2dv(tc.data);
glVertex3dv(v.data);
}
/*!
* 三角形を分割して描画
* @param[in] v0,v1,v2 三角形頂点座標
* @param[in] tc1,tc2,tc3 三角形頂点でのテクスチャ座標値
* @param[in] level 分割レベル
*/
void DrawTriangle(Vec3 v0, Vec3 v1, Vec3 v2, Vec2 tc0, Ve...
{
if(!level){
// 分割レベル0のとき三角形をそのまま描画
glDisable(GL_LIGHTING);
glBegin(GL_TRIANGLES);
glTexCoord2dv(tc0.data); glVertex3dv(v0.data);
glTexCoord2dv(tc1.data); glVertex3dv(v1.data);
glTexCoord2dv(tc2.data); glVertex3dv(v2.data);
glEnd();
}
int layer = 1 << level; // 三角形の各辺の分割数
// v0を(0,0),v1を(1.0),v2を(0,1)として三角形を(s,t)でパ...
float s0, s1, t0, t1;
float ds = 1.0/float(layer);
float dt = 1.0/float(layer);
s0 = 0.0;
s1 = s0+ds;
t0 = 0.0;
t1 = t0+dt;
int n;
n = layer;
for(int i = 0; i < layer; ++i){ // s方向のレイヤー
t0 = 0.0;
t1 = t0+dt;
for(int j = 0; j < n; ++j){ // t方向のレイヤー
glBegin(GL_TRIANGLES);
SetVertex(s0, t0, v0, v1, v2, tc0, tc1, tc2);
SetVertex(s1, t0, v0, v1, v2, tc0, tc1, tc2);
SetVertex(s0, t1, v0, v1, v2, tc0, tc1, tc2);
glEnd();
if(j != n-1){
glBegin(GL_TRIANGLES);
SetVertex(s0, t1, v0, v1, v2, tc0, tc1, tc2);
SetVertex(s1, t0, v0, v1, v2, tc0, tc1, tc2);
SetVertex(s1, t1, v0, v1, v2, tc0, tc1, tc2);
glEnd();
}
t0 += dt;
t1 += dt;
}
s0 += ds;
s1 += ds;
n--;
}
}
}}
GLSLの呼び出しコードは以下.
#code(C){{
/*!
* シーンのレンダリング
*/
void RenderScene(void)
{
glColor3f(0.0, 0.0, 1.0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, g_uTexHeight);
// GLSLを有効にする
glUseProgram(g_GLSL.Prog);
glUniform1i(glGetUniformLocation(g_GLSL.Prog, "HeightMap...
glUniform1i(glGetUniformLocation(g_GLSL.Prog, "SubLevel"...
glUniform1f(glGetUniformLocation(g_GLSL.Prog, "Height"),...
// ライティングは無視しているのでラインで描画
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glPushMatrix();
glTranslatef(-0.5, 0.0, -0.5);
// 三角形ポリゴンを分割して描画
DrawTriangle(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 0.0, 0.0), V...
Vec2(0.0, 0.0), Vec2(1.0, 0.0), Vec2(1.0, 1.0), 2);
DrawTriangle(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 0.0, 1.0), V...
Vec2(0.0, 0.0), Vec2(1.0, 1.0), Vec2(0.0, 1.0), 2);
glPopMatrix();
glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
}}
g_uTexHeightにはハイトフィールドとなるテクスチャが格納さ...
*結果 [#p0150a6b]
ハイトフィールドとして以下の画像を用いた.
#ref(tex_sphere.png)
CPU側で2レベル,GPU側で2レベル,計レベル4まで分割した結果...
&ref(disp_map_1_1.jpg); &ref(disp_map_2_1.jpg);
左の画像が通常の結果,右はGLSLを無効にした場合である.
ハイトフィールド画像の暗いところほど凹んでいる.
#ref(disp_map_3_1.jpg);
この画像はジオメトリシェーダでの分割レベルを3にした場合で...
最大出力要素数の制限により出力されていない三角形があるの...
*ソースコード [#e99c6dbf]
Visual Studio 2008用のソースコードを以下に置く.ビルド・...
#ref(glsl_displacementmap.zip)
終了行:
----
#contents
----
*ディスプレースメントマッピング [#h56092c6]
レンダリング時にフラグメントシェーダにおいてテクスチャに...
バンプマッピングでは表面の細かな凸凹を少ないポリゴン数で...
一方,実際にジオメトリが凸凹になっているわけではないので...
これに対して,テクスチャに格納されたハイトフィールドを用...
ディスプレースメントマッピング(displacement mapping)であ...
*テッセレーション [#r01e7ebe]
ディスプレースメントマッピングを行う場合,まず,描画する...
生成された新しい頂点をテクスチャの値に応じてポリゴン法線...
これをテッセレーション(tessellation)と呼ぶ.
テッセレーションはCPU側でやってもよいのだが,
ここではジオメトリシェーダを用いてやってみる.
ただし,前述([[GLSLによるジオメトリシェーダ#qb36625f]]参...
(各頂点が8要素を持つとして最大頂点数が128,この頂点数で三...
CPUである程度分割した後,GPUで再度分割するという風にして...
ジオメトリシェーダでテッセレーションを行うために,三角形...
三角形ポリゴンの分割には様々な方法が考えられるが,まず,...
#ref(tri_parameterize.gif)
頂点v0を原点として,v1を(s,t)=(1,0),v2を(0,1)となるよう...
任意の(s,t)における座標値v(s,t)=v0+s(v1-v0)+t(v2-v0)が計...
三角形の細分割方法として,ここでは元の三角形ポリゴンと同...
元の三角形ポリゴンのエッジの中点を結ぶ形で新しいポリゴン...
#ref(tri_subdiv1.gif)
上の図で数値は(s,t)のパラメータ値を表す.これをさらに分割...
#ref(tri_subdiv2.gif)
となる.1回分割した状態をレベル1, 2回分割した状態をレベル...
レベル1の時の辺の分割数は2,レベル2で4,レベルLで2^Lとなる.
また,生成される三角形の数はn=4^Lとなる.ジオメトリシェー...
生成できる三角形は42以下なので,レベル2が最大となる.
また,色情報がなければレベル3までは分割可能である.
上の図において赤く塗りつぶした領域に注目すると,
-s=0のエッジとs=0.25の頂点で構成される三角形が4個
-s=0の頂点とs=0.25のエッジで構成される三角形が3個
で構成されていることが分かる.緑,青の領域についても同様に...
-s=i/nのエッジとs=(i+1)/nの頂点で構成される三角形が(n-i)個
-s=i/nの頂点とs=(i+1)/nのエッジで構成される三角形が(n-i-1...
となる.ここで,i=0,1,...,n-1であり,n=4^Lである.
これをコードにすると,
#code(C){{
int layer = 1 << level; // 三角形の各辺の分割数
float s0, s1, t0, t1;
float ds = 1.0/float(layer);
float dt = 1.0/float(layer);
s0 = 0.0; s1 = s0+ds;
t0 = 0.0; t1 = t0+dt;
int n = layer;
for(int i = 0; i < layer; ++i){ // s方向
t0 = 0.0; t1 = t0+dt;
for(int j = 0; j < n; ++j){ // t方向
// (s0, t0),(s1, t0),(s0, t1)で三角形を生成
...
if(j != n-1){
// (s0, t1),(s1, t0),(s1, t1)で三角形を生成
...
}
t0 += dt; t1 += dt;
}
s0 += ds; s1 += ds;
n--;
}
}}
となる.
*シェーダコード [#f1c4a0b5]
頂点シェーダ,フラグメントシェーダは頂点座標や色をパスス...
-頂点シェーダ
#code(C){{
#version 120
void main(void)
{
gl_FrontColor = gl_Color;
gl_Position = gl_Vertex;
gl_TexCoord[0] = gl_TextureMatrix[0]*gl_MultiTexCoord0;
}
}}
-フラグメントシェーダ
#code(C){{
#version 120
void main(void)
{
gl_FragColor = gl_Color;
}
}}
ジオメトリシェーダでは新しい三角形ポリゴンを生成して,テ...
#code(C){{
#version 120
#extension GL_EXT_geometry_shader4 : enable
uniform sampler2D HeightMap;
uniform int SubLevel;
uniform float Height;
/*!
* 三角形上のパラメータ座標値から新しい頂点を生成
* @param[in] s,t パラメータ座標値(v0を(0,0),v1を(1.0),v2...
*/
void SetVertex(float s, float t)
{
gl_TexCoord[0] = gl_TexCoordIn[0][0]+s*(gl_TexCoordIn[1]...
// gl_FrontColor = gl_FrontColorIn[0]+s*(gl_FrontColorIn...
vec4 pos = gl_PositionIn[0]+s*(gl_PositionIn[1]-gl_Posit...
pos.y = length(texture2D(HeightMap, gl_TexCoord[0].xy).x...
gl_Position = gl_ModelViewProjectionMatrix*pos;
EmitVertex();
}
void main(void)
{
int level = SubLevel;
int layer = 1 << level; // 三角形の各辺の分割数
// v0を(0,0),v1を(1.0),v2を(0,1)として三角形を(s,t)でパ...
float s0, s1, t0, t1;
float ds = 1.0/float(layer);
float dt = 1.0/float(layer);
s0 = 0.0;
s1 = s0+ds;
t0 = 0.0;
t1 = t0+dt;
int n;
n = layer-1;
for(int i = 0; i < layer; ++i){ // s方向のレイヤー
t0 = 0.0;
t1 = t0+dt;
for(int j = 0; j < n; ++j){ // t方向のレイヤー
SetVertex(s0, t0);
SetVertex(s1, t0);
SetVertex(s0, t1);
EndPrimitive();
SetVertex(s0, t1);
SetVertex(s1, t0);
SetVertex(s1, t1);
EndPrimitive();
t0 += dt;
t1 += dt;
}
SetVertex(s0, t0);
SetVertex(s1, t0);
SetVertex(s0, t1);
EndPrimitive();
s0 += ds;
s1 += ds;
n--;
}
}
}}
元の三角形はx-z平面上にあり,高さ方向(法線方向)はy軸と平...
SetVertex関数内のgl_FrontColorの行をコメントアウトしなけ...
生成できるポリゴン数は42に制限される.
*シェーダのビルドと呼び出し [#h849d980]
CPU側でもテッセレーションのコードを実装して,CPUである程...
ディスプレースメントマッピングをしている.
CPU側のテッセレーションのコードは以下.
#code(C){{
/*!
* 三角形上のパラメータ座標値から新しい頂点を生成して描画
* @param[in] s,t パラメータ座標値(v0を(0,0),v1を(1.0),v2...
* @param[in] v0,v1,v2 三角形頂点座標
* @param[in] tc1,tc2,tc3 三角形頂点でのテクスチャ座標値
*/
void SetVertex(float s, float t, Vec3 v0, Vec3 v1, Vec3 v...
{
Vec3 v = v0+s*(v1-v0)+t*(v2-v0);
Vec2 tc = tc0+s*(tc1-tc0)+t*(tc2-tc0);
glTexCoord2dv(tc.data);
glVertex3dv(v.data);
}
/*!
* 三角形を分割して描画
* @param[in] v0,v1,v2 三角形頂点座標
* @param[in] tc1,tc2,tc3 三角形頂点でのテクスチャ座標値
* @param[in] level 分割レベル
*/
void DrawTriangle(Vec3 v0, Vec3 v1, Vec3 v2, Vec2 tc0, Ve...
{
if(!level){
// 分割レベル0のとき三角形をそのまま描画
glDisable(GL_LIGHTING);
glBegin(GL_TRIANGLES);
glTexCoord2dv(tc0.data); glVertex3dv(v0.data);
glTexCoord2dv(tc1.data); glVertex3dv(v1.data);
glTexCoord2dv(tc2.data); glVertex3dv(v2.data);
glEnd();
}
int layer = 1 << level; // 三角形の各辺の分割数
// v0を(0,0),v1を(1.0),v2を(0,1)として三角形を(s,t)でパ...
float s0, s1, t0, t1;
float ds = 1.0/float(layer);
float dt = 1.0/float(layer);
s0 = 0.0;
s1 = s0+ds;
t0 = 0.0;
t1 = t0+dt;
int n;
n = layer;
for(int i = 0; i < layer; ++i){ // s方向のレイヤー
t0 = 0.0;
t1 = t0+dt;
for(int j = 0; j < n; ++j){ // t方向のレイヤー
glBegin(GL_TRIANGLES);
SetVertex(s0, t0, v0, v1, v2, tc0, tc1, tc2);
SetVertex(s1, t0, v0, v1, v2, tc0, tc1, tc2);
SetVertex(s0, t1, v0, v1, v2, tc0, tc1, tc2);
glEnd();
if(j != n-1){
glBegin(GL_TRIANGLES);
SetVertex(s0, t1, v0, v1, v2, tc0, tc1, tc2);
SetVertex(s1, t0, v0, v1, v2, tc0, tc1, tc2);
SetVertex(s1, t1, v0, v1, v2, tc0, tc1, tc2);
glEnd();
}
t0 += dt;
t1 += dt;
}
s0 += ds;
s1 += ds;
n--;
}
}
}}
GLSLの呼び出しコードは以下.
#code(C){{
/*!
* シーンのレンダリング
*/
void RenderScene(void)
{
glColor3f(0.0, 0.0, 1.0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, g_uTexHeight);
// GLSLを有効にする
glUseProgram(g_GLSL.Prog);
glUniform1i(glGetUniformLocation(g_GLSL.Prog, "HeightMap...
glUniform1i(glGetUniformLocation(g_GLSL.Prog, "SubLevel"...
glUniform1f(glGetUniformLocation(g_GLSL.Prog, "Height"),...
// ライティングは無視しているのでラインで描画
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glPushMatrix();
glTranslatef(-0.5, 0.0, -0.5);
// 三角形ポリゴンを分割して描画
DrawTriangle(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 0.0, 0.0), V...
Vec2(0.0, 0.0), Vec2(1.0, 0.0), Vec2(1.0, 1.0), 2);
DrawTriangle(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 0.0, 1.0), V...
Vec2(0.0, 0.0), Vec2(1.0, 1.0), Vec2(0.0, 1.0), 2);
glPopMatrix();
glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
}}
g_uTexHeightにはハイトフィールドとなるテクスチャが格納さ...
*結果 [#p0150a6b]
ハイトフィールドとして以下の画像を用いた.
#ref(tex_sphere.png)
CPU側で2レベル,GPU側で2レベル,計レベル4まで分割した結果...
&ref(disp_map_1_1.jpg); &ref(disp_map_2_1.jpg);
左の画像が通常の結果,右はGLSLを無効にした場合である.
ハイトフィールド画像の暗いところほど凹んでいる.
#ref(disp_map_3_1.jpg);
この画像はジオメトリシェーダでの分割レベルを3にした場合で...
最大出力要素数の制限により出力されていない三角形があるの...
*ソースコード [#e99c6dbf]
Visual Studio 2008用のソースコードを以下に置く.ビルド・...
#ref(glsl_displacementmap.zip)
ページ名: