热门搜索 :
考研考公
您的当前位置:首页正文

WebGL初学:构建一个多彩三角形与矩形

来源:东饰资讯网

最近老学了一门新的课程:WebGL。实验一就是利用WebGL绘制一个顶点颜色不同的三角形和矩形,就像下面这样:


矩形.png
三角形.png

直接上代码吧:
HTML页面:使用canvas元素生成画布。

<canvas id="webgl-1" width="640" height="480">
        Your browser doesn't appear to support the HTML5 <code>&lt;canvas&gt;</code> element.
</canvas>
<br>
<canvas id="webgl-2" width="640" height="480">
        Your browser doesn't appear to support the HTML5 <code>&lt;canvas&gt;</code> element.
</canvas>

这里我是直接用了两个canvas元素以提供两个不同形状的绘制。
然后是javascript代码。
利用WebGL需要使用着色器,这里不多介绍。
1.从HTML页面获取canvas元素的上下文,这里主要要获取到gl对象:

function initWebGL(canvas) {
    var gl;
    try {
        gl = canvas.getContext("webgl");
        gl.viewport(0, 0, canvas.width, canvas.height);
    } catch (e) {
        var msg = "无法从canvas中获取webgl!" + e.toString();
        alert(msg);
        throw Error(msg);
    }

    return gl;
}

2.着色器源码:

// =======================================
// 顶点着色器和片元着色器
// =======================================
var vsSource = `
attribute vec3 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;

void main() {
  gl_Position = vec4(a_Position, 1.0);
  v_Color = a_Color;
}
`;

var fsSource = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;

void main() {
  gl_FragColor = v_Color;
}
`;

3.需要对着色器进行编译及使用:

function loadShader(gl, type, source) {
    // 1.创建着色器对象
    var shader;
    if(type === "vertex") {
        shader = gl.createShader(gl.VERTEX_SHADER);
    } else if(type === "fragment") {
        shader = gl.createShader(gl.FRAGMENT_SHADER);
    }

    // 2.向着色器对象中填充着色器程序的源代码
    gl.shaderSource(shader, source);

    // 3.编译着色器
    
    var compiled = gl.getShaderParameter(shader, 
    if (!compiled) {
        var error = gl.getShaderInfoLog(shader);
        console.log('Failed to compile shader: ' + error);
        gl.deleteShader(shader);
        return -1;
    }

    // 4.返回着色器对象
    return shader;
}

function initShader(gl, vertSource, fragSource) {
    // 加载顶点着色器和片元着色器
    var vertShader = loadShader(gl, "vertex", vertSource);
    var fragShader = loadShader(gl, "fragment", fragSource);
    if(!vertShader || !fragShader) {
        return null;
    }
    // 1.创建着色器程序
    var shaderProgram = gl.createProgram();
    

    // 2.为程序对象分配着色器
    gl.attachShader(shaderProgram, vertShader);
    gl.attachShader(shaderProgram, fragShader);

    // 3.连接程序对象
    gl.linkProgram(shaderProgram);
    // 创建失败, alert
    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
      alert('无法初始化着色器程序: ' + gl.getProgramInfoLog(shaderProgram));
      console.log(gl.getProgramInfoLog(shaderProgram));
      return null;
    }

    // 4.使用程序对象
    gl.useProgram(shaderProgram);
    gl.program = shaderProgram;

    return true;
}

4.创建三角形对象:

function createTriangle(gl) {
    var verts = new Float32Array([
        0.0, 0.5,
        -0.5, -0.5,
        0.5, -0.5,
    ]);
    
    var colors = new Float32Array([
      1.0,  0.0,  0.0,
      0.0,  1.0,  0.0,
      0.0,  0.0,  1.0,
    ]);

    var vSIZE = verts.BYTES_PER_ELEMENT;
    var vertexBuffer = gl.createBuffer();
    var cSIZE = colors.BYTES_PER_ELEMENT;
    var colorBuffer = gl.createBuffer();

    var triangle = {
        vertsArray: verts,
        colorsArray: colors,
        vertBuffer: vertexBuffer,
        colorBuffer: colorBuffer,
        vSIZE: vSIZE,
        cSIZE: cSIZE,
        nVert: 3,
        primType: gl.TRIANGLES
    };

    return triangle;
}

5.类似地,创建矩形对象:

function createSquare(gl) {
    var verts = new Float32Array([
        0.5, 0.5,
        0.5, -0.5,
        -0.5, 0.5,
        -0.5, -0.5
    ]);
    
    var colors = new Float32Array([
      1.0,  0.0,  0.0,
      0.0,  1.0,  0.0,
      0.0,  0.0,  1.0,
      1.0,  1.0,  0.0
    ]);

    var vSIZE = verts.BYTES_PER_ELEMENT;
    var vertexBuffer = gl.createBuffer();

    var cSIZE = colors.BYTES_PER_ELEMENT;
    var colorBuffer = gl.createBuffer();

    var square = {
        vertsArray: verts,
        colorsArray: colors,
        vertBuffer: vertexBuffer,
        colorBuffer: colorBuffer,
        vSIZE: vSIZE,
        cSIZE: cSIZE,
        nVert: 4,
        primType: gl.TRIANGLE_STRIP
    };

    return square;
}

6.初始化缓存:

function initBuffer(gl, obj) {
    gl.bindBuffer(gl.ARRAY_BUFFER, obj.vertBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, obj.vertsArray, gl.STATIC_DRAW);

    var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, obj.vSIZE * 2 , 0);
    gl.enableVertexAttribArray(a_Position);

    gl.bindBuffer(gl.ARRAY_BUFFER, obj.colorBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, obj.colorsArray, gl.STATIC_DRAW);

    var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
    gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, obj.cSIZE * 3 , 0);
    gl.enableVertexAttribArray(a_Color);
}

7.主程序入口:

window.onload = function main() {
    var canvas1 = document.getElementById('webgl-1');
    var gl1 = initWebGL(canvas1);
    initShader(gl1, vsSource, fsSource);

    var obj1 = createSquare(gl1);
    initBuffer(gl1, obj1);
    drawScene(canvas1, gl1, obj1);
    
    var canvas2 = document.getElementById('webgl-2');
    var gl2 = initWebGL(canvas2);
    initShader(gl2, vsSource, fsSource);

    var obj2 = createTriangle(gl2);
    initBuffer(gl2, obj2);
    drawScene(canvas2, gl2, obj2);
};

8.完成!

Top