最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 【得物技术】走进Web3D的世界(1) 画个立方体吧

    正文概述 掘金(得物技术)   2021-02-10   681

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

    GLSL github.com/wshxbqq/GLS…

    Shader thebookofshaders.com/01/

    矩阵 bk.tw.lvfukeji.com/wiki/%E7%9F…

    齐次坐标 bk.tw.lvfukeji.com/wiki/%E9%BD…

    最终效果

    【得物技术】走进Web3D的世界(1) 画个立方体吧

    step1:建立webgl渲染上下文

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

    const canvasDom = document.getElementById('canvas')
    gl = canvasDom.getContext('webgl')
    
    //开启深度检测
    gl.enable(gl.DEPTH_TEST)
    

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

    关于着色器shader是一个超级大的话题(推荐看TheBooksOfShader,尴尬的是作者没写完)。

    大致可以这么理解:

    • 顶点着色器确定了画布上点的位置

    • 3d世界中基础的几何图形是三角形,片元着色器代表了区域的表现形式

    先看一下webgl的坐标系,z+轴是面向我们的视角:

    【得物技术】走进Web3D的世界(1) 画个立方体吧

    下面这段是顶点着色器:

    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:创建一个程序

    记住就好,就是调用api

    const program = gl.createProgram();
    

    step4:链接程序与着色器

    记住就好,就是调用api

    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表示从0取48个点绘制

    总结

    上述过程就是一个完整的webgl绘画流程。

    完整的代码

    <!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>
    

    文|alex

    关注得物技术,携手走向技术的云端


    起源地下载网 » 【得物技术】走进Web3D的世界(1) 画个立方体吧

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元