WebGLで最小限のコードでテクスチャ

WebGLで三角形にテクスチャを貼るための大体最小限のコードです。残念ながらファイル1つというわけにはなってません。

- 画像ファイルがいる
- 画像ファイルをローカルで利用しようとするとクロスドメインなんとかに引っかかるので、webサーバを立てる必要がある

webサーバに関しては、http://qiita.com/sudahiroshi/items/e74d61d939f18779970d このあたりを参考にするとらくできるのではないでしょうか。

```html:texture.html
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>WebGL triangle</title>

    <script id="shader-vs" type="x-shader/x-vertex">
        attribute vec3 aVertexPosition;
        attribute vec2 aTexCoord;
        
        varying vec2 vTexCoord;
        
        void main(void) {
            gl_Position = vec4(aVertexPosition, 1.0);
            vTexCoord = aTexCoord;
        }
    </script>

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

        uniform sampler2D texture0;
        
        varying vec2 vTexCoord;
        
        void main(void) {
            gl_FragColor = texture2D(texture0, vTexCoord);
        }
    </script>

    <script type="text/javascript">
        var gl;
        var shaderProgram;
        var triangleVertexPositionBuffer;

        function initGL(canvas) {
            try {
                gl = canvas.getContext("experimental-webgl");
                gl.viewport(0, 0, canvas.width, canvas.height);
            } catch (e) {
                console.log(e);
            }
            if (!gl) {
                alert("Could not initialize WebGL, sorry :-(");
            }
        }

        function getShader(id) {
            var shaderScript = document.getElementById(id);
            if (!shaderScript) {
                return null;
            }

            var str = "";
            var k = shaderScript.firstChild;
            while (k) {
                if (k.nodeType == 3) {
                    str += k.textContent;
                }
                k = k.nextSibling;
            }

            var shader;
            if (shaderScript.type == "x-shader/x-fragment") {
                shader = gl.createShader(gl.FRAGMENT_SHADER);
            } else if (shaderScript.type == "x-shader/x-vertex") {
                shader = gl.createShader(gl.VERTEX_SHADER);
            } else {
                return null;
            }

            gl.shaderSource(shader, str);
            gl.compileShader(shader);

            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
                alert(gl.getShaderInfoLog(shader));
                return null;
            }

            return shader;
        }

        function initShaders() {
            var fragmentShader = getShader("shader-fs");
            var vertexShader = getShader("shader-vs");

            shaderProgram = gl.createProgram();
            gl.attachShader(shaderProgram, vertexShader);
            gl.attachShader(shaderProgram, fragmentShader);
            gl.linkProgram(shaderProgram);

            if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
                alert("Could not initialise shaders");
            }

            gl.useProgram(shaderProgram);

            shaderProgram.vertexPositionAttribute =
                gl.getAttribLocation(shaderProgram, "aVertexPosition");

            shaderProgram.texCoordAttribute =
                gl.getAttribLocation(shaderProgram, "aTexCoord");

            shaderProgram.textureLocation =
                gl.getUniformLocation(shaderProgram, "texture0");
        }

        function initBuffers() {
            triangleVertexPositionBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
            var vertices = [
                 0.0,  1.0,  0.0,
                -1.0, -1.0,  0.0,
                 1.0, -1.0,  0.0
            ];
            gl.bufferData(
                gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
            triangleVertexPositionBuffer.itemSize = 3;
            triangleVertexPositionBuffer.numItems = 3;

            var texcoords = [
                0.0, 1.0,
                0.0, 0.0,
                1.0, 0.0,
            ];
            texCoordBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
            gl.bufferData(
                gl.ARRAY_BUFFER, new Float32Array(texcoords), gl.STATIC_DRAW);
            texCoordBuffer.itemSize = 2;
            texCoordBuffer.numItems = 3;
        }

        var texture;
        function initTexture() {
            texture = gl.createTexture();
            var image = document.getElementById("qiita");
            gl.bindTexture(gl.TEXTURE_2D, texture);
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
            gl.texImage2D(
                gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
            gl.bindTexture(gl.TEXTURE_2D, null);
        }

        function drawScene() {
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

            gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
            gl.vertexAttribPointer(
                shaderProgram.vertexPositionAttribute,
                triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
            gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

            gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
            gl.vertexAttribPointer(
                shaderProgram.texCoordAttribute,
                texCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
            gl.enableVertexAttribArray(shaderProgram.texCoordAttribute);

            gl.bindTexture(gl.TEXTURE_2D, texture);
            gl.uniform1i(shaderProgram.textureLocation, 0);            

            gl.drawArrays(
                gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);
        }

        function webGLStart() {
            var canvas = document.getElementById("gl-canvas");
            initGL(canvas);
            initShaders();
            initBuffers();
            initTexture();
        
            gl.clearColor(0.0, 0.0, 0.0, 1.0);
            gl.enable(gl.DEPTH_TEST);

            drawScene();
        }
    </script>


</head>

  <body>
    <canvas id="gl-canvas" width="480" height="320"></canvas>
  </body>

  <img id="qiita" src="./qiita.png" onload="webGLStart();">
</html>
```