OpenHarmony开发之WebGL开发指导与介绍

WebGL的全称为Web Graphic Library(网页图形库),主要用于交互式渲染2D图形和3D图形。目前OpenHarmony中使用的WebGL是基于OpenGL裁剪的OpenGL ES,可以在HTML5的canvas元素对象中使用,无需使用插件,支持跨平台。WebGL程序是由JavaScript代码组成的,其中使用的API可以利用用户设备提供的GPU硬件完成图形渲染和加速。

基本概念

着色器

可以理解为运行在显卡中的指令和数据。在WebGL中,着色器是用OpenGL ES着色语言(GLSL)编写的。

完整的着色器包括顶点着色器和片元着色器。顶点着色器和片元着色器的交互则涉及到图片光栅化。

  • 顶点着色器:最基本的任务是接收三维空间中点的坐标,将其处理为二维空间中的坐标并输出。
  • 片元着色器:最基本的任务是对需要处理的屏幕上的每个像素输出一个颜色值。
  • 图片光栅化:将顶点着色器输出的二维空间中的点坐标,转化为需要处理的像素并传递给片元着色器的过程。

缓冲区

驻存于内存中的JavaScript对象,存储着即将推送到着色器中的attribute对象。

着色器程序

将缓冲区中的数据推送到着色器中还需涉及“着色器程序”,一个负责关联着色器和缓冲区的JavaScript对象。一个WebGLProgram 对象由两个编译过后的 WebGLShader 组成,即顶点着色器和片段着色器(均由 GLSL 语言所写)。

运作机制

图1 WebGL运作机制

  • 应用前端HTML5绘制界面组件。
  • Native API完成前端JavaScript与C++代码交互。
  • JavaScript engine为图形框架,为WebGL模块提供绘制对象Surface。
  • WebGL模块对外暴露OpenGL ES的GPU绘制接口。
  • 中间接口层EGL(Embedded Graphics Library)完成不同平台的适配。

场景介绍

WebGL主要帮助开发者在前端开发中完成图形图像的相关处理,比如绘制彩色图形等。

说明:

目前该功能仅支持使用兼容JS的类Web开发范式开发。

接口说明

表1 WebGL主要接口列表

接口名 描述
canvas.getContext 获取canvas对象上下文。
webgl.createBuffer(): WebGLBuffer null 创建与初始化WebGL数据缓冲区。
webgl.bindBuffer(target: GLenum, buffer: WebGLBuffer null): void 将WebGL数据缓冲区与目标进行绑定。
webgl.bufferData(target: GLenum, srcData: ArrayBufferView, usage: GLenum, srcOffset: GLuint, length?: GLuint): void 创建并初始化WebGL的数据存储区。
webgl.getAttribLocation(program: WebGLProgram, name: string): GLint 从给定WebGL着色程序中获取着色器中attribute变量的地址。
webgl.vertexAttribPointer(index GLuint, size: GLint, type: GLenum, normalized: GLboolean, stride: GLsizei, offset: GLintptr): void 将缓冲区对象分配给变量。
webgl.enableVertexAttribArray(index: GLuint): void 连接变量与分配给它的缓冲区对象。
webgl.clearColor(red: GLclampf, green:GLclampf, blue: GLclampf, alpha: GLclampf): void 清空<canvas>指定的颜色。
webgl.clear(mask: GLbitfield): void 清空<canvas>。
webgl.drawArrays(mode: GLenum, first:;GLint, count: GLsizei): void 执行数据绘制。
webgl.flush(): void 刷新数据至GPU,清空缓冲区。
webgl.createProgram(): WebGLProgram null 创建着色器程序对象。

开发步骤

以下分别展示无着色器绘制2D图形和着色器绘制彩色三角形的两个场景示例及开发过程。

说明: 使用WebGL开发时,为保证界面图形显示效果,请使用真机运行。

无着色器绘制2D图形

此场景为未使用WebGL绘制的2D图形(CPU绘制非GPU绘制)。开发示例如下:

  1. 创建页面布局。index.hml示例如下:
    <div class="container">
        <canvas ref="canvas1" style="width : 400px; height : 200px; background-color : lightyellow;"></canvas>
        <button class="btn-button" onclick="BtnDraw2D">BtnDraw2D</button>
    </div>
  1. 设置页面样式。index.css示例如下:
    .container {
        flex-direction: column;
        justify-content: center;
        align-items: center;
    }
    .btn-button {
        margin: 1px;
        height: 40px;
        width: 220px;
        background-color: lightblue;
        font-size: 20px;
        text-color: blue;
    }
  1. 编辑JavaScript代码文件,增加2D绘制逻辑代码。index.js示例如下:
    // index.js
    export default {//NAPI交互代码
        data: {
            title: "DEMO BY TEAMOL",
            fit:"cover",
            fits: ["cover", "contain", "fill", "none", "scale-down"]
        },
        onInit() {
            this.title = this.$t('strings.world');
        },
        BtnDraw2D(){
            // 获取canvas元素
            const canvas = this.$refs.canvas1;
            // 获取2D上下文
            const ctx = canvas.getContext('2d');
    
            // 执行CPU绘制函数
            // Set line width
            ctx.lineWidth = 10;
            // Wall
            ctx.strokeRect(75, 140, 150, 110);
            // Door
            ctx.fillRect(130, 190, 40, 60);
            // Roof
            ctx.beginPath();
            ctx.moveTo(50, 140);
            ctx.lineTo(150, 60);
            ctx.lineTo(250, 140);
            ctx.closePath();
            ctx.stroke();
        }
    }
    

图1 点击按钮绘制2D图形的效果图

着色器绘制彩色三角形

此场景为使用WebGL绘制的彩色三角形图形(GPU绘制)。开发示例如下:

  1. 创建页面布局。index.hml示例如下:
    <div class="container">
    <canvas ref="canvas1" style="width : 400px; height : 200px; background-color : lightyellow;"></canvas>
    <button class="btn-button" onclick="BtnColorTriangle">BtnColorTriangle</button>
    </div>
  1. 设置页面样式。index.css示例如下:
    .container {
        flex-direction: column;
        justify-content: center;
        align-items: center;
    }
    .btn-button {
        margin: 1px;
        height: 40px;
        width: 220px;
        background-color: lightblue;
        font-size: 20px;
        text-color: blue;
    }    
  1. 编辑JavaScript代码文件,增加彩色三角形绘制逻辑代码。index.js示例如下:
    // index.js
    
    // WebGL相关预定义
    var gl = {
        DEPTH_BUFFER_BIT: 0x00000100,
        STENCIL_BUFFER_BIT: 0x00000400,
        COLOR_BUFFER_BIT: 0x00004000,
        POINTS: 0x0000,
        LINES: 0x0001,
        LINE_LOOP: 0x0002,
        LINE_STRIP: 0x0003,
        TRIANGLES: 0x0004,
        TRIANGLE_STRIP: 0x0005,
        TRIANGLE_FAN: 0x0006,
        ZERO: 0,
        ONE: 1,
        SRC_COLOR: 0x0300,
        ONE_MINUS_SRC_COLOR: 0x0301,
        SRC_ALPHA: 0x0302,
        ONE_MINUS_SRC_ALPHA: 0x0303,
        DST_ALPHA: 0x0304,
        ONE_MINUS_DST_ALPHA: 0x0305,
        DST_COLOR: 0x0306,
        ONE_MINUS_DST_COLOR: 0x0307,
        SRC_ALPHA_SATURATE: 0x0308,
        FUNC_ADD: 0x8006,
        BLEND_EQUATION: 0x8009,
        BLEND_EQUATION_RGB: 0x8009,
        BLEND_EQUATION_ALPHA: 0x883D,
        FUNC_SUBTRACT: 0x800A,
        FUNC_REVERSE_SUBTRACT: 0x800B,
        BLEND_DST_RGB: 0x80C8,
        BLEND_SRC_RGB: 0x80C9,
        BLEND_DST_ALPHA: 0x80CA,
        BLEND_SRC_ALPHA: 0x80CB,
        CONSTANT_COLOR: 0x8001,
        ONE_MINUS_CONSTANT_COLOR: 0x8002,
        CONSTANT_ALPHA: 0x8003,
        ONE_MINUS_CONSTANT_ALPHA: 0x8004,
        BLEND_COLOR: 0x8005,
        ARRAY_BUFFER: 0x8892,
        ELEMENT_ARRAY_BUFFER: 0x8893,
        ARRAY_BUFFER_BINDING: 0x8894,
        ELEMENT_ARRAY_BUFFER_BINDING: 0x8895,
        STREAM_DRAW: 0x88E0,
        STATIC_DRAW: 0x88E4,
        DYNAMIC_DRAW: 0x88E8,
        BUFFER_SIZE: 0x8764,
        BUFFER_USAGE: 0x8765,
        CURRENT_VERTEX_ATTRIB: 0x8626,
        FRONT: 0x0404,
        BACK: 0x0405,
        FRONT_AND_BACK: 0x0408,
        CULL_FACE: 0x0B44,
        BLEND: 0x0BE2,
        DITHER: 0x0BD0,
        STENCIL_TEST: 0x0B90,
        DEPTH_TEST: 0x0B71,
        SCISSOR_TEST: 0x0C11,
        POLYGON_OFFSET_FILL: 0x8037,
        SAMPLE_ALPHA_TO_COVERAGE: 0x809E,
        SAMPLE_COVERAGE: 0x80A0,
        NO_ERROR: 0,
        INVALID_ENUM: 0x0500,
        INVALID_VALUE: 0x0501,
        INVALID_OPERATION: 0x0502,
        OUT_OF_MEMORY: 0x0505,
        CW: 0x0900,
        CCW: 0x0901,
        LINE_WIDTH: 0x0B21,
        ALIASED_POINT_SIZE_RANGE: 0x846D,
        ALIASED_LINE_WIDTH_RANGE: 0x846E,
        CULL_FACE_MODE: 0x0B45,
        FRONT_FACE: 0x0B46,
        DEPTH_RANGE: 0x0B70,
        DEPTH_WRITEMASK: 0x0B72,
        DEPTH_CLEAR_VALUE: 0x0B73,
        DEPTH_FUNC: 0x0B74,
        STENCIL_CLEAR_VALUE: 0x0B91,
        STENCIL_FUNC: 0x0B92,
        STENCIL_FAIL: 0x0B94,
        STENCIL_PASS_DEPTH_FAIL: 0x0B95,
        STENCIL_PASS_DEPTH_PASS: 0x0B96,
        STENCIL_REF: 0x0B97,
        STENCIL_VALUE_MASK: 0x0B93,
        STENCIL_WRITEMASK: 0x0B98,
        STENCIL_BACK_FUNC: 0x8800,
        STENCIL_BACK_FAIL: 0x8801,
        STENCIL_BACK_PASS_DEPTH_FAIL: 0x8802,
        STENCIL_BACK_PASS_DEPTH_PASS: 0x8803,
        STENCIL_BACK_REF: 0x8CA3,
        STENCIL_BACK_VALUE_MASK: 0x8CA4,
        STENCIL_BACK_WRITEMASK: 0x8CA5,
        VIEWPORT: 0x0BA2,
        SCISSOR_BOX: 0x0C10,
        COLOR_CLEAR_VALUE: 0x0C22,
        COLOR_WRITEMASK: 0x0C23,
        UNPACK_ALIGNMENT: 0x0CF5,
        PACK_ALIGNMENT: 0x0D05,
        MAX_TEXTURE_SIZE: 0x0D33,
        MAX_VIEWPORT_DIMS: 0x0D3A,
        SUBPIXEL_BITS: 0x0D50,
        RED_BITS: 0x0D52,
        GREEN_BITS: 0x0D53,
        BLUE_BITS: 0x0D54,
        ALPHA_BITS: 0x0D55,
        DEPTH_BITS: 0x0D56,
        STENCIL_BITS: 0x0D57,
        POLYGON_OFFSET_UNITS: 0x2A00,
        POLYGON_OFFSET_FACTOR: 0x8038,
        TEXTURE_BINDING_2D: 0x8069,
        SAMPLE_BUFFERS: 0x80A8,
        SAMPLES: 0x80A9,
        RGBA8: 0x8058,
        SAMPLE_COVERAGE_VALUE: 0x80AA,
        SAMPLE_COVERAGE_INVERT: 0x80AB,
        COMPRESSED_TEXTURE_FORMATS: 0x86A3,
        DONT_CARE: 0x1100,
        FASTEST: 0x1101,
        NICEST: 0x1102,
        GENERATE_MIPMAP_HINT: 0x8192,
        BYTE: 0x1400,
        UNSIGNED_BYTE: 0x1401,
        SHORT: 0x1402,
        UNSIGNED_SHORT: 0x1403,
        INT: 0x1404,
        UNSIGNED_INT: 0x1405,
        FLOAT: 0x1406,
        DEPTH_COMPONENT: 0x1902,
        ALPHA: 0x1906,
        RGB: 0x1907,
        RGBA: 0x1908,
        LUMINANCE: 0x1909,
        LUMINANCE_ALPHA: 0x190A,
        UNSIGNED_SHORT_4_4_4_4: 0x8033,
        UNSIGNED_SHORT_5_5_5_1: 0x8034,
        UNSIGNED_SHORT_5_6_5: 0x8363,
        FRAGMENT_SHADER: 0x8B30,
        VERTEX_SHADER: 0x8B31,
        MAX_VERTEX_ATTRIBS: 0x8869,
        MAX_VERTEX_UNIFORM_VECTORS: 0x8DFB,
        MAX_VARYING_VECTORS: 0x8DFC,
        MAX_COMBINED_TEXTURE_IMAGE_UNITS: 0x8B4D,
        MAX_VERTEX_TEXTURE_IMAGE_UNITS: 0x8B4C,
        MAX_TEXTURE_IMAGE_UNITS: 0x8872,
        MAX_FRAGMENT_UNIFORM_VECTORS: 0x8DFD,
        SHADER_TYPE: 0x8B4F,
        DELETE_STATUS: 0x8B80,
        LINK_STATUS: 0x8B82,
        VALIDATE_STATUS: 0x8B83,
        ATTACHED_SHADERS: 0x8B85,
        ACTIVE_UNIFORMS: 0x8B86,
        ACTIVE_ATTRIBUTES: 0x8B89,
        SHADING_LANGUAGE_VERSION: 0x8B8C,
        CURRENT_PROGRAM: 0x8B8D,
        NEVER: 0x0200,
        LESS: 0x0201,
        EQUAL: 0x0202,
        LEQUAL: 0x0203,
        GREATER: 0x0204,
        NOTEQUAL: 0x0205,
        GEQUAL: 0x0206,
        ALWAYS: 0x0207,
        KEEP: 0x1E00,
        REPLACE: 0x1E01,
        INCR: 0x1E02,
        DECR: 0x1E03,
        INVERT: 0x150A,
        INCR_WRAP: 0x8507,
        DECR_WRAP: 0x8508,
        VENDOR: 0x1F00,
        RENDERER: 0x1F01,
        VERSION: 0x1F02,
        NEAREST: 0x2600,
        LINEAR: 0x2601,
        NEAREST_MIPMAP_NEAREST: 0x2700,
        LINEAR_MIPMAP_NEAREST: 0x2701,
        NEAREST_MIPMAP_LINEAR: 0x2702,
        LINEAR_MIPMAP_LINEAR: 0x2703,
        TEXTURE_MAG_FILTER: 0x2800,
        TEXTURE_MIN_FILTER: 0x2801,
        TEXTURE_WRAP_S: 0x2802,
        TEXTURE_WRAP_T: 0x2803,
        TEXTURE_2D: 0x0DE1,
        TEXTURE: 0x1702,
        TEXTURE_CUBE_MAP: 0x8513,
        TEXTURE_BINDING_CUBE_MAP: 0x8514,
        TEXTURE_CUBE_MAP_POSITIVE_X: 0x8515,
        TEXTURE_CUBE_MAP_NEGATIVE_X: 0x8516,
        TEXTURE_CUBE_MAP_POSITIVE_Y: 0x8517,
        TEXTURE_CUBE_MAP_NEGATIVE_Y: 0x8518,
        TEXTURE_CUBE_MAP_POSITIVE_Z: 0x8519,
        TEXTURE_CUBE_MAP_NEGATIVE_Z: 0x851A,
        MAX_CUBE_MAP_TEXTURE_SIZE: 0x851C,
        TEXTURE0: 0x84C0,
        TEXTURE1: 0x84C1,
        TEXTURE2: 0x84C2,
        TEXTURE3: 0x84C3,
        TEXTURE4: 0x84C4,
        TEXTURE5: 0x84C5,
        TEXTURE6: 0x84C6,
        TEXTURE7: 0x84C7,
        TEXTURE8: 0x84C8,
        TEXTURE9: 0x84C9,
        TEXTURE10: 0x84CA,
        TEXTURE11: 0x84CB,
        TEXTURE12: 0x84CC,
        TEXTURE13: 0x84CD,
        TEXTURE14: 0x84CE,
        TEXTURE15: 0x84CF,
        TEXTURE16: 0x84D0,
        TEXTURE17: 0x84D1,
        TEXTURE18: 0x84D2,
        TEXTURE19: 0x84D3,
        TEXTURE20: 0x84D4,
        TEXTURE21: 0x84D5,
        TEXTURE22: 0x84D6,
        TEXTURE23: 0x84D7,
        TEXTURE24: 0x84D8,
        TEXTURE25: 0x84D9,
        TEXTURE26: 0x84DA,
        TEXTURE27: 0x84DB,
        TEXTURE28: 0x84DC,
        TEXTURE29: 0x84DD,
        TEXTURE30: 0x84DE,
        TEXTURE31: 0x84DF,
        ACTIVE_TEXTURE: 0x84E0,
        REPEAT: 0x2901,
        CLAMP_TO_EDGE: 0x812F,
        MIRRORED_REPEAT: 0x8370,
        FLOAT_VEC2: 0x8B50,
        FLOAT_VEC3: 0x8B51,
        FLOAT_VEC4: 0x8B52,
        INT_VEC2: 0x8B53,
        INT_VEC3: 0x8B54,
        INT_VEC4: 0x8B55,
        BOOL: 0x8B56,
        BOOL_VEC2: 0x8B57,
        BOOL_VEC3: 0x8B58,
        BOOL_VEC4: 0x8B59,
        FLOAT_MAT2: 0x8B5A,
        FLOAT_MAT3: 0x8B5B,
        FLOAT_MAT4: 0x8B5C,
        SAMPLER_2D: 0x8B5E,
        SAMPLER_CUBE: 0x8B60,
        VERTEX_ATTRIB_ARRAY_ENABLED: 0x8622,
        VERTEX_ATTRIB_ARRAY_SIZE: 0x8623,
        VERTEX_ATTRIB_ARRAY_STRIDE: 0x8624,
        VERTEX_ATTRIB_ARRAY_TYPE: 0x8625,
        VERTEX_ATTRIB_ARRAY_NORMALIZED: 0x886A,
        VERTEX_ATTRIB_ARRAY_POINTER: 0x8645,
        VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: 0x889F,
        IMPLEMENTATION_COLOR_READ_TYPE: 0x8B9A,
        IMPLEMENTATION_COLOR_READ_FORMAT: 0x8B9B,
        COMPILE_STATUS: 0x8B81,
        LOW_FLOAT: 0x8DF0,
        MEDIUM_FLOAT: 0x8DF1,
        HIGH_FLOAT: 0x8DF2,
        LOW_INT: 0x8DF3,
        MEDIUM_INT: 0x8DF4,
        HIGH_INT: 0x8DF5,
        FRAMEBUFFER: 0x8D40,
        RENDERBUFFER: 0x8D41,
        RGBA4: 0x8056,
        RGB5_A1: 0x8057,
        RGB565: 0x8D62,
        DEPTH_COMPONENT16: 0x81A5,
        STENCIL_INDEX8: 0x8D48,
        DEPTH_STENCIL: 0x84F9,
        RENDERBUFFER_WIDTH: 0x8D42,
        RENDERBUFFER_HEIGHT: 0x8D43,
        RENDERBUFFER_INTERNAL_FORMAT: 0x8D44,
        RENDERBUFFER_RED_SIZE: 0x8D50,
        RENDERBUFFER_GREEN_SIZE: 0x8D51,
        RENDERBUFFER_BLUE_SIZE: 0x8D52,
        RENDERBUFFER_ALPHA_SIZE: 0x8D53,
        RENDERBUFFER_DEPTH_SIZE: 0x8D54,
        RENDERBUFFER_STENCIL_SIZE: 0x8D55,
        FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: 0x8CD0,
        FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: 0x8CD1,
        FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: 0x8CD2,
        FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: 0x8CD3,
        COLOR_ATTACHMENT0: 0x8CE0,
        DEPTH_ATTACHMENT: 0x8D00,
        STENCIL_ATTACHMENT: 0x8D20,
        DEPTH_STENCIL_ATTACHMENT: 0x821A,
        NONE: 0,
        FRAMEBUFFER_COMPLETE: 0x8CD5,
        FRAMEBUFFER_INCOMPLETE_ATTACHMENT: 0x8CD6,
        FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: 0x8CD7,
        FRAMEBUFFER_INCOMPLETE_DIMENSIONS: 0x8CD9,
        FRAMEBUFFER_UNSUPPORTED: 0x8CDD,
        FRAMEBUFFER_BINDING: 0x8CA6,
        RENDERBUFFER_BINDING: 0x8CA7,
        MAX_RENDERBUFFER_SIZE: 0x84E8,
        INVALID_FRAMEBUFFER_OPERATION: 0x0506,
        UNPACK_FLIP_Y_WEBGL: 0x9240,
        UNPACK_PREMULTIPLY_ALPHA_WEBGL: 0x9241,
        CONTEXT_LOST_WEBGL: 0x9242,
        UNPACK_COLORSPACE_CONVERSION_WEBGL: 0x9243,
        BROWSER_DEFAULT_WEBGL: 0x9244,
        TEXTURE_MAX_LOD: 0x813B,
        TEXTURE_BASE_LEVEL: 0x813C,
        TEXTURE_IMMUTABLE_FORMAT: 0x912F,
        UNIFORM_BLOCK_BINDING: 0x8A3F,
        UNIFORM_BLOCK_DATA_SIZE: 0x8A40,
        UNIFORM_BLOCK_ACTIVE_UNIFORMS: 0x8A42,
        UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: 0x8A43,
        UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: 0x8A44,
        UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: 0x8A46,
        RED: 0x1903,
        PIXEL_UNPACK_BUFFER: 0x88EC,
        RGB8: 0x8051,
        R16F: 0x822D,
        COPY_WRITE_BUFFER: 0x8F37,
        TEXTURE_3D: 0x806F,
        COMPRESSED_R11_EAC: 0x9270,
        COPY_READ_BUFFER: 0x8F36,
        TRANSFORM_FEEDBACK_BUFFER: 0x8C8E,
        TRANSFORM_FEEDBACK_BUFFER_BINDING: 0x8C8F,
        TRANSFORM_FEEDBACK_BUFFER_SIZE: 0x8C85,
        TRANSFORM_FEEDBACK_BUFFER_START: 0x8C84,
        UNIFORM_BUFFER_BINDING: 0x8A28,
        UNIFORM_BUFFER_SIZE: 0x8A2A,
        UNIFORM_BUFFER_START: 0x8A29,
        DYNAMIC_READ: 0x88E9,
        READ_FRAMEBUFFER: 0x8CA8,
        COLOR_ATTACHMENT1: 0x8CE1,
        INTERLEAVED_ATTRIBS: 0x8C8C,
        UNIFORM_OFFSET: 0x8A3B,
        UNIFORM_TYPE: 0x8A37,
        UNIFORM_SIZE: 0x8A38,
        UNIFORM_BLOCK_INDEX: 0x8A3A,
        UNIFORM_ARRAY_STRIDE: 0x8A3C,
        UNIFORM_MATRIX_STRIDE: 0x8A3D,
        UNIFORM_IS_ROW_MAJOR: 0x8A3E,
        TEXTURE_MAX_ANISOTROPY_EXT: 0x84FE
    }
    
    // 顶点着色器程序
    var VSHADER_SOURCE =
        'attribute vec4 a_Position;\n' + // attribute variable
        'attribute vec4 a_Color;\n' +
        'varying vec4 v_Color;\n' +
        'void main() {\n' +
        '  gl_Position = a_Position;\n' + // Set the vertex coordinates of the point
        '  v_Color = a_Color;\n' +
        '}\n';
    
    // 片元着色器程序
    var FSHADER_SOURCE =
        'precision mediump float;\n' +
        'varying vec4 v_Color;\n' +
        'void main() {\n' +
        '  gl_FragColor = v_Color;\n' +
        '}\n';
    
    function initVertexBuffers(gl) {
        // 顶点坐标和颜色
        var verticesColors = new Float32Array([
            0.0, -0.5, 1.0, 0.0, 0.0,
            -0.5, -0.8, 0.0, 1.0, 0.0,
            0.5, -0.8, 0.0, 0.0, 1.0,
        ]);
    
        var n = 3; // 点的个数
        var FSIZE = verticesColors.BYTES_PER_ELEMENT; //数组中每个元素的字节数
    
        // 创建缓冲区对象
        var vertexBuffer = gl.createBuffer();
        if (!vertexBuffer) {
            console.log('Failed to create the buffer object');
            return -1;
        }
    
        // 将缓冲区对象绑定到目标
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        // 向缓冲区对象写入数据
        gl.bufferData(gl.ARRAY_BUFFER, verticesColors.buffer, gl.STATIC_DRAW);
    
        // 获取着色器中attribute变量a_Position的地址
        var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
        if (a_Position < 0) {
            console.log('Failed to get the storage location of a_Position');
            return -1;
        }
        // 将缓冲区对象分配给a_Position变量
        gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 5 * FSIZE, 0);
    
        // 连接a_Position变量与分配给它的缓冲区对象
        gl.enableVertexAttribArray(a_Position);
    
        // 获取着色器中attribute变量a_Color的地址
        var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
        if (a_Color < 0) {
            console.log('Failed to get the storage location of a_Color');
            return -1;
        }
        // 将缓冲区对象分配给a_Color变量
        gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2);
    
        // 连接a_Color变量与分配给它的缓冲区对象
        gl.enableVertexAttribArray(a_Color);
    
        // 解除绑定
        gl.bindBuffer(gl.ARRAY_BUFFER, null);
    
        return n;
    }
    
    /**
     * 创建并使能一个program对象
     * @param gl 表示 WebGL上下文对
     * @param vshader 表示顶点着色器
     * @param fshader 表示片段着色器
     * @return 如果WebGLProgram对象被创建并成功作为当前对象,则返回true;否则返回false 
     */
    function initShaders(gl, vshader, fshader) {
        var program = createProgram(gl, vshader, fshader);
        console.log("======createProgram program: " + program);
    
        if (!program) {
            console.log('Failed to create program');
            return false;
        }
        gl.useProgram(program);
        gl.program = program;
    
        return true;
    }
    
    /**
     * 创建一个linked program对象
     * @param gl 表示 WebGL上下文对象
     * @param vshader 表示顶点着色器
     * @param fshader 表示片段着色器
     * @return 如果创建program成功,则返回创建的program;否则返回null
     */
    function createProgram(gl, vshader, fshader) {
        console.log("======createProgram start======");
        // 创建shader对象
        var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);
        console.log("======vertexShader: " + vertexShader);
        var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
        if (!vertexShader || !fragmentShader) {
            return null;
        }
    
        // 创建program对象
        var program = gl.createProgram();
        console.log("======createProgram program: " + program);
    
        if (!program) {
            return null;
        }
    
        // 将着色器附加到对象
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
    
        // 连接程序对象
        gl.linkProgram(program);
    
        // 检查连接对象的结果
        var linked = gl.getProgramParameter(program, 0x8B82);
        console.log("======getProgramParameter linked: " + linked);
    
        if (!linked) {
            var error = gl.getProgramInfoLog(program);
            console.log('Failed to link the program: ' + error);
            gl.deleteProgram(program);
            gl.deleteShader(fragmentShader);
            gl.deleteShader(vertexShader);
            return null;
        }
        return program;
    }
    
    /**
      * 创建一个shader对象
      * @param gl 表示 WebGL上下文对象
      * @param type 表示shader类型
      * @param source 表示shader的源码 
      * @return 如果操作成功,返回创建的着色器对象;否则返回false
      */ 
    function loadShader(gl, type, source) {
        console.log("======into loadShader====");
        // 创建shader对象
        var shader = gl.createShader(type);
        if (shader == null) {
            console.log('Failed to create the shader.');
            return null;
        }
    
        // 设置shader program
        gl.shaderSource(shader, source);
    
        // 编译shader
        gl.compileShader(shader);
    
        // 检查shader编译结果
        var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
        if (!compiled) {
            var error = gl.getShaderInfoLog(shader);
            console.log('Failed to compile the shader: ' + error);
            gl.deleteShader(shader);
            return null;
        }
    
        return shader;
    }
    
    export default {
        data: {
            title: "DEMO BY TEAMOL",
            fit:"cover",
            fits: ["cover", "contain", "fill", "none", "scale-down"]
        }
        ,onInit() {
            this.title = this.$t('strings.world');
        }
        ,BtnColorTriangle() {
            // 获取canvas元素
            const el = this.$refs.canvas1;
            // 获取webgl上下文
            var gl = el.getContext('webgl');
    
            if (!gl) {
                console.log('Failed to get the rendering context for WebGL');
                return;
            }
    
            // 初始化着色器
            if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
                console.log('Failed to initialize shaders.');
                return;
            }
    
            // 设置顶点位置
            var n = initVertexBuffers(gl);
            if (n < 0) {
                console.log('Failed to set the positions of the vertices');
                return;
            }
    
            // 指定清空<canvas>的颜色
            gl.clearColor(0.0, 0.0, 0.0, 1.0);
    
            // 清空<canvas>
            gl.clear(gl.COLOR_BUFFER_BIT);
    
            // 绘制三角形
            gl.drawArrays(gl.TRIANGLES, 0, n);
    
            // 清buffer
            gl.flush();
        }
    }

图2 点击按钮绘制彩色三角形的效果图

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容