x01.EarthRun

月亮绕着地球转,地球绕着太阳转,一个 TranslateTransform3D + RotationTransform3D 即可搞定。难的是球体(Sphere)绘制。

作为球体,由经度、纬度划分为一小块一小块的。球体的绘制,说白了,就是这一小块一小块的绘制。除上下极点外,每小块由四个点(Point3D)构成,即两个三角形。

现在,只要求出了这些 Point3D,问题即可解决。为简便,不妨设球心 O (0,0,0),半径 r1 。(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 坐标。参考代码如下:

Trangulate
  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 

 

posted on 2012-12-03 00:32  x01  阅读(1029)  评论(1编辑  收藏  举报

导航