当前位置: 首页 > Web前端 > JavaScript

WebGL的HelloWorld

时间:2023-03-26 23:28:13 JavaScript

本文整理自div侠在凹凸2022的技术分享,简单介绍了在WebGL中绘制一个基本图形的过程。希望大家理解之后,在使用3d渲染库的时候就少一些迷茫。四种常用的页面绘制工具关于h5页面的图形绘制,我们多半说说这四种工具:html+css、svg、canvas2d、webgl。html+css是最常见的绘图工具。用css画图和写页面布局是一样的。在制作图表的时候,我们可以使用css来定义图表的样式。其他的就是根据不同的数据给元素添加元素。不同的属性。这种开发方式对于图表元素简单,数据节点少的场景非常友好。不仅可以减少开发的工具数量,也不需要引入不必要的代码库。但是随时需要绘制的图形越来越多,css代码也越来越复杂。另外,css没有逻辑语义,代码会变得难以阅读和维护。svg是可缩放矢量图形。它与html和css紧密结合。可以用svg作为img的src,也可以用css来操作svg的属性。svg和html都是文本标记语言。svg相比于html,增加了对线性图形的支持,包括圆弧、贝塞尔曲线等,同时svg支持等可重用类的语法,这让他可以画很多东西的图形,代码仍然保持一定的可读性。但是,svg也有一些缺点。因为图是一个元素节点。当数据量很大时,页面刷新带来的布局和渲染计算开销会非常大。而且,完整的svg把结构、样式、复用逻辑都放在了一起,相比html+css+js的三段式模式,显得不够整洁。Canvas2D是画布的二维绘图上下文。它提供了一系列方法来修改和绘制画布区域中的图像。与前两者的开箱即用相比,canvas2d的很多图形和颜色都需要自己实现和封装,这使得这个工具的上手难度比较大,但是如果你做好了这些基本的事情,你将有一个绘图工具,完全覆盖了前两个工具的功能,并且易于扩展。webGL也是canvas的绘图上下文,是opengles的web实现。最大的特点是下层可以直接使用GPU的并行能力。在处理大量图形、像素级处理和3D物体的场景中具有高性能优势。四种工具的选型思路当我们拿到一个绘图需求时,首先要看这个需求中使用的图形是否比较小和简单。如果是的话,可以直接选择css进行快速开发。如果图形简单但很多,或者图形有一些曲线要求,这时候svg可以很快应付。如果图形之间结构复杂,数量多,选择canvas2d。而当图形数量级大到一定量,或者每个像素都需要处理,或者需要大量的3D显示时,我们就不得不使用webgl,webgl的helloworld,webgl的helloworld不像其他的可以用一两行代码搞定的工具,不过有四十多行代码。虽然这串代码在每个3d渲染库中都有对应的封装方式,我们基本不需要手写,但是学习这串代码可以让我们对webgl的绘制过程有一个基本的了解。webgl绘图有五个步骤:createwebgldrawingcontext,createshaderprogramming,associatetoglcontext(与step3并行)createdata,putbuffer和associatebuffertoglcontext(同step2步骤并行)gpu加载数据在缓存中绘制图形CreateWebglcontextconstcanvas=document.createElement('canvas');constgl=canvas.getContext('webgl');创建着色器程序constprogram=gl.createProgram();gl.attachShader(program,/*一个着色器(下面的vertexShader)*/);gl.linkProgram(program);gl.useProgram(program);Shader是gpu运行的程序,我们使用glCreateProgram创建一个空的程序对象,然后使用glAttachShader将编译好的shader代码填充到这个程序对象中。什么是shader,如何编译,后面再说,这里可以看成是某个功能的编译代码。将几个这样的编译函数放入程序对象中后,gpu执行程序对象,并将像素信息作为输入参数,依次执行程序对象中的函数。填入shader代码后,调用glLinkProgram将程序链接到gl上下文,使用glUseProgram启用程序。接下来,让我们看看着色器代码是如何制作的。constvertex=`属性vec2位置;voidmain(){gl_Position=vec4(position,1.0,1.0);}`;constvertexShader=gl.createShader(gl.VERTEX_SHADER);gl.shaderSource(vertexShader,vertex);gl.编译着色器(顶点着色器);首先,我们定义一个变量vertex,给它赋值一串其他语言格式的代码串。这串代码就是glsl代码,很像C语言。代码接收一个传入的二维向量position,然后将他的执行环境中的全局变量gl_Position设置为一个四维向量,四维向量的前两个维度的分量就是传入的二维向量.接下来,使用glCreateShader创建着色器。VERTEX_SHADER常量表示这个shader是一个vertexshader,vertexshader对应一个fragmentshader,vertexshader处理确定点的位置。片元着色器将顶点形成的图中的所有位置一一处理,比如用两点画一条直线,两点由顶点着色器确定,片元着色器确定后绘制直线。两个点的位置。我们创建一个空的顶点着色器对象vertexShader后,就可以使用glShaderSource将之前的字符串代码放入顶点着色器对象中,然后使用glCompileShader将这段代码编译成可执行文件。这个过程类似于C语言的编译过程。gl.attachShader(program,/*某个shader(下面的vertexShader)*/);gl.attachShader(program,vertexShader);完成这一步后,还需要回到上面的注释,将shader对象关联到program对象中。当然,您必须编写片段着色器,并使用相同的步骤将片段着色器与程序对象相关联。将数据存入缓冲区constpoints=newFloat32Array([-1,-1,0,1,1,-1]);constbufferId=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,bufferId);gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW);经过以上操作,我们已经有了一个加载了着色器代码的程序对象,在gl绘图上下文中启用了。接下来,我们需要为这个程序定义数据。在顶点着色器中,代码接受一个传入的二维向量,这就是我们现在要定义的。先定义一个类型化数组,初始化时放入6个数,这6个数会被绘图程序分成三组,放入三个vertexshader调用。另外,使用类型化数组是为了优化性能,使得在数据量很大的情况下,数据占用的空间更少。有了数据之后,调用glCreateBuffer创建一个buffer对象,使用glBindBuffer将这个对象关联到gl绘图上下文,最后调用glBufferData将点数据放入buffer中。gpu加载缓存中的数据constvPosition=gl.getAttribLocation(program,"position");gl.vertexAttribPointer(vPosition,2,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(vPosition);这一步我们首先调用glGetAttribLocation获取变量position在程序对象中的位置,调用glVertexAttribPointer设置这个变量的长度为2,设置类型为glFLOAT,使用glEnableVertexAttribArray使这个变量能够绘制图形gl.clear(gl.COLOR_BUFFER_BIT);gl。drawArrays(gl.TRIANGLES,0,points.length/2);在最后一步,只需使用glClear清除颜色缓冲区,然后使用glDrawArrays进行绘制即可。其中,gl.TRIANGLES决定了片元着色器的绘制范围。当这个值为gl.POINTS时,shader会将点两两连接起来,gl.TRIANGLES让第三个点组成一组绘制三角形。这样,一个hello的webgl世界就完成了,上面的三角就是这40行代码输出的图像。综上所述,本程序在three.js等3d框架和工具库中都有一定的封装。通过那些库来画webgl还是比较方便的,但是如果不了解这些库最基本的操作,就很难遇到问题很容易绕来绕去。所以希望这篇文章能够增加你对web3d底层方面的理解,在学习这些3d工具库的时候给你一些帮助。GPU与渲染管线:如何用WebGL绘制最简单的几何图形?欢迎关注傲兔实验室博客:aotu.io或关注傲兔实验室公众号(AOTULabs),不定期推送文章。