Edited at

normalizeはバーテックスシェーダのあとで

More than 1 year has passed since last update.

謎解きはディナーのあとで

みたいなタイトルを目指しました。

HTML5カンファレンスでShaderの話をさせてもらう機会をいただきまして、

その時にDEMOをするのにShdr Editorというオンラインエディタを使いました。

http://shdr.bkcore.com/

控え室でWebGLな人たちと話をしていた時、DEMOの様子を少し見せたところ、

@kyasbal_1994 に、「normalize はフラグメントシェーダでした方がいいよ」と教えてもらった。

Shdrのデフォルトコードにそれは含まれている

precision highp float;

attribute vec3 position;
attribute vec3 normal;
uniform mat3 normalMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
varying vec3 fNormal;
varying vec3 fPosition;

void main()
{
fNormal = normalize(normalMatrix * normal); // <-- ここ
vec4 pos = modelViewMatrix * vec4(position, 1.0);
fPosition = pos.xyz;
gl_Position = projectionMatrix * pos;
}

ぜったいにバーテックスシェーダで normalize してはいけないということではなくて、

varying でフラグメントジェーダに渡す前に normalize しても線形補間されたあとのベクトルの長さは 1.0 ではなくなっているということでして。

たしかに、 normalize されたベクトルの length で色を指定してみると真っ白になるはずがそうはならない。

precision highp float;

uniform float time;
uniform vec2 resolution;
varying vec3 fPosition;
varying vec3 fNormal;

void main()
{
// vec3 normal = normalize(fNormal);// <-- これだと真っ白になる
vec3 normal = fNormal;
gl_FragColor = vec4(length(normal));
}

実際の例はこちら

https://goo.gl/RsdhSN

数値的には微妙な差でも色々重ねがけしていくと問題になることがあるらしい。