在开始正文前,先说下Axiom3D里遇到的二个BUG.

  1.在启动axiom生成的程序中,我发现输出里总是有一些如"billboard_type","billboard_origin"这些不能解析,我开始还在想是不是文件格式版本过期或是啥的,反正后面我查了下,发现这些是有对应解析类的,在对比对应的Ogre相应位置代码,发现ParticleSystemRenderer在Ogre中是多重继承,C#天生不支持,但是我发现ScriptableObject本身是从DisposableObject继承的,那么只需要把ParticleSystemRenderer 从DisposableObject 继承改为从ScriptableObject 继承,然后在BillboardParticleRenderer类中方法SetParameter 修改成如下:

  1. public override bool SetParameter(string attr, string val)
  2. {
  3. try
  4. {
  5. Properties[attr] = val;
  6. return true;
  7. }
  8. catch (Exception e)
  9. {
  10. LogManager.Instance.Write(e.Message);
  11. return false;
  12. }
  13.  
  14. //if ( this.attribParsers.ContainsKey( attr ) )
  15. //{
  16. // var args = new object[2];
  17. // args[ 0 ] = val.Split( ' ' );
  18. // args[ 1 ] = this;
  19. // this.attribParsers[ attr ].Invoke( null, args );
  20. // //ParticleSystemRendererAttributeParser parser =
  21. // // (ParticleSystemRendererAttributeParser)attribParsers[attr];
  22.  
  23. // //// call the parser method
  24. // //parser(val.Split(' '), this);
  25. // return true;
  26. //}
  27. //return false;
  28. }

BillboardParticleRenderer修改

  具体修改意义我简单说下,原来的修改格式是针对内部特性方法的,但是BillboardParticleRenderer类里全是内部特性类的,从前面的继承修改加这段代码,就是为了让BillboardParticleRenderer能自己查找自己的特性类并找到对应的设置方法.

  2.这个BUG和ManualObject有关,我在设置ManualObject时,发现一些奇怪的问题,设置的颜色不能用,当时还以为是材质,灯光这些,后面全排除后,找到ManualObject里的CopyTempVertexToBuffer方法,发现有处逻辑不对.如下修改:

  1. protected virtual void CopyTempVertexToBuffer()
  2. {
  3. this.tempVertexPending = false;
  4. var rop = this.currentSection.RenderOperation;
  5.  
  6. if (rop.vertexData.vertexCount == && !this.currentUpdating)
  7. {
  8. // first vertex, autoorganise decl
  9. var oldDcl = rop.vertexData.vertexDeclaration;
  10. rop.vertexData.vertexDeclaration = oldDcl.GetAutoOrganizedDeclaration(false, false);
  11.  
  12. HardwareBufferManager.Instance.DestroyVertexDeclaration(oldDcl);
  13. }
  14.  
  15. ResizeTempVertexBufferIfNeeded(++rop.vertexData.vertexCount);
  16.  
  17. var elemList = rop.vertexData.vertexDeclaration.Elements;
  18.  
  19. #if !AXIOM_SAFE_ONLY
  20. unsafe
  21. #endif
  22. {
  23. // get base pointer
  24. var buf = BufferBase.Wrap(this.tempVertexBuffer);
  25. buf.Ptr = this.declSize * (rop.vertexData.vertexCount - );
  26.  
  27. //var pFloat = buf.ToFloatPointer();
  28. //var pRGBA = buf.ToUIntPointer();
  29.  
  30. foreach (var elem in elemList)
  31. {
  32. var offest = elem.Offset;
  33. buf.Ptr += offest;
  34. var pFloat = buf.ToFloatPointer();
  35. var pRGBA = buf.ToUIntPointer();
  36. var idx = ;
  37. RenderSystem rs;
  38. int dims;
  39. switch (elem.Semantic)
  40. {
  41. case VertexElementSemantic.Position:
  42. pFloat[idx++] = this.tempVertex.position.x;
  43. pFloat[idx++] = this.tempVertex.position.y;
  44. pFloat[idx] = this.tempVertex.position.z;
  45. break;
  46. case VertexElementSemantic.Normal:
  47. pFloat[idx++] = this.tempVertex.normal.x;
  48. pFloat[idx++] = this.tempVertex.normal.y;
  49. pFloat[idx] = this.tempVertex.normal.z;
  50. break;
  51. case VertexElementSemantic.TexCoords:
  52. dims = VertexElement.GetTypeCount(elem.Type);
  53. for (var t = ; t < dims; ++t)
  54. {
  55. pFloat[idx++] = this.tempVertex.texCoord[elem.Index][t];
  56. }
  57. break;
  58. case VertexElementSemantic.Diffuse:
  59. rs = Root.Instance.RenderSystem;
  60. if (rs != null)
  61. {
  62. pRGBA[idx] = (uint)rs.ConvertColor(this.tempVertex.color);
  63. }
  64. else
  65. {
  66. pRGBA[idx] = (uint)this.tempVertex.color.ToRGBA(); // pick one!
  67. }
  68. break;
  69. default:
  70. // nop ?
  71. break;
  72. }
  73. }
  74. }
  75. }

CopyTempVertexToBuffer

  简单来说,和原来地形的高度生成错误比较类似,把字节个数直接当做索引来用,ManualObject里的元素都是4个字节,还有一个简单的方法,直接让indx=elem.offset/4应该也是对的,但是我认为这种修改方法不算太好,如采用现在的方法.

  现在开始正文,从ManualObject来说,ManualObject是Ogre模仿了Opengl里立即绘制模式的一种写法,但是他和立即绘制模式本质是不同的,写法虽然是这样,但是他也是采用缓冲区的方法,意思来说,就是写法让习惯写立即模式的人爽,效率也是,当然ManualObject里的有些元素写法顺序规定的和OpenGL的不一样.先来看一段代码,这段代码是我从Ogre论坛里考过来的,把里面的C++写法改变下就行了,非常容易.

  1. public static ManualObject CreateTetrahedron(Vector3 position, Single scale)
  2. {
  3. ManualObject manObTetra = new ManualObject("Tetrahedron");
  4. manObTetra.CastShadows = false;
  5.  
  6. // render just before overlays (so all objects behind the transparent tetrahedron are visible)
  7. manObTetra.RenderQueueGroup = RenderQueueGroupID.Overlay - ; // = 99
  8.  
  9. Vector3[] c = new Vector3[]; // corners
  10.  
  11. // calculate corners of tetrahedron (with point of origin in middle of volume)
  12. Single mbot = scale * 0.2f; // distance middle to bottom
  13. Single mtop = scale * 0.62f; // distance middle to top
  14. Single mf = scale * 0.289f; // distance middle to front
  15. Single mb = scale * 0.577f; // distance middle to back
  16. Single mlr = scale * 0.5f; // distance middle to left right
  17. // width / height / depth
  18. c[] = new Vector3(-mlr, -mbot, mf); // left bottom front
  19. c[] = new Vector3(mlr, -mbot, mf); // right bottom front
  20. c[] = new Vector3(, -mbot, -mb); // (middle) bottom back
  21. c[] = new Vector3(, mtop, ); // (middle) top (middle)
  22.  
  23. // add position offset for all corners (move tetrahedron)
  24. for (Int16 i = ; i <= ; i++)
  25. c[i] += position;
  26.  
  27. // create bottom
  28. manObTetra.Begin("floor", OperationType.TriangleList);
  29. manObTetra.Position(c[]);
  30. manObTetra.Color(ColorEx.Red);
  31. manObTetra.Position(c[]);
  32. manObTetra.Position(c[]);
  33. manObTetra.Triangle(, , );
  34. manObTetra.End();
  35. // create right back side
  36. manObTetra.Begin("edm/floor", OperationType.TriangleList);
  37. manObTetra.Position(c[]);
  38. manObTetra.Color(ColorEx.Green);
  39. manObTetra.Position(c[]);
  40. manObTetra.Position(c[]);
  41. manObTetra.Triangle(, , );
  42. manObTetra.End();
  43. // create left back side
  44. manObTetra.Begin("edm/floor", OperationType.TriangleList);
  45. manObTetra.Position(c[]);
  46. manObTetra.Color(ColorEx.Green);
  47. manObTetra.Position(c[]);
  48. manObTetra.Color(ColorEx.Red);
  49. manObTetra.Position(c[]);
  50. manObTetra.Color(ColorEx.Blue);
  51. manObTetra.Triangle(, , );
  52. manObTetra.End();
  53. // create front side
  54. manObTetra.Begin("BaseWhiteNoLighting", OperationType.TriangleList);
  55. manObTetra.Color(ColorEx.White);
  56. manObTetra.Position(c[]);
  57. manObTetra.Position(c[]);
  58. manObTetra.Position(c[]);
  59. manObTetra.Triangle(, , );
  60. manObTetra.End();
  61.  
  62. return manObTetra;
  63.  
  64. }

Tetrahedron ManualObject

  这段代码也是我发现ManualObject里的颜色不能用的BUG的代码.我们从ManualObject里的代码来看一些注意事项,ManualObject是从Begin()方法调用后,根据第一个顶点到第二个顶点来生成顶点元素组成部分的.简单来说:

  1.调用Begin方法后,需要最先调用Position方法,在第一个Position调用前如调用Color,Normal会引起元素实际与声明的组成部分对应不上.

  2.在第一个Position和第二个Position之间出现的元素是这个缓冲区顶点的声明组成部分,如在第一个与第二个只出现了Color,那么你在第二个Position后声明Normal是无效的.

  3.这个倒是OpenGL里的状态机有点像,在第一个Position与第二个Position调用Color,Normal这些后,不需要在第二个Position之后每次调用,如果调用,color,normal会采用新的值,直接看代码里的TempVertex类型tempVertex属性每次调用Position,Color,Normal就知道原因了.

  下面放出上面代码生成效果图:

  下面再给出一个立方体生成的ManualObject,和上面有些区别,大致就这二种写法.

  1. public static ManualObject CreateCube(Vector3 center, float length, bool bLine = false)
  2. {
  3. string material = "BaseWhiteNoLighting";
  4. ManualObject manual = new ManualObject("manualCube");
  5. Vector3[] positions = new Vector3[]{
  6. center + new Vector3(length, length, length),
  7. center + new Vector3(-length, length, length),
  8. center + new Vector3(-length, -length, length),
  9. center + new Vector3(length, -length, length),
  10. center + new Vector3(length, length, -length),
  11. center + new Vector3(-length, length, -length),
  12. center + new Vector3(-length, -length, -length),
  13. center + new Vector3(length, -length, -length)
  14. };
  15. ushort[] indexs = new ushort[]{
  16. ,,,,,,
  17. ,,,,,,
  18. ,,,,,,
  19. ,,,,,,
  20. ,,,,,,
  21. ,,,,,
  22. };
  23. if (bLine)
  24. manual.Begin(material, OperationType.LineList);
  25. else
  26. manual.Begin(material, OperationType.TriangleList);
  27. for (int i = ; i < positions.Length; i++)
  28. {
  29. manual.Position(positions[i]);
  30. }
  31. for (int i = ; i < indexs.Length; i++)
  32. {
  33. manual.Index(indexs[i]);
  34. }
  35. manual.End();
  36. return manual;
  37. }

ManualObject Cube

  注意要让三角形与线同一顶点索引,每六个顶点索引中间二个是相同的,这样不生成线,但是三角形能正常生成,注意Ogre里也是逆时针.效果图就不发了.大家一看就知道是啥样的.

  其实ManualObject与Mesh的区别不大,都是保存顶点状态与索引,ManualObject也有方法直接ConvertToMesh直接转为Mesh.不过要注意,ManualObject继承MovableObject,可以直接挂接到Node下,而Mesh只是一种资源,需要先以Entity为载体,再挂接到Node下,不过这样也使得Mesh更复杂,能完成与承载的功能也更多.

  下面我们用Mesh来自定义一个模型,这个模型用来演示一个立方坐标轴,其中,XY与YZ可以用来展示,可以放入不同的材质,而XZ用来演示3D波动数据,这里我们用Cg加三维噪声来模拟,如这过程(柏林噪声实践(二) 水与火,顶点纹理拾取),最后大致效果如下:

图2:

  代码分二部分,一部分是坐标轴的建立,这个主要是用到Mesh,一部分是每桢活动的数据,这个部分就用到Cg着色器代码,记的添加Cg着色器解析的插件。

  下面是如何构建整个坐标轴的代码:

  1. public class Axis3D
  2. {
  3. public Mesh Self { get; set; }
  4. public Vector3 range;
  5.  
  6. public Axis3D(string name, Vector3 range)
  7. {
  8. this.range = range;
  9. Mesh mesh = MeshManager.Instance.CreateManual(name, "General", null);
  10.  
  11. float arrow1 = 30.0f;
  12. float arrow2 = 20.0f;
  13. float arrow3 = 3.0f;
  14. var vertices = new float[]{
  15. 0.0f,0.0f,0.0f,//Origin
  16. range.x,0.0f,0.0f,//x
  17. 0.0f,range.y,0.0f,//y
  18. 0.0f,0.0f,range.z,//z
  19.  
  20. range.x,range.y,0.0f,//xy plane
  21. range.x,0.0f,range.z,//xz plane
  22. 0.0f,range.y,range.z,//yz plane
  23. range.x,range.y,range.z,//origin offest
  24.  
  25. range.x+arrow1,0.0f,0.0f,
  26. range.x+arrow2,0.0f,-arrow3,
  27. range.x+arrow2,0.0f,arrow3,
  28.  
  29. 0.0f,range.y+arrow1,0.0f,
  30. -arrow3,range.y+arrow2,arrow3,
  31. arrow3,range.y+arrow2,-arrow3,
  32.  
  33. 0.0f,0.0f,range.z + arrow1,
  34. arrow3,0.0f,range.z+arrow2,
  35. -arrow3,0.0f,range.z+arrow2
  36. };
  37.  
  38. mesh.SharedVertexData = new VertexData();
  39. mesh.SharedVertexData.vertexCount = ;
  40. var decl = mesh.SharedVertexData.vertexDeclaration;
  41. decl.AddElement(, , VertexElementType.Float3, VertexElementSemantic.Position);
  42. var vbuf = HardwareBufferManager.Instance.CreateVertexBuffer(decl.Clone(),
  43. mesh.SharedVertexData.vertexCount, BufferUsage.StaticWriteOnly);
  44. vbuf.WriteData(, vbuf.Size, vertices, true);
  45. mesh.SharedVertexData.vertexBufferBinding.SetBinding(, vbuf);
  46.  
  47. SubMesh subMeshAxes = mesh.CreateSubMesh("axes");
  48. short[] indexs = new short[]{
  49. ,,
  50. ,,
  51. ,,
  52. };
  53. HardwareIndexBuffer ibuf = HardwareBufferManager.Instance.CreateIndexBuffer(IndexType.Size16, indexs.Length, BufferUsage.StaticWriteOnly);
  54. ibuf.WriteData(, ibuf.Size, indexs, true);
  55. subMeshAxes.useSharedVertices = true;
  56. subMeshAxes.indexData.indexBuffer = ibuf;
  57. subMeshAxes.indexData.indexCount = indexs.Length;
  58. subMeshAxes.indexData.indexStart = ;
  59. subMeshAxes.OperationType = OperationType.LineList;
  60.  
  61. SubMesh subMeshArrow = mesh.CreateSubMesh("arrow");
  62. indexs = new short[]{
  63. ,,,
  64. ,,,
  65. ,,
  66. };
  67. ibuf = HardwareBufferManager.Instance.CreateIndexBuffer(IndexType.Size16, indexs.Length, BufferUsage.StaticWriteOnly);
  68. ibuf.WriteData(, ibuf.Size, indexs, true);
  69. subMeshArrow.useSharedVertices = true;
  70. subMeshArrow.indexData.indexBuffer = ibuf;
  71. subMeshArrow.indexData.indexCount = indexs.Length;
  72. subMeshArrow.indexData.indexStart = ;
  73. subMeshArrow.OperationType = OperationType.TriangleList;
  74.  
  75. SubMesh subMeshPlaneXY = mesh.CreateSubMesh("planeXY");
  76. CreatePlaneXY(subMeshPlaneXY);
  77. SubMesh subMeshPlaneYZ = mesh.CreateSubMesh("planeYZ");
  78. CreatePlaneYZ(subMeshPlaneYZ);
  79.  
  80. SubMesh subMeshPlaneXZ = mesh.CreateSubMesh("planeXZ");
  81. CreateRenderPlane(subMeshPlaneXZ);
  82.  
  83. mesh.BoundingBox = new AxisAlignedBox(Vector3.Zero, range);
  84. mesh.BoundingSphereRadius = range.Length;
  85. mesh.Load();
  86.  
  87. Self = mesh;
  88. }
  89.  
  90. private void CreateAxis(SubMesh subMesh)
  91. {
  92. subMesh.useSharedVertices = false;
  93. subMesh.vertexData = new VertexData();
  94.  
  95. }
  96.  
  97. private void CreatePlaneXY(SubMesh subMesh)
  98. {
  99. int verticeLong = ;
  100. var vertices = new float[]{
  101. 0.0f,0.0f,0.0f,//Origin
  102. 0.0f,0.0f,
  103. range.x,0.0f,0.0f,//x
  104. 1.0f,0.0f,
  105. 0.0f,range.y,0.0f,//y
  106. 0.0f,1.0f,
  107. range.x,range.y,0.0f,//xy plane
  108. 1.0f,1.0f,
  109. };
  110. subMesh.useSharedVertices = false;
  111. subMesh.vertexData = new VertexData();
  112. subMesh.vertexData.vertexCount = verticeLong;
  113. var decl = subMesh.vertexData.vertexDeclaration;
  114. decl.AddElement(, , VertexElementType.Float3, VertexElementSemantic.Position);
  115. decl.AddElement(, VertexElement.GetTypeSize(VertexElementType.Float3), VertexElementType.Float2, VertexElementSemantic.TexCoords, );
  116. var buf = HardwareBufferManager.Instance.CreateVertexBuffer(decl.Clone(), verticeLong, BufferUsage.StaticWriteOnly);
  117. buf.WriteData(, buf.Size, vertices);
  118. subMesh.vertexData.vertexBufferBinding.SetBinding(, buf);
  119.  
  120. var indexs = new short[]{
  121. ,,,
  122. ,,
  123. };
  124. var ibuf = HardwareBufferManager.Instance.CreateIndexBuffer(IndexType.Size16, indexs.Length, BufferUsage.StaticWriteOnly);
  125. ibuf.WriteData(, ibuf.Size, indexs, true);
  126. subMesh.indexData.indexBuffer = ibuf;
  127. subMesh.indexData.indexCount = indexs.Length;
  128. subMesh.indexData.indexStart = ;
  129. subMesh.OperationType = OperationType.TriangleList;
  130. subMesh.MaterialName = "axis3D/xy";
  131. }
  132.  
  133. private void CreatePlaneYZ(SubMesh subMesh)
  134. {
  135. int verticeLong = ;
  136. var vertices = new float[]{
  137. 0.0f,0.0f,0.0f,//Origin
  138. 0.0f,0.0f,
  139. 0.0f,range.y,0.0f,//y
  140. 0.0f,1.0f,
  141. 0.0f,0.0f,range.z,//z
  142. 1.0f,0.0f,
  143. 0.0f,range.y,range.z,//yz plane
  144. 1.0f,1.0f,
  145. };
  146. subMesh.useSharedVertices = false;
  147. subMesh.vertexData = new VertexData();
  148. subMesh.vertexData.vertexCount = verticeLong;
  149. var decl = subMesh.vertexData.vertexDeclaration;
  150. decl.AddElement(, , VertexElementType.Float3, VertexElementSemantic.Position);
  151. decl.AddElement(, VertexElement.GetTypeSize(VertexElementType.Float3), VertexElementType.Float2, VertexElementSemantic.TexCoords, );
  152. var buf = HardwareBufferManager.Instance.CreateVertexBuffer(decl.Clone(), verticeLong, BufferUsage.StaticWriteOnly);
  153. buf.WriteData(, buf.Size, vertices);
  154. subMesh.vertexData.vertexBufferBinding.SetBinding(, buf);
  155.  
  156. var indexs = new short[]{
  157. ,,,
  158. ,,
  159. };
  160. var ibuf = HardwareBufferManager.Instance.CreateIndexBuffer(IndexType.Size16, indexs.Length, BufferUsage.StaticWriteOnly);
  161. ibuf.WriteData(, ibuf.Size, indexs, true);
  162. subMesh.indexData.indexBuffer = ibuf;
  163. subMesh.indexData.indexCount = indexs.Length;
  164. subMesh.indexData.indexStart = ;
  165. subMesh.OperationType = OperationType.TriangleList;
  166. subMesh.MaterialName = "axis3D/yz";
  167. }
  168.  
  169. public void Rendering(float delt)
  170. {
  171.  
  172. }
  173.  
  174. public void CreateRenderPlane(SubMesh subMesh)
  175. {
  176. var xc = 5.0f;
  177. var yc = 5.0f;
  178.  
  179. var xr = (int)(range.x/xc) - ;
  180. var yr = (int)(range.z/yc) - ;
  181.  
  182. var halfx = 0.0f;// xr * xc * 0.5f;
  183. var halfy = 0.0f;// yr * yc * 0.5f;
  184. var length = (xr + ) * (yr + ) * ;
  185. float[] vertices = new float[length];
  186.  
  187. int index = ;
  188. for (int j = ; j <= yr; j++)
  189. {
  190. for (int i = ; i <= xr; i++)
  191. {
  192. vertices[index++] = xc * i - halfx;
  193. vertices[index++] = 0.0f;
  194. vertices[index++] = yc * j - halfy;
  195.  
  196. //vertices[index++] = 0.3f;
  197. //vertices[index++] = 0.3f;
  198. //vertices[index++] = 0.3f;
  199. }
  200. }
  201.  
  202. length = xr * yr * ;
  203. int[] indexs = new int[length];
  204. index = ;
  205. for (int j = ; j < yr; j++)
  206. {
  207. for (int i = ; i < xr; i++)
  208. {
  209. indexs[index++] = (j + ) * (xr + ) + i;
  210. indexs[index++] = (j + ) * (xr + ) + i;
  211. indexs[index++] = (j + ) * (xr + ) + i + ;
  212.  
  213. indexs[index++] = (j + ) * (xr + ) + i + ;
  214. indexs[index++] = (j + ) * (xr + ) + i;
  215. indexs[index++] = (j + ) * (xr + ) + i + ;
  216. }
  217. }
  218.  
  219. subMesh.useSharedVertices = false;
  220. subMesh.vertexData = new VertexData();
  221. subMesh.vertexData.vertexCount = (xr + ) * (yr + );
  222. var decl = subMesh.vertexData.vertexDeclaration;
  223. decl.AddElement(, , VertexElementType.Float3, VertexElementSemantic.Position);
  224. //decl.AddElement(0, VertexElement.GetTypeSize(VertexElementType.Float3), VertexElementType.Float3, VertexElementSemantic., 0);
  225. var buf = HardwareBufferManager.Instance.CreateVertexBuffer(decl.Clone(), subMesh.vertexData.vertexCount, BufferUsage.StaticWriteOnly);
  226. buf.WriteData(, buf.Size, vertices);
  227. subMesh.vertexData.vertexBufferBinding.SetBinding(, buf);
  228.  
  229. var ibuf = HardwareBufferManager.Instance.CreateIndexBuffer(IndexType.Size32, indexs.Length, BufferUsage.StaticWriteOnly);
  230. ibuf.WriteData(, ibuf.Size, indexs, true);
  231. subMesh.indexData.indexBuffer = ibuf;
  232. subMesh.indexData.indexCount = indexs.Length;
  233. subMesh.indexData.indexStart = ;
  234. subMesh.OperationType = OperationType.TriangleList;
  235. subMesh.MaterialName = "noise3D";
  236. }
  237. //private void
  238. }

Axis3D Mesh

  我们就简化轴,只用一条线和一个三角形来表示,XY与YZ面需要不同的材质,我们各分一个SubMesh更好化分。注意Mesh可以申请顶点缓冲区(所有SubMesh可以直接用这个顶点缓冲缓冲区),但是没有索引缓冲区,意思就是Mesh本身不负责绘制元素,需要SubMesh绘制。而SubMesh由useSharedVertices确认是由采用SubMesh的索引缓冲区。这样做兼容性还是不错的,至少我想到一些文件格式都可以转化成Mesh这种结构。

  在这个坐标轴了,Mesh建立了公共顶点,三条线和三个三角形都用到这个公共顶点。其中顶点缓冲区Ogre直接封装的是DX的那些类,申明VertexDeclaration与对应的VectexElement表明顶点元素的组成,前面的ManualObject在第一个Position与第二个Position之间申请的Color,Normal一样是这个过程,只是根据调用的方法,自动创建的VectexElement。而SubMesh如果表明直接用的是公共顶点,则只需要声明索引缓冲区就行了,申明索引缓冲区因为不需要指明顶点的构成元素,只需要说明是用32位字节还是16位字节,再对一些元素,如用法,连接模式行了。

  至于建立XY,YZ面,则没用公共顶点缓冲区,那就需要自己申请自己的顶点缓冲区和索引缓冲区,申请过程和上面一样,需要指定useSharedVertices用false,对应的SubMesh可以自己指定对应的MaterialName。

  最后则是XZ面,这个面,我们用来建立一些点,然后用Cg着色器代码控制顶点位置的Y轴,如何坐标有平滑性的波动,我们用到Noise,详细请看(柏林噪声实践(二) 水与火,顶点纹理拾取),这里不多说了。

  下面先给出对应的材质代码:

  1. // CG Vertex shader definition
  2. vertex_program noise3D_VS cg
  3. {
  4. source v4.cg
  5. entry_point main
  6. profiles vp40
  7. default_params
  8. {
  9. param_named_auto mvp worldviewproj_matrix
  10. param_named_auto time2 frame_time
  11. param_named_auto time1 time
  12. param_named_auto time3 time_0_x 10.0
  13. }
  14. }
  15.  
  16. fragment_program noise3D_PS cg
  17. {
  18. source v4.cg
  19. entry_point fragmentShader
  20. profiles fp30
  21. }
  22.  
  23. material noise3D
  24. {
  25. technique
  26. {
  27. pass
  28. {
  29. cull_hardware none
  30. vertex_program_ref noise3D_VS
  31. {
  32. //param_named_auto time custom 0
  33. }
  34. texture_unit
  35. {
  36. texture cloud.jpg
  37. }
  38. fragment_program_ref noise3D_PS
  39. {
  40. }
  41. texture_unit
  42. {
  43. texture cloud.jpg
  44. }
  45. }
  46. }
  47. }

Material Noise3D

  Cg着色器代码:

  1. #define ONE 0.00390625
  2. #define ONEHALF 0.001953125
  3.  
  4. float fade(float t) {
  5. //return t*t*(3.0-2.0*t); // Old fade
  6. return t*t*t*(t*(t*6.0-15.0)+10.0);
  7. // Improved fade
  8. }
  9.  
  10. float noise(float3 P,sampler2D permTexture)
  11. {
  12. float3 Pi = ONE*floor(P)+ONEHALF;
  13. float3 Pf = P-floor(P);
  14. // Noise contributions from (x=0, y=0), z=0 and z=1
  15. float perm00 = tex2D(permTexture, Pi.xy).a ;
  16. float3 grad000 = tex2D(permTexture, float2(perm00, Pi.z)).rgb * 4.0 - 1.0;
  17. float n000 = dot(grad000, Pf);
  18. float3 grad001 = tex2D(permTexture, float2(perm00, Pi.z + ONE)).rgb * 4.0 - 1.0;
  19. float n001 = dot(grad001, Pf - float3(0.0, 0.0, 1.0));
  20. // Noise contributions from (x=0, y=1), z=0 and z=1
  21. float perm01 = tex2D(permTexture, Pi.xy + float2(0.0, ONE)).a ;
  22. float3 grad010 = tex2D(permTexture, float2(perm01, Pi.z)).rgb * 4.0 - 1.0;
  23. float n010 = dot(grad010, Pf - float3(0.0, 1.0, 0.0));
  24. float3 grad011 = tex2D(permTexture, float2(perm01, Pi.z + ONE)).rgb * 4.0 - 1.0;
  25. float n011 = dot(grad011, Pf - float3(0.0, 1.0, 1.0));
  26. // Noise contributions from (x=1, y=0), z=0 and z=1
  27. float perm10 = tex2D(permTexture, Pi.xy + float2(ONE, 0.0)).a ;
  28. float3 grad100 = tex2D(permTexture, float2(perm10, Pi.z)).rgb * 4.0 - 1.0;
  29. float n100 = dot(grad100, Pf - float3(1.0, 0.0, 0.0));
  30. float3 grad101 = tex2D(permTexture, float2(perm10, Pi.z + ONE)).rgb * 4.0 - 1.0;
  31. float n101 = dot(grad101, Pf - float3(1.0, 0.0, 1.0));
  32. // Noise contributions from (x=1, y=1), z=0 and z=1
  33. float perm11 = tex2D(permTexture, Pi.xy + float2(ONE, ONE)).a ;
  34. float3 grad110 = tex2D(permTexture, float2(perm11, Pi.z)).rgb * 4.0 - 1.0;
  35. float n110 = dot(grad110, Pf - float3(1.0, 1.0, 0.0));
  36. float3 grad111 = tex2D(permTexture, float2(perm11, Pi.z + ONE)).rgb * 4.0 - 1.0;
  37. float n111 = dot(grad111, Pf - float3(1.0, 1.0, 1.0));
  38. // Blend contributions along x
  39. float4 n_x = lerp(float4(n000, n001, n010, n011), float4(n100, n101, n110, n111), fade(Pf.x));
  40. // Blend contributions along y
  41. float2 n_xy = lerp(n_x.xy, n_x.zw, fade(Pf.y));
  42. // Blend contributions along z
  43. float n_xyz = lerp(n_xy.x, n_xy.y, fade(Pf.z));
  44. return n_xyz;
  45. }
  46.  
  47. float turbulence(int octaves, float3 P, float lacunarity, float gain,sampler2D permTexture)
  48. {
  49. float sum = ;
  50. float scale = ;
  51. float totalgain = ;
  52. for(int i=;i<octaves;i++){
  53. sum += totalgain*noise(P*scale,permTexture);
  54. scale *= lacunarity;
  55. totalgain *= gain;
  56. }
  57.  
  58. return abs(sum);
  59. }
  60.  
  61. struct v_Output {
  62. float4 position : POSITION;
  63. //float pc : TEXCOORD0;
  64. float2 pc : TEXCOORD0;
  65. };
  66.  
  67. v_Output main(float3 position : POSITION,
  68. uniform float4x4 mvp,
  69. uniform float time1,
  70. uniform float time2,
  71. uniform float time3,
  72. uniform sampler2D permTexture)
  73. {
  74. v_Output OUT;
  75. float time = time3 + time1 + time2 * ;
  76. float3 pf = float3(position.xz,time);
  77. //float ty = noise(pf,permTexture);
  78. //水
  79. //float ty = turbulence(4,pf,2,0.5,permTexture);
  80. //float yy = ty * 0.5 + 0.5;
  81. //火
  82. float ty = turbulence(,pf,0.6,,permTexture);
  83. float yy = ty * 0.5;
  84. float4 pos = float4(position.x,yy,position.z,);
  85. OUT.pc = float2(position.x*0.01,position.z*0.01);
  86. //float4 pos = float4(position.x,50,position.z,1);
  87. OUT.position = mul(mvp,pos);
  88. //OUT.pc = yy;
  89. return OUT;
  90. }
  91.  
  92. struct f_Output {
  93. float4 color : COLOR;
  94. };
  95.  
  96. f_Output fragmentShader(v_Output vin,uniform sampler2D texture)
  97. {
  98. f_Output OUT;
  99. OUT.color = tex2D(texture, vin.pc);
  100. OUT.color = OUT.color + float4(0.1,0.1,0.1,0.1);
  101. return OUT;
  102. }

Cg Noise3

  这里简单说明一下材质代码,相关着色器代码具体意思大家移步前面链接。

  在noise3D material中,vertex_program与fragment_program分别指定顶点和片断着色器,source指定相对路径的源文件代码位置,而entry_point指定当前着色器主函数,profiles指定硬件要求,因为我们用到纹理拾取,顶点着色器内纹理,所以在opengl下需要满足vp40才行,相关profiles对应硬件与说明请看Declaring Vertex/Geometry/Fragment Programs,vp40要求比较新的显卡。其中default_params相当于我们给着色器中uniform变量设定的初始值,param_named_auto指明由Ogre内部自动更新,详情请看Using Vertex/Geometry/Fragment Programs in a Pass。大家对应一下顶点着色器中的default_params参数与Cg里的代码,就能看明白是怎么个意思,Ogre这一块封装的相当不错,用起来没有别扭的感觉,并且还非常方便与人性化。在对应的material,对应Pass里指明vertex_program_ref与fragment_program_ref与前面对应,其中着色器需要的纹理直接紧接着对应的着色器后添加texture_unit就行,个数对应上。

  总的来说,这里主要测试自动创建一些简单模型与着色器代码的基本用法,都是比较基础的,也可以看出Ogre对于这里的处理还是相当不错,方便又容易理解。

  

Axiom3D:手动创建ManualObject与Mesh,以及如何使用Cg着色器语言的更多相关文章

  1. DirectX11 With Windows SDK--02 顶点/像素着色器的创建、顶点缓冲区

    前言 由于在Direct3D 11中取消了固定管线,要想绘制图形必须要了解可编程渲染管线的流程,一个能绘制出图形的渲染管线最少需要有这两个可编程着色器:顶点着色器和像素着色器. 本章会直接跳过渲染管线 ...

  2. ogre3D学习基础16 -- 手动创建实体(ManualObject)

    这一节练习一下手动创建实体,用到了对象(ManualObject) 第一,依然是模板 #include "ExampleApplication.h" class Example1 ...

  3. 通过手动创建统计信息优化sql查询性能案例

    本质原因在于:SQL Server 统计信息只包含复合索引的第一个列的信息,而不包含复合索引数据组合的信息 来源于工作中的一个实际问题, 这里是组合列数据不均匀导致查询无法预估数据行数,从而导致无法选 ...

  4. 手动创建VS单元测试,显示代码覆盖率

    Visual Studio 号称有史以来最强大的IDE,确实如此.创建单元测试也是一键完成:在方法的代码块中右键“Create Unit Test…”,勾选测试项,填项目名,完成.VS就会自动帮你创建 ...

  5. java web(一) 使用sql标签库+tomcat+mysql手动创建一个jsp练习总结

    2016-09-0111:06:53                                     使用sql标签库+tomcat+mysql手动创建一个jsp 1. 1.1安装tomcat ...

  6. Maven 系列 二 :Maven 常用命令,手动创建第一个 Maven 项目【转】

    1.根据 Maven 的约定,我们在D盘根目录手动创建如下目录及文件结构: 2.打开 pom.xml 文件,添加如下内容: <project xmlns="http://maven.a ...

  7. 用Sqlplus手动创建Oracle11g数据库

    用Sqlplus手动创建Oracle数据库 刚开始学习Oracle数据库,菜鸟一个,使用sqlplus创建数据库遇到了很多问题,通过不断地百度,终于创建成功了.所以顺便把整个过程中犯的一些最低级的错误 ...

  8. servlet和手动创建servlet,断点调试

    1.    什么是Servlet Servlet是一种用Java语言编写的Web应用组件 Servlet主要用于动态网页输出,扩展了Web服务器的功能 Servlet由Servlet容器进行管理 2. ...

  9. Maven手动创建多模块项目

    Maven手动创建多模块项目 我要创建的项目名称是:unicorn,项目包含两个模块,分别是unicorn-core和unicorn-web.包的路径是com.goldpalm.tour. 项目创建流 ...

随机推荐

  1. Status bar and navigation bar appear over my view's bounds in iOS 7

    转自:http://stackoverflow.com/questions/17074365/status-bar-and-navigation-bar-appear-over-my-views-bo ...

  2. 深入理解Linux内核-系统调用

    系统调用:用户态进程向内核发出的,实现用户态进程调用硬件设备的函数或者中断:优点:使编程更容易,将用户从学习硬件设备的低级编程特性中解放:提高系统到安全性,内核在满足请求之前可以做正确性检查:提高可移 ...

  3. hibernate的flush()、refresh()、clear()针对一级缓存的操作的区别

    首先session是有一级缓存的,目的是为了减少查询数据库的时间,提高效率,一级缓存的生命周期和session是一样的, session.flush()和session.clear()就针对sessi ...

  4. Memory Leak检測神器--LeakCanary初探

      在之前的文章Android内存泄露的几种情形中提到过在开发中常见的内存泄露问题,可是过于草率.因为刚开年,工作还没正式展开,就看了一下Github开源大户Square的LeakCanary,并用公 ...

  5. openssl生成SSL证书的流程

    SSL证书通过在客户端浏览器和Web服务器之间建立一条SSL安全通道(Secure socketlayer(SSL),SSL安全协议主要用来提供对用户和服务器的认证:对传送的数据进行加密和隐藏:确保数 ...

  6. Asp.Net MVC绑定DropDownList等控件

    测试环境:vs2013..Net4.5.mvc5 一.Asp.Net MVC绑定控件原理说明 以Html.TextBox为例 /// <param name="name"&g ...

  7. 玩转Bootstrap(JS插件篇)-第1章 模态弹出框 :1-1导入JavaScript插件

    导入JavaScript插件 Bootstrap除了包含丰富的Web组件之外,如前面介绍的下拉菜单.按钮组.导航.分页等.他还包括一些JavaScript的插件. Bootstrap的JavaScri ...

  8. 【造轮子】MFC实现BlockingQueue

    最近任务需要在MFC下做多线程生产者消费者模式的东西,我找了半天貌似MFC没有类似Java里面BlockingQueue那样的工具(也许是我手残没找到). 网上好像也有很多大佬去实现这个.但是我没仔细 ...

  9. LVS负载均衡模型及算法概述

    集群类型 LB: Load Balancing,负载均衡 HA:High Availability, 高可用 HP:High Performance, 高性能   负载均衡 负载均衡设备 Hardwa ...

  10. C语言引用连接脚本lds中的符号——清除bss段,c实现方式

    之前我们的启动文件清除bss和拷贝都是通过汇编的方式的实现,但是,我们能够使用C语言,就不使用汇编: 先看连接脚本: SECTIONS { . = 0x30000000; __code_start = ...