jit.gl.shader / GLSL でポイントスプライト #maxmsp #jitter #glsl

ジオメトリシェーダ

ジオメトリシェーダは、レンダリングパイプラインにおいて、バーテックスシェーダの後に配置されており、GPU上でプリミティブの変換や増減が可能なシェーダだそうです。

スクリーンショット 2014-08-05 19.29.40

ポイントスプライト

ポイントスプライトという手法は、CPUからpointsで与えた点群をジオメトリシェーダを用いてtriangleなどに変換しテクスチャを貼ることで、GPUの計算能力を活かしてテクスチャ付きのパーティクルをつくる方法です。

スクリーンショット 2014-08-05 18.46.52

実装してみた

今回はGLSL1.2で使えるジオメトリシェーダ(Geometry Shader)を用いて、ポイントスプライトを実装してみました。OpenGL 4.0 シェーディング言語 -実例で覚えるGLSLプログラミング-に掲載されているコードを参考にしています。ジオメトリシェーダは、Maxのjit.gl.shaderでもちゃんと使えるのですが、ググっても解説がないためつまずくポイントも多かったため、少し詳しく紹介します。

スクリーンショット 2014-08-05 18.46.57

パラメーターの宣言

[html]
<param name="size" type="vec2" default="1. 1." />
[/html]
ジオメトリシェーダに限らない事ですが、Maxから指定するパラメーターは、param要素として指定します。初期値も与えられますがコンマで区切っては駄目みたいなので注意です。

パラメーターのバインド

[html]
<language name="glsl" version="1.2">
<bind param="size" program="gp" />
<bind param="tex0" program="fp" />
<program>
</program>
</language>
[/html]

宣言したパラメーターが、どのプログラマブルシェーダで利用されるかをprogram属性にbindします。例:sizeをgeometry shaderで利用する。例外ですがテクスチャをシェーダで扱いたい場合には、Maxの場合tex0というパラメーターが予約されているようで、宣言していなくても使えました。マルチテクスチャをやる場合については未調査です。

サンプルコードで使われているプログラム名称

  • “gp” : geometry shader
  • “fp” : fragment shader
  • “vp” : vertex shader

ジオメトリシェーダの宣言

[html]
<program name="gp" vertices_out="4" input_type="points" output_type="triangle_strip" type="geometry">
<![CDATA[
/*glslのプログラムを記述*/
]]>
</program>
[/html]
program要素を宣言します。vertices_out / input_type / output_typeが合ってないと実行できません。今回は、”points”を”triangle_strip”に変換し”4”つのvertexが出力されるという設定になっています。

ジオメトリシェーダのコード

[c]
#version 120
#extension GL_EXT_geometry_shader4 : enable

uniform vec2 size;
varying in vec2 texdim0[1];

void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_PositionIn[0];
gl_Position.x -= size.x/2;
gl_Position.y += size.y/2;
gl_TexCoord[0].st = vec2(0,0) * texdim0[0];
EmitVertex();
gl_Position.y -= size.y;
gl_TexCoord[0].st = vec2(0,1) * texdim0[0];
EmitVertex();
gl_Position.x += size.x;
gl_Position.y += size.y;
gl_TexCoord[0].st = vec2(1,0) * texdim0[0];
EmitVertex();
gl_Position.y -= size.y;
gl_TexCoord[0].st = vec2(1,1) * texdim0[0];
EmitVertex();
}
[/c]
#extension GL_EXT_geometry_shader4 : enable でジオメトリシェーダを有効化しています。main関数では、Maxから受け取ったsizeを使ってポイント(頂点)を、四つ頂点へと増加させています。特殊な書き方ですがEmitVertex()を呼ぶことでgl_texCoord[0]に設定されている頂点を出力しています。gl_TexCoordには、テクスチャの参照位置を入れていますね。Maxから受け取るテクスチャの座標が正規化いないので、texdim0[0]を掛けています。

JXS TIPS

  • 日本語でコメントが書かれているとMaxが即落ちる
  • ポイントスプライトで使うテクスチャのバインド先は、jit.gl.shaerではなく、jit.gl のオブジェクト
  • jit.gl.mesh: unbinding vertex array: GL Error: Invalid operation

    というエラーが出た場合は、jit.gl.meshのdraw_modeがpointsになっていない可能性があります。

続きを読む jit.gl.shader / GLSL でポイントスプライト #maxmsp #jitter #glsl

jit.gl.shader / GLSL でフォグ #maxmsp #jitter #glsl

スクリーンショット 2014-08-05 03.50.41

OpenGL Superbibleのサンプルコードです。

JXS / GLSL

[html]
<jittershader name="mrr-3colored-lights">
<description>
</description>

<language name="glsl" version="1.2">
<program name="vp" type="vertex">
<![CDATA[

#version 120

void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix *gl_Vertex;

vec3 lightPos = gl_LightSource[0].position.xyz;

vec3 N = normalize(gl_NormalMatrix * gl_Normal);
vec4 V = gl_ModelViewMatrix *gl_Vertex;
vec3 L = normalize(lightPos – V.xyz);
vec3 H = normalize(L + vec3(0,0,1));

const float specularExp = 128.0;

float NdotL =max(0,dot(N,L));
vec4 diffuse = gl_Color * vec4(NdotL);

float NdotH = max(0,dot(N,H));
vec4 specular = vec4(0);

if(NdotL >0){
specular = vec4(pow ( NdotH,specularExp));
}

gl_FogFragCoord =length(V);
gl_FrontColor = (diffuse + specular);
}
]]>
</program>
<program name="fp" type="fragment">
<![CDATA[

#version 120

void main()
{
const float e = 2.71828;
float fogFactor = pow(0.5 *gl_FogFragCoord,2);
fogFactor = clamp(pow(e,-fogFactor),0,1);

const vec4 fogColor =vec4(0.5,0.5,0.5,0.4);
gl_FragColor = mix(fogColor,gl_Color,fogFactor);
}
]]>
</program>
</language>
</jittershader>
[/html]

Vertex Shaderの方でカメラからの距離を算出しておいて、Fragment Shadreで色を計算する時にFogの方程式を使ってFog量を決めています。

jit.gl.shader / GLSL でプロシージャルテクスチャ(星)生成 その2 #maxmsp #jitter #glsl

スクリーンショット 2014-08-05 01.25.04

配色がRedbull感

OpenGL Superbibleのサンプルコードです。レッドブルが飲みたくなる配色。

JXS / GLSLコード

[html]
<jittershader name="mrr-3colored-lights">
<description>
</description>

<language name="glsl" version="1.2">
<program name="vp" type="vertex">
<![CDATA[

#version 120

varying vec3 N,L,V;

void main(void)
{
vec3 lightPos = gl_LightSource[0].position.xyz;

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

//map object-space position onto unit sphere
V =gl_Vertex.xyz;

//eye-space normal
N = gl_NormalMatrix * gl_Normal;

//eye-space light vector
vec4 Veye = gl_ModelViewMatrix * gl_Vertex;
L =lightPos – Veye.xyz;
}

]]>
</program>
<program name="fp" type="fragment">
<![CDATA[

#version 120

varying vec3 V;
varying vec3 N;
varying vec3 L;

const vec3 myRed = vec3(0.6,0,0);
const vec3 myYellow = vec3(0.6,0.5,0);
const vec3 myBlue = vec3(0,0.3,0.6);

//Star Vertex
const vec3 myHalfSpace0 = vec3(0.31,0.95,0);
const vec3 myHalfSpace1 = vec3(-0.81,0.59,0);
const vec3 myHalfSpace2 = vec3(-0.81,-0.59,0);
const vec3 myHalfSpace3 = vec3(0.31,-0.95,0);
const vec3 myHalfSpace4 = vec3(1.,0.,0.);

const float stripeThickness = 0.4;
const float starSize = 0.2;
const float smoothEdgeTol = 0.005;
const float ambientLighting = 0.5;
const float specularExp = 128.0;
const float specularIntensity = 1.;

void main()
{
vec4 distVector;
float distScalar;

vec3 NN = normalize(N);
vec3 NL = normalize(L); //for ambient;
vec3 NH = normalize(NL +vec3(0,0,1)); //for specular
vec3 NV = normalize(V);

float myInOut = -3;

distVector.x = dot(NV, myHalfSpace0);
distVector.y = dot(NV, myHalfSpace1);
distVector.z = dot(NV, myHalfSpace2);
distVector.w = dot(NV, myHalfSpace3);
distScalar = dot(NV,myHalfSpace4);

distVector += starSize;
distScalar += starSize;

//map 0 ~ 1
distVector = smoothstep(0.,smoothEdgeTol, distVector);
distScalar = smoothstep(0.,smoothEdgeTol, distScalar);

myInOut += dot(distVector, vec4(1.0));
myInOut += distScalar;
myInOut = clamp(myInOut, 0,1);

vec3 surfColor = mix(myYellow, myRed, myInOut);

myInOut = smoothstep(0,smoothEdgeTol,abs(NV.z) – stripeThickness);
surfColor = mix(myBlue,surfColor,myInOut);

surfColor *= (ambientLighting + vec3(max(0,dot(NN,NL))));
surfColor += (specularIntensity * vec3(pow(max(0,dot(NN,NH)),specularExp)));

gl_FragColor = vec4(surfColor,1);
}
]]>
</program>
</language>
</jittershader>
[/html]

星の各点との内積をとって、星の頂点方向の長さ(0以上1以下)を合計し星のサイズをオフセットとして加算。その値が閾値を超えたら赤色にして、超えなかったら黄色に塗って星を描画している。星の頂点位置とVertexの単位ベクトルの関係性を使って星の形を描画しているのだが、ちょっとまだ理解しきれていない・・・。

jit.gl.shader / GLSL でプロシージャルテクスチャ(ビーチボール)生成

スクリーンショット 2014-08-04 23.30.07

夏だしビーチボールで夏感を演出

嘘です。プログラムだけでテクスチャ生成する手法をプロシージャルテクスチャと呼ぶそうですが、OpenGL Superbibleにビーチボールのサンプルがあったので実装してみました。法線ベクトルやVertexの位置を利用して色を決めてますね。まだアルゴリズムを飲み込めてないので、ポケモンのハイパーボールを練習で作ってみようか。

JXS / GLSLコード

[html]
<jittershader name="mrr-3colored-lights">
<description>
</description>

<language name="glsl" version="1.2">
<program name="vp" type="vertex">
<![CDATA[

#version 120

varying vec3 N,L,V;

void main(void)
{
vec3 lightPos = gl_LightSource[0].position.xyz;

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

//map object-space position onto unit sphere
V =gl_Vertex.xyz;

//eye-space normal
N = gl_NormalMatrix * gl_Normal;

//eye-space light vector
vec4 Veye = gl_ModelViewMatrix * gl_Vertex;
L =lightPos – Veye.xyz;
}

]]>
</program>
<program name="fp" type="fragment">
<![CDATA[

#version 120

varying vec3 V;
varying vec3 N;
varying vec3 L;

const vec3 myRed = vec3(1,0,0);
const vec3 myYellow = vec3(1,1,0);
const vec3 myGreen = vec3(0,1,0);
const vec3 myBlue = vec3(0,0,1);
const vec3 myWhite = vec3(1,1,1);
const vec3 myBlack = vec3(0,0,0);

const vec3 northHalfSpace = vec3(0,0,1);
const vec3 northeastHalfSpace = vec3(0.707,0,0.707);
const vec3 northwestHalfSpace = vec3(-0.707,0,0.707);
const float capSize = 0.03;
const float smoothEdgeTol = 0.0005;
const float ambientLighting = 0.1;
const float specularExp = 10.0;
const float specularIntensity = 0.5;

void main()
{
vec3 NN = normalize(N);
vec3 NL = normalize(L); //for ambient;
vec3 NH = normalize(NL +vec3(0,0,1)); //for specular
vec3 NV = normalize(V);

float mirror = (NV.x >= 0) ? 1. : -1.;
NV.xz *= mirror; //

vec4 distance;
distance.x = dot(NV, northHalfSpace);
distance.y = dot(NV, northeastHalfSpace);
distance.z = dot(NV, northwestHalfSpace);

distance.w = abs(NV.y) – 1.0 + capSize;
distance = smoothstep(vec4(0.), vec4(smoothEdgeTol), distance);

vec3 surfColor = mix(myBlack,myRed,distance.x);
surfColor += mix(myBlack,myGreen,distance.y * (1.0 – distance.z));
surfColor += mix(surfColor, myBlue, 1.0 – distance.y);

//top bottom
surfColor = mix(surfColor, myWhite, distance.w);

//ambient
surfColor *= (ambientLighting + vec3(max(0,dot(NN,NL))));
//specluar
surfColor += (specularIntensity *vec3(pow(max(0,dot(NN,NH)),specularExp)));

gl_FragColor = vec4(surfColor,1);
}
]]>
</program>
</language>
</jittershader>
[/html]

jit.gl.shader / GLSL で specular lighting を実装してみた #maxmsp #jitter #glsl

スクリーンショット 2014-08-04 22.09.47

Specular Lighting

OpenGL Superbibleのサンプルコードを練習がてら実装してみました。こちらの本は5th Editionも出ているのですが、Maxの対応がOpenGL2.0 / GLSL1.2 までなので、4th Editionを使っています。

JXS / GLSLサンプルコード

[html]
<jittershader name="mrr.specular">
<description>
specular-light
</description>

<language name="glsl" version="1.2">
<program name="vp" type="vertex">
<![CDATA[

#version 120

void main(void)
{
//normal MVP transform
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

//Lighting
vec3 lightPos = gl_LightSource[0].position.xyz;

vec3 N = normalize(gl_NormalMatrix * gl_Normal);
vec4 V = gl_ModelViewMatrix * gl_Vertex;
vec3 L = normalize(lightPos – V.xyz);
vec3 H = normalize(L + vec3(0,0,1));

const float specularExp = 128.;

//calculate diffuse lighting
float NdotL = max(0,dot(N,L));
gl_FrontColor = gl_Color *vec4(NdotL);

//calculate specular lighting
float NdotH = 0;//max(0.0, dot(N,H));

if(NdotL > 0.0){
NdotH = max(0.0,dot(N,H) * 8.0 – 7.0);
}

gl_TexCoord[0] = vec4(NdotH,0,0,1);
}
]]>
</program>
<program name="fp" type="fragment">
<![CDATA[

#version 120

void main()
{
//add diffuse & specular
gl_FragColor = gl_Color + gl_TexCoord[0];
}
]]>
</program>
</language>
</jittershader>
[/html]

おまけ

スクリーンショット 2014-08-04 21.38.19
法線ベクトルで色を塗ってみました。