25. 绘制立方体的CubeSceneNode类

有了上一个教程创建平面QuadSceneNode类的基础,创建立方体就比较容易理解了,CubeSceneNode类的代码如下,也很简单:

namespace StunEngine.SceneNodes
{
    /// 
    /// 创建一个立方体
    /// 
    public class CubeSceneNode : GenericMaterialSceneNode
    {

        #region 构造函数和成员变量       

        /// 
        /// 创建一个新CubeSceneNode对象,不使用细节纹理。
        /// 
        /// 引擎
        /// 所属场景
        /// 立方体使用的漫反射纹理
        public CubeSceneNode(StunXnaGE engine, Scene setScene, string setDiffuseTextureName) : this(engine, setScene, setDiffuseTextureName,Vector2 .One ,null ,Vector2 .Zero ) { }

        /// 
        /// 创建一个新CubeSceneNode对象,使用细节纹理。
        /// 
        /// 引擎
        /// 所属场景
        /// 立方体使用的漫反射纹理
        /// 漫反射纹理UV重复次数
        /// 立方体使用的细节纹理
        /// 细节纹理UV重复次数
        public CubeSceneNode(StunXnaGE engine, Scene setScene, string setDiffuseTextureName, Vector2 setDiffuseTiles, string setDetailTextureName, Vector2 setDetailTiles)
            : base(engine, setScene,setDiffuseTextureName ,setDiffuseTiles ,setDetailTextureName ,setDetailTiles)
        {
            
        }  
      
        #endregion

        /// 
        /// 初始化CubeSceneNode对象。注意不要使用Initialize,它只被引擎调用。 
        /// 
        public override void Initialize()
        {
            this.UpdateOrder = SceneManagement.SceneNodeOrdering.SceneNode.GetValue();
            base.Initialize();            
            this.mesh =MeshBuilder.CreateCube (engine .GraphicsDevice);    
        }        

        #region 单元测试

#if DEBUG

        /// 
        /// 测试CubeSceneNode类
        /// 
        public static void TestCubeSceneNode()
        {
            CubeSceneNode cube1 = null;
            CubeSceneNode cube2 = null;

            TestGame.Start("测试CubeSceneNode类",
                delegate
                {
                    //添加一个覆盖有岩石纹理的长方体
                    cube1 = new CubeSceneNode(TestGame.engine, TestGame.scene, "Textures\\Rock", new Vector2(2.0f, 2.0f), "Textures\\dirty", Vector2.One );
                    TestGame.scene.AddNode(cube1);                    
                    Vector3 scale = new Vector3(4.0f, 2.0f, 4.0f);
                    cube1.Pose.SetScale(ref scale);
                    Vector3 position = new Vector3(-4f, 1.0f, -4.0f);
                    cube1.Pose.SetPosition (ref position);
                    cube1.Material.SpecularColor = new Vector3(1.0f, 1.0f, 1.0f);
                    cube1.Material.SpecularPower = 50;

                    //添加一个只有顶点颜色的立方体
                    cube2 = new CubeSceneNode(TestGame.engine, TestGame.scene, null);
                    TestGame.scene.AddNode(cube2);
                    
                    scale = new Vector3(4.0f, 4.0f, 4.0f);
                    cube2.Pose.SetScale(ref scale);
                    position = new Vector3(4f, 2.0f, -4.0f);
                    cube2.Pose.SetPosition(ref position);
                    cube2.Material.DiffuseColor = new Vector3(1.0f, 0.0f, 0.0f);
                    cube2.Material.SpecularColor = new Vector3(1.0f, 1.0f, 1.0f);
                    cube2.Material.SpecularPower = 50;

                    //不显示光标
                    TestGame.scene.IsShowMouse = false;
                    TestGame.scene.Camera.MovementSpeed = 30.0f;
                },
                delegate
                {
                    //按数字1键则切换使用的technique
                    if (Input.KeyboardKeyJustPressed(Keys.D1))
                    {
                        if (cube1.Material.CurrentTechniqueName == "SimpleTextured")
                            cube1.Material.CurrentTechniqueName = "TexturedLights";
                        else
                            cube1.Material.CurrentTechniqueName = "SimpleTextured";
                    }
                    //按数字2键则切换平面上的纹理
                    if (Input.KeyboardKeyJustPressed(Keys.D2))
                    {
                        if (cube1.Material.DiffuseTextureName == "Textures\\Grass")
                            cube1.Material.DiffuseTextureName = "Textures\\Rock";
                        else
                            cube1.Material.DiffuseTextureName = "Textures\\Grass";
                    }
                    //按数字3键切换漫反射纹理平铺值
                    if (Input.KeyboardKeyJustPressed(Keys.D3))
                    {
                        if (cube1.Material.DiffuseUVTile == Vector2.One)
                            cube1.Material.DiffuseUVTile = new Vector2(2.0f, 2.0f);
                        else
                            cube1.Material.DiffuseUVTile = Vector2.One;
                    }
                });
        }
#endif
        #endregion
    }
}

关键还是在于创建立方体顶点和索引的方法,它位于MeshBuilder类的静态方法CreateCube中:

/// 
/// 创建一个立方体。        
/// 
/// 图形设备
/// 
public static Mesh CreateCube(GraphicsDevice g)
{
    // 创建24个顶点。正方体有8个顶点,但是因为需要设置法线数据,所以必须定义24个顶点,每个面4个共24个,否则光照是不正确的
    VertexPositionNormalTexture[] vertices = new VertexPositionNormalTexture[24];

    // 设置8个顶点的位置
    Vector3 forwardBottomLeft = new Vector3(-HALF, -HALF, HALF);
    Vector3 forwardBottomRight = new Vector3(HALF, -HALF, HALF);
    Vector3 forwardUpperLeft = new Vector3(-HALF, HALF, HALF);
    Vector3 forwardUpperRight = new Vector3(HALF, HALF, HALF);

    Vector3 backBottomLeft = new Vector3(-HALF, -HALF, -HALF);
    Vector3 backBottomRight = new Vector3(HALF, -HALF, -HALF);
    Vector3 backUpperLeft = new Vector3(-HALF, HALF, -HALF);
    Vector3 backUpperRight = new Vector3(HALF, HALF, -HALF);


    #region 前面的顶点

    // 左下角顶点 - 0
    vertices[0].Position = forwardBottomLeft;
    vertices[0].TextureCoordinate = new Vector2(0, 1);
    vertices[0].Normal = Vector3.Backward;

    //  左上角顶点 - 1
    vertices[1].Position = forwardUpperLeft;
    vertices[1].TextureCoordinate = new Vector2(0, 0);
    vertices[1].Normal = Vector3.Backward;

    // 右下角顶点 - 2
    vertices[2].Position = forwardBottomRight;
    vertices[2].TextureCoordinate = new Vector2(1, 1);
    vertices[2].Normal = Vector3.Backward;

    // 右上角顶点 - 3
    vertices[3].Position = forwardUpperRight;
    vertices[3].TextureCoordinate = new Vector2(1, 0);
    vertices[3].Normal = Vector3.Backward;

    #endregion

    #region 后面的顶点

    // 左下角顶点-4
    vertices[4].Position = backBottomLeft;
    vertices[4].TextureCoordinate = new Vector2(0, 1);
    vertices[4].Normal = Vector3.Forward;

    //  左上角顶点-5
    vertices[5].Position = backUpperLeft;
    vertices[5].TextureCoordinate = new Vector2(0, 0);
    vertices[5].Normal = Vector3.Forward;

    // 右下角顶点-6
    vertices[6].Position = backBottomRight;
    vertices[6].TextureCoordinate = new Vector2(1, 1);
    vertices[6].Normal = Vector3.Forward;

    // 右上角顶点-7
    vertices[7].Position = backUpperRight;
    vertices[7].TextureCoordinate = new Vector2(1, 0);
    vertices[7].Normal = Vector3.Forward;
    #endregion

    #region 左面的顶点

    // 左下角顶点-0
    vertices[8].Position = forwardBottomLeft;
    vertices[8].TextureCoordinate = new Vector2(0, 1);
    vertices[8].Normal = Vector3.Left ;

    // 左上角顶点-1
    vertices[9].Position = forwardUpperLeft;
    vertices[9].TextureCoordinate = new Vector2(0, 0);
    vertices[9].Normal = Vector3.Left ;

    // 右下角顶点-4
    vertices[10].Position = backBottomLeft;
    vertices[10].TextureCoordinate = new Vector2(1, 1);
    vertices[10].Normal = Vector3.Left ;


    // 右上角顶点-5
    vertices[11].Position = backUpperLeft;
    vertices[11].TextureCoordinate = new Vector2(1, 0);
    vertices[11].Normal = Vector3.Left ;
    #endregion

    #region 右面的顶点

    //  左下角顶点-2
    vertices[12].Position = forwardBottomRight;
    vertices[12].TextureCoordinate = new Vector2(0, 1);
    vertices[12].Normal = Vector3.Right ;

    // 左上角顶点-3
    vertices[13].Position = forwardUpperRight;
    vertices[13].TextureCoordinate = new Vector2(0, 0);
    vertices[13].Normal = Vector3.Right;

    // 右下角顶点-6
    vertices[14].Position = backBottomRight;
    vertices[14].TextureCoordinate = new Vector2(1, 1);
    vertices[14].Normal = Vector3.Right;


    // 右上角顶点-7
    vertices[15].Position = backUpperRight;
    vertices[15].TextureCoordinate = new Vector2(1, 0);
    vertices[15].Normal = Vector3.Right;
    #endregion

    #region 上面的顶点

    //  左下角顶点-1
    vertices[16].Position = forwardUpperLeft;
    vertices[16].TextureCoordinate = new Vector2(0, 1);
    vertices[16].Normal = Vector3.Up;

    // 左上角顶点-5
    vertices[17].Position = backUpperLeft;
    vertices[17].TextureCoordinate = new Vector2(0, 0);
    vertices[17].Normal = Vector3.Up;

    // 右下角顶点-3
    vertices[18].Position = forwardUpperRight;
    vertices[18].TextureCoordinate = new Vector2(1, 1);
    vertices[18].Normal = Vector3.Up;

    // 右上角顶点-7
    vertices[19].Position = backUpperRight;
    vertices[19].TextureCoordinate = new Vector2(1, 0);
    vertices[19].Normal = Vector3.Up;
    #endregion

    #region 下面的顶点

    //  左下角顶点-0
    vertices[20].Position = forwardBottomLeft;
    vertices[20].TextureCoordinate = new Vector2(0, 1);
    vertices[20].Normal = Vector3.Down;

    // 左上角顶点-4
    vertices[21].Position = backBottomLeft;
    vertices[21].TextureCoordinate = new Vector2(0, 0);
    vertices[21].Normal = Vector3.Down;

    // 右下角顶点-2
    vertices[22].Position = forwardBottomRight;
    vertices[22].TextureCoordinate = new Vector2(1, 1);
    vertices[22].Normal = Vector3.Down;


    // 右上角顶点-6
    vertices[23].Position = backBottomRight;
    vertices[23].TextureCoordinate = new Vector2(1, 0);
    vertices[23].Normal = Vector3.Down;
    #endregion

    //36个索引,每个面有两个三角形,每个三角形有3个索引,所以共36个索引,因为索引数量不会超过65536个,所以它的数据类型为ushort,可以减少发送到显卡的数据量
    ushort[] indices = {   
                        // 前面的正方形
                        0, 1, 2,
                        1, 3, 2,

                        // 后面的正方形
                        4, 6, 5,
                        6, 7, 5,

                        // 左面的正方形
                        9, 8, 10,
                        9, 10, 11,                                

                        // 右面的正方形
                        12, 13, 14,
                        13, 15, 14,

                        // 上面的正方形                                
                         16, 17, 18,
                         18, 17, 19,

                        // 下面的正方形                                
                        20, 22, 21,
                        22, 23, 21
                    };

    //创建顶点缓冲
    VertexBuffer vb = new VertexBuffer(g, typeof(VertexPositionNormalTexture), vertices.Length, BufferUsage.None);
    vb.SetData(vertices,0,24);

    //设置顶点声明
    VertexDeclaration vxDeclaration = new VertexDeclaration(g, VertexPositionNormalTexture.VertexElements);

    //创建索引缓冲
    IndexBuffer ib = new IndexBuffer(g, typeof(ushort), indices.Length, BufferUsage.None);
    ib.SetData(indices);

    return new Mesh(PrimitiveType.TriangleList, vb, vxDeclaration, ib, 24, 12);
}

创建顶点数据的示意图如下图所示,第一个数字表示顶点序号,括号中数字表示坐标:

立方体的顶点

不知道如何使用TriangleStrip形式定义顶点,就用TriangleList吧,毕竟TriangleList容易理解。只有8个顶点也弄得我头晕脑胀,有人第一次做就全做对吗?如果有的话这个人的头脑真的是很清楚。 单元测试截图如下:

单元测试

文件下载(已下载 1871 次)

发布时间:2010/4/23 下午2:56:35  阅读次数:6856

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号