티스토리 뷰

   WebGL을 이용하여, Text Rendering을 하는 것은 JavaScript의 지식을 비교적 많이 필요로 한다. 그 외에는 WebGL의 사각형에, JavaScript로 렌더링된 Text 이미지를 텍스쳐링하는 것만 수행하면 된다. Windows platform에서 OpenGL의 wgl을 이용하여 text를 렌더링해본 경험이 있다면, 혹은 glut를 이용하여 text를 렌더링해본 경험이 있다면, WebGL에서의 방법은 비교적 복잡한 코드 구조를 만들어 내는 것에 거부감을 느낄지도 모르겠다. 하지만, 이 방법은 OpenGL에서 동적 text를 렌더링 하는 유일한 방법으로(효율성을 제외) 생각되므로 소개하도록 하겠다. 기본 원리는 OpenGL/wgl의 wglUseFontBitmaps(...);를 이용한 방법과 다를 바 없다.(차이점은 앞서 소개한 바와 같이 WebGL이 OpenGL ES를 기반으로 하므로 반드시 Shader를 사용해야 한다는 점 등이 있을 수 있음)

   텍스트 렌더링의 전체적 수행 과정은 아래와 같다.
[1] JavaScript를 이용하여 Text를 렌더링 한다.
[2] WebGL의 사각형에 [1]의 결과를 텍스쳐링하여 렌더링 한다.

   상기한 두 단계의 세부 수행 과정은 아래와 같다.
[1] JavaScript를 이용하여 Text를 렌더링 한다.
    (1) canvas객체를 생성한다. ex) var aaa= document.createElement("canvas");
    (2) (1)의 결과로 부터 2d 컨텍스트를 얻어온다. ex) var bbb= aaa.getContext("2d");
    (3) (2)의 결과에 텍스트를 렌더링한다. ex) bbb.fillText("텍스트", 100, 100);
    (4) 마지막으로 (1)을 이용하여 WebGL에 사용할 텍스쳐릉 생성한다.
[2] WebGL의 사각형에 [1]의 결과를 텍스쳐링하여 렌더링 한다.
    //따로 설명할 필요는 없을 듯 하다. 이전 글 009. WebGL - Prac08 - Texture를 참조한다.

[1]-(1)에서 canvas 객체를 생성한다고 했을 때, var aaa= document.createElement("canvas"); 와 같이 써도 되지만,
body 본문 내에 <canvas id="text" style="border: none" width="128" height="128"></canvas>와 같이 HTML을 작성한 후, var aaa= document.getElementById("text");와 같이 canvas엘리먼트를 얻어오는 JavaScript를 사용해도 된다. JavaScript에 의해 렌더링된 텍스트를 직접확인하기 위해 우선 두번째 방법을 사용해 보도록 하겠다.

길게 설명하는 것 보다 아래의 소스코드 몇 줄이 더 잘 전달 될 것이다.
[code WebGL]
function createTexture(){
    var txtImg=    document.getElementById("text");
    var ctx=       txtImg.getContext("2d");
    ctx.fillStyle= "black";
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    ctx.save();
           
    ctx.font=  "bold 20px Arial";
    var str=   "www.jrr.kr";

    ctx.fillStyle=   "rgb(255, 150, 00)";
    ctx.fillText(str, (ctx.canvas.width-ctx.measureText(str).width)/2, 72);
    ctx.restore();

    g_Texture=    gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, g_Texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, txtImg, true);
    gl.generateMipmap(gl.TEXTURE_2D);
}
[/code]
당연히 위의 코드는 <canvas id="text" style="border: none" width="128" height="128"></canvas>라는 HTML코드가 본문에 존재했을 때 제대로 동작할 것이다.
   이것으로 [1] JavaScript를 이용하여 Text를 렌더링은 끝이다.(ㅡㅡ;) 거듭말 하지만 JavaScript의 각 메소드와 프로퍼티는 다른 사이트(https://developer.mozilla.org/en/JavaScript)를 참고해야 할 것이다. WebGL에 생성된 WebGL 텍스쳐(변수명, g_Texture)를 사각형에 붙이기 전에 JavaScript로 렌더링된 Text를 확인해 보면 결과는 아래와 같다.


전체 코드는 아래와 같다.
[code WebGL]
<html>

<head>
    <title>WebGL - Prac09 - Text Rendering</title>
    <script type="text/javascript">
        function start(){
            createTexture();
        }

        function createTexture(){
            var txtImg=    document.getElementById("text");
            var ctx=    txtImg.getContext("2d");
            ctx.fillStyle=    "black";
            ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
            ctx.save();
           
            ctx.font=    "bold 20px Arial";
            var str=    "www.jrr.kr";

            ctx.fillStyle = "rgb(255, 150, 00)";
            ctx.fillText(str, (ctx.canvas.width-ctx.measureText(str).width)/2, 72);
            ctx.restore();

            //g_Texture=    gl.createTexture();
            //gl.bindTexture(gl.TEXTURE_2D, g_Texture);
            //gl.texImage2D(gl.TEXTURE_2D, 0, txtImg, true);
            //gl.generateMipmap(gl.TEXTURE_2D);
        }
    </script>

</head>

<body onload="start()">
    <canvas id="text" style="border: none" width="128" height="128"></canvas>
</body>

</html>
[/code]
WebGL부분은 아직 사용하지 않으므로 주석처리 하였다. 위 코드와 결과물은 WebGL을 사용하지 않고, 오직 JavaScript만을 이용한 것임을 볼 수 있다.(즉, WebGL의 텍스쳐로 사용할 이미지를 생성하는 것은 JavaScript를 이용한 것이다.)

   이제 위의 결과를 WebGL의 사각형에 텍스쳐링 하여 최종 결과를 생성해 보자. 이전 까지의 예제에서는 삼각형을 렌더링 하였는데, 이번 예제에서는 텍스쳐 전체를 렌더링 해야 하므로 사각형을 렌더링해 보도록 하겠다.
[code WebGL]
var verAry=[
    0.5, 0.0, 0.0,
    0.5, 0.5, 0.0,
    0.0, 0.0, 0.0,
    0.0, 0.5, 0.0
];//Vertex Position 버퍼

var texAry= [
    1.0, 0.0,
    1.0, 1.0,
    0.0, 0.0,
    0.0, 1.0
];//Vertex TextureCoordinate 버퍼
[/code]
위와 같이 사각형을 위한 Vertex Position/Vertex TextureCoordinate 를 각각 생성한 후, WebGL에 바인딩을 한다. 그 후,
[code WebGL]
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
[/code]
Triangle Strip를 이용하여 사각형을 렌더링 한다.

최종 코드는 아래와 같다.
[code WebGL]
<html>

<head>
    <title>WebGL - Prac08 - Text Rendering</title>
    <script src="glMath.js" type="text/javascript"></script>
    <script type="text/javascript">
        var gl;
        var g_hVertPos;
        var g_hVertTex;
        var g_hWorld;

        var g_transPosX=0;

        var g_mtxView;

        var g_Texture=    null;//
        var g_hSampler1;

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

            if( !initShader() ){
                return;
            }

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

            var texAry= [
                1.0, 0.0,
                1.0, 1.0,
                0.0, 0.0,
                0.0, 1.0
            ];//

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


            var glBufTex=    gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, glBufTex);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texAry), gl.STATIC_DRAW);

            gl.clearColor(0.4, 0.5, 0.6, 1.0);

            gl.bindBuffer(gl.ARRAY_BUFFER, glBufVert);
            gl.vertexAttribPointer(g_hVertPos, 3, gl.FLOAT, false, 0, 0);

            gl.bindBuffer(gl.ARRAY_BUFFER, glBufTex);
            gl.vertexAttribPointer(g_hVertTex, 2, gl.FLOAT, false, 0, 0);

            g_mtxView=    new Matrix();

            createTexture();

            //0.05초 마다 drawScene 호출
            setInterval(drawScene, 30);
        }

        function drawScene(){
       

            gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
           
            //x좌표 값을 변경 시킨 후 GLSL에 넘긴다.
            g_transPosX+=    0.01;
            if( g_transPosX>0.5 )    g_transPosX=    0;

            g_mtxView.translate(g_transPosX, 0, 0);
            gl.uniformMatrix4fv(g_hWorld, false, g_mtxView.flattern());
           
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
        }

        function createTexture(){
            var txtImg=    document.getElementById("text");
            var ctx=    txtImg.getContext("2d");
            ctx.fillStyle=    "black";
            ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
            ctx.save();
           
            ctx.font=    "bold 20px Arial";
            var str=    "www.jrr.kr";

            ctx.fillStyle = "rgb(255, 150, 00)";
            ctx.fillText(str, (ctx.canvas.width-ctx.measureText(str).width)/2, 72);
            ctx.restore();

            g_Texture=    gl.createTexture();
            gl.bindTexture(gl.TEXTURE_2D, g_Texture);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, txtImg);
        }

        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(FragmentShader): " + 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);

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

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

            g_hWorld=    gl.getUniformLocation(shaderProgram, "gWorld");
            if( g_hWorld==-1 ){
                alert("Unable to find 'gView' uniform location.");
                return false;
            }

            g_hSampler1=    gl.getUniformLocation(shaderProgram, "gSampler1");
            if( g_hSampler1==-1 ){
                alert("Unable to find 'gSampler1' uniform location.");
                return false;
            }

            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 vec2 aTexCoordinate;

        uniform mat4 gWorld;

        varying vec2 vTexCoordinate;

        void main(){
            gl_Position=    gWorld * vec4(aPos, 1.0);
            vTexCoordinate=    aTexCoordinate;
        }
    </script>

    <script id="FragmentShader" type="x-shader/x-vertex">
        precision mediump vec2;
        varying vec2 vTexCoordinate;

        uniform sampler2D gSampler1;

        void main(){
            gl_FragColor= texture2D(gSampler1, vTexCoordinate);
        }
    </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 <code>&lt;canvas&gt;</code> element.
    </canvas>
    <canvas id="text" style="border: none" width="128" height="128"></canvas>
</body>

</html>
[/code]
5Line와 같이 glMath.js가 사용되었음에 주의한다.

위 코드의 결과는 아래와 같다.

'Computer > WebGL' 카테고리의 다른 글

012. WebGL - GWTGL - GWT 기본  (0) 2011.05.25
011. WebGL - GwtGL - About GwtGL  (0) 2011.05.11
010. WebGL - Prac09 - Text Rendering  (0) 2010.04.19
009. WebGL - Prac08 - Texture  (0) 2010.04.10
008. WebGL - Prac07 - JavaScript 파일  (0) 2010.04.07
007. WebGL - Prac06 - Animation  (0) 2010.04.07
댓글
Total
164,033
Today
27
Yesterday
30