走进Web3D的世界(1) 画个立方体吧

需要了解一下的前置知识(下面是推荐阅读的链接)

GLSL
Shader
矩阵
齐次坐标

最终效果

先看一下最终效果,有个直观映象吧

在这里插入图片描述

step1:建立webgl渲染上下文

这个就是简单的获取dom然后获取上下文 (注意下这里因为是画3d所以要开启深度检测)

const canvasDom = document.getElementById('canvas')
gl = canvasDom.getContext('webgl')

//开启深度检测
gl.enable(gl.DEPTH_TEST)

step2:创建顶点着色器与片元着色器

关于着色器shader是一个超级大的话题

大致可以这么理解

  • 顶点着色器确定了画布上点的位置
  • 3d世界中基础的几何图形是三角形,片元着色器确定了这块区域的表现形式

先看一下webgl的坐标系,z+轴是面向我们的视角
在这里插入图片描述
下面这段是顶点着色器

const Vertex = `
        attribute vec3 vPosition;
        void main() { 
            gl_PointSize = 1.0; 
            gl_Position =  mat4(1,0, 0, 0 ,0, 0.52, -0.85, 0, 0, 0.85, 0.52, 0, 0, 0, 0,1)*mat4(0.52,0, 0.85, 0 ,0, 1, 0, 0, -0.85, 0, 0.52, 0, 0, 0, 0,1)*vec4(vPosition, 1);
        }
    `

attribute :只能存在于vertex shader中,一般用于保存顶点或法线数据,它可以在数据缓冲区中读取数据

vec3 vPosition 定义了一个3维向量 因为3d空间一个点(x,y,z)

mat4(1,0, 0, 0 ,0, 0.52, -0.85, 0, 0, 0.85, 0.52, 0, 0, 0, 0,1)是一个齐次矩阵 表示绕y轴旋转45度

mat4(0.52,0, 0.85, 0 ,0, 1, 0, 0, -0.85, 0, 0.52, 0, 0, 0, 0,1)表示绕z轴旋转45度

这样我们才能看到3d的效果

下面这个就是编译shader 固定套路 记住就好了 (开发中不大会用原生手写webgl👹)

const vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, Vertex);
    gl.compileShader(vertexShader);

下面这段是片元着色器

const Fragment = `
        #ifdef GL_ES
        precision highp float;
        #endif
        void main() {
            gl_FragColor = vec4(1.0,0,0,1.0);
        }
    `

表示的意思是 画布上的颜色是红色 vec4(1.0,0,0,1.0)

然后也是固定套路

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, Fragment);
    gl.compileShader(fragmentShader);

step3:创建一个程序

记住就好了 没啥特别的

const program = gl.createProgram();

step4:链接程序与着色器

记住就好了 没啥特别的 。。。

gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);

step5:建立缓冲数据

cube是用来获取顶点坐标

剩下的都是套路 api就不展开了 可以去mdn上查阅

//cube是用来获取顶点坐标
function cube(size = 1.0) {
        const h = 0.5 * size;
        const vertices = [
            [-h, -h, -h],
            [-h, h, -h],
            [h, h, -h],
            [h, -h, -h],
            [-h, -h, h],
            [-h, h, h],
            [h, h, h],
            [h, -h, h],
        ];

        const positions = [];
        function quad(a, b, c, d, e, f, g, h) {
            [a, b, c, d, e, f, g, h].forEach((i) => {
                positions.push(vertices[i]);
            });
        }

        quad(0, 1, 1, 2, 2, 3, 3, 0);
        quad(4, 5, 5, 6, 6, 7, 7, 4);
        quad(1, 2, 2, 6, 6, 5, 5, 1);
        quad(0, 3, 3, 7, 7, 4, 4, 0);
        quad(0, 1, 1, 5, 5, 4, 4, 0);
        quad(3, 7, 7, 6, 6, 2, 2, 3);

        return { positions};
    }

    const geometry = cube(1.0);

    console.log(geometry)

    const points = new Float32Array(geometry.positions.flat());
    const bufferId = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
    gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

step6渲染

const Position = gl.getAttribLocation(program, 'vPosition');//获取顶点着色器中的position变量的地址
gl.vertexAttribPointer(Position, 3, gl.FLOAT, false, 0, 0);//给变量设置长度和类型
gl.enableVertexAttribArray(Position);//激活这个变量

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
gl.drawArrays(gl.LINES, 0, 48)

gl.drawArrays(gl.LINES, 0, 48)就是渲染的api

webgl中有7种图元 (表示怎么画)

gl.POINTS 孤立点 绘制一系列点
gl.LINES 绘制一系列单独线段。每两个点作为端点,线段之间不连接
gl.LINE_STRIP 连续线段 绘制一个线条。即,绘制一系列线段,上一点连接下一点
gl.LINE_LOOP 连续线圈 绘制一个线圈。即,绘制一系列线段,上一点连接下一点,并且最后一点与第一个点相连
gl.TRIANGLES 孤立三角形
gl.TRIANGLE_STRIP 三角带
gl.TRIANGLE_FAN 三角扇

0,48表示取的顶点索引

总结

上述过程是一个完整的绘画流程,很多步骤都需要记忆,套路都是一样的,孰能生巧。。。

完整的代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D立方体</title>
</head>

<body>
    <canvas id='canvas' width="800" height="800"></canvas>
</body>
<script>

    // 第一步 创建webgl上下文
    const canvasDom = document.getElementById('canvas')
    gl = canvasDom.getContext('webgl')

    //开启深度检测
    gl.enable(gl.DEPTH_TEST)
    console.log(gl)

    // 第二步 创建顶点着色器与片元着色器
    const Vertex = `
        attribute vec3 vPosition;
        void main() { 
            gl_PointSize = 1.0; 
            gl_Position =  mat4(1,0, 0, 0 ,0, 0.52, -0.85, 0, 0, 0.85, 0.52, 0, 0, 0, 0,1)*mat4(0.52,0, 0.85, 0 ,0, 1, 0, 0, -0.85, 0, 0.52, 0, 0, 0, 0,1)*vec4(vPosition, 1);
        }
    `

    const vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, Vertex);
    gl.compileShader(vertexShader);

    const Fragment = `
        #ifdef GL_ES
        precision highp float;
        #endif
        void main() {
            gl_FragColor = vec4(1.0,0,0,1.0);
        }
    `

    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, Fragment);
    gl.compileShader(fragmentShader);

    //第三步 创建程序对象
    const program = gl.createProgram();

    // 第四步 链接程序与着色器
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);

    gl.linkProgram(program);
    gl.useProgram(program);

    //第五步 建立缓冲数据
    function cube(size = 1.0) {
        const h = 0.5 * size;
        const vertices = [
            [-h, -h, -h],
            [-h, h, -h],
            [h, h, -h],
            [h, -h, -h],
            [-h, -h, h],
            [-h, h, h],
            [h, h, h],
            [h, -h, h],
        ];

        const positions = [];
        function quad(a, b, c, d, e, f, g, h) {
            [a, b, c, d, e, f, g, h].forEach((i) => {
                positions.push(vertices[i]);
            });
        }

        quad(0, 1, 1, 2, 2, 3, 3, 0);
        quad(4, 5, 5, 6, 6, 7, 7, 4);
        quad(1, 2, 2, 6, 6, 5, 5, 1);
        quad(0, 3, 3, 7, 7, 4, 4, 0);
        quad(0, 1, 1, 5, 5, 4, 4, 0);
        quad(3, 7, 7, 6, 6, 2, 2, 3);

        return { positions};
    }

    const geometry = cube(1.0);

    console.log(geometry)

    const points = new Float32Array(geometry.positions.flat());
    const bufferId = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
    gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

    // 第六步 渲染
    const Position = gl.getAttribLocation(program, 'vPosition');//获取顶点着色器中的position变量的地址
    gl.vertexAttribPointer(Position, 3, gl.FLOAT, false, 0, 0);//给变量设置长度和类型
    gl.enableVertexAttribArray(Position);//激活这个变量

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
    gl.drawArrays(gl.LINES, 0, 48)
</script>

</html>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值