WebGL入门-基本概念

WebGL(Web Graphics Library)是一种3D绘图标准,它允许JavaScript和OpenGL ES 2.0相结合,为HTML5 Canvas提供硬件3D加速渲染。

WebGL入门-基本概念
推荐使用NSDT 3DConvert进行3D模型格式转换,支持glb、obj、stp、fbx、ifc等多种3D模型格式之间进行互相转换,在转换过程中,能够很好的保留模型原有的颜色、材质等信息。

webGL 使用 canvas 标签进行开发,扩展了web复杂图形渲染的三维层次。

示例:画点

使用webGL画一个点,主要有以下几个步骤:

  1. 创建一个含有 标签的 HTML
  2. 创建一个用于编写webGL程序的JS
  3. 创建顶点着色器
  4. 创建片元着色器
  5. 融合顶点和片元着色器
  6. 清除背景
  7. 画出图形

代码如下:

<!Doctype html>
<html>
  <head>
    <title> web-gl example </title>
  </head>
  
  <body onload="main()">
    <canvas id="web-gl-example" width="400" height="400" />
    <script src="./main.js" />
  </body>
</html>
function initShader(gl, p, f) {}

/**
* @todos 
* 1.获取canvas标签对象 
* 2.获取web-gl-context对象 
* 3.编写着色器 
* 4.清空背景
* 5.画在背景上
*/
function main() {
    const canvas = document.getElementById("web-gl-example");
    
    const gl = canvas.getContext("web-gl");
    
    /* 顶点着色器:设置大小、位置 */
    const pointShader = `
        void main() {
            gl_PointSize = 10.0; // 像素大小
            gl_Position = vec4(0.0, 0.0, 0.0, 1.0); // vector4 四维齐次坐标 
                                                    // x,y,z,w => (x/w, y/w, z/w)
        }
    `
    /* 片元着色器:描述像素的特征 */
    const fragShader = `
        void main() {
            gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); // RGBA格式颜色
        }
    `
    
    /* 错误判断; initShader() 是融合两个着色器的方法 */
    if (initShader(gl, pointShader, fragShader) === null) 
        throw new Error("着色器编写出错!");
    
    // 清空背景
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.Color_Buffer_Bit); // 全大写
    
    /*
     * api描述:多种功能的画图API,根据传参的不同而绘画形式不同
     */
    gl.drawArrays(gl.Point, 0, 1); // 全大写
}

坐标系

webgl 的坐标系是右手坐标系,即:X轴平行与屏幕上下边沿,Y轴平行于屏幕左右边沿,Z轴垂直与屏幕向外延申,原点位于canvas的中心。简略坐标朝向如图所示:

其他

缓冲区

webgl的缓冲区是用来存放展示信息的内存块,当我们绘画、清除的时候会使用他们。通常web-gl包含三种缓冲区:

  1. 颜色缓冲区
  2. 深度缓冲区
  3. 模板缓冲区

着色器 -- shader

着色器是web-gl的核心,它包含了图形中像素的绘画信息。web-gl拥有两种着色器:

  1. 顶点着色器:描述点的信息:大小、位置等
  2. 片元着色器:描述片元/像素(fragment) 的信息,颜色、光照等

外部动态参数

使用attribute/uniform关键字进行传递参数到着色器程序中,使着色器函数内部变量随外部动态变化进行交互。 API 参考:

  1. gl.getAttributeLocation(program, name); // 获取Attribute变量的位置
  2. gl.vertexAttrib3f(location, ...args); // 给内部Attribute变量赋值
  3. ... // 赋值函数可以进行参数数目的扩展,从 1 - 4 个。
  4. gl.getUniformLocation(program, name); // 获取Uniform变量的地址
  5. gl.uniform3f(location, ...args);
  6. ... // 与attribute类似

参考代码如下:

function main()  {
    ... // 获取 canvas + web-gl 对象
    const pointShader = `
        attribute vec4 p_Position; // <描述> <类型> <变量名>
        void main() {
            gl_Position = p_Position;
            gl_PointSize = 10.0;
        }
    `;
    
    ... // 片元着色器 + 融合着色器方法
    
    // 获取 p_Position 的位置
    const p_Position = gl.getAttributeLocation(gl.program, 'p_Position');
    
    // 赋值
    gl.vertexAttrib3f(p_Position, 0.0, 0.0, 0.0);
    
    ... // 继续清除背景+画点
}

注意:Attribute 和 Uniform 的差别是:Attribute 变量是单个顶点的特征;Uniform 变量是所有点的共同特征,编程层面上基本类似。后面还会出现varying, 这里暂且不谈。

坐标转换

在用户交互过程中,用户点击事件触发在 Client 上面,导致在获取变化位置时要进行坐标转换。从屏幕坐标到canvas坐标到web-gl坐标。如图:

需要从左上角的屏幕原点,转到canvas的左上原点:

let x = clientX - canvas.top;
let y = clientY - canvas.left;

再从canvas转换到webgl:

x = (canvas.width / 2) - x; // 横向中心点
y = -((canvas.height / 2) - y) = y - (canvas.height / 2); // 纵向中心点,更改坐标轴方向

最后单位化:

x /= (canvas.width / 2);
y /= (canvas.height / 2); 

多个点的绘制

多个点的绘制主要依赖以下步骤:

  1. 使用数组记录点的位置
  2. 清空背景
  3. 遍历数组,依次画出点

代码如下:

// gl 的初始化,shader的初始化
const points = [[0, 0], [0.5, 0.5], [-0.5, 0.5]];
const pointPosition = gl.getAttributeLocation(gl.program, 'PointPosition');

gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear();

for (let i = 0; i < points.length; i++) {
    gl.vertexAttrib3f(pointPosition, points[i][0], points[i][1], 0.0);
    
    gl.drawArrays(gl.Points, 0, 1);
}
NSDT场景编辑器 | NSDT 数字孪生 | GLTF在线编辑器 | 3D模型在线转换 | UnrealSynth虚幻合成数据生成器 | 3D模型自动纹理化工具
2023 power by nsdt©鄂ICP备2023000829号