关于.Net框架下3D游戏的设计与实现——2.2,使用我们的Axiom

由于前几个月工作较忙,一直都没有继续研究Axiom,最近终于节点结束可以继续研究一下C#了^_^

    上一篇说道了如何将Axiom连接到我们的工程,并使用Axiom应用程序框架生成一个空Axiom项目。今天我们来探讨一下如何让Axiom渲染一些我们需要的3D物件。

    首先渲染一个3D物件到场景。在Axiom给出的ExampleApplication类当中有这样一个虚函数protected virtual void CreateScene() ,它是用来初始化场景的我们可以在它里面设置我们要渲染3D物件。上一节我们用AxiomTest继承了ExampleApplication,我们可以在AxiomTest中复写CreateScene() 并在它里创建我们的3D世界,代码如下:

       protected override void CreateScene()

        {

            // 实体

            Entity ent;



            // 节点

            SceneNode node;



            // Set the default lighting

            SceneManager.AmbientLight = ColorEx.White;



             // Create knot object

            ent = SceneManager.CreateEntity("Knot1", "knot.mesh");

            node = SceneManager.RootSceneNode;
            node.AttachObject(ent);

            node.Scale(new Vector3(0.1f, 0.1f, 0.1f));



            // 给我们的物件换个材质

            ent.MaterialName = "TextureFX/Water";   



        }

 

这就是显示出来的结果:

 接下来我们添加天空盒和地面,在Axiom下这些操作都变得非常简单:

             SceneManager.SetSkyBox(true, "Skybox/Stormy", 50);

            Plane plane = new Plane(Vector3.UnitY, Vector3.Zero);             MeshManager.Instance.CreatePlane(                 "MyPlane", plane, 150000, 150000, 20, 20, true, 1, 100, 100, Vector3.UnitZ);

            Entity planeEnt = SceneManager.CreateEntity("Plane", "MyPlane");             planeEnt.MaterialName = "Examples/Rockwall";             node.AttachObject(planeEnt); 将上面的代码插入到CreateScene()函数中即可。

以上是最基本的通过Entity在场景中绘制物体,基本过程就是用SceneManager的CreateEntity方法通过已经存在的资源来创建一个Entity然后再把这个Entity的节点绑到场景节点上,是不是很简单^_^

接下来讨论点稍微有难度的,我们来画线段,当然在Axiom中有有关画线的例子,你会发现用Axiom画线比较繁琐,基本和直接用Direct画线差不多。

这里给出一个简单的例子:

    /// <summary>

    ///	此类用于绘制3D空间中的线

    /// </summary>

    public class Line3d : SimpleRenderable

    {

        // constants for buffer source bindings

        const int POSITION = 0;

        const int COLOR = 1;



        public Line3d(Vector3 startPoint, Vector3 endPoint, ColorEx color)

        {

            vertexData = new VertexData();

            vertexData.vertexCount = 2;

            vertexData.vertexStart = 0;



            VertexDeclaration decl = vertexData.vertexDeclaration;

            VertexBufferBinding binding = vertexData.vertexBufferBinding;



            // add a position and color element to the declaration

            decl.AddElement(POSITION, 0, VertexElementType.Float3, VertexElementSemantic.Position);

            decl.AddElement(COLOR, 0, VertexElementType.Color, VertexElementSemantic.Diffuse);



            // create a vertex buffer for the position

            HardwareVertexBuffer buffer =

                HardwareBufferManager.Instance.CreateVertexBuffer(

                decl.GetVertexSize(POSITION),

                vertexData.vertexCount,

                BufferUsage.StaticWriteOnly);



            Vector3[] pos = new Vector3[] { startPoint, endPoint };



            // write the data to the position buffer

            buffer.WriteData(0, buffer.Size, pos, true);



            // bind the position buffer

            binding.SetBinding(POSITION, buffer);



            // create a color buffer

            buffer = HardwareBufferManager.Instance.CreateVertexBuffer(

                decl.GetVertexSize(COLOR),

                vertexData.vertexCount,

                BufferUsage.StaticWriteOnly);



            



            int colorValue = Root.Instance.RenderSystem.ConvertColor(color);



            int[] colors = new int[] { colorValue, colorValue };



            // write the data to the position buffer

            buffer.WriteData(0, buffer.Size, colors, true);



            // bind the color buffer

            binding.SetBinding(COLOR, buffer);



            // MATERIAL

            // grab a copy of the BaseWhite material for our use

            Material material = MaterialManager.Instance.GetByName("BaseWhite");

            material = material.Clone("LineMat");

            // disable lighting to vertex colors are used

            material.Lighting = false;

            // set culling to none so the triangle is drawn 2 sided

            material.CullingMode = CullingMode.None;



            this.Material = material;



            // set the bounding box of the line

            this.box = new AxisAlignedBox(startPoint, endPoint);

        }



        /// <summary>

        /// 

        /// </summary>

        /// <param name="startPoint">Point where the line will start.</param>

        /// <param name="direction">The direction the vector is heading in.</param>

        /// <param name="length">The length (magnitude) of the line vector.</param>

        /// <param name="color">The color which this line should be.</param>

        public Line3d(Vector3 startPoint, Vector3 direction, float length, ColorEx color)

        {

            // normalize the direction vector to ensure all elements fall in [0,1] range.

            direction.Normalize();



            // calculate the actual endpoint

            Vector3 endPoint = startPoint + (direction * length);



            vertexData = new VertexData();

            vertexData.vertexCount = 2;

            vertexData.vertexStart = 0;



            VertexDeclaration decl = vertexData.vertexDeclaration;

            VertexBufferBinding binding = vertexData.vertexBufferBinding;



            // add a position and color element to the declaration

            decl.AddElement(POSITION, 0, VertexElementType.Float3, VertexElementSemantic.Position);

            decl.AddElement(COLOR, 0, VertexElementType.Color, VertexElementSemantic.Diffuse);



            // create a vertex buffer for the position

            HardwareVertexBuffer buffer =

                HardwareBufferManager.Instance.CreateVertexBuffer(

                decl.GetVertexSize(POSITION),

                vertexData.vertexCount,

                BufferUsage.StaticWriteOnly);



            Vector3[] pos = new Vector3[] { startPoint, endPoint };



            // write the data to the position buffer

            buffer.WriteData(0, buffer.Size, pos, true);



            // bind the position buffer

            binding.SetBinding(POSITION, buffer);



            // create a color buffer

            buffer = HardwareBufferManager.Instance.CreateVertexBuffer(

                decl.GetVertexSize(COLOR),

                vertexData.vertexCount,

                BufferUsage.StaticWriteOnly);



            int colorValue = Root.Instance.RenderSystem.ConvertColor(color);



            int[] colors = new int[] { colorValue, colorValue };



            // write the data to the position buffer

            buffer.WriteData(0, buffer.Size, colors, true);



            // bind the color buffer

            binding.SetBinding(COLOR, buffer);



            // MATERIAL

            // grab a copy of the BaseWhite material for our use

            Material material = MaterialManager.Instance.GetByName("BaseWhite");

            material = material.Clone("LineMat");

            // disable lighting to vertex colors are used

            material.Lighting = false;

            // set culling to none so the triangle is drawn 2 sided

            material.CullingMode = CullingMode.None;



            this.Material = material;



            // set the bounding box of the line

            this.box = new AxisAlignedBox(startPoint, endPoint);

        }



        /// <summary>

        /// 

        /// </summary>

        /// <param name="camera"></param>

        /// <returns></returns>

        public override float GetSquaredViewDepth(Camera camera)

        {

            Vector3 min, max, mid, dist;

            min = box.Minimum;

            max = box.Maximum;

            mid = ((min - max) * 0.5f) + min;

            dist = camera.DerivedPosition - mid;



            return dist.LengthSquared;

        }



        /// <summary>

        /// 

        /// </summary>

        /// <param name="op"></param>

        public override void GetRenderOperation(RenderOperation op)

        {

            op.vertexData = vertexData;

            op.indexData = null;

            op.operationType = OperationType.LineList;

            op.useIndices = false;

        }



        public override float BoundingRadius

        {

            get

            {

                return 0;

            }

        }



    }
这个类封装了简单的画线方法,但是问题出现了,如果要画不定数量条线断而且每条每帧位置都有变化(比如要把场景中所有的实体的包围球用线框画出来),那该怎么办呢?
在游戏循环中是不能每帧都new的!否则效率将相当低!
以下是我想到的一种解决方案:
    class LinesList : SimpleRenderable

    {

        // constants for buffer source bindings

        const int POSITION = 0;

        const int COLOR = 1;



        const int c_maxPointCount = 10000;



        public static int MaxPointCount

        {

            get { return c_maxPointCount; }

        }



        HardwareVertexBuffer _posBuffer = null;

        Vector3[] _posData = new Vector3[c_maxPointCount];

        

        HardwareVertexBuffer _colorBuffer = null;

        int[] _colorData = new int[c_maxPointCount];

        



        public LinesList()

        {

            vertexData = new VertexData();

            vertexData.vertexCount = c_maxPointCount;

            vertexData.vertexStart = 0;



            VertexDeclaration decl = vertexData.vertexDeclaration;

            VertexBufferBinding binding = vertexData.vertexBufferBinding;



            // add a position and color element to the declaration

            decl.AddElement(POSITION, 0, VertexElementType.Float3, VertexElementSemantic.Position);

            decl.AddElement(COLOR, 0, VertexElementType.Color, VertexElementSemantic.Diffuse);



            // create a vertex buffer for the position

            _posBuffer =

                HardwareBufferManager.Instance.CreateVertexBuffer(

                decl.GetVertexSize(POSITION),

                vertexData.vertexCount,

                BufferUsage.DynamicWriteOnly);





            // write the data to the position buffer

            _posBuffer.WriteData(0, _posBuffer.Size, _posData, true);



            // bind the position buffer

            binding.SetBinding(POSITION, _posBuffer);



            // create a color buffer

            _colorBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(

                decl.GetVertexSize(COLOR),

                vertexData.vertexCount,

                BufferUsage.DynamicWriteOnly);



            // write the data to the position buffer

            _colorBuffer.WriteData(0, _colorBuffer.Size, _colorData, true);



            // bind the color buffer

            binding.SetBinding(COLOR, _colorBuffer);



            // MATERIAL

            // grab a copy of the BaseWhite material for our use

            Material material = MaterialManager.Instance.GetByName("BaseWhite");

            material = material.Clone("LineMat");

            // disable lighting to vertex colors are used

            material.Lighting = false;

            // set culling to none so the triangle is drawn 2 sided

            material.CullingMode = CullingMode.None;



            this.Material = material;



            // set the bounding box of the line

            this.box = new AxisAlignedBox(new Vector3(-1000, -1000, -1000), new Vector3(1000, 1000, 1000));

        }





        /// <summary>

        /// 

        /// </summary>

        /// <param name="camera"></param>

        /// <returns></returns>

        public override float GetSquaredViewDepth(Camera camera)

        {

            Vector3 min, max, mid, dist;

            min = box.Minimum;

            max = box.Maximum;

            mid = ((min - max) * 0.5f) + min;

            dist = camera.DerivedPosition - mid;



            return dist.LengthSquared;

        }



        /// <summary>

        /// 

        /// </summary>

        /// <param name="op"></param>

        public override void GetRenderOperation(RenderOperation op)

        {

            op.vertexData = vertexData;

            op.indexData = null;

            op.operationType = OperationType.LineList;

            op.useIndices = false;

        }



        public override float BoundingRadius

        {

            get

            {

                return 0;

            }

        }



        public void Update(Vector3[] posList, ColorEx[] colorList)

        {

            for (int i = 0; i < c_maxPointCount; i++)

            {

                _posData[i] = Vector3.Zero;

                if (i < posList.Length)

                {

                    _posData[i] = posList[i];

                }



                _colorData[i] = 0;

                if (i < colorList.Length)

                {

                    _colorData[i] = Root.Instance.RenderSystem.ConvertColor(ColorEx.Blue);

                }

            }

            _posBuffer.WriteData(0, _posBuffer.Size, _posData, true);

            _colorBuffer.WriteData(0, _colorBuffer.Size, _colorData, true);

        }

    }
使用这个类创建一个对象然后每帧更新所有线段起点和终点的位置还有颜色即可。
本节到此结束。下一节我们继续深入Axiom。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值