マイペースなプログラミング日記

DTMやプログラミングにお熱なd-kamiがマイペースに書くブログ

Lambertシェーディングを試してみる

シェーダーとしてまずLambertを勉強した。ライトの向いてる方向と法線の内積求めて、diffuseと色をかけるだけでできてしまうらしい。参考ページを見て作ってた。フラグメントシェーダーをまず載せて、その後に全体のプログラムを載せる。その前にプログラムのスクリーンショット。右の方からライトを当てている

Fragmentシェーダー、法線とライトの方向の内積をとって、diffuseをかけている。今回は物体の色は無視している

precision mediump float;

//法線ベクトル
varying vec3 N;

//ライトの向いている方向
vec3 light_dir = vec3(-1.0, 0.0, 0.0);
//lightのdiffuse
vec4 light_diffuse = vec4(0.8, 0.8, 0.8, 1.0);

void main(){
    //法線ベクトルとライトの方向の内積をdiffuseにかけたものを色とする
    gl_FragColor = vec4(light_diffuse.rgb * dot(N, light_dir), 1.0);
}

プログラム全体

<html><head>
<meta http-equiv="content-type" content="text/html; charset=Shift_JIS">
    <title></title>
    <script type="text/javascript" src="./js/glMatrix-0.js"></script>
    <script type="text/javascript" src="./js/gun3.js"></script>
    <script type="text/javascript" src="./js/object3d.js"></script>
    <script>
window.onload = function(){
	//HTML5のキャンバス取得
    var canvas = document.getElementById("canvas");
    
    //WebGLのハンドル(?)取得
    var gl = canvas.getContext("experimental-webgl");
    
    //Vertexシェーダー取得
    var vertexShader = createShader(gl, "2d-vertex-shader", gl.VERTEX_SHADER);
    
    //Fragmentシェーダー取得
    var fragmentShader = createShader(gl, "2d-fragment-shader", gl.FRAGMENT_SHADER);

	//シェーダーをリンクする
    program = createProgram(gl, vertexShader, fragmentShader);

    var mvMatrix = mat4.create();
    var pMatrix = mat4.create();
    
    //シェーダーにデータを渡すためのハンドル(?)取得
    var pMatrixLocation = gl.getUniformLocation(program, "u_PMatrix");
    var mvMatrixLocation = gl.getUniformLocation(program, "u_MVMatrix");
    var nMatrixLocation = gl.getUniformLocation(program, "u_NormalMatrix");
    var positionLocation = gl.getAttribLocation(program, "a_position");
    var normalLocation = gl.getAttribLocation(program, "a_normal");
    
    //銃のモデルから表示オブジェクトを作る
    var object = new Object3D(gl);
    object.initBuffer(gun3.vertices, gun3.faces, gun3.normals);
    object.setHandle(positionLocation, normalLocation);

    var rotate = 135;
    gl.enable(gl.DEPTH_TEST);

    setInterval(function(){
        mat4.perspective(45, 450.0 / 450.0, 1.0, 10.0, pMatrix);
        mat4.identity(mvMatrix);
        
        //銃の表示位置を指定
        mat4.translate(mvMatrix, [0.0, -0.5, -5.0]);
        //銃を回転させる
        mat4.rotate(mvMatrix, rotate * 3.1415 / 180.0, [0, 1, 0]);

		//シェーダーにデータを渡す
        gl.uniformMatrix4fv(pMatrixLocation, false, pMatrix);
        gl.uniformMatrix4fv(mvMatrixLocation, false, mvMatrix);

        var normalMatrix = mat3.create();
        mat4.toInverseMat3(mvMatrix, normalMatrix);
        mat3.transpose(normalMatrix);
        gl.uniformMatrix3fv(nMatrixLocation, false, normalMatrix);
        
        gl.clearColor(0.7, 0.7, 0.7, 1.0);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        
        object.draw();
    }, 16);
}

function createShader(gl, shaderId, type) {
    var shader = gl.createShader(type);
    var source = document.getElementById(shaderId).innerHTML;
    
    gl.shaderSource(shader, source);
    gl.compileShader(shader);
    
    return shader;
}

function createProgram(gl, vertexShader, fragmentShader){
    var program = gl.createProgram();

    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);

    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
        alert(gl.getShaderInfoLog(vertexShader));
        alert(gl.getShaderInfoLog(fragmentShader));
    }
    
    gl.useProgram(program);
    
    return program;
}
    </script>
    
    <script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec3 a_position;
attribute vec3 a_normal;
varying vec3 N;

uniform mat4 u_MVMatrix;
uniform mat4 u_PMatrix;
uniform mat3 u_NormalMatrix;

void main(){
    N = normalize(u_NormalMatrix * a_normal);
    gl_Position = u_PMatrix * u_MVMatrix * vec4(a_position, 1.0);
}
    </script>

    <script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;

varying vec3 N;

vec3 light_dir = vec3(1.0, 0.0, 0.0);
vec4 light_diffuse = vec4(0.8, 0.8, 0.8, 1.0);

void main(){
    //法線ベクトルとライトの方向の内積をdiffuseにかけたものを色とする
    gl_FragColor = vec4(light_diffuse.rgb * dot(N, light_dir), 1.0);
}
	</script>
  </head>
  <body>
    <canvas id="canvas" width="450" height="450"></canvas>
  

</body></html>

この中で使っているObject3D

var Object3D = function(gl){
    var vertexBuffer = null;
    var indexBuffer = null;
    var normalBUffer = null;
    
    var positionHandle = null;
    var normalHandle = null;
    
    var length = 0;

    this.initBuffer = function(vertices, indices, normals){
       initVertexBuffer(vertices);
       initIndexBuffer(indices);
       initNormalBuffer(normals);
       
       length = indices.length;
    }
    
    this.setHandle = function(pHandle, nHandle){
        positionHandle = pHandle;
        normalHandle = nHandle;
    }
    
    this.draw = function(){
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        gl.enableVertexAttribArray(positionHandle);
        gl.vertexAttribPointer(positionHandle, 3, gl.FLOAT, false, 0, 0);
        
        gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
        gl.enableVertexAttribArray(normalHandle);
        gl.vertexAttribPointer(normalHandle, 3, gl.FLOAT, false, 0, 0);
        
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
        gl.drawElements(gl.TRIANGLES, length, gl.UNSIGNED_SHORT, 0);
    }
    
    function initVertexBuffer(vertices){
        vertexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    }
    
    function initIndexBuffer(indices){
        indexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
    }
    
    function initNormalBuffer(normals){
        normalBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
    }
}

glMatrixはこちらから

gun3.jsは
gun3.js 直