[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
SlideShare a Scribd company logo
シェーダ
書いてますか?
2015/01/27(Tue) Ryo Tsuruda
Agenda
● 自己紹介
● 本日の目的
● シェーダとは
● シェーダを見てみる
● シェーダを書いてみる
● まとめ
自己紹介
自己紹介
● 名前:りょう
● 趣味:猫とプログラミング
● 仕事:ゲーム作り
○ 今まではサーバ、インフラ、ネイティブアプリなど
※今回の内容は、仕事とは関係なく趣味での発表です
本日の目的
本日の目的
● シェーダとは何か?を知る
● Cocos2d-xでシェーダを書けるようになる
● シェーダの仕組みの理解
やらないこと
注意事項
● シェーダのプロではないので、質問など答えら
れない場合もあります
● Android/iOSで動作させるための OpenGL ES
のプログラマブルシェーダついての説明です
● Cocos2d-x v3.xでのみ動作確認しています
シェーダとは
シェーダとは
● GPUに命令して処理させるもの
● スクリーンに表示させる色を制御するもの
床井研究室
http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20090827
シェーダとは
書いたことがある方?
シェーダの例
● トゥーンシェーダ
● ファーシェーダ
● 他多数
シェーダの例 (cont.)
シェーダの例 (cont.)
!?
シェーダの言語
● シェーダを書くために必要な言語
○ GLSL(OpenGL Shading Language)
○ GLSL ES (OpenGL for Embedded System)
● 他には、
○ DirectX : HLSL(High Level Shading Language)
○ NVIDIA : Cg
○ iOS : Metal Shading Language
シェーダの言語
● Cocos2d-xではどの言語を使っていますか?
○ C++ ?
○ Lua ?
○ JavaScript ?
● どのbindingからも利用できます
シェーダの処理の流れ
1. ノードを作成 (Sprite::create())
2. バーテックスシェーダ(Vertex Shader)
○ 頂点シェーダとも
3. フラグメントシェーダ(Fragment Shader)
○ ピクセルシェーダとも 
4. 画面に表示
複数のシェーダで
処理
シェーダを見てみる
バーテックスシェーダ(Sprite)
const char* ccPositionTextureColor_noMVP_vert = STRINGIFY(
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
n#ifdef GL_ESn
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
n#elsen
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
n#endifn
void main()
{
gl_Position = CC_PMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
); ccShader_PositionTextureColor_noMVP.vert
フラグメントシェーダ(Sprite)
const char* ccPositionTextureColor_noMVP_frag = STRINGIFY(
n#ifdef GL_ESn
precision lowp float;
n#endifn
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
}
);
ccShader_PositionTextureColor_noMVP.frag
バーテックスシェーダ(解説)
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
void main()
{
gl_Position = CC_PMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
attribute
Cocos2d-xからバーテックスシェーダに渡される値
vec4 a_position
頂点情報
(Cocos2d-xでbindingしている変数)
vec2 a_texCoord
テクスチャのマッピング情報
(Cocos2d-xでbindingしている変数)
vec4 a_color
色情報
(Cocos2d-xでbindingしている変数)
バーテックスシェーダ(解説)
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
void main()
{
gl_Position = CC_PMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
varying
フラグメントシェーダに渡すための値
lopw / mediump
値の精度(floatとかdoubleと同じ)
vec4 v_fragmentColor
色情報
vec4 v_texCoord
テクスチャの情報
バーテックスシェーダ(解説)
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
void main()
{
gl_Position = CC_PMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
main()
最初に呼ばれる関数
gl_Position
OpenGLで処理するポジション情報
CC_PMatrix
座標情報を調整するための変数
(Cocos2d-xでbindingしている変数)
フラグメントシェーダ(解説)
precision lowp float;
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
}
precision
精度の定義
フラグメントシェーダ(解説)
precision lowp float;
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
}
varying
フラグメントシェーダから渡される値
vec4 v_fragmentColor
色情報
vec4 v_texCoord
テクスチャの情報
フラグメントシェーダ(解説)
precision lowp float;
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
}
main()
最初に呼ばれる関数
gl_FragColor
OpenGLで処理する色情報
CC_Texture0
テクスチャの情報(Cocos2d-xでbindingしている変数)
texture2D()
テクスチャから指定座標の色情報を抜き出す
Cocos2d-xで定義されている変数
// uniform names
const char* GLProgram::UNIFORM_NAME_AMBIENT_COLOR = "CC_AmbientColor";
const char* GLProgram::UNIFORM_NAME_P_MATRIX = "CC_PMatrix";
const char* GLProgram::UNIFORM_NAME_MV_MATRIX = "CC_MVMatrix";
const char* GLProgram::UNIFORM_NAME_MVP_MATRIX = "CC_MVPMatrix";
const char* GLProgram::UNIFORM_NAME_NORMAL_MATRIX = "CC_NormalMatrix";
const char* GLProgram::UNIFORM_NAME_TIME = "CC_Time";
const char* GLProgram::UNIFORM_NAME_SIN_TIME = "CC_SinTime";
const char* GLProgram::UNIFORM_NAME_COS_TIME = "CC_CosTime";
const char* GLProgram::UNIFORM_NAME_RANDOM01 = "CC_Random01";
const char* GLProgram::UNIFORM_NAME_SAMPLER0 = "CC_Texture0";
const char* GLProgram::UNIFORM_NAME_SAMPLER1 = "CC_Texture1";
const char* GLProgram::UNIFORM_NAME_SAMPLER2 = "CC_Texture2";
const char* GLProgram::UNIFORM_NAME_SAMPLER3 = "CC_Texture3";
const char* GLProgram::UNIFORM_NAME_ALPHA_TEST_VALUE = "CC_alpha_value";
// Attribute names
const char* GLProgram::ATTRIBUTE_NAME_COLOR = "a_color";
const char* GLProgram::ATTRIBUTE_NAME_POSITION = "a_position";
const char* GLProgram::ATTRIBUTE_NAME_TEX_COORD = "a_texCoord";
const char* GLProgram::ATTRIBUTE_NAME_TEX_COORD1 = "a_texCoord1";
const char* GLProgram::ATTRIBUTE_NAME_TEX_COORD2 = "a_texCoord2";
const char* GLProgram::ATTRIBUTE_NAME_TEX_COORD3 = "a_texCoord3";
const char* GLProgram::ATTRIBUTE_NAME_NORMAL = "a_normal";
const char* GLProgram::ATTRIBUTE_NAME_BLEND_WEIGHT = "a_blendWeight";
const char* GLProgram::ATTRIBUTE_NAME_BLEND_INDEX = "a_blendIndex";
シェーダを書いてみる
真っ赤にしてみる
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
void main()
{
gl_Position = CC_PMatrix * a_position;
- v_fragmentColor = a_color;
+ v_fragmentColor = vec4(1.0, 0.0, 0.0, 1.0);
v_texCoord = a_texCoord;
}
バーテックスシェーダ
?確かに赤いけど、真っ赤ではない
バーテックスシェーダの役割
● 頂点を決める
○ ポリゴンの頂点をどの位置に表示するか
○ 表示する色を決めるのはフラグメントシェーダ
void main()
{
gl_Position = CC_PMatrix * a_position;
- v_fragmentColor = a_color;
+ v_fragmentColor = vec4(1.0, 0.0, 0.0, 1.0);
v_texCoord = a_texCoord;
}
フラグメントシェーダに色情報を渡
しているだけ
次こそ、真っ赤にしてみる
precision lowp float;
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
- gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
表示される色を赤色に変更
(他の色情報は破棄)
真っ赤になった
シェーダが違う
次はどうなるでしょうか?
precision lowp float;
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
- gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
+ gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, vec2(v_texCoord.x/2.0, v_texCoord.y);
}
テクスチャから抽出する座標を変更
見た目が半分なった
シェーダの書き方
● とにかく試行錯誤
○ コンパイルエラーを出してくれる
○ 型には厳密
● 感覚
○ 少しの調整で大きく変わることもある
cocos2d: ERROR: 0:21: No matching function for call to
texture2D(sampler2D, float)
ERROR: 0:21: '/' does not operate on 'float' and 'int'
シェーダの書き方 (cont.)
● 動的コンパイル
○ アプリのビルド時ではなく、実行時にコンパイル
○ コンパイルしたデータはキャッシュすること
○ リソースではなく、文字列としてコードに埋める
■ I/O待ちが発生するためCocos2d-xはこうしている
● デバッグ難しい
○ 実行して、コンパイルエラーをチェックしている
○ WebGLを試せるWebサービスなどで動作チェック
○ http://glslsandbox.com
● 実機で確認
○ GPUを使っているので、実機での確認必須
自作シェーダの適用
// スプライトの作成
auto sprite = Sprite::create("HelloWorld.png");
this->addChild(sprite);
// シェーダの読込みと適用
auto glProgram = GLProgram::createWithFilenames("shader.vert", "shader.frag");
auto glProgramState = GLProgramState::getOrCreateWithGLProgram(glProgram);
sprite->setGLProgramState(glProgramState);
// uniformに値を代入
glProgramState->setUniformVec2("touchPosition", touchPosition);
uniform
プログラムからバーテックスシェーダやフラグメントシェーダに渡される値
グレイスケール(vert)
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
void main(void) {
gl_Position = CC_PMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
グレイスケール(frag)
precision lowp float;
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
// Gray scale(RGB)
const vec3 grayScale = vec3(0.298912, 0.586611, 0.114478);
void main(void) {
vec4 color = texture2D(CC_Texture0, v_texCoord);
float grayScaleColor = dot(color.rgb, grayScale);
gl_FragColor = vec4(vec3(grayScaleColor), color.a);
}
グレイスケール
ブラー(vert)
varying vec2 v_texCoord;
varying vec2 v_blurTexCoords[14];
uniform float u_rate;
void main() {
gl_Position = CC_PMatrix * a_position;
v_texCoord = a_texCoord;
v_blurTexCoords[ 0] = v_texCoord + vec2(-0.028 * u_rate, 0.0);
v_blurTexCoords[ 1] = v_texCoord + vec2(-0.024 * u_rate, 0.0);
v_blurTexCoords[ 2] = v_texCoord + vec2(-0.020 * u_rate, 0.0);
v_blurTexCoords[ 3] = v_texCoord + vec2(-0.016 * u_rate, 0.0);
v_blurTexCoords[ 4] = v_texCoord + vec2(-0.012 * u_rate, 0.0);
v_blurTexCoords[ 5] = v_texCoord + vec2(-0.008 * u_rate, 0.0);
v_blurTexCoords[ 6] = v_texCoord + vec2(-0.004 * u_rate, 0.0);
v_blurTexCoords[ 7] = v_texCoord + vec2( 0.004 * u_rate, 0.0);
v_blurTexCoords[ 8] = v_texCoord + vec2( 0.008 * u_rate, 0.0);
v_blurTexCoords[ 9] = v_texCoord + vec2( 0.012 * u_rate, 0.0);
v_blurTexCoords[10] = v_texCoord + vec2( 0.016 * u_rate, 0.0);
v_blurTexCoords[11] = v_texCoord + vec2( 0.020 * u_rate, 0.0);
v_blurTexCoords[12] = v_texCoord + vec2( 0.024 * u_rate, 0.0);
v_blurTexCoords[13] = v_texCoord + vec2( 0.028 * u_rate, 0.0);
}
ブラー(frag)
varying vec2 v_texCoord;
varying vec2 v_blurTexCoords[14];
void main()
{
gl_FragColor = vec4(0.0);
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[ 0])*0.
0044299121055113265;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[ 1])*0.00895781211794;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[ 2])*0.0215963866053;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[ 3])*0.0443683338718;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[ 4])*0.0776744219933;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[ 5])*0.115876621105;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[ 6])*0.147308056121;
gl_FragColor += texture2D(CC_Texture0, v_texCoord )*0.159576912161;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[ 7])*0.147308056121;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[ 8])*0.115876621105;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[ 9])*0.0776744219933;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[10])*0.0443683338718;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[11])*0.0215963866053;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[12])*0.00895781211794;
gl_FragColor += texture2D(CC_Texture0, v_blurTexCoords[13])*0.
0044299121055113265;
ブラー
ノイズ(vert)
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;
#ifdef GL_ES
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
#else
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
#endif
void main(void) {
gl_Position = CC_PMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
ノイズ(frag)
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
uniform vec2 resolution;
const float intensity = 0.05;
vec3 noise(vec2 uv)
{
vec2 p = abs(sin(uv * 13.0 + uv.x * CC_Time[1] * sin(uv.y)));
return vec3(sin (0.2 * CC_Time[1] + sin(p * 0.5) * CC_Time[1] / cos(50.0)) * 10.0,0.3+0.5 * abs(sin
(CC_Time[1] * tan(5.0))));
}
void main(void)
{
gl_FragColor.xyz = intensity * noise(gl_FragCoord.xy / sin(resolution.xy * CC_Time[1] * 0.01)) +
(1. - intensity) *
texture2D(CC_Texture0,v_texCoord.xy).xyz;
gl_FragColor.w = 1.;
}
ノイズ
旗(vert)
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;
#ifdef GL_ES
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
#else
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
#endif
void main(void) {
gl_Position = CC_PMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
旗(frag)
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 v_texCoord;
void main( void ) {
float len = length(v_texCoord);
vec2 uv = vec2(v_texCoord.x - (v_texCoord.x / len) * cos(len - CC_Time[1]) * 0.05,
v_texCoord.y - (v_texCoord.y / len) * sin(len * 12.0 - CC_Time[1] * 7.0) * 0.05);
gl_FragColor = texture2D(CC_Texture0, uv);
}
旗
波(vert)
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;
#ifdef GL_ES
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
#else
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
#endif
void main(void) {
gl_Position = CC_PMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
波(frag)
#ifdef GL_ES
precision highp float;
#endif
uniform vec2 resolution;
uniform vec2 touchPosition;
varying vec2 v_texCoord;
void main(void) {
vec2 tc = v_texCoord;
vec2 p = vec2(tc.x-touchPosition.x, tc.y-touchPosition.y);
float len = length(p);
vec2 uv = tc + (p / len) * cos(len * 14.0 - CC_Time[1] * 8.0) * 0.04;
vec3 col = texture2D(CC_Texture0, uv).xyz;
gl_FragColor = vec4(col, 1.0);
}
波
GLES Sandboxより(vert)
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;
#ifdef GL_ES
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
#else
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
#endif
void main(void) {
gl_Position = CC_PMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
GLES Sandboxより(frag)
http://glslsandbox.com/e#22390.2
画像が別物に
まとめ
まとめ
● 次のステップに向けて
○ 今回は超基本なので、本格的なものは勉強が必要
○ 数学の知識が必要となることが多いです
● 差別化
○ シェーダを自作すると、大きな差別化を図れる
○ コンソール出身の方が作るゲームには自作シェーダが
多いのではないでしょうか

More Related Content

【TechBuzz】第9回cocos2d-x勉強会「シェーダ書いてますか?」