化石原创文章,转载请注明来源并保留原文链接


坐标系统。既然是一个3D系统,那么跟其他的3D一样,都有x、y、z三根轴。WebGL的这三个轴的值约束在(-1,-1,-1)到(1,1,1)之间。这个意思是,你可以把投影到屏幕上的WebGL图形看成如下:

WebGL坐标系统

这个投影被约束在一个立方体内,这个立方体对角的两个点的值是(1,1,1)和(-1,-1,-1)。超出立方体范围的任何东西,不会被WebGL渲染。

这里的坐标系统跟通用的3D坐标系统不一样,后者并没有约束x、y、z的范围。比如我们在Unity3d、THREE.js、UnrealEngine4中,世界坐标、本地坐标都没有这样的约束。这里讲的坐标系统,是WebGL、OpenGL、Direct3D在渲染每个像素的时候的系统。如果从实际的着色器来讲,就是顶点着色器的输出空间(事实上上顶点输出后GPU还有工序,这里我们暂时不管,先知道你现在的数值必须在这个范围之内才会被显示)。 这个刚接触的时候不必要太介意。我后面会有管线的文章专门记录这个事情。


化石原创文章,转载请注明来源并保留原文链接



化石原创文章,转载请注明来源并保留原文链接


在3ds max给一个模型附上不同的材质,比如不同的面或者不同的部分,再导出到Unity3d的时候就会产生submesh。原则是使用同一个材质的面会组进同一个submesh。

Unity官方的说法是(官方文档的Mesh.trangles):

Mesh.trangles:
这个数组包含了网格(mesh)中的所有的三角形。

这个数组是一系列索引到顶点数组(vertex array)的值。这个三角形数组里面元素的数量必定是3的倍数(3个顶点组成一个三角形)。顶点可以通过索引值来共享。如果网格包含了多个子网格(sub-mesh)或者材质,那么三角形数组会包含所有的属于子网格的三角形。

如果是原来没有submesh的模型,在Unity中你可以用
Mesh.subMeshCount、Mesh.setTriangles组合去设置同样的效果,当然,同时你需要给每个subMesh一个自己的材质。这个可以通过Renderer的materials来实现。

Unity官方说法(Mesh.SetTriangles)

子网格代表了一系列使用同一个材质的三角形。当一个网格被用在带多个材质(material)的Renderer组件上的时候,你必须保证每个子网格都对应一个材质。

在babylon.js里面,同样有类似的理念:

https://doc.babylonjs.com/how_to/multi_materials


化石原创文章,转载请注明来源并保留原文链接



化石原创文章,转载请注明来源并保留原文链接


这个是即使看了维基上的图文解释,也不容易搞清楚的概念。但是拿出代码实现来看,就非常清楚。

所谓Column-major,即在连续的内存中,表现的元素是列-连续的。而Row-major,则是行-连续的。维基上用二维数组来解释这个概念,在我看来反而让人混淆。其实用一维看这个问题更清楚。

比如,如下矩阵,在数学书上这么表示:

Row-major matrix AND Column-major

图是借来的,带红色线的是Row-major,湖蓝的是Column-major。去除线两个矩阵其实是一样的。那什么导致了它们会有所谓的,Row-major和Column-major差异?

答案是:在程序里存储的连续性方式。

现在把上面的两个矩阵在你心里抹去那些线,两个矩阵就是同一个矩阵。我们在写代码的时候,必须就这个形式上矩阵元素做存储,我这里以javascript代码做演示:

function Matrix3(a11, a21, a31,
                 a12, a22, a32,
                 a13, a23, a33) {

     //column major
     this[0] = a11 || 0.0;
     this[1] = a21 || 0.0;
     this[2] = a31 || 0.0;
     this[3] = a12 || 0.0;
     this[4] = a22 || 0.0;
     this[5] = a32 || 0.0;
     this[6] = a13 || 0.0;
     this[7] = a23 || 0.0;
     this[8] = a33 || 0.0;
}

上面的代码中,类Matrix3的构造,存储9个参数带进来的元素。由this的下标0、1、2、3、4、5、6、7、8连续着看,我们是按照先“列”、再“行”的方式进行整个过程。这个就叫Column-major。 回到上面的图,正好是我们的湖蓝色线的走向。

参数命名好的话就是这样:

function Matrix3(column0Row0, column0Row1, column0Row2,
                 column1Row0, column1Row1, column1Row2,
                 column2Row0, column2Row1, column2Row2) {

     //column major
     this[0] = column0Row0 || 0.0;
     this[1] = column0Row1 || 0.0;
     this[2] = column0Row2 || 0.0;
     this[3] = column1Row0 || 0.0;
     this[4] = column1Row1 || 0.0;
     this[5] = column1Row2 || 0.0;
     this[6] = column2Row0 || 0.0;
     this[7] = column2Row1 || 0.0;
     this[8] = column2Row2 || 0.0;
}

那么很显然,Row-major写法的话,就是让0到7的元素以红色线的顺序存储既是。这里我就不贴代码了。

如果是现实中加入了translation的矩阵,则

OpenGL标准中说到(下文第2段,黑体):

For programming purposes, OpenGL matrices are 16-value arrays with base vectors laid out contiguously in memory. The translation components occupy the 13th, 14th, and 15th elements of the 16-element matrix, where indices are numbered from 1 to 16 as described in section 2.11.2 of the OpenGL 2.1 Specification.

Column-major versus row-major is purely a notational convention. Note that post-multiplying with column-major matrices produces the same result as pre-multiplying with row-major matrices. The OpenGL Specification and the OpenGL Reference Manual both use column-major notation. You can use any notation, as long as it's clearly stated.

Sadly, the use of column-major format in the spec and blue book has resulted in endless confusion in the OpenGL programming community. Column-major notation suggests that matrices are not laid out in memory as a programmer would expect. 

出处:  https://www.opengl.org/archives/resources/faq/technical/transformations.htm 

第一段(斜体,特别是黑色)中OpenGL标准定义,一个4×4的矩阵-包含了16个元素,作为translation的x、y、z应该放在第13,14,15位置(正整数,以1位起始)。

在OpenGL的很多地方,可以看到纸面的表述,矩阵如下:

1 0 0 x
0 1 0 y
0 0 1 z
0 0 0 0

但是在内存中,其实它是如下存放(先摆行里的元素,也就是先第一行,再第二行):

[1, 0, 0, 0,
 0, 1, 0, 0,
 0, 0, 1, 0,
 x, y, z, 0]

所以,OpenGL标准里说的矩阵都是“Column-major”。

所以,如果写自己的矩阵库,概念(名称)重要,重要的是要符合OpenGL的标准:连续的内存中,13、14、15个元素是translation的x、y、z。


化石原创文章,转载请注明来源并保留原文链接



化石原创文章,转载请注明来源并保留原文链接


这一篇是WebGL的HelloWorld,代码能在指定的画布上画出同一种颜色。代码尽量少。只是为了make your hand dirty。

代码效果如下(如我们在前面说过的,WordPress可以嵌入自定义的WebGL代码,所以这里是实时的WebGL输出):

 

在wordPress后台加入的代码如下,这里的mycanvas定死了是400×320,因为考虑到文章本身的区域不是很大。

<canvas id="mycanvas" width="400" height="320"></canvas> 
<script>
   var canvas = document.getElementById('mycanvas');
   var gl = canvas.getContext('experimental-webgl');
   gl.clearColor(0.9, 0.5, 0.3, 1);
   gl.clear(gl.COLOR_BUFFER_BIT);
</script>

如果要在浏览器里“全屏”显示,那么我们需要让canvs占据整个body的空间。所以可以用如下方式:

<html>
   <head>
   </head>
   <body>
      <canvas id = "mycanvas"></canvas>
   </body>
   <script>
       var canvas = document.getElementById('mycanvas');
       canvas.width = document.body.clientWidth;
       canvas.height = document.body.clientHeight;
       var gl = canvas.getContext('experimental-webgl');
       gl.clearColor(0.9, 0.5, 0.3, 1);
       gl.clear(gl.COLOR_BUFFER_BIT);
   </script>
</html>

默认情况下,如果你跑动上面的代码,会发现即使浏览器放到最大,横向和竖向的滚动条都会出现。这个问题是我们的body的margin属性不是0(这是html的css的概念)。要想去除滚动条,需要这样:

<html>
   <head>
   </head>
   <body style="margin:0">
      <canvas id = "mycanvas"></canvas>
   </body>
   <script>
       var canvas = document.getElementById('mycanvas');
       canvas.width = document.body.clientWidth;
       canvas.height = document.body.clientHeight;
       var gl = canvas.getContext('experimental-webgl');
       gl.clearColor(0.9, 0.5, 0.3, 1);
       gl.clear(gl.COLOR_BUFFER_BIT);
   </script>
</html>

第4行里就是方式。

对于上面的WebGL,做了几件事情

1、第一个需要的就是要“画布”。这是第5行的canvas做的事情。

2、第二个,有了canvas以后,我们接着要拿的就是Context,通过这个Context,我们能引用到所有的WebGL可用的API和相关的属性。这是11行做的事情。

3、所以第11和第12行,我们就能通过context中的clearColor和clear方法真正让GPU做事了。第11行的方法,告诉WebGL“擦除”颜色现在被设置成为了(red,green、blue、alpha)组合。第12行则是执行“擦除”命令。命令执行的时候,会去查询我们刚刚设置的颜色。所以屏幕色彩就变成了我们看到的橘色。

注:

getContext()的参数可以是:
1、2d
2、webgl
3、webgl2
4、bitmaprenderer
5、experimental-webgl

化石原创文章,转载请注明来源并保留原文链接



化石原创文章,转载请注明来源并保留原文链接


为解释一套系统的菜单,客户使用了xmind制作了文档。按照传统做法,得用人工把这个xmind的图一点点的变成Unity里的东西,因为菜单有好多层,每层节点数量也不少。人工做起来工作量不小,所以花了点时间研究。

发现xmind可以到处xml的文档格式,那么问题就简单多了。只要写个通过xml构造出菜单树的类即可。这样客户随时改变意图,只要提交xmind的设计。我就能瞬间换好这个菜单。

做出的效果如下图:

Unity 演示 xml 菜单树

图中的Unity3d版本5.6。所有的菜单内容都是通过读取xml文件自动生成的。浏览的过程借助了我自己写的类。可以在文后的代码中得到。

要说明的是,客户在菜单内容中有&号,这个需要使用工具(自己写)或者手动改一下,在其后加入amp;。否则System.xml解析xml文件会错误。

工程源代码放在这里:

https://github.com/jycgame/Unity3dMenuTreeFromXml


化石原创文章,转载请注明来源并保留原文链接