龙空技术网

OpenGL和WebGL入门

软件技术及人才和养生 408

前言:

当前姐妹们对“css最下层”都比较关注,朋友们都想要分析一些“css最下层”的相关文章。那么小编同时在网络上收集了一些对于“css最下层””的相关文章,希望朋友们能喜欢,各位老铁们快快来学习一下吧!

OpenGL是业界使用最广泛的2D和3D图形API,将成千上万的应用程序带到各种计算机平台上。它与窗口系统和操作系统无关,并且网络透明。 OpenGL使PC、工作站和超级计算类型硬件的软件开发人员能够在CAD、内容创建、能源、娱乐、游戏开发、制造、医疗和虚拟现实等市场中创建高性能,视觉上引人注目的图形软件应用程序。 OpenGL公开了最新图形硬件的所有功能。经常做UI的开发者有可能一眼就看出OpenGL的UI界面和其它技术制作界面的区别。OpenGL第一个版本就很成熟,后续不断升级,是一个超级平台,欢迎大家来学习OpenGL开发。

OpenGL 4.6概览

OpenGL 4.6和OpenGL阴影语言4.60规范于2017年7月31日发布。

OpenGL 4.6的新功能包括:

GL_ARB_gl_spirv和GL_ARB_spirv_extensions标准化对OpenGL的SPIR-V支持

GL_ARB_indirect_parameters和GL_ARB_shader_draw_parameters用于减少与渲染几何批量相关的CPU开销

GL_ARB_pipeline_statistics_query和GL_ARB_transform_feedback_overflow_query标准化OpenGL对Direct3D中可用功能的支持

GL_ARB_texture_filter_anisotropic(基于GL_EXT_texture_filter_anisotropic)将先前IP限制的功能引入OpenGL,以改善纹理场景的视觉质量

GL_ARB_polygon_offset_clamp(基于GL_EXT_polygon_offset_clamp)可抑制与渲染阴影相关的常见视觉伪影,即“漏光”

GL_ARB_shader_atomic_counter_ops和GL_ARB_shader_group_vote添加了所有桌面供应商支持的着色器内在函数,以改善功能和性能

GL_KHR_no_error通过允许应用程序指示其期望无错误操作来减少驱动程序开销,因此无需生成错误

OpenGL 4.6的新扩展包括:

GL_KHR_parallel_shader_compileWGL_ARB_create_context_no_errorGLX_ARB_create_context_no_errorGL_EXT_memory_objectGL_EXT_memory_object_fdGL_EXT_memory_object_win32GL_EXT_semaphoreGL_EXT_semaphore_fdGL_EXT_semaphore_win32GL_EXT_win32_keyed_mutex
WebGL入门

Web前端开发比较热门,这里专门介绍WebGL开发。其它介绍请关注上面OpenGL开源社区里的链接

Web应用程序很有吸引力,因为它们是共享您的工作的绝佳方式。用户所需要做的只是打开一个Web链接。 WebGL是浏览器实现的界面,可让Web应用程序访问功能强大的硬件加速渲染。无需插件或安装。 WebGL基于OpenGL的移动版本; “ OpenGL ES”不需要最新的图形硬件,具有很高的便携性,并且可以在较旧的台式机和大多数移动设备上运行。而且,甚至更好的是,您无需为每个操作系统都进行特殊的构建。您可能会发现WebGL创建程序的速度要比台式机和移动设备快几倍。

我将在本页顶部解释如何制作旋转字符,并介绍基本的启动,JavaScript的使用,加载纹理,着色器,网格和文件加载以及矩阵处理。为了避免多余的教程内容,我将假设您至少已经完成了现代OpenGL编程的基础知识-这意味着您对着色器和顶点缓冲区有所了解。我将假定读者熟悉基本的HTML,但不一定熟悉JavaScript或更新的Web界面。我们将不会使用任何框架或高级接口,因为已经有足够的资源来使用这些框架或高级接口。

技术概述

编写WebGL软件时,您会发现自己在几种语言之间切换。

Language 功能

HTML5 编写带矩形画布的页面,画布内进行渲染

JavaScript 调用GL函数,用AJAX加载资源,处理用户输入,编写主逻辑

GLSL 编写shaders来定义渲染的风格

我们将只使用5中的一项或多项新功能来编写一些基本的HTML。JavaScript具有一个文件加载接口,通常称为“ AJAX”(异步JavaScript和XML),因为它旨在将XML文件序列化为JavaScript。对象,但我们将其用作通用文件加载器,该加载器返回包含文件内容的字符串。着色器语言有一个或两个非常小的区别,与OpenGL ES相同,具有基于OpenGL ES 2.0规范的WebGL 1.0和基于ES 3.0的WebGL 2.0。

Basic HTML Skeleton 基本HTML骨架

我们可以从制作一个非常简单的HTML网页开始。

我们首先制作一个简单的HTML网页,上面有一个画布区域(以阴影显示)。我们将能够使用任何其他Web界面元素与我们的代码进行交互。

WebGL软件的基本概念是我们编写一个普通的网页,并使用新的HTML5画布标签定义渲染将绘制到的页面区域(空白矩形)。您可以使用HTML的任何形式,文本区域和其他元素来与您的可视化进行交互-可以说我们内置了用户界面库。

我开始是这样的:

<html><head></head><body><canvas id="mycanvas">This text will appear if the browser doesn't support HTML5.</canvas><br /><small><i>A model from a recent Ludum Dare game jam.You can view the source code of the page to see how I display this.</i></small></body></html>

如果您在浏览器中打开它,您将看不到任何东西-只是默认300x150像素画布所在的空间。我们将在不久后为其附加GL上下文。为此,我们添加一些JavaScript,它将与我们的Web文档对话。

在我们的HTML中,画布是一个简单的标签,带有DOM ID作为代码钩。我们还可以提供宽度和高度属性来指定页面上画布的实际大小。

我们利用DOM(文档对象模型)从我们的JavaScript代码访问网页元素。这就像给每个元素的HTML标签提供id =“ my_thingy”属性一样简单。该浏览器还具有BOM(浏览器对象模型),该BOM提供了内置功能来处理通过鼠标,游戏手柄或键盘进行的用户交互。

JavaScript启动代码

JavaScript取代了C作为图形库的主要接口语言。如果您以前从未使用过JavaScript,那么您应该知道除了名称之外,它与Java语言无关-从人们仍然认为Java是一个好主意的时代起,这就是一种营销计划! JavaScript是一种客户端脚本语言,这意味着客户端的Web浏览器会下载您的整个源代码,然后在自己的CPU上的浏览器中运行它。这意味着您可以执行功能更强大的交互式调试,并且不需要重新编译,但是比C慢一点。我们能在html内任何地方写script,不过我喜欢写在最后,需要加如下:

<script>            console.log("starting WebGL");          var canvas = document.getElementById("mycanvas");                     canvas.width = 512;                     canvas.height = 256;            var gl = canvas.getContext("webgl");          gl.clearColor(0.85, 0.85, 0.85, 1.0);            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);            // set some GL states that I want to use for rendering            gl.cullFace(gl.BACK);            gl.frontFace(gl.CCW);            gl.enable(gl.CULL_FACE);            gl.enable(gl.DEPTH_TEST);  </script>          

我在这里介绍一些新概念。第一条指令与printf()的JavaScript等效。如果转到浏览器的开发人员菜单,则可以打开JavaScript控制台,并且应该看到该消息。每次刷新或重新加载页面时都将其打开是很好的,因为它会为您提供很好的错误信息,您可能不会注意到这些错误信息,因为页面可能会继续看起来正确加载。

我使用DOM来获取我的canvas元素作为JavaScript对象。请注意,JavaScript不使用强类型-一切都是一个var对象,我可以告诉您这引起的问题远远超过其解决的问题。无论如何,我的第一个动作是从JavaScript修改画布的width和height属性,这应该更改其在页面上的大小。

接下来,我要求画布使用新的WebGL上下文进行设置,并将其作为名为gl的对象进行跟踪。该对象将成为我们所有WebGL功能的接口。

我的最终指令使用gl对象调用GL函数。它们几乎与OpenGL函数名称和常量相同,除了gl和GL_被删除了,我们通过新对象访问它们。如果您想使背景透明并且要显示页面背景,则可以在此处将aplha通道设置为0.0。如果刷新网页,您应该会看到画布变大并且变色了。

阅读参考,您会注意到WebGL不支持较新的OpenGL的“顶点数组对象”(VAO)。在没有VAO的OpenGL中,这实际上是非常繁琐的渲染,因为每次绘制时都必须设置顶点属性指针。 WebGL有一个VAO扩展。您可以在扩展注册表中看到它。我们可以在脚本块中查询它,这将返回一个新对象,该对象然后是我们与VAO扩展功能子集的接口:

var vao_ext = gl.getExtension ("OES_vertex_array_object");if (!vao_ext) {  console.error ("ERROR: Your browser does not support WebGL VAO extension");}

如果用户的浏览器/系统不支持该功能,则可以使用浏览器控制台的错误日志记录机制进行报告。它还在控制台的输出中包括一个行号链接。

异步加载纹理

实际上,将纹理加载到WebGL中比使用常规OpenGL要容易得多,因为我们不需要图像加载库-HTML已经加载了图像。我们可以使用网页上显示的图像作为纹理,也可以在JavaScript中安静地加载图像。请注意,这是异步的,因此稍后会在您提供图像URL后的代码中实际创建纹理。

var texture = gl.createTexture();texture.is_loaded = false;var image = new Image();image.onload = function () {  gl.bindTexture (gl.TEXTURE_2D, texture);  gl.pixelStorei (gl.UNPACK_FLIP_Y_WEBGL, true);  gl.texImage2D (gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE,    image);  gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);  gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);  gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);  gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);  texture.is_loaded = true;  console.log ("texture loaded ");}image.src = "webgl_starter/heckler.png";

请注意,我做了一些非常不寻常的事情,并在纹理内设置了is_loaded属性。我们知道OpenGL纹理甚至都不是对象-它们当然没有属性!在JavaScript中,我们可以向现有对象动态添加新属性。 由于现代网络使用异步下载模型,因此我们无法确定何时实际下载资源。如果连接不良,主循环启动后一分钟内,加载功能可能甚至无法执行。同时,我们至少将拥有一个有效但为空的纹理,并带有一个要检查的标志。在足以复杂地异步加载文件的C程序中,我们将进行如下设置:

start_loading_shader();start_loading_texture();start_loading_mesh();while ( !everything_has_loaded() ) {  sleep();}// end of loading function

我们不允许在JavaScript中使用跨线程的等待循环,因此,我们可以做的最好的事情就是在主循环中添加if语句检查,这样它就不会在所有必需的资源加载之前尝试绘制。例如:

if (texture.is_loaded) {  gl.activeTexture (gl.TEXTURE0);  gl.bindTexture (gl.TEXTURE_2D, texture);  ...  // draw with the texture}...// rest of drawing code

您会看到注入一些状态属性为什么有用的原因,以及我们在WebGL演示中看到的资源“弹出”效果从何而来。如果要避免这种奇怪的影响,您可以使用一个函数来检查是否在渲染之前加载了所有资源,而是渲染了一些“加载..”文本,但是从我的经验来看,这个大型商业项目有很多如果要下载大量资源数据,如果他们不得不在移动设备上或连接不良的情况下等待很长时间,则可能会带来非常糟糕的用户体验-您可能会发现用户宁愿选择“弹出”,也不愿等待很长时间。

从HTML脚本加载着色器

我通常希望将着色器存储在外部文件中,但这实际上在JavaScript中有点不方便,JavaScript也希望异步加载它们。对于多部分着色器,使用此机制实际上是一件烦人的事。您可以将两个着色器连接到一个文件中。您还可以将着色器存储在JavaScript字符串中。相反,大多数开发人员发现将着色器放置在自己的脚本块中更加方便,这样您就不必担心字符串格式或异步下载。我将顶点着色器放在其他脚本之上的自己的脚本块中:

<script id="heckler.vert" type="text/glsl">              attribute vec3 vp;              attribute vec2 vt;              attribute vec3 vn;            uniform mat4 PV, M;            varying vec2 st;              varying vec3 n;          void main () {              st = vt;              n = vec3 (PV * M * vec4 (vn, 0.0));              gl_Position = PV * M * vec4 (vp, 1.0);              }  </script>        

我将属性的类型设置为适当的外观,以使浏览器不会认为应该使用JavaScript。我设置了id属性,以便以后获取。用于WebGL 1.0的GLSL使用较旧的OpenGL 2.1和OpenGL ES而不是较新的输入和输出的acoderibute和不同的关键字。同样,我在脚本块中有一个片段着色器:

<script id="heckler.frag" type="text/glsl"> \u003cscript id \u003d“ heckler.frag” type \u003d“ text / glsl”\u003e

precision mediump float; 精密中型浮子;

varying vec2 st;              varying vec3 n;              uniform sampler2D dm;void main () {              vec4 texel = texture2D (dm, st);            vec3 nn = normalize (n);              vec3 fwd = normalize (vec3 (0.0, 0.0, -1.0));              gl_FragColor = texel;              gl_FragColor.rgb = gl_FragColor.rgb * dot (nn, fwd) * 0.7              + 0.3 * gl_FragColor.rgb;              }  </script>       

我们用varying代替in,,以及内置的gl_FragColor代替了输出变量。 WebGL片段着色器需要在顶部具有确切的精度声明。

要将这些块的内容作为JavaScript字符串获取,请在加载网格后执行以下操作:

          var el =  document.getElementById ("heckler.vert");          var vs_str =  el.innerHTML;          el =  document.getElementById ("heckler.frag");          var fs_str =  el.innerHTML

我只是再次使用DOM来获取字符串。可以将着色器放在可见的文本区域中,然后实时编辑它们,而不是脚本块。 Web元素具有您可以定义的一系列.on ....()函数。当用户单击某些内容或更改了文本时,将触发回调函数-您的函数可以重新编译着色器。

之后,我将定期查看代码来编译着色器,并获取一些变量来保存制服的位置。请注意,我还分别将点,纹理坐标和法线的属性位置分别绑定到0、1和2。

var vs =  gl.createShader (gl.VERTEX_SHADER);          var fs =  gl.createShader (gl.FRAGMENT_SHADER);          gl.shaderSource  (vs, vs_str);          gl.shaderSource  (fs, fs_str);          gl.compileShader  (vs);          if  (!gl.getShaderParameter (vs, gl.COMPILE_STATUS)) {          console.error ("ERROR compiling vert  shader. log: " +          gl.getShaderInfoLog (vs));          }          gl.compileShader  (fs);          if  (!gl.getShaderParameter (fs, gl.COMPILE_STATUS)) {          console.error ("ERROR compiling frag  shader. log: " +          gl.getShaderInfoLog (fs));          }          var sp =  gl.createProgram ();          gl.attachShader  (sp, vs);          gl.attachShader  (sp, fs);          gl.bindAttribLocation  (sp, 0, "vp");          gl.bindAttribLocation  (sp, 1, "vt");          gl.bindAttribLocation  (sp, 2, "vn");          gl.linkProgram  (sp);          if  (!gl.getProgramParameter (sp, gl.LINK_STATUS)) {          console.error ("ERROR linking program.  log: " + gl.getProgramInfoLog (sp));          }          gl.validateProgram  (sp);          if  (!gl.getProgramParameter(sp, gl.VALIDATE_STATUS)) {          console.error ("ERROR validating  program. log: " +          gl.getProgramInfoLog (sp));          }          var heckler_PV_loc  = gl.getUniformLocation (sp, "PV");          var heckler_M_loc  = gl.getUniformLocation (sp, "M");

“ PV”是我的组合投影和视图矩阵,“ M”是我的模型矩阵。尽管类似于C语言中的OpenGL,但您可以看到诸如字符串函数之类的东西更容易处理。如果刷新浏览器并在控制台中查看,则如果该信息不起作用,则会出现错误消息(包括着色器和链接器日志)。如果要确保已加载着色器代码,则可以使用警报(vs_str);抛出带有顶点着色器字符串的警报框。

用AJAX加载网格文件

我有一个要渲染的网格文件-我为最近的游戏卡纸制作的Wavefront .obj文件。我想做的是将.obj文件读入一个字符串,然后使用JavaScript字符串解析函数(非常好)将其分解为点,纹理坐标和法线的列表。我们可以为此使用AJAX,其工作方式如下:

var xmlhttp = new  XMLHttpRequest();          xmlhttp.open  ("GET", "OUR_URL_STRING_HERE", true);          xmlhttp.onload =  function (e) {          var str = xmlhttp.responseText;          var lines = str.split ('\n');          for (var i = 0; i < lines.length; i++) {          //...parsing code goes here...          }          }          xmlhttp.send ();

首先,我们获得一个到新XMLHTTPRequest(AJAX的真实名称)的接口。我们告诉它它将使用HTTP“ GET”请求从URL检索文件,该文件将作为字符串提供。最后,它更喜欢异步工作,这在JavaScript中进行设置可能非常棘手,但是值得获得最佳加载时间。如果您想跳过这些麻烦事,可以将open()函数的第三个参数设置为false,但是浏览器会在控制台中向您投诉。

我们可以以与处理纹理相同的方式使用AJAX处理异步下载-添加is_loaded属性。我还将检查纹理是否已加载,因为如果先加载VAO并使用其他纹理进行渲染,它将看起来很糟糕:

var my_vao =  start_loading_obj ("meshes/my_mesh.obj");          ...          // _inside the  main drawing loop_          if  (my_vao.is_loaded && texture.is_loaded) {          vao_ext.bindVertexArrayOES (my_vao);          ...          // draw stuff that requires the VAO          }

我不会在此处粘贴50行左右的.obj解析文件,但是您可以在obj_parser.js上查看它。您可以采用多种方法来构造JavaScript对象和函数。 JavaScript的另一个烦人的局限性是,您不能像在C语言中那样真正地从一个函数中传回一个以上的变量。您可能会考虑创建一个包含VAO和点数的网格容器对象,或者只是将顶点点数添加为像我在这里一样,您的VAO中的另一个属性-这取决于您希望在工作代码中拥有多少抽象。

function  start_loading_obj (url) {          // first create an empty VAO          var vao = vao_ext.createVertexArrayOES ();          // inject an is_loaded boolean          vao.is_loaded = false;          // inject point count into VAO (yeah...)          vao.pc = 0;            var xmlhttp = new XMLHttpRequest();            xmlhttp.open ("GET", url, true);            xmlhttp.onload = function (e) {            var str = xmlhttp.responseText;            var lines = str.split ('\n');            for (var i = 0; i < lines.length; i++) {            //...parsing code goes here...            }            // store loaded state and point count in  VAO            vao.pc = sorted_vp.length / 3;            vao.is_loaded = true;            }            // start loading            xmlhttp.send ();            // return the empty VAO            return vao;            }       

请注意,类似于纹理创建,第一步是创建有效但为空的VAO。下载开始时,它将返回给函数调用者。这意味着,即使下载尚未完成,我们的主程序仍然对最终的VAO具有有效的句柄,并且可以检查其状态。发送功能开始HTTP握手。文件实际下载到客户端后,在原始函数调用返回后的某个时间onload回调函数将启动。在测试时很容易在这里犯一个错误。在本地网络上,下载不会有延迟。从另一个具有大网格的大陆,延迟可能会花费一些时间-在测试异步下载代码时,请检查可能最长和最坏的连接。您肯定会因很少的检查标志和回调而犯错误,并且拥有假定某些内容未经过充分检查就下载的代码。 在解析代码中,您可以使用str.split('\\ n');命令返回一个字符串数组;文件中的每一行一个,并使用for(var i= 0; i<clines.length; i ++){请注意,JavaScript使用动态数组(基本上是C ++向量),并且它们始终知道自己的长度。

要包含外部JavaScript文件,我们只需添加另一个脚本块,然后指定src =“ path_to_file.js”属性即可。

<script src="webgl_starter/obj_parser.js">            </script>

我在这里有我文件的相对路径。请注意,您必须具有结束脚本标记-您不能像使用其他类型的HTML元素一样具有单个自闭合的<script />标记。这个新的脚本块实际上应该出现在我们的其他块之前,以便浏览器在使用它之前对其进行解析。如果您不这样做,它仍然可以工作,但是浏览器可能会警告您,它被迫降低了脚本的加载效率。

跨域文件访问

如果您是从桌面加载网页,则AJAX可能会投诉并拒绝加载文件,因为它违反了安全策略。您可以将内容放在本地网络服务器上-有许多轻量级服务器可用。您可以使用--disable-web-security命令行标志启动Chrome以忽略此预防措施,也可以仅使用Firefox,Firefox应该完全忽略此问题并加载文件。

创建矩阵

您将需要一组用于JavaScript的向量和矩阵数学函数。布兰登·琼斯(Brandon Jones)的gl-matrix是一个非常受欢迎的库。我也将我的数学库移植到JavaScript。您当然也可以自己编写。仅将矩阵和向量保留为JavaScript的本机数组格式比创建自定义数据结构更容易。

值得一看的是JavaScript数学库的源代码,以了解函数,参数和数组在JavaScript中的工作方式。函数没有声明-只是定义。它们都以函数关键字而不是数据类型为前缀,并且可以返回或不返回值。参数只是给定名称,不需要var前缀。可以进行curry和更高级的功能编程。数组以方括号内的逗号分隔值列表形式给出。使用以下任一方法创建一个空数组

var my_array = []

要么

var my_array = new Array ().

我只在数学库中包含另一个脚本块。我使用外观熟悉的函数创建视图和投影矩阵:

var cam_dirty =  true;          var V = look_at  ([0.0, 0.4, 1.0], [0.0, 0.4, 0.0],          normalise_vec3 ([0.0, 1.0, 0.0]));          var aspect =  canvas.clientWidth / canvas.clientHeight;          var P =  perspective (67.0, aspect, 0.1, 100.0);          var PV =  mult_mat4_mat4 (P, V);

注意:我的画布尺寸是整数,但是这里的除法是浮点除法,而不是整数除法。这可能是您第一次接触到可怕的JavaScript。如果您想要特定的数据类型,通常必须使用特定的截断或解析函数来强制执行它-在大多数情况下,浮点数或字符串似乎是JavaScript中默认的一种假定数据类型。

画循环

要在JavaScript中循环,最好的策略是创建函数,将要循环的代码放入其中,并在完成时通知浏览器您要再次调用此函数。不幸的是,请求重复调用的实际功能似乎尚未在所有浏览器上标准化。我从Google的webgl-utils.js文件中摘录了一个片段,以将其封装在跨浏览器功能中:

          window.requestAnimFrame  = (function() {          return  window.requestAnimationFrame ||          window.webkitRequestAnimationFrame ||          window.mozRequestAnimationFrame ||          window.oRequestAnimationFrame ||          window.msRequestAnimationFrame ||          function(callback, element) {          return window.setTimeout (callback, 1000 /  60);          };          })();

如果将其放在脚本块中的某个地方,我们可以调用它。我们还将编写一个重复函数来绘制图形。如果愿意,可以在启动代码之后输入:

          var  previous_millis;          function main_loop  () {            // update timers            var current_millis = performance.now ();            var elapsed_millis = current_millis -  previous_millis;            previous_millis = current_millis;            var elapsed_s = elapsed_millis / 1000.0;                    // draw            gl.clear (gl.COLOR_BUFFER_BIT |  gl.DEPTH_BUFFER_BIT);            gl.activeTexture (gl.TEXTURE0);            gl.bindTexture (gl.TEXTURE_2D, texture);            gl.useProgram (sp);            if (cam_dirty) {            gl.uniformMatrix4fv (heckler_PV_loc,  gl.FALSE, new Float32Array (PV));            cam_dirty = false;            }            var R = rotate_y_deg (identity_mat4 (),  current_millis * 0.075);            gl.uniformMatrix4fv (heckler_M_loc, gl.FALSE,  new Float32Array (R));            vao_ext.bindVertexArrayOES (heckler_vao);            gl.drawArrays (gl.TRIANGLES, 0,  heckler_vao.pc);                      // "automatically re-call this function  please"            window.requestAnimFrame (main_loop, canvas);            }        

我喜欢在循环中添加一些计时器,以便可以制作动画,测量帧速率等。您可以使用浏览器的performance.now()函数来执行此操作,这可以使您自页面加载后以毫秒为单位,系统的最高精度可达纳秒级-比JavaScript的数据和时间函数可靠得多。之后,我开始绘制代码。我更新了投影的矩阵统一形式,并查看是否尚未更新。矩阵的统一更新功能有些特殊之处。在WebGL中,必须将transposition参数设置为false-它不会为您进行转换。最好将矩阵数组强制为32位浮点数据类型,您可以通过创建一个新的Float32Array对象来实现。在函数的最后,我再次调用了请求调用函数。缓冲区交换和最终图像在画布上的实际绘制都是自动处理的。在脚本块的末尾,我们实际上可以调用此函数,它将开始循环过程:

          previous_millis =  performance.now();          main_loop ();

这些就是WebGL的基础知识,如果您之前已经做过一些OpenGL的话,这些知识就足够了。

进阶

浏览器具有许多您可以访问的功能。您可以查看用户与鼠标,键盘,移动设备的触摸屏,甚至是新的W3C游戏手柄/操纵杆界面的交互。您可以查看设置更复杂的异步文件流。

拥有来自HTML的一组GUI工具不容小under。您可以在图表,滑块,按钮上使用Web的所有附加功能,最重要的是,您可以进行文本渲染。如果您愿意通过CSS将其覆盖在画布上。您还可以将画布浮动在其他Web内容上,并使背景透明。

浏览器具有内置的调试,源,步进和监视列表工具。您可以在浏览器中进行一些非常全面的调试,甚至在应用程序运行时输入新的JavaScript代码。尝试这些工具是一个好主意。

请确保观看新的WebGL 2.0标准的开发,并查看您的浏览器是否已运行此版本的早期版本。

标签: #css最下层