본문 바로가기
Computer/WebGL

006. WebGL - Prac05 - DrawTriangleWithColor

by DogBull 2010. 4. 6.
이전의 예제 004. WebGL - Prac03 - DrawPoints, DrawLines, DrawTriangles. 에서 단색의 삼각형을 렌더링하여 보았다. 이는 아래와 같이 Fragment Shader에서 붉은색으로만 색상값을 지정하고 있기 때문이다.

<script id="FragmentShader" type="x-shader/x-vertex">
    void main(){
        gl_FragColor= vec4(1.0, 0.0, 0.0, 1.0);
    }
</script>


이제부터 단색이 아닌, 사용자가 직접 각 Vertex 마다 다른 색상을 지정해 보도록 하겠다.

우선 위와같이 작성되어 있던 Fragment Shader 코드를 아래와 같이 수정한다.

<script id="FragmentShader" type="x-shader/x-vertex">

    precision mediump vec4;
   
    varying vec4 vColor;
    void main(){
        gl_FragColor= vColor;
    }
</script>

위의 코드에 사용된, 변수명 vColor의 값은 Vertex에서 지정할것이다.

두번째로, Vertex Shader 코드를 아래와 같이 수정한다.

<script id="VertexShader" type="x-shader/x-vertex">
    attribute vec3 aPos;
    attribute vec4 aColor;

    varying vec4 vColor;

    void main(){
        gl_Position= vec4(aPos, 1.0);
        vColor= aColor;
    }
</script>

이전에 작성했던 코드에 4~5라인 정도가 추가되었다. 위의 Vertex Shader 코드를 보면, Fragment Shader코드에서 사용하게될 vColor값을 설정하는 것을 볼 수 있다. Vertex/Fragment Shader 코드 모두 varying vec4 vColor;의 구문을 지니고 있음 기억해 둔다. vColor의 값을 aColor의 값을 그대로 복사하고 있는데, aColor이 선언 방식이 버텍스의 위치값으로 사용되었던 aPos와 동일함을 볼 수 있다. 이전에 aPos에 대해 수행했던 그대로, aColor역시 변수에 대한 핸들을 얻어와야 한다.

vertexColorAttribute=    gl.getAttribLocation(shaderProgram, "aColor");           
if( vertexColorAttribute==-1 ){
    alert("Unable to find Vertex Color Attribute Location.");
    return false;
}
gl.enableVertexAttribArray(vertexColorAttribute);

변수명 vertexColorAttribute는 자신의 프로그램 구조에 맞는 적당한 곳에 두면된다.

여기까지 코딩이 완료되었다면, Shader에게 Color 정보를 넘기기 위한 준비작업이 끝난것이다.
이제, Color 정보를 작성해 보도록 하자.


var colorAry= [
   1.0, 0.0, 0.0, 1.0,
   0.0, 1.0, 0.0, 1.0,
    0.0, 0.0, 1.0, 1.0
];

var triangleColorBuffer=    gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colorAry), gl.STATIC_DRAW);

앞서 버턱스 좌표값을 위해 수행하였던 구문와 동일한 함수들을 사용한 것을 볼 수 있다. 1.버퍼를 만들고, 2.버퍼를바인딩하고, 3. 바인딩된 버퍼에 값을 쓰는 과정이 나타나 있다. 렌더링될 버텍스가 3개이므로 색상의 개수도 3개인 것에 유의한다. 만약 생상의 개수가 더 많으면 아무런 의미가 없고, 적다면 흰색으로 렌더링될 것이다.

여기까지의 코딩은, Shader에게 넘겨줄 Color 정보 채우기를 완료한 상태이다.
이제, Shader에게 Color 정보를 넘겨 보도록 하겠다.


gl.bindBuffer(gl.ARRAY_BUFFER, triangleColorBuffer);
gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);

앞서 생성하였던 색상 버퍼(triangleColorBuffer)를 vertexColorAttribute라는 핸들을 통해 Shader로 전담함을 볼 수 있다. Color 값은 RGBA의 4개의 채널을 갖고, 데이터 타입은 float형이다.

최종 결과는 아래와 같다.


전체 코드는 아래와 같다.

<html>

<head>
    <title>WebGL - Prac05 - DrawTriangleWithColor</title>
    <script type="text/javascript">
        var gl;
        var vertexPositionAttribute;
        var vertexColorAttribute;

        function start(){
            if( !initWebGL() ){
                return;
            }

            if( !initShader() ){
                return;
            }

            var verAry=    [
                0.0, 0.0, 0.0,
                0.5, 0.0, 0.0,
                0.0, 1.0, 0.0
            ];

            var colorAry= [
                1.0, 0.0, 0.0, 1.0,
                0.0, 1.0, 0.0, 1.0,
                0.0, 0.0, 1.0, 1.0
            ];

            var triangleVertBuffer=    gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verAry), gl.STATIC_DRAW);

            //색상 버퍼 생성
            var triangleColorBuffer=    gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, triangleColorBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colorAry), gl.STATIC_DRAW);

            gl.clearColor(0.4, 0.5, 0.6, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);

            gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertBuffer);
            gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);

            //색상 버퍼를 Shder에 넘김
            gl.bindBuffer(gl.ARRAY_BUFFER, triangleColorBuffer);
            gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);

            gl.drawArrays(gl.TRIANGLES, 0, 3);

            alert("finish!");
        }

        function initWebGL(){
            var canvas=    document.getElementById("WebGL-Canvas");
            if( !canvas ){
                alert("Can't find WebGL-Canvas.");
                return false;
            }

            try{
                gl=    canvas.getContext("experimental-webgl");
            }catch(e){
            }

            if( !gl ){
                alert("Unable to initialize WebGL. Your browser may not support it.");
                return false;
            }

            return true;
        }

        function initShader(){
            var vertexShaderDesc=    getShader("VertexShader");
            var vertexShader=        gl.createShader(gl.VERTEX_SHADER);
            gl.shaderSource(vertexShader, vertexShaderDesc);
            gl.compileShader(vertexShader);
            if( !gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS) ){
                alert("Error(VertexShader): " + gl.getShaderInfoLog(vertexShader));
                return false;
            }

            var fragmentShaderDesc=    getShader("FragmentShader");
            var fragmentShader=        gl.createShader(gl.FRAGMENT_SHADER);
            gl.shaderSource(fragmentShader, fragmentShaderDesc);
            gl.compileShader(fragmentShader);
            if( !gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS) ){
                alert("Error(PixelShader): " + gl.getShaderInfoLog(fragmentShader));
                return false;
            }

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

            if( !gl.getProgramParameter(shaderProgram, gl.LINK_STATUS) ){
                alert("Unagle to initialize the shader program.");
                return false;
            }

            gl.useProgram(shaderProgram);

            vertexPositionAttribute=    gl.getAttribLocation(shaderProgram, "aPos");
            if( vertexPositionAttribute==-1 ){
                alert("Unable to find Vertex Attribute Location.");
                return false;
            }
            gl.enableVertexAttribArray(vertexPositionAttribute);

            //색상 값을 전달할, GLSL에서의 변수명 "aColor"에 대한 핸들을 얻어온다.
            vertexColorAttribute=    gl.getAttribLocation(shaderProgram, "aColor");           
            if( vertexColorAttribute==-1 ){
                alert("Unable to find Vertex Color Attribute Location.");
                return false;
            }
            gl.enableVertexAttribArray(vertexColorAttribute);

            return true;
        }

        function getShader(id){
            var shaderScript=    document.getElementById(id);
            if( !shaderScript ){
                alert("Unable to get shader script. id='" + id + "'");
                return null;
            }

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

            return shaderDesc;
        }

    </script>

    <script id="VertexShader" type="x-shader/x-vertex">
        attribute vec3 aPos;
        attribute vec4 aColor;

        varying vec4 vColor;

        void main(){
            gl_Position= vec4(aPos, 1.0);
            vColor= aColor;
        }
    </script>

    <script id="FragmentShader" type="x-shader/x-vertex">
        precision mediump vec4;
        varying vec4 vColor;
        void main(){
            gl_FragColor= vColor;
        }
    </script>
</head>

<body onload="start()">
    <canvas id="WebGL-Canvas" style="border: 1px solid green" width="400" height="300">
        Your browser doesn't appear to support the HTML5 <canvas> element.
    </canvas>
</body>
</html>