前几天解决了原生WebGL开发中的一个问题,就是在一个场景中绘制多个几何网格特征不同的模型,比如本文所做的绘制多个圆锥和圆柱在同一个场景中,今天抽空把解决的办法记录下来,同时也附上代码。首先声明,圆柱和圆锥的网格生成是我自己写的polyhedron.js模块,如果要加载其他模型,只需要把geometry换成其他几何体的网格即可,本文的重点不在于使用什么几何模型,而在于如何将各种不同的模型绘制到同一个场景中去。

第一件事,我们还是先把依赖的模型生成的js文件贴出来,以便参考者能够将代码组装起来。首先看工程目录结构,如下图

该工程实际用到的文件就是这4个红框框出的文件,其中除了jquery-2.1.4.min.js以外(请于cdn或百度或51cto站点自行下载),剩下的minMatrix.js,polyhedron.js,testCoordinates.html本作都将贴出完整的源码,以便参考者本地调试。

首先贴出minMatrix.js源码,minMatrix.js负责向量矩阵的运算,由于不是本文的中心论点,故不做赘述,如下所示

  1. // ------------------------------------------------------------------------------------------------
  2. // minMatrix.js
  3. // version 0.0.1
  4. // Copyright (c) doxas
  5. // ------------------------------------------------------------------------------------------------
  6.  
  7. function matIV(){
  8. this.create = function(){
  9. return new Float32Array(16);
  10. };
  11. this.identity = function(dest){
  12. dest[0] = 1; dest[1] = 0; dest[2] = 0; dest[3] = 0;
  13. dest[4] = 0; dest[5] = 1; dest[6] = 0; dest[7] = 0;
  14. dest[8] = 0; dest[9] = 0; dest[10] = 1; dest[11] = 0;
  15. dest[12] = 0; dest[13] = 0; dest[14] = 0; dest[15] = 1;
  16. return dest;
  17. };
  18. this.multiply = function(mat1, mat2, dest){
  19. var a = mat1[0], b = mat1[1], c = mat1[2], d = mat1[3],
  20. e = mat1[4], f = mat1[5], g = mat1[6], h = mat1[7],
  21. i = mat1[8], j = mat1[9], k = mat1[10], l = mat1[11],
  22. m = mat1[12], n = mat1[13], o = mat1[14], p = mat1[15],
  23. A = mat2[0], B = mat2[1], C = mat2[2], D = mat2[3],
  24. E = mat2[4], F = mat2[5], G = mat2[6], H = mat2[7],
  25. I = mat2[8], J = mat2[9], K = mat2[10], L = mat2[11],
  26. M = mat2[12], N = mat2[13], O = mat2[14], P = mat2[15];
  27. dest[0] = A * a + B * e + C * i + D * m;
  28. dest[1] = A * b + B * f + C * j + D * n;
  29. dest[2] = A * c + B * g + C * k + D * o;
  30. dest[3] = A * d + B * h + C * l + D * p;
  31. dest[4] = E * a + F * e + G * i + H * m;
  32. dest[5] = E * b + F * f + G * j + H * n;
  33. dest[6] = E * c + F * g + G * k + H * o;
  34. dest[7] = E * d + F * h + G * l + H * p;
  35. dest[8] = I * a + J * e + K * i + L * m;
  36. dest[9] = I * b + J * f + K * j + L * n;
  37. dest[10] = I * c + J * g + K * k + L * o;
  38. dest[11] = I * d + J * h + K * l + L * p;
  39. dest[12] = M * a + N * e + O * i + P * m;
  40. dest[13] = M * b + N * f + O * j + P * n;
  41. dest[14] = M * c + N * g + O * k + P * o;
  42. dest[15] = M * d + N * h + O * l + P * p;
  43. return dest;
  44. };
  45. this.scale = function(mat, vec, dest){
  46. dest[0] = mat[0] * vec[0];
  47. dest[1] = mat[1] * vec[0];
  48. dest[2] = mat[2] * vec[0];
  49. dest[3] = mat[3] * vec[0];
  50. dest[4] = mat[4] * vec[1];
  51. dest[5] = mat[5] * vec[1];
  52. dest[6] = mat[6] * vec[1];
  53. dest[7] = mat[7] * vec[1];
  54. dest[8] = mat[8] * vec[2];
  55. dest[9] = mat[9] * vec[2];
  56. dest[10] = mat[10] * vec[2];
  57. dest[11] = mat[11] * vec[2];
  58. dest[12] = mat[12];
  59. dest[13] = mat[13];
  60. dest[14] = mat[14];
  61. dest[15] = mat[15];
  62. return dest;
  63. };
  64. this.translate = function(mat, vec, dest){
  65. dest[0] = mat[0]; dest[1] = mat[1]; dest[2] = mat[2]; dest[3] = mat[3];
  66. dest[4] = mat[4]; dest[5] = mat[5]; dest[6] = mat[6]; dest[7] = mat[7];
  67. dest[8] = mat[8]; dest[9] = mat[9]; dest[10] = mat[10]; dest[11] = mat[11];
  68. dest[12] = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2] + mat[12];
  69. dest[13] = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2] + mat[13];
  70. dest[14] = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2] + mat[14];
  71. dest[15] = mat[3] * vec[0] + mat[7] * vec[1] + mat[11] * vec[2] + mat[15];
  72. return dest;
  73. };
  74. this.rotate = function(mat, angle, axis, dest){
  75. var sq = Math.sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
  76. if(!sq){return null;}
  77. var a = axis[0], b = axis[1], c = axis[2];
  78. if(sq != 1){sq = 1 / sq; a *= sq; b *= sq; c *= sq;}
  79. var d = Math.sin(angle), e = Math.cos(angle), f = 1 - e,
  80. g = mat[0], h = mat[1], i = mat[2], j = mat[3],
  81. k = mat[4], l = mat[5], m = mat[6], n = mat[7],
  82. o = mat[8], p = mat[9], q = mat[10], r = mat[11],
  83. s = a * a * f + e,
  84. t = b * a * f + c * d,
  85. u = c * a * f - b * d,
  86. v = a * b * f - c * d,
  87. w = b * b * f + e,
  88. x = c * b * f + a * d,
  89. y = a * c * f + b * d,
  90. z = b * c * f - a * d,
  91. A = c * c * f + e;
  92. if(angle){
  93. if(mat != dest){
  94. dest[12] = mat[12]; dest[13] = mat[13];
  95. dest[14] = mat[14]; dest[15] = mat[15];
  96. }
  97. } else {
  98. dest = mat;
  99. }
  100. dest[0] = g * s + k * t + o * u;
  101. dest[1] = h * s + l * t + p * u;
  102. dest[2] = i * s + m * t + q * u;
  103. dest[3] = j * s + n * t + r * u;
  104. dest[4] = g * v + k * w + o * x;
  105. dest[5] = h * v + l * w + p * x;
  106. dest[6] = i * v + m * w + q * x;
  107. dest[7] = j * v + n * w + r * x;
  108. dest[8] = g * y + k * z + o * A;
  109. dest[9] = h * y + l * z + p * A;
  110. dest[10] = i * y + m * z + q * A;
  111. dest[11] = j * y + n * z + r * A;
  112. return dest;
  113. };
  114.  
  115. this.lookAt = function(eye, center, up, dest){
  116. var eyeX = eye[0], eyeY = eye[1], eyeZ = eye[2];
  117. var centerX = center[0], centerY = center[1], centerZ = center[2];
  118. var upX = up[0], upY = up[1], upZ = up[2];
  119.  
  120. if(eyeX == centerX && eyeY == centerY && eyeZ == centerZ){
  121. return this.identity(dest);
  122. }
  123.  
  124. var x0, x1, x2, y0, y1, y2, z0, z1, z2, l;
  125.  
  126. z0 = eyeX - centerX; z1 = eyeY - centerY; z2 = eyeZ - centerZ;
  127. l = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
  128. z0 *= l; z1 *= l; z2 *= l;
  129.  
  130. x0 = upY * z2 - upZ * z1; x1 = upZ * z0 - upX * z2; x2 = upX * z1 - upY * z0;
  131. l = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
  132. if(!l){
  133. x0 = 0; x1 = 0; x2 = 0;
  134. } else {
  135. l = 1 / l;
  136. x0 *= l; x1 *= l; x2 *= l;
  137. }
  138.  
  139. y0 = z1 * x2 - z2 * x1; y1 = z2 * x0 - z0 * x2; y2 = z0 * x1 - z1 * x0;
  140. l = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
  141. if(!l){
  142. y0 = 0; y1 = 0; y2 = 0;
  143. } else {
  144. l = 1 / l;
  145. y0 *= l; y1 *= l; y2 *= l;
  146. }
  147.  
  148. dest[0] = x0; dest[1] = y0; dest[2] = z0; dest[3] = 0;
  149. dest[4] = x1; dest[5] = y1; dest[6] = z1; dest[7] = 0;
  150. dest[8] = x2; dest[9] = y2; dest[10] = z2; dest[11] = 0;
  151. dest[12] = -(x0 * eyeX + x1 * eyeY + x2 * eyeZ);
  152. dest[13] = -(y0 * eyeX + y1 * eyeY + y2 * eyeZ);
  153. dest[14] = -(z0 * eyeX + z1 * eyeY + z2 * eyeZ);
  154. dest[15] = 1;
  155. return dest;
  156. };
  157.  
  158. this.view = function(eye, at, up, dest){
  159.  
  160. var forward = [];
  161. forward[0] = at[0] - eye[0];
  162. forward[1] = at[1] - eye[1];
  163. forward[2] = at[2] - eye[2];
  164. var l = Math.sqrt(forward[0]*forward[0] + forward[1]*forward[1] + forward[2]*forward[2]);
  165. forward[0] = forward[0]/l; forward[1] = forward[1]/l; forward[2] = forward[2]/l;
  166.  
  167. var side = [];
  168. side[0] = forward[2]*up[1] - up[2]*forward[1];
  169. side[1] = forward[0]*up[2] - up[0]*forward[2];
  170. side[2] = forward[1]*up[0] - up[1]*forward[0];
  171. l = Math.sqrt(side[0]*side[0] + side[1]*side[1] + side[2]*side[2]);
  172. side[0] = side[0]/l; side[1] = side[1]/l; side[2] = side[2]/l;
  173.  
  174. up[0] = side[2]*forward[1] - forward[2]*side[1];
  175. up[1] = side[0]*forward[2] - forward[0]*side[2];
  176. up[2] = side[1]*forward[0] - forward[1]*side[0];
  177.  
  178. var dest = [];
  179. dest[0] = side[0]; dest[1] = up[0]; dest[2] = -forward[0]; dest[3] = 0;
  180. dest[4] = side[1]; dest[5] = up[1]; dest[6] = -forward[1]; dest[7] = 0;
  181. dest[8] = side[2]; dest[9] = up[2]; dest[10]= -forward[2]; dest[11]= 0;
  182. dest[12]= 0; dest[13]= 0; dest[14]= 0; dest[15]= 1;
  183.  
  184. dest[0] = dest[0]; dest[1] = dest[1]; dest[2] = dest[2]; dest[3] = dest[3];
  185. dest[4] = dest[4]; dest[5] = dest[5]; dest[6] = dest[6]; dest[7] = dest[7];
  186. dest[8] = dest[8]; dest[9] = dest[9]; dest[10] = dest[10]; dest[11] = dest[11];
  187. dest[12] = dest[0] * (-eye[0]) + dest[4] * (-eye[1]) + dest[8] * (-eye[2]) + dest[12];
  188. dest[13] = dest[1] * (-eye[0]) + dest[5] * (-eye[1]) + dest[9] * (-eye[2]) + dest[13];
  189. dest[14] = dest[2] * (-eye[0]) + dest[6] * (-eye[1]) + dest[10] * (-eye[2]) + dest[14];
  190. dest[15] = dest[3] * (-eye[0]) + dest[7] * (-eye[1]) + dest[11] * (-eye[2]) + dest[15];
  191.  
  192. return dest;
  193. }
  194.  
  195. /**
  196. * 正交投影
  197. */
  198. this.ortho = function(left, right, bottom, top, near, far, dest){
  199.  
  200. var a = 2/(right-left);
  201. var b = -(right+left)/(right-left);
  202. var c = 2/(top-bottom);
  203. var d = -(top+bottom)/(top-bottom);
  204. var e = 2/(far-near);
  205. var f = -(far+near)/(far-near);
  206.  
  207. dest[0] = a; dest[1] = 0; dest[2] = 0; dest[3] = b;
  208. dest[4] = 0; dest[5] = c; dest[6] = 0; dest[7] = d;
  209. dest[8] = 0; dest[9] = 0; dest[10]= e; dest[11]= f;
  210. dest[12]= 0; dest[13]= 0; dest[14]= 0; dest[15]= 1;
  211.  
  212. return dest;
  213. }
  214.  
  215. /**
  216. * 透视投影
  217. */
  218. this.perspective = function(fovy, aspect, near, far, dest){
  219. var t = near * Math.tan(fovy * Math.PI / 360);
  220. var r = t * aspect;
  221. var a = r * 2, b = t * 2, c = far - near;
  222. dest[0] = near * 2 / a;
  223. dest[1] = 0;
  224. dest[2] = 0;
  225. dest[3] = 0;
  226. dest[4] = 0;
  227. dest[5] = near * 2 / b;
  228. dest[6] = 0;
  229. dest[7] = 0;
  230. dest[8] = 0;
  231. dest[9] = 0;
  232. dest[10] = -(far + near) / c;
  233. dest[11] = -1;
  234. dest[12] = 0;
  235. dest[13] = 0;
  236. dest[14] = -(far * near * 2) / c;
  237. dest[15] = 0;
  238. return dest;
  239. };
  240. this.transpose = function(mat, dest){
  241. dest[0] = mat[0]; dest[1] = mat[4];
  242. dest[2] = mat[8]; dest[3] = mat[12];
  243. dest[4] = mat[1]; dest[5] = mat[5];
  244. dest[6] = mat[9]; dest[7] = mat[13];
  245. dest[8] = mat[2]; dest[9] = mat[6];
  246. dest[10] = mat[10]; dest[11] = mat[14];
  247. dest[12] = mat[3]; dest[13] = mat[7];
  248. dest[14] = mat[11]; dest[15] = mat[15];
  249. return dest;
  250. };
  251. this.inverse = function(mat, dest){
  252. var a = mat[0], b = mat[1], c = mat[2], d = mat[3],
  253. e = mat[4], f = mat[5], g = mat[6], h = mat[7],
  254. i = mat[8], j = mat[9], k = mat[10], l = mat[11],
  255. m = mat[12], n = mat[13], o = mat[14], p = mat[15],
  256. q = a * f - b * e, r = a * g - c * e,
  257. s = a * h - d * e, t = b * g - c * f,
  258. u = b * h - d * f, v = c * h - d * g,
  259. w = i * n - j * m, x = i * o - k * m,
  260. y = i * p - l * m, z = j * o - k * n,
  261. A = j * p - l * n, B = k * p - l * o,
  262. ivd = 1 / (q * B - r * A + s * z + t * y - u * x + v * w);
  263. dest[0] = ( f * B - g * A + h * z) * ivd;
  264. dest[1] = (-b * B + c * A - d * z) * ivd;
  265. dest[2] = ( n * v - o * u + p * t) * ivd;
  266. dest[3] = (-j * v + k * u - l * t) * ivd;
  267. dest[4] = (-e * B + g * y - h * x) * ivd;
  268. dest[5] = ( a * B - c * y + d * x) * ivd;
  269. dest[6] = (-m * v + o * s - p * r) * ivd;
  270. dest[7] = ( i * v - k * s + l * r) * ivd;
  271. dest[8] = ( e * A - f * y + h * w) * ivd;
  272. dest[9] = (-a * A + b * y - d * w) * ivd;
  273. dest[10] = ( m * u - n * s + p * q) * ivd;
  274. dest[11] = (-i * u + j * s - l * q) * ivd;
  275. dest[12] = (-e * z + f * x - g * w) * ivd;
  276. dest[13] = ( a * z - b * x + c * w) * ivd;
  277. dest[14] = (-m * t + n * r - o * q) * ivd;
  278. dest[15] = ( i * t - j * r + k * q) * ivd;
  279. return dest;
  280. };
  281. this.rotateByAnyAxis = function(RawMat, axis, rad, destMat){
  282.  
  283. };
  284. }

接下来就要贴出几何体生成工具 polyhedron.js,我们用到的几何体是其中的圆锥 coneGeo和圆柱 cylinderGeo,这两个类都是PolyhedronGeometry的子类,几何体都包含顶点成员this.vertices,法向成员this.normals,索引成员this.faces。具体构造详见代码如下

  1. /**
  2. * Created by ccentry on 2018/10/15.
  3. */
  4.  
  5. /**
  6. * 圆锥
  7. * radius:底面半径
  8. * height:圆锥高度
  9. * meshDensity:网格密度
  10. * */
  11. var coneGeo = function(radius, height, segment){
  12. //锥顶
  13. var top = [0, height, 0];
  14. //锥底,锥底半径radius
  15. //根据segment来切割锥底圆
  16. var sliceNum = segment || 3;
  17. var rad = Math.PI*2/sliceNum;
  18. var bottom = [];
  19. for(var i=0; i<sliceNum; i++){
  20. bottom[i*3] = radius*Math.cos(rad*i);
  21. bottom[i*3 + 1] = 0;
  22. bottom[i*3 + 2] = radius*Math.sin(rad*i);
  23. }
  24. //圆锥的顶点
  25. this.vertices = [];
  26. //顶点法向
  27. this.normals = [];
  28. //锥顶
  29. for(var i=0; i<sliceNum; i++){
  30. this.vertices[i*3] = top[0];
  31. this.vertices[i*3+1] = top[1];
  32. this.vertices[i*3+2] = top[2];
  33. }
  34. //锥面圆环
  35. for(var i=0; i<bottom.length; i++){
  36. this.vertices[3*sliceNum+i] = bottom[i];
  37. }
  38. //锥底圆环
  39. for(var i=0; i<bottom.length; i++){
  40. this.vertices[2*3*sliceNum+i] = bottom[i];
  41. }
  42. //锥底圆心
  43. this.vertices.push(0, 0, 0);
  44. //圆锥面索引
  45. this.faces = [];
  46. for(var i=sliceNum; i<2*sliceNum-1; i++){
  47. //圆锥侧面
  48. this.faces.push(i, i-sliceNum, i+1);
  49. //圆锥底面
  50. this.faces.push(3*sliceNum, sliceNum+i, sliceNum+i+1);
  51. }
  52. //补侧面
  53. this.faces.push(2*sliceNum-1, sliceNum-1, sliceNum);
  54. //补底面
  55. this.faces.push(3*sliceNum, 3*sliceNum-1, 2*sliceNum);
  56. //计算所有顶点法向
  57. this.computeNormal4EachVertex();
  58. };
  59.  
  60. /**
  61. * 圆柱
  62. * radius:底面半径
  63. * height:圆柱高度
  64. * meshDensity:网格密度
  65. * */
  66. var cylinderGeo = function(radius, height, segment){
  67. radius = radius || 1;
  68. height = height || 1;
  69. //根据网格密度来切割圆柱体底圆
  70. var sliceNum = segment || 3;
  71. //底面圆弧度
  72. var rad = Math.PI*2/sliceNum;
  73. //底面圆环顶点
  74. var bottomVertices = [];
  75. //顶面顶点
  76. var topVertices = [];
  77. //切割底面圆和底面圆
  78. for(var i=0; i<sliceNum; i++){
  79. bottomVertices[3*i] = radius * Math.cos(rad * i);
  80. bottomVertices[3*i+1] = 0;
  81. bottomVertices[3*i+2] = radius * Math.sin(rad * i);
  82.  
  83. topVertices[3*i] = radius * Math.cos(rad * i);
  84. topVertices[3*i+1] = height;
  85. topVertices[3*i+2] = radius * Math.sin(rad * i);
  86. }
  87. //圆柱的顶点
  88. this.vertices = [];
  89. for(var i=0; i<bottomVertices.length; i++){
  90. //底面圆
  91. this.vertices[i] = bottomVertices[i];
  92. //顶面圆
  93. this.vertices[bottomVertices.length + i] = topVertices[i];
  94. //柱底圈
  95. this.vertices[2*bottomVertices.length + i] = bottomVertices[i];
  96. //柱顶圈
  97. this.vertices[3*bottomVertices.length + i] = topVertices[i];
  98. }
  99. //底面圆心;
  100. this.vertices.push(0, 0, 0);
  101. //顶面圆心
  102. this.vertices.push(0, height, 0);
  103. //圆柱的面
  104. this.faces = [];
  105. for(var i=0; i<sliceNum-1; i++){
  106. //底面圆
  107. this.faces.push(4*sliceNum, i, i+1);
  108. //顶面圆
  109. this.faces.push(4*sliceNum+1, sliceNum+i+1, sliceNum+i);
  110. //柱身
  111. this.faces.push(2*sliceNum+i, 3*sliceNum+i, 2*sliceNum+i+1);
  112. this.faces.push(3*sliceNum+i, 3*sliceNum+i+1, 2*sliceNum+i+1);
  113. }
  114. //补底面圆
  115. this.faces.push(4*sliceNum, sliceNum-1, 0);
  116. //补顶面圆
  117. this.faces.push(4*sliceNum+1, sliceNum, 2*sliceNum-1);
  118. //补柱身
  119. this.faces.push(3*sliceNum-1, 4*sliceNum-1, 2*sliceNum);
  120. this.faces.push(4*sliceNum-1, 3*sliceNum, 2*sliceNum);
  121. //顶点法向
  122. this.normals = [];
  123. //计算所有顶点法向
  124. this.computeNormal4EachVertex();
  125. };
  126.  
  127. /**
  128. * 球体
  129. * radius:球体半径
  130. * meshDensity:网格密度
  131. * */
  132. var sphereGeo = function(radius, widthSegments, heightSegments){
  133. var phiStart = 0;
  134. var phiLength = Math.PI * 2;
  135. var thetaStart = 0;
  136. var thetaLength = Math.PI;
  137. var thetaEnd = thetaStart + thetaLength;
  138. var ix, iy;
  139. var index = 0;
  140. var grid = [];
  141. var vertex = {};
  142. var normal = {};
  143. //存储
  144. var indices = [];
  145. var vertices = [];
  146. var normals = [];
  147. var uvs = [];
  148. //生成顶点,法向,uv
  149. for ( iy = 0; iy <= heightSegments; iy ++ ) {
  150. var verticesRow = [];
  151. var v = iy / heightSegments;
  152. for ( ix = 0; ix <= widthSegments; ix ++ ) {
  153. var u = ix / widthSegments;
  154. //顶点
  155. vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
  156. vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
  157. vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
  158. vertices.push( vertex.x, vertex.y, vertex.z );
  159. //法向
  160. normal.x = vertex.x; normal.y = vertex.y; normal.z = vertex.z;
  161. //单位化
  162. this.normalize([normal.x, normal.y, normal.z]);
  163. normals.push( normal.x, normal.y, normal.z );
  164. //uv
  165. uvs.push( u, 1 - v );
  166. verticesRow.push( index ++ );
  167. }
  168. grid.push( verticesRow );
  169. }
  170. //索引数组
  171. for ( iy = 0; iy < heightSegments; iy ++ ) {
  172. for ( ix = 0; ix < widthSegments; ix ++ ) {
  173. var a = grid[ iy ][ ix + 1 ];
  174. var b = grid[ iy ][ ix ];
  175. var c = grid[ iy + 1 ][ ix ];
  176. var d = grid[ iy + 1 ][ ix + 1 ];
  177. if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
  178. if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
  179. }
  180. }
  181. //构造geometry
  182. this.faces = indices;
  183. this.vertices = vertices;
  184. this.normals = normals;
  185. //this.uv = uvs;
  186. };
  187.  
  188. var cubeGeo = function(width, height, depth){
  189. this.vertices = [];
  190. this.faces = [];
  191. var bottom = [];
  192. bottom[0] = [width/2, 0, depth/2];
  193. bottom[1] = [-width/2, 0, depth/2];
  194. bottom[2] = [-width/2, 0, -depth/2];
  195. bottom[3] = [width/2, 0, -depth/2];
  196. var top = [];
  197. top[0] = [width/2, height, depth/2];
  198. top[1] = [-width/2, height, depth/2];
  199. top[2] = [-width/2, height, -depth/2];
  200. top[3] = [width/2, height, -depth/2];
  201. for(var i=0; i<4; i++){
  202. for(var j=0; j<3; j++){
  203. this.vertices.push(bottom[i][j]);
  204. }
  205. }
  206. for(var i=0; i<4; i++){
  207. for(var j=0; j<3; j++){
  208. this.vertices.push(top[i][j]);
  209. }
  210. }
  211. for(var i=0; i<3; i++){
  212. this.faces.push(i, i+4, i+1);
  213. this.faces.push(i+4, i+5, i+1);
  214. }
  215. //补面
  216. this.faces.push(3, 7, 0);
  217. this.faces.push(7, 4, 0);
  218. //补底面
  219. this.faces.push(0, 1, 2, 2, 3, 0);
  220. //补底面
  221. this.faces.push(4, 7, 6, 6, 5, 4);
  222. };
  223.  
  224. var PolyhedronGeometry = function(){
  225. this.type = "PolyhedronGeometry";
  226. };
  227.  
  228. PolyhedronGeometry.prototype = {
  229. //坐标单位话
  230. normalize : function(arr){
  231. if(arr instanceof Array){
  232. var sum = 0;
  233. for(var i=0; i<arr.length; i++){
  234. sum += arr[i]*arr[i];
  235. }
  236. for(var i=0; i<arr.length; i++){
  237. arr[i] = arr[i]/sum;
  238. }
  239. }
  240. },
  241. //计算顶点法向
  242. computeVertexNormal: function(face3){
  243. //顶点逆时针绕向
  244. //向量v1-v0
  245. var v1_0 = {};
  246. v1_0.x = face3[1][0] - face3[0][0];
  247. v1_0.y = face3[1][1] - face3[0][1];
  248. v1_0.z = face3[1][2] - face3[0][2];
  249. //向量v2-v1
  250. var v2_1 = {};
  251. v2_1.x = face3[2][0] - face3[1][0];
  252. v2_1.y = face3[2][1] - face3[1][1];
  253. v2_1.z = face3[2][2] - face3[1][2];
  254. //v1_0 叉乘 v2_1
  255. var normal = {};
  256. normal.x = v1_0.y * v2_1.z - v2_1.y * v1_0.z;
  257. normal.y = v1_0.z * v2_1.x - v2_1.z * v1_0.x;
  258. normal.z = v1_0.x * v2_1.y - v2_1.x * v1_0.y;
  259. var normalArray = [normal.x, normal.y, normal.z];
  260. this.normalize(normalArray);
  261. return normalArray;
  262. },
  263. computeNormal4EachVertex:function(){
  264. //遍历索引,通过hash插值构造normals数组
  265. var normalList = [];
  266. for(var i=0; i<this.faces.length; i=i+3){
  267. //顶点索引
  268. var vertex0 = this.faces[i];
  269. var vertex1 = this.faces[i+1];
  270. var vertex2 = this.faces[i+2];
  271. //顶点
  272. var v0 = [this.vertices[3*vertex0], this.vertices[3*vertex0+1], this.vertices[3*vertex0+2]];
  273. var v1 = [this.vertices[3*vertex1], this.vertices[3*vertex1+1], this.vertices[3*vertex1+2]];
  274. var v2 = [this.vertices[3*vertex2], this.vertices[3*vertex2+1], this.vertices[3*vertex2+2]];
  275. //取出索引指向的顶点坐标
  276. var face3 = [v0, v1, v2];
  277. var normalArray = this.computeVertexNormal(face3);
  278. var normal0 = {index:vertex0, normal:normalArray};
  279. var normal1 = {index:vertex1, normal:normalArray};
  280. var normal2 = {index:vertex2, normal:normalArray};
  281. normalList.push(normal0, normal1, normal2);
  282. }
  283. //根据index属性排序
  284. var sortedNormalList = [];
  285. var total = normalList.length;
  286. for(var i=0; i<total; i++){
  287. for(var j=0; j<normalList.length; j++){
  288. if(normalList[j].index === i){
  289. sortedNormalList[i] = {index:normalList[j].index, normal:normalList[j].normal};
  290. //删掉该normal节点
  291. normalList.splice(j, 1);
  292. break;
  293. }
  294. }
  295. }
  296. for(var i=0; i<sortedNormalList.length; i++){
  297. var normal = sortedNormalList[i].normal;
  298. this.normals.push(normal[0], normal[1], normal[2]);
  299. }
  300. }
  301. };
  302.  
  303. coneGeo.prototype = new PolyhedronGeometry();
  304. cylinderGeo.prototype = new PolyhedronGeometry();
  305. sphereGeo.prototype = new PolyhedronGeometry();
  306. cubeGeo.prototype = new PolyhedronGeometry();

以上就是几何体的构造函数,我们的圆锥和圆柱即将由此生成。接下来进入我们今天的重点,如何将多个圆锥圆柱绘制进一个场景中去,直接上html代码,场景代码如下

  1. <html>
  2. <head>
  3. <meta http-equiv="content-type" content="text/html; charset=gb2312">
  4. <script type="text/JavaScript" src="minMatrix.js"></script>
  5. <script type="text/JavaScript" src="jquery-2.1.4.min.js"></script>
  6. <script type="text/javascript" src="polyhedron.js"></script>
  7.  
  8. <script id="vs" type="x-shader/x-vertex">
  9. attribute vec3 position;
  10. attribute vec3 normal;
  11. attribute vec4 color;
  12. uniform mat4 mvpMatrix;
  13. uniform mat4 invMatrix;
  14. uniform vec3 lightDirection;
  15. uniform vec4 ambientColor;
  16. varying vec4 vColor;
  17. uniform float lightS;
  18.  
  19. void main(void){
  20. vec3 invLight = normalize(invMatrix * vec4(lightDirection, 0)).xyz;
  21. float diffuse = clamp(dot(normal, invLight), 0.0, 1.0) * lightS;
  22. vColor = color * vec4(vec3(diffuse), 1.0) + ambientColor;
  23. gl_Position = mvpMatrix * vec4(position, 1.0);
  24. }
  25. </script>
  26.  
  27. <script id="fs" type="x-shader/x-fragment">
  28. precision mediump float;
  29. varying vec4 vColor;
  30. void main(void){
  31. gl_FragColor = vColor;
  32. }
  33. </script>
  34.  
  35. <script>
  36. onload = function(){
  37. // canvas对象获取
  38. var c = document.getElementById('canvas');
  39. c.width = 1000;
  40. c.height = 800;
  41.  
  42. // webgl的context获取
  43. var gl = c.getContext('webgl') || c.getContext('experimental-webgl');
  44. //初始化gl
  45. initGL(gl);
  46. // 顶点着色器和片段着色器的生成
  47. var v_shader = create_shader('vs');
  48. var f_shader = create_shader('fs');
  49. // 程序对象的生成和连接
  50. var prg = create_program(v_shader, f_shader);
  51.  
  52. // attributeLocation的获取
  53. var attLocation = new Array(2);
  54. attLocation[0] = gl.getAttribLocation(prg, 'position');
  55. attLocation[1] = gl.getAttribLocation(prg, 'normal');
  56. attLocation[2] = gl.getAttribLocation(prg, 'color');
  57.  
  58. // 将元素数attribute保存到数组中
  59. var attStride = new Array(2);
  60. attStride[0] = 3;
  61. attStride[1] = 3;
  62. attStride[2] = 4;
  63.  
  64. /**
  65. * 光
  66. * */
  67. // 环境光,漫反射光
  68. var ambientColor = [0.2, 0.2, 0.2, 1.0];
  69. // 光照强度
  70. var lightS = 1.6;
  71. // 平行光源的方向
  72. var lightDirection = [1, 1, 1];
  73.  
  74. /**
  75. * 视图矩阵
  76. */
  77. // matIV对象生成
  78. var m = new matIV();
  79. // 画布的宽高比
  80. var aspect = c.width / c.height;
  81. var mMatrix = m.identity(m.create());
  82. var invMatrix = m.identity(m.create());
  83. var tmpMatrix = m.identity(m.create());
  84. var mvpMatrix = m.identity(m.create());
  85. // 将视图矩阵根据宽高比进行反比,避免X/Y平面内出现变形
  86. tmpMatrix[0] = 1/aspect;
  87. // 得到mvpMatrix定位坐标矩阵
  88. //m.multiply(tmpMatrix, mMatrix, mvpMatrix);
  89. // mMatrix的逆矩阵
  90. //m.inverse(mMatrix, invMatrix);
  91.  
  92. /**
  93. * 绑定shader的uniform
  94. * */
  95. // 取得uniformLocation
  96. var uniLocation = new Array();
  97. uniLocation[0] = gl.getUniformLocation(prg, 'mvpMatrix');
  98. uniLocation[1] = gl.getUniformLocation(prg, 'invMatrix');
  99. uniLocation[2] = gl.getUniformLocation(prg, 'lightDirection');
  100. uniLocation[3] = gl.getUniformLocation(prg, 'ambientColor');
  101. uniLocation[4] = gl.getUniformLocation(prg, 'lightS');
  102. // 向uniformLocation中传入坐标变换矩阵
  103. gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
  104. gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
  105. gl.uniform3fv(uniLocation[2], lightDirection);
  106. gl.uniform4fv(uniLocation[3], ambientColor);
  107. gl.uniform1f(uniLocation[4], lightS);
  108.  
  109. //绘制坐标系
  110. drawCoordinates(0, 1, 0, 0);
  111.  
  112. // 清理gl
  113. gl.flush();
  114.  
  115. /**
  116. * 交互
  117. * */
  118.  
  119. //判断是否鼠标左键按下
  120. var mouseLeftKeyDown = false;
  121. //判断是否鼠标右键按下
  122. var mouseRightKeyDown = false;
  123. //标记鼠标x坐标
  124. var mouseX;
  125. //标记鼠标y坐标
  126. var mouseY;
  127. //标记鼠标z坐标
  128. var mouseZ;
  129. //旋转球的半径
  130. var R = 250;
  131.  
  132. $('#canvas').mousedown(function(e){
  133.  
  134. var inCircle = false;
  135.  
  136. if(e.which == 1){
  137. mouseLeftKeyDown = true;
  138. mouseRightKeyDown = false;
  139.  
  140. mouseX = e.clientX - 0.5*c.width;
  141. mouseY = -(e.clientY - 0.5*c.height);
  142. if(R*R - mouseX*mouseX - mouseY*mouseY > 0){
  143. mouseZ = Math.sqrt(R*R - mouseX*mouseX - mouseY*mouseY);
  144. } else {
  145. mouseLeftKeyDown = false;
  146. }
  147.  
  148. //转动前向量坐标
  149. $('#cordX').val(mouseX);
  150. $('#cordY').val(mouseY);
  151. $('#cordZ').val(mouseZ);
  152.  
  153. } else if(e.which == 3){
  154. mouseRightKeyDown = true;
  155. mouseLeftKeyDown = false;
  156. }
  157. });
  158.  
  159. $('#canvas').mouseup(function(e){
  160. if(e.which == 1){
  161. mouseLeftKeyDown = false;
  162. } else if(e.which == 3){
  163. mouseRightKeyDown = false;
  164. }
  165. });
  166.  
  167. $('#canvas').mouseout(function(e){
  168. mouseLeftKeyDown = false;
  169. mouseRightKeyDown = false;
  170. });
  171.  
  172. $('#canvas').mousemove(function(e){
  173. if(mouseLeftKeyDown){//鼠标左键按下
  174.  
  175. var X_1 = e.clientX - 0.5*c.width;
  176. var Y_1 = -(e.clientY - 0.5*c.height);
  177. if(R*R - X_1*X_1 - Y_1*Y_1 > 0){
  178. var Z_1 = Math.sqrt(R*R - X_1*X_1 - Y_1*Y_1);
  179. } else {
  180. mouseLeftKeyDown = false;
  181. }
  182.  
  183. //转动前向量坐标
  184. $('#cordX').val(mouseX);
  185. $('#cordY').val(mouseY);
  186. $('#cordZ').val(mouseZ);
  187.  
  188. //转动后向量坐标
  189. $('#cordX1').val(X_1);
  190. $('#cordY1').val(Y_1);
  191. $('#cordZ1').val(Z_1);
  192.  
  193. //先算出转动轴向量
  194. var axisX = -(Z_1*mouseY-mouseZ*Y_1);
  195. var axisY = -(X_1*mouseZ-mouseX*Z_1);
  196. var axisZ = +(Y_1*mouseX-mouseY*X_1);
  197. //轴向量单位化
  198. var mod_axis = Math.sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);
  199. axisX = axisX/mod_axis;
  200. axisY = axisY/mod_axis;
  201. axisZ = axisZ/mod_axis;
  202.  
  203. var a1 = mMatrix[0]*axisX + mMatrix[1]*axisY + mMatrix[2]*axisZ + mMatrix[3]*0;
  204. var a2 = mMatrix[4]*axisX + mMatrix[5]*axisY + mMatrix[6]*axisZ + mMatrix[7]*0;
  205. var a3 = mMatrix[8]*axisX + mMatrix[9]*axisY + mMatrix[10]*axisZ + mMatrix[11]*0;
  206. var a4 = mMatrix[12]*axisX + mMatrix[13]*axisY + mMatrix[14]*axisZ + mMatrix[15]*0;
  207.  
  208. axisX = a1;
  209. axisY = a2;
  210. axisZ = a3;
  211. //轴向量单位化
  212. mod_axis = Math.sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);
  213. axisX = axisX/mod_axis;
  214. axisY = axisY/mod_axis;
  215. axisZ = axisZ/mod_axis;
  216.  
  217. //法向坐标
  218. $('#axisX').val(axisX);
  219. $('#axisY').val(axisY);
  220. $('#axisZ').val(axisZ);
  221.  
  222. //计算转轴向量和转前向量的点积
  223. $('#00').val(axisX*mouseX + axisY*mouseY + axisZ*mouseZ);
  224. //计算转轴向量和转后向量的点积
  225. $('#01').val(axisX*X_1 + axisY*Y_1 + axisZ*Z_1);
  226.  
  227. //再计算转动角弧度
  228. //a=(x1,y1,z1),b=(x2,y2,z2) a*b=x1x2+y1y2+z1z2 |a|=√(x1^2+y1^2+z1^2).|b|=√(x2^2+y2^2+z2^2)
  229. //cosθ=a*b/(|a|*|b|) 角θ=arccosθ
  230. //Math.acos(x) 反余弦函数
  231. var ab = X_1*mouseX + Y_1*mouseY + Z_1*mouseZ;
  232. var mod_a = Math.sqrt(X_1*X_1 + Y_1*Y_1 + Z_1*Z_1);
  233. var mod_b = Math.sqrt(mouseX*mouseX + mouseY*mouseY + mouseZ*mouseZ);
  234. var cosθ = ab/(mod_a*mod_b);
  235. var rad = Math.acos(cosθ);
  236.  
  237. //转角弧度
  238. $('#rad').val(rad);
  239.  
  240. rotateModel(axisX, axisY, axisZ, rad);
  241.  
  242. mouseX = X_1;
  243. mouseY = Y_1;
  244. mouseZ = Z_1;
  245.  
  246. }
  247. });
  248.  
  249. $('#rotate').click(function(){
  250. var axisX = $('.axisX').val();
  251. var axisY = $('.axisY').val();
  252. var axisZ = $('.axisZ').val();
  253. var rad = $('.rad').val();
  254. rad = rad * Math.PI / 180;
  255.  
  256. var a1 = mMatrix[0]*axisX + mMatrix[1]*axisY + mMatrix[2]*axisZ + mMatrix[3]*0;
  257. var a2 = mMatrix[4]*axisX + mMatrix[5]*axisY + mMatrix[6]*axisZ + mMatrix[7]*0;
  258. var a3 = mMatrix[8]*axisX + mMatrix[9]*axisY + mMatrix[10]*axisZ + mMatrix[11]*0;
  259. var a4 = mMatrix[12]*axisX + mMatrix[13]*axisY + mMatrix[14]*axisZ + mMatrix[15]*0;
  260.  
  261. axisX = a1;
  262. axisY = a2;
  263. axisZ = a3;
  264. //轴向量单位化
  265. mod_axis = Math.sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);
  266. axisX = axisX/mod_axis;
  267. axisY = axisY/mod_axis;
  268. axisZ = axisZ/mod_axis;
  269.  
  270. rotateModel(axisX, axisY, axisZ, rad);
  271. });
  272.  
  273. /**
  274. * 模型旋转函数
  275. * x:旋转轴向量的x轴分量
  276. * y:旋转轴向量的y轴分量
  277. * z:旋转轴向量的z轴分量
  278. * rad:绕旋转轴旋转的弧度
  279. */
  280. function rotateModel(x, y, z, rad){
  281. initGL(gl);
  282.  
  283. // 模型旋转6度
  284. //var rad = 1 * Math.PI / 180;
  285. // 模型坐标变换矩阵的生成(沿着Y轴旋转)
  286. //m.rotate(mMatrix, rad, [x, y, z], mMatrix);
  287. //m.multiply(tmpMatrix, mMatrix, mvpMatrix);
  288. // mMatrix的逆矩阵
  289. //m.inverse(mMatrix, invMatrix);
  290. // 向uniformLocation中传入坐标变换矩阵
  291. //gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
  292. //gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
  293. // 使用索引进行绘图,画三角面
  294. //gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_SHORT, 0);
  295.  
  296. drawCoordinates(x, y, z, rad);
  297.  
  298. // context刷新
  299. gl.flush();
  300. }
  301.  
  302. /**
  303. * 生成着色器的函数
  304. */
  305. function create_shader(id){
  306. // 用来保存着色器的变量
  307. var shader;
  308.  
  309. // 根据id从HTML中获取指定的script标签
  310. var scriptElement = document.getElementById(id);
  311.  
  312. // 如果指定的script标签不存在,则返回
  313. if(!scriptElement){return;}
  314.  
  315. // 判断script标签的type属性
  316. switch(scriptElement.type){
  317.  
  318. // 顶点着色器的时候
  319. case 'x-shader/x-vertex':
  320. shader = gl.createShader(gl.VERTEX_SHADER);
  321. break;
  322.  
  323. // 片段着色器的时候
  324. case 'x-shader/x-fragment':
  325. shader = gl.createShader(gl.FRAGMENT_SHADER);
  326. break;
  327. default :
  328. return;
  329. }
  330.  
  331. // 将标签中的代码分配给生成的着色器
  332. gl.shaderSource(shader, scriptElement.text);
  333.  
  334. // 编译着色器
  335. gl.compileShader(shader);
  336.  
  337. // 判断一下着色器是否编译成功
  338. if(gl.getShaderParameter(shader, gl.COMPILE_STATUS)){
  339.  
  340. // 编译成功,则返回着色器
  341. return shader;
  342. }else{
  343.  
  344. // 编译失败,弹出错误消息
  345. alert(gl.getShaderInfoLog(shader));
  346. }
  347. }
  348.  
  349. /**
  350. * 程序对象的生成和着色器连接的函数
  351. */
  352. function create_program(vs, fs){
  353. // 程序对象的生成
  354. var program = gl.createProgram();
  355.  
  356. // 向程序对象里分配着色器
  357. gl.attachShader(program, vs);
  358. gl.attachShader(program, fs);
  359.  
  360. // 将着色器连接
  361. gl.linkProgram(program);
  362.  
  363. // 判断着色器的连接是否成功
  364. if(gl.getProgramParameter(program, gl.LINK_STATUS)){
  365.  
  366. // 成功的话,将程序对象设置为有效
  367. gl.useProgram(program);
  368.  
  369. // 返回程序对象
  370. return program;
  371. }else{
  372.  
  373. // 如果失败,弹出错误信息
  374. alert(gl.getProgramInfoLog(program));
  375. }
  376. }
  377.  
  378. /**
  379. * 生成VBO的函数
  380. */
  381. function create_vbo(data){
  382. // 生成缓存对象
  383. var vbo = gl.createBuffer();
  384.  
  385. // 绑定缓存
  386. gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
  387.  
  388. // 向缓存中写入数据
  389. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
  390.  
  391. // 将绑定的缓存设为无效
  392. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  393.  
  394. // 返回生成的VBO
  395. return vbo;
  396. }
  397.  
  398. /**
  399. * 绑定VBO相关的函数
  400. */
  401. function set_attribute(vbo, attL, attS){
  402. // 处理从参数中得到的数组
  403. for(var i in vbo){
  404. // 绑定缓存
  405. gl.bindBuffer(gl.ARRAY_BUFFER, vbo[i]);
  406.  
  407. // 将attributeLocation设置为有效
  408. gl.enableVertexAttribArray(attL[i]);
  409.  
  410. //通知并添加attributeLocation
  411. gl.vertexAttribPointer(attL[i], attS[i], gl.FLOAT, false, 0, 0);
  412. }
  413. }
  414.  
  415. /**
  416. * IBO的生成函数
  417. */
  418. function create_ibo(data){
  419. // 生成缓存对象
  420. var ibo = gl.createBuffer();
  421.  
  422. // 绑定缓存
  423. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
  424.  
  425. // 向缓存中写入数据
  426. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int16Array(data), gl.STATIC_DRAW);
  427.  
  428. // 将缓存的绑定无效化
  429. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  430.  
  431. // 返回生成的IBO
  432. return ibo;
  433. }
  434.  
  435. /**
  436. * 初始化gl
  437. * */
  438. function initGL(gl){
  439. // 设定canvas初始化的颜色
  440. gl.clearColor(0.0, 0.0, 0.0, 1.0);
  441. // 设定canvas初始化时候的深度
  442. gl.clearDepth(1.0);
  443. // canvas的初始化
  444. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  445. // 将深度测试设置为有效
  446. gl.enable(gl.DEPTH_TEST);
  447. // 指定一般深度测试的评价方法
  448. gl.depthFunc(gl.LEQUAL);
  449. // 将遮挡剔除设置为有效
  450. gl.enable(gl.CULL_FACE);
  451. }
  452.  
  453. /**
  454. * bindBuffer
  455. * */
  456. function bindBuffer(vertexArray, normalArray, colorArray, indices){
  457. /**
  458. * 三角面
  459. */
  460. // 生成VBO
  461. var position_vbo = create_vbo(vertexArray);
  462. var normal_vbo = create_vbo(normalArray);
  463. var color_vbo = create_vbo(colorArray);
  464. // 将VBO进行绑定并添加
  465. set_attribute([position_vbo, normal_vbo, color_vbo], attLocation, attStride);
  466. // 生成IBO
  467. var ibo = create_ibo(indices);
  468. // IBO进行绑定并添加
  469. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
  470. }
  471.  
  472. /**
  473. * 画坐标系
  474. **/
  475. function drawCoordinates(x, y, z, rad){
  476. /**
  477. * y轴
  478. * */
  479. //空间变换
  480. mMatrix = m.identity(m.create());
  481. m.rotate(mMatrix, rad, [x, y, z], mMatrix);
  482. // 得到mvpMatrix定位坐标矩阵
  483. m.multiply(tmpMatrix, mMatrix, mvpMatrix);
  484. // mMatrix的逆矩阵
  485. m.inverse(mMatrix, invMatrix);
  486. // 向uniformLocation中传入坐标变换矩阵
  487. gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
  488. gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
  489. //圆柱模型
  490. var cylinder = new cylinderGeo(0.03, 0.5, 15);
  491. var cylinderPositionY = cylinder.vertices;
  492. var cylinderNormalY = cylinder.normals;
  493. var cylinderColor = [];
  494. for(var i=0; i<cylinderPositionY.length/3; i++){
  495. cylinderColor.push(0.6, 1.0, 0.0, 1.0);
  496. }
  497. var cylinderIndexY = cylinder.faces;
  498. //写缓存绑定vertex-shader
  499. bindBuffer(cylinderPositionY, cylinderNormalY, cylinderColor, cylinderIndexY);
  500. // 使用索引进行绘图,画三角面
  501. gl.drawElements(gl.TRIANGLES, cylinderIndexY.length, gl.UNSIGNED_SHORT, 0);
  502.  
  503. //空间变换
  504. mMatrix = m.identity(m.create());
  505. m.translate(mMatrix, [0, 0.5, 0], mMatrix);
  506. m.rotate(mMatrix, rad, [x, y, z], mMatrix);
  507. // 得到mvpMatrix定位坐标矩阵
  508. m.multiply(tmpMatrix, mMatrix, mvpMatrix);
  509. // mMatrix的逆矩阵
  510. m.inverse(mMatrix, invMatrix);
  511. // 向uniformLocation中传入坐标变换矩阵
  512. gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
  513. gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
  514. //圆锥模型
  515. var cone = new coneGeo(0.05, 0.25, 15);
  516. var conePositionY = cone.vertices;
  517. var coneNormalY = cone.normals;
  518. var coneColorY = [];
  519. for(var i=0; i<conePositionY.length/3; i++){
  520. coneColorY.push(0.6, 1.0, 0.0, 1.0);
  521. }
  522. var coneIndexY = cone.faces;
  523. bindBuffer(conePositionY, coneNormalY, coneColorY, coneIndexY);
  524. // 使用索引进行绘图,画三角面
  525. gl.drawElements(gl.TRIANGLES, coneIndexY.length, gl.UNSIGNED_SHORT, 0);
  526.  
  527. /**
  528. * x轴
  529. * */
  530. //空间变换
  531. mMatrix = m.identity(m.create());
  532. m.rotate(mMatrix, -90*Math.PI/180, [0, 0, 1], mMatrix);
  533. m.rotate(mMatrix, rad, [x, y, z], mMatrix);
  534. // 得到mvpMatrix定位坐标矩阵
  535. m.multiply(tmpMatrix, mMatrix, mvpMatrix);
  536. // mMatrix的逆矩阵
  537. m.inverse(mMatrix, invMatrix);
  538. // 向uniformLocation中传入坐标变换矩阵
  539. gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
  540. gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
  541. //圆柱模型
  542. var cylinderPositionX = cylinder.vertices;
  543. var cylinderNormalX = cylinder.normals;
  544. var cylinderColorX = [];
  545. for(var i=0; i<cylinderPositionX.length/3; i++){
  546. cylinderColorX.push(0.6, 0.1, 0.0, 1.0);
  547. }
  548. var cylinderIndexX = cylinder.faces;
  549. //写缓存绑定vertex-shader
  550. bindBuffer(cylinderPositionX, cylinderNormalX, cylinderColorX, cylinderIndexX);
  551. // 使用索引进行绘图,画三角面
  552. gl.drawElements(gl.TRIANGLES, cylinderIndexX.length, gl.UNSIGNED_SHORT, 0);
  553.  
  554. //空间变换
  555. mMatrix = m.identity(m.create());
  556. m.translate(mMatrix, [0.5, 0, 0], mMatrix);
  557. m.rotate(mMatrix, -90*Math.PI/180, [0, 0, 1], mMatrix);
  558. m.rotate(mMatrix, rad, [x, y, z], mMatrix);
  559. // 得到mvpMatrix定位坐标矩阵
  560. m.multiply(tmpMatrix, mMatrix, mvpMatrix);
  561. // mMatrix的逆矩阵
  562. m.inverse(mMatrix, invMatrix);
  563. // 向uniformLocation中传入坐标变换矩阵
  564. gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
  565. gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
  566. //圆锥模型
  567. var conePositionX = cone.vertices;
  568. var coneNormalX = cone.normals;
  569. var coneColorX = [];
  570. for(var i=0; i<conePositionX.length/3; i++){
  571. coneColorX.push(0.6, 0.1, 0.0, 1.0);
  572. }
  573. var coneIndexX = cone.faces;
  574. bindBuffer(conePositionX, coneNormalX, coneColorX, coneIndexX);
  575. // 使用索引进行绘图,画三角面
  576. gl.drawElements(gl.TRIANGLES, coneIndexX.length, gl.UNSIGNED_SHORT, 0);
  577.  
  578. /**
  579. * z轴
  580. * */
  581. //空间变换
  582. mMatrix = m.identity(m.create());
  583. m.rotate(mMatrix, 90*Math.PI/180, [1, 0, 0], mMatrix);
  584. //圆锥姿态
  585. m.rotate(mMatrix, rad, [x, y, z], mMatrix);
  586. // 得到mvpMatrix定位坐标矩阵
  587. m.multiply(tmpMatrix, mMatrix, mvpMatrix);
  588. // mMatrix的逆矩阵
  589. m.inverse(mMatrix, invMatrix);
  590. // 向uniformLocation中传入坐标变换矩阵
  591. gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
  592. gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
  593. //圆柱模型
  594. var cylinderPositionZ = cylinder.vertices;
  595. var cylinderNormalZ = cylinder.normals;
  596. var cylinderColorZ = [];
  597. for(var i=0; i<cylinderPositionZ.length/3; i++){
  598. cylinderColorZ.push(0.0, 0.1, 0.6, 1.0);
  599. }
  600. var cylinderIndexZ = cylinder.faces;
  601. //写缓存绑定vertex-shader
  602. bindBuffer(cylinderPositionZ, cylinderNormalZ, cylinderColorZ, cylinderIndexZ);
  603. // 使用索引进行绘图,画三角面
  604. gl.drawElements(gl.TRIANGLES, cylinderIndexZ.length, gl.UNSIGNED_SHORT, 0);
  605.  
  606. //空间变换
  607. mMatrix = m.identity(m.create());
  608. m.translate(mMatrix, [0, 0, 0.5], mMatrix);
  609. m.rotate(mMatrix, 90*Math.PI/180, [1, 0, 0], mMatrix);
  610. m.rotate(mMatrix, rad, [x, y, z], mMatrix);
  611. // 得到mvpMatrix定位坐标矩阵
  612. m.multiply(tmpMatrix, mMatrix, mvpMatrix);
  613. // mMatrix的逆矩阵
  614. m.inverse(mMatrix, invMatrix);
  615. // 向uniformLocation中传入坐标变换矩阵
  616. gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
  617. gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
  618. //圆锥模型
  619. var conePositionZ = cone.vertices;
  620. var coneNormalZ = cone.normals;
  621. var coneColorZ = [];
  622. for(var i=0; i<conePositionZ.length/3; i++){
  623. coneColorZ.push(0.0, 0.1, 0.6, 1.0);
  624. }
  625. var coneIndexZ = cone.faces;
  626. bindBuffer(conePositionZ, coneNormalZ, coneColorZ, coneIndexZ);
  627. // 使用索引进行绘图,画三角面
  628. gl.drawElements(gl.TRIANGLES, coneIndexZ.length, gl.UNSIGNED_SHORT, 0);
  629. }
  630. };
  631.  
  632. </script>
  633. <script src="polyhedron.js"></script>
  634.  
  635. </head>
  636. <body>
  637. <canvas id="canvas"></canvas>
  638. <br/>
  639. 转动前X坐标:<input id="cordX">转动前Y坐标:<input id="cordY">转动前Z坐标:<input id="cordZ">和转轴的点积:<input id="00">
  640. <br/>
  641. 转动后X坐标:<input id="cordX1">转动后Y坐标:<input id="cordY1">转动后Z坐标:<input id="cordZ1">和转轴的点积:<input id="01">
  642. <br/>
  643. 旋转轴X坐标分量:<input id="axisX">旋转轴Y坐标分量:<input id="axisY">旋转轴Z坐标分量:<input id="axisZ">
  644. <br/>
  645. 旋转角度:<input id="rad">
  646. <br/>
  647. ===============================================旋转操作参数===============================================
  648. <br/>
  649. 旋转轴X坐标分量:<input class='axisX'>旋转轴Y坐标分量:<input class="axisY">旋转轴Z坐标分量:<input class="axisZ">
  650. 旋转角度:<input class="rad">
  651. <button id="rotate">旋转</button>
  652. </body>
  653. </html>

以上是渲染场景的html代码,我们先来看一下最终结果,如下图

如图可以看到,我们成功将3个圆柱,3个圆锥绘制到场景中去了,那么这个实现的核心部分在哪里呢,我们来分析一下,其中绘图是采用索引缓存的方式写入的,而和顶点着色器attribute类型的变量进行传值的数组每次绘制一个几何体对象都会被覆写,然后重新写入索引缓存,然后重新gl.drawElements绘制。这就是向一个场景中绘入多个模型的核心思想,每次要写入一个几何体,就重新向顶点着色器的attribute变量传值,重新写入索引缓存,重新绘图,而每次绘图都不会将之前绘制完成的几何体从场景中擦除(这就是增量渲染)。

通过记录这个工程案例,对gl的缓存机制又有新的认识。引用本文请注明出处https://www.cnblogs.com/ccentry/p/9864847.html

原生WebGL场景中绘制多个圆锥圆柱的更多相关文章

  1. 在WebGL场景中管理多个卡牌对象的实验

    这篇文章讨论如何在基于Babylon.js的WebGL场景中,实现多个简单卡牌类对象的显示.选择.分组.排序,同时建立一套实用的3D场景代码框架.由于作者美工能力有限,所以示例场景视觉效果可能欠佳,本 ...

  2. 在WebGL场景中进行棋盘操作的实验

    这篇文章讨论如何在基于Babylon.js的WebGL场景中,建立棋盘状的地块和多个可选择的棋子对象,在点选棋子时显示棋子的移动范围,并且在点击移动范围内的空白地块时向目标地块移动棋子.在这一过程中要 ...

  3. 在WebGL场景中使用2DA*寻路

      这篇文章将讨论如何在一个自定义的地面网格上进行简单的2D寻路,以及确定路径后如何使用基于物理引擎的运动方式使物体沿路径到达目标地点.读者需要预先对WebGL和Babylonjs知识有一些了解,可以 ...

  4. 在WebGL场景中建立游戏规则

    在前三篇文章的基础上,为基于Babylon.js的WebGL场景添加了类似战棋游戏的基本操作流程,包括从手中选择单位放入棋盘.显示单位具有的技能.选择技能.不同单位通过技能进行交互.处理交互结果以及进 ...

  5. osg 在场景中绘制坐标轴(xyz)

    //x y z font_size osg::Geode* makeCoordinate(float a_x,float a_y,float a_z,float font_size) { osg::r ...

  6. 如何在3D场景中在模型上面绘制摄取点

    有些时候,我们在屏幕上面绘制一个摄取点,在单屏玩游戏的模式下,我们并不能觉得有什么不妥.但是最近VR的热火朝天,我们带上眼镜看双屏的时候,总觉得这个摄取点看着很不舒服. 这个问题该怎么解决?在这里我首 ...

  7. 基于 HTML5 WebGL 的 3D 场景中的灯光效果

    构建 3D 的场景除了创建模型,对模型设置颜色和贴图外,还需要有灯光的效果才能更逼真的反映真实世界的场景.这个例子我觉得既美观又代表性很强,所以拿出来给大家分享一下. 本例地址:http://www. ...

  8. 使用着色器在WebGL3D场景中呈现行星表面地形

    实验目的:按照一定规律生成类地行星地表地形区块,并用合理的方式将地形块显示出来 涉及知识:Babylon.js引擎应用.着色器编程.正态分布.数据处理.canvas像素操作 github地址:http ...

  9. WebGL场景的两种地面构造方法

    总述:大部分3D编程都涉及到地面元素,在场景中我们使用地面作为其他物体的承载基础,同时也用地面限制场景使用者的移动范围,还可以在通过设置地块的属性为场景的不同位置设置对应的计算规则.本文在WebGL平 ...

随机推荐

  1. Win7电脑无法安全删除硬件并弹出媒体的解决方法

    有很多用户经常会在win7系统中使用移动硬盘或U盘来拷贝数据,而当使用完了之后,一般为了数据能够更安全,都会右击选择安全删除硬件进行退出,可是有win7系统用户却发现要弹出设备的还好无法安全删除硬件并 ...

  2. rocketmq双主发送消息 SLAVE_NOT_AVAILABLE 状态

    RocketMQ最佳实践之Producer 投递状态 发送消息时,将得到包含SendStatus的SendResult.首先,我们假设消息的isWaitStoreMsgOK = true(默认是tru ...

  3. Java java httpclient4.5 进行http,https通过SSL安全验证跳过,封装接口请求 get,post(formdata,json)封装,文件上传下载

    package api; import java.util.*; import java.net.URI; import org.apache.http.Consts; import org.apac ...

  4. 404 Note Found 队-Alpha9

    目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...

  5. What to do next to activate this settings for already existing users

    Link: http://sharepoint.stackexchange.com/questions/89284/sharepoint-2013-mysite-increase-quota Cent ...

  6. TestNG+Maven+IDEA 自动化测试(二) TestNG.xml

    示例代码: https://github.com/ryan255/TestNG-Demo 项目代码结构参考上一章 TestNG+Maven+IDEA 自动化测试(一) 环境搭建 maven插件引入 & ...

  7. 数据存储之归档解档 NSKeyedArchiver NSKeyedUnarchiver

    在构建应用程序时,有一个重要的问题是如何在每次启动之间持久化数据,以便重现最后一次关闭应用前的状态.在iOS和OS X上,苹果提供了三种选择:Core Data.属性列表(Property List) ...

  8. python 文件上传本地服务器

    1:python之上传文件 1.1.url代码 """untitled1222 URL Configuration The `urlpatterns` list rout ...

  9. java核心技术-多线程之引导概念

    前两篇文章分别讲了,Java线程相关基础概念以及线程的内存模型,本节作为后续章节的引导,个人认为对于学习后面的只是还是比较重要.好了,既然说了多线程,那么首先要弄清以下几个问题: 1. 什么是多线程? ...

  10. 将select的默认小三角替换成别的图片,且实现点击图片出现下拉框选择option

    最近做项目,要求修改select下拉框的默认三角样式,因为它在不同浏览器的样式不同且有点丑,找找网上也没什么详细修改方法,我就总结一下自己的吧. 目标是做成下图效果: 图一:将默认小三角换成红圈的三角 ...