x01.EarthRun
月亮绕着地球转,地球绕着太阳转,一个 TranslateTransform3D + RotationTransform3D 即可搞定。难的是球体(Sphere)绘制。
作为球体,由经度、纬度划分为一小块一小块的。球体的绘制,说白了,就是这一小块一小块的绘制。除上下极点外,每小块由四个点(Point3D)构成,即两个三角形。
现在,只要求出了这些 Point3D,问题即可解决。为简便,不妨设球心 O 为(0,0,0),半径 r 为 1 。(WPF 3D 坐标:左到右 x 轴,下到上 y 轴,屏幕里到外 z 轴)
如何求球面某经纬度交叉点 A (x,y,z)的 3D 坐标呢?
1. 忽略 z 轴,设角 AOX (纬度偏移)度数为 a,则 x = cos(a); y = sin(a); 同理,z = cos(a);
2. 设经度偏移角度 AOZ 为 b,此时,y 不变。忽略 y 轴,则 x = cos(a)*sin(b); z = cos(a)*cos(b);
即:(cos(a)*sin(b), sin(a), cos(a)*cos(b)) 为 A 3D 坐标。参考代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
protected void Triangulate(DependencyPropertyChangedEventArgs e, Point3DCollection vertices, Vector3DCollection normals, Int32Collection indices, PointCollection textures) { vertices.Clear(); normals.Clear(); indices.Clear(); textures.Clear(); for (int stack = 0; stack <= Stacks; stack++) { double phi = Math.PI / 2 - stack * Math.PI / Stacks; double y = Radius * Math.Sin(phi); double scale = -Radius * Math.Cos(phi); for (int slice = 0; slice <= Slices; slice++) { double theta = slice * 2 * Math.PI / Slices; double x = scale * Math.Sin(theta); double z = scale * Math.Cos(theta); Vector3D normal = new Vector3D(x, y, z); normals.Add(normal); vertices.Add(normal + Center); textures.Add(new Point((double)slice / Slices, (double)stack / Stacks)); } } // stack == 0 for (int slice = 0; slice < Slices; slice++) { indices.Add(slice + 1); indices.Add(Slices + 1 + slice); indices.Add(Slices + 1 + slice + 1); } for (int stack = 1; stack < Stacks - 1; stack++) { for (int slice = 0; slice < Slices; slice++) { indices.Add(stack * (Slices + 1) + slice); indices.Add((stack + 1) * (Slices + 1) + slice); indices.Add(stack * (Slices + 1) + slice + 1); indices.Add(stack * (Slices + 1) + slice + 1); indices.Add((stack + 1) * (Slices + 1) + slice); indices.Add((stack + 1) * (Slices + 1) + slice + 1); } } // stack == Stacks - 1 for (int slice = 0; slice < Slices; slice++) { int stack = Stacks - 1; indices.Add(stack * (Slices + 1) + slice); indices.Add((stack + 1) * (Slices + 1) + slice); indices.Add(stack * (Slices + 1) + slice + 1); } }
其中,slice 即经度,stack 即纬度,phi 即 a, theta 即 b,它是从 -z 轴 0 到 360 度,+y 轴 90 到 -90 度。
源代码可到 x01.download 中下载,运行效果图如下:
关于 3D 编程,Charles Pezold 的 《3D.Programming.for.Windows》值得一读,下载链接 http://download.csdn.net/detail/china_x01/4816647