DirectX天空球和天空盒子模型

来源:互联网 发布:韩国淘宝网站 编辑:程序博客网 时间:2024/04/28 13:37

在一些大型的3D游戏中,有几个必不可少的元素,比如说天空和大地,这些元素的存在可以增加3D场景的真实感。三维场景中天空和大地场景的模拟其实很简单,这种场景跟古人所说的“天圆地方”有着异曲同工之妙。天空其实就是一个很大的容器,把整个世界都罩在下面,大地就是一个平面,场景中所有的元素都显示在二者所包围的空间中。三维天空的技术主要包括三种类型:一种是平面型天空(Sky Plane),仅用一个平面盖在所有元素的头顶。这种技术有点弱,很容易被识破,真实感也很低,有时还需要用雾来覆盖远景以增加真实感,但是效果和技术含量依然很低;还有一种就是天空穹庐(Sky Dome),有时也称为天空球,即放到场景元素头顶上的是一个曲面,通常都会为一个半球,这种技术的真实性和立体感最强,但是不是目前使用最广泛的方案,通常会涉及到天空无缝衔接的素材匮乏等的问题;另外一种就是天空盒子(Sky Box),即把天空做成一个立方体,所有的元素都罩在其下,这种技术是目前使用最广泛的三维天空模拟技术,在一些高级的应用中,天空盒子的纹理可能同时会用来生成Cube Map,并用之来做水面倒影、云影、反光等很眩的特效,网络上关于这方面的素材也很多,感兴趣的可以自己搜一下。这里主要给出后面两种模型的实现即天空球和天空盒子,引擎框架用的是微软的DirectX,用C#来实现。

天空球

因为最近在研究道路的三维仿真,所以实现的背景就是道路的三维显示,为了增加真实感,在其上罩了一个天空球。关于道路的三维显示,采用了一个很简单的思路,利用传感器采集的道路数据,一般是是BMP格式的,把采集获得的BMP数据的输出作为道路的高程图(Height Map),根据各个点像素值计算道路的高程值(世界坐标系中Y方向上的高度值),建立顶点缓冲和顶点索引缓冲,再进行三角形构网和道路的纹理贴图就OK了。Demo版本的思路暂时是这样的,这里给出Demo版本的实现。这里贴上一张道路的三维网格效果图如下:


天空球的实现更加简单,利用专业的软件3dsMax把天空模型和大地模型做好,导出.x文件,再利用DirectX提供的接口将其加载进去,然后进行相应的坐标系空间转换调整一下就行了。3dsMax下建好的模型如下:



下面再贴上一张DirectX下实现的带有天空球的道路模型:



这里贴上该模型实现的核心代码:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using Microsoft.DirectX;using Microsoft.DirectX.Direct3D;using System.IO;namespace RoadSkydom{    public partial class RoadSkydom : Form    {        private Device m_device = null;        bool pause = false;        Mesh skyboxMesh = null;        Material skyboxMeshMaterials;        Texture[] skyboxMeshTextures;        Microsoft.DirectX.Direct3D.Material[] meshMaterials1;        float Angle = 0, ViewZ = -5.0f;                private float angleY = 0.01f;//定义绕Y轴旋转变量        private int mouseLastX, mouseLastY;//记录鼠标按下时的坐标位置        private bool isRotateByMouse = false;//记录是否由鼠标控制旋转        private bool isMoveByMouse = false;//记录是否由鼠标控制移动        private CustomVertex.PositionTextured[] vertices;//定义顶点变量        private Texture texture;//定义贴图变量        private Material material;//定义材质变量        private VertexBuffer vertexBuffer;//定义顶点缓冲变量        private IndexBuffer indexBuffer;//定义索引缓冲变量        private int[] indices;//定义索引号变量        private int xCount = 5, yCount = 4;//定义横向和纵向网格数目        private float cellHeight = 1f, cellWidth = 1f;//定义单元的宽度和长度        Material bottomMaterial;//底部材质变量        Texture bottomTexture;//底部纹理变量        VertexBuffer bottomVertexBuffer = null;//保存建立底部正方形的顶点        private VertexBuffer borderFrontVertexBuffer = null;        private CustomVertex.PositionColored[] borderFrontVertices;//定义前面边缘顶点变量        private IndexBuffer borderFrontIndexBuffer;//定义前面边缘顶点索引缓冲变量        private int[] borderFrontIndices;//定义前面边缘顶点的索引号变量        private VertexBuffer borderBackVertexBuffer = null;        private CustomVertex.PositionColored[] borderBackVertices;//定义背面边缘顶点变量        private IndexBuffer borderBackIndexBuffer;//定义背面边缘顶点索引缓冲变量        private int[] borderBackIndices;//定义背面边缘顶点的索引号变量        private VertexBuffer borderLeftVertexBuffer = null;        private CustomVertex.PositionColored[] borderLeftVertices;//定义左面边缘顶点变量        private IndexBuffer borderLeftIndexBuffer;//定义左面边缘顶点索引缓冲变量        private int[] borderLeftIndices;//定义左面边缘顶点的索引号变量        private VertexBuffer borderRightVertexBuffer = null;        private CustomVertex.PositionColored[] borderRightVertices;//定义右面边缘顶点变量        private IndexBuffer borderRightIndexBuffer;//定义右面边缘顶点索引缓冲变量        private int[] borderRightIndices;//定义右面边缘顶点的索引号变量        public RoadSkydom()        {            InitializeComponent();        }        public bool InitializeGraphics()        {            try            {                PresentParameters presentParams = new PresentParameters();                presentParams.Windowed = true;//不是全屏显示,在一个窗口显示                presentParams.SwapEffect = SwapEffect.Discard; //后备缓存交换的方式                presentParams.EnableAutoDepthStencil = true; //允许使用自动深度模板测试                //深度缓冲区单元为16位二进制数                presentParams.AutoDepthStencilFormat = DepthFormat.D16;                m_device = new Device(0, DeviceType.Hardware, this,  //建立设备类对象          CreateFlags.SoftwareVertexProcessing, presentParams);                //设置设备重置事件(device.DeviceReset)事件函数为this.OnResetDevice                m_device.DeviceReset += new System.EventHandler(this.OnResetDevice);                this.OnCreateDevice(m_device, null);//自定义方法,初始化Device的工作放到这个方法中                this.OnResetDevice(m_device, null);//调用设备重置事件(device.DeviceReset)事件函数            }//设备重置事件函数要设置Device参数,初始函数中必须调用该函数            catch (DirectXException)            {                return false;            }            return true;        }        public void OnCreateDevice(object sender, EventArgs e)        {            Device device = (Device)sender;            ExtendedMaterial[] materials = null;            //设定运行程序所在目录的上两级目录为当前默认目录            Directory.SetCurrentDirectory(Application.StartupPath + @"\..\..\..\");            GraphicsStream adjacency;                        skyboxMesh = Mesh.FromFile("skydom_bottom.x", MeshFlags.Managed, m_device, out adjacency, out materials);            if (skyboxMeshTextures == null)//如果还未设置纹理,为3D图形增加纹理和材质            {                skyboxMeshTextures = new Texture[materials.Length];//纹理数组                meshMaterials1 = new Material[materials.Length];//材质数组                for (int i = 0; i < materials.Length; i++)//读入纹理和材质                {                    meshMaterials1[i] = materials[i].Material3D;                    meshMaterials1[i].Ambient = meshMaterials1[i].Diffuse;                    skyboxMeshTextures[i] = TextureLoader.FromFile(m_device,                                        materials[i].TextureFilename);                }            }//下句优化Mesh,减少属性的状态改变提高渲染速度            skyboxMesh.Optimize(MeshFlags.Managed | MeshFlags.OptimizeAttributeSort, adjacency);            material = new Material();            material.Diffuse = Color.White;            material.Specular = Color.LightGray;            material.SpecularSharpness = 15.0F;            device.Material = material;            texture = TextureLoader.FromFile(device, @"F:\\workdir\\VC# Based DirectX\\RoadTexture.jpg");            //底部材料和贴图            bottomMaterial = new Material();            bottomMaterial.Ambient = Color.FromArgb(200, 255, 255, 255);            bottomMaterial.Diffuse = Color.FromArgb(200, 255, 255, 255);            bottomTexture = TextureLoader.FromFile(device, "F:\\workdir\\VC# Based DirectX\\BottomTexture.bmp");            bottomVertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionNormalTextured), 6, device, 0, CustomVertex.PositionNormalTextured.Format, Pool.Default);            bottomVertexBuffer.Created += new System.EventHandler(this.OnCreateBottomVertexBuffer);            this.OnCreateBottomVertexBuffer(device, null);        }        //底部顶点        public void OnCreateBottomVertexBuffer(object sender, EventArgs e)        {            CustomVertex.PositionNormalTextured[] bottomVerts = (CustomVertex.PositionNormalTextured[])bottomVertexBuffer.Lock(0, 0);//绘制底面正方形的6个顶点            string bitmapPath = @"F:\\workdir\\VC# Based DirectX\\RoadHeight.BMP";            float minHeight = GetMinHeight(bitmapPath);            float xWidth = GetBitMapWidth(bitmapPath);            float yHeight = GetBitMapHeight(bitmapPath);            bottomVerts[0].Position = new Vector3(-100.0f, minHeight - 5.0f, -100.0f);            bottomVerts[0].Normal = new Vector3(0, 0, -1);            bottomVerts[0].Tu = 0.0f;//顶点0纹理坐标Tu            bottomVerts[0].Tv = 5.0f;//纹理图片沿Y轴方向重复贴图50次            bottomVerts[1].Position = new Vector3(-100.0f, minHeight - 5.0f, yHeight + 100.0f);            bottomVerts[1].Normal = new Vector3(0, 0, -1);            bottomVerts[1].Tu = 0.0f;            bottomVerts[1].Tv = 0.0f;            bottomVerts[2].Position = new Vector3(xWidth + 100.0f, minHeight - 5.0f, yHeight + 100.0f);            bottomVerts[2].Normal = new Vector3(0, 0, -1);            bottomVerts[2].Tu = 5.0f;            bottomVerts[2].Tv = 0.0f;            bottomVerts[3].Position = new Vector3(-100.0f, minHeight - 5.0f, -100.0f);            bottomVerts[3].Normal = new Vector3(0, 0, -1);            bottomVerts[3].Tu = 0.0f;            bottomVerts[3].Tv = 5.0f;            bottomVerts[4].Position = new Vector3(xWidth + 100.0f, minHeight - 5.0f, yHeight + 100.0f);            bottomVerts[4].Normal = new Vector3(0, 0, -1);            bottomVerts[4].Tu = 5.0f;            bottomVerts[4].Tv = 0.0f;            bottomVerts[5].Position = new Vector3(xWidth + 100.0f, minHeight - 5.0f, -100.0f);            bottomVerts[5].Normal = new Vector3(0, 0, -1);            bottomVerts[5].Tu = 5.0f;            bottomVerts[5].Tv = 5.0f;            bottomVertexBuffer.Unlock();        }        //避免精度损失        public float GetBitMapHeight(string bitmapPath)        {            Bitmap bitmap = new Bitmap(bitmapPath);            xCount = (bitmap.Width - 1) / 2;            yCount = xCount;            cellWidth = bitmap.Width / xCount;            cellHeight = bitmap.Height / yCount;            return (float)(yCount * cellHeight);        }        //避免精度损失        public float GetBitMapWidth(string bitmapPath)        {            Bitmap bitmap = new Bitmap(bitmapPath);            xCount = (bitmap.Width - 1) / 2;            yCount = xCount;            cellWidth = bitmap.Width / xCount;            cellHeight = bitmap.Height / yCount;            return (float)(xCount * cellWidth);        }        //获得高度图Y方向上的最小高度值         public float GetMinHeight(string bitmapPath)        {            float minHeight = 6553500.0f;            Bitmap bitmap = new Bitmap(bitmapPath);            xCount = (bitmap.Width - 1) / 2;            yCount = xCount;            cellWidth = bitmap.Width / xCount;            cellHeight = bitmap.Height / yCount;            for (int i = 0; i < yCount + 1; i++)                for (int j = 0; j < xCount + 1; j++)                {                    Color color = bitmap.GetPixel((int)(j * cellWidth), (int)(i * cellHeight));                    float height = float.Parse(color.R.ToString()) +                    float.Parse(color.G.ToString()) + float.Parse(color.B.ToString());                    height /= 10;                    if (height < minHeight)                        minHeight = height;                }            return minHeight;        }        public void OnResetDevice(object sender, EventArgs e)        {            Device device = (Device)sender;            device.RenderState.ZBufferEnable = true; //允许使用深度缓冲            device.RenderState.Ambient = System.Drawing.Color.White;//设定环境光为白色            device.Lights[0].Type = LightType.Directional;  //设置灯光类型            device.Lights[0].Diffuse = Color.White;//设置灯光颜色            device.Lights[0].Direction = new Vector3(0, -1, 0);//设置灯光位置            device.Lights[0].Update();//更新灯光设置,创建第一盏灯光            device.Lights[0].Enabled = true;//使设置有效            string bitmapPath = @"F:\\workdir\\VC# Based DirectX\\RoadHeight.BMP";            Bitmap bitmap = new Bitmap(bitmapPath);            xCount = (bitmap.Width - 1) / 2;            yCount = xCount;            cellWidth = bitmap.Width / xCount;            cellHeight = bitmap.Height / yCount;            vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionTextured), (xCount + 1) * (yCount + 1), device,                Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Default);            vertices = new CustomVertex.PositionTextured[(xCount + 1) * (yCount + 1)];//定义顶点            for (int i = 0; i < yCount + 1; i++)            {                for (int j = 0; j < xCount + 1; j++)                {                    Color color = bitmap.GetPixel((int)(j * cellWidth), (int)(i * cellHeight));                    float height = float.Parse(color.R.ToString()) + float.Parse(color.G.ToString()) + float.Parse(color.B.ToString());                    height /= 10;                    vertices[j + i * (xCount + 1)].Position = new Vector3(j * cellWidth, height, i * cellHeight);                    vertices[j + i * (xCount + 1)].Tu = (float)j / (xCount + 1);                    vertices[j + i * (xCount + 1)].Tv = (float)i / (yCount + 1);                }            }            vertexBuffer.SetData(vertices, 0, LockFlags.None);            CamTarget = new Vector3(bitmap.Width / 2, 0f, bitmap.Height / 2);//设置摄像机目标位置            indexBuffer = new IndexBuffer(typeof(int), 6 * xCount * yCount, device, Usage.WriteOnly, Pool.Default);            indices = new int[6 * xCount * yCount];            for (int i = 0; i < yCount; i++)            {                for (int j = 0; j < xCount; j++)                {                    indices[6 * (j + i * xCount)] = j + i * (xCount + 1);                    indices[6 * (j + i * xCount) + 1] = j + (i + 1) * (xCount + 1);                    indices[6 * (j + i * xCount) + 2] = j + i * (xCount + 1) + 1;                    indices[6 * (j + i * xCount) + 3] = j + i * (xCount + 1) + 1;                    indices[6 * (j + i * xCount) + 4] = j + (i + 1) * (xCount + 1);                    indices[6 * (j + i * xCount) + 5] = j + (i + 1) * (xCount + 1) + 1;                }            }            indexBuffer.SetData(indices, 0, LockFlags.None);            /*******第1个四周边界********/            float minY = GetMinHeight(bitmapPath) - 5.0f;            borderFrontVertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored),                2 * (xCount + 1),//四周的一个面封闭总共所需要的顶点的数目                device,                Usage.Dynamic | Usage.WriteOnly,                CustomVertex.PositionColored.Format,                Pool.Default);            borderFrontVertices = new CustomVertex.PositionColored[2 * (xCount + 1)];//定义顶点            int k;            for (k = 0; k < xCount + 1; k++)//X轴上的点的定义            {                borderFrontVertices[k].Position = new Vector3(k * cellWidth, minY, 0.0f);                borderFrontVertices[k].Color = System.Drawing.Color.Red.ToArgb();            }            for (; k < 2 * (xCount + 1); k++)//高程图上的边界点的定义            {                Color color = bitmap.GetPixel((int)((k - xCount - 1) * cellWidth), 0);                float height = float.Parse(color.R.ToString()) + float.Parse(color.G.ToString()) + float.Parse(color.B.ToString());                height /= 10;                borderFrontVertices[k].Position = new Vector3((k - xCount - 1) * cellWidth, height, 0);//i * cellHeight=0                borderFrontVertices[k].Color = System.Drawing.Color.Aqua.ToArgb();            }            borderFrontVertexBuffer.SetData(borderFrontVertices, 0, LockFlags.None);            borderFrontIndexBuffer = new IndexBuffer(typeof(int),                6 * xCount * 1,                device,                Usage.WriteOnly,                Pool.Default);            borderFrontIndices = new int[6 * xCount * 1];//初始化索引顶点            for (int j = 0; j < xCount; j++)            {                borderFrontIndices[6 * (j)] = j;                borderFrontIndices[6 * (j) + 1] = j + (xCount + 1);                borderFrontIndices[6 * (j) + 2] = j + 1;                borderFrontIndices[6 * (j) + 3] = j + 1;                borderFrontIndices[6 * (j) + 4] = j + (xCount + 1);                borderFrontIndices[6 * (j) + 5] = j + (xCount + 1) + 1;            }            borderFrontIndexBuffer.SetData(borderFrontIndices, 0, LockFlags.None);            /**第2个四周边界**/            borderBackVertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored),                2 * (xCount + 1),//四周的一个面封闭总共所需要的顶点的数目                device,                Usage.Dynamic | Usage.WriteOnly,                CustomVertex.PositionColored.Format,                Pool.Default);            borderBackVertices = new CustomVertex.PositionColored[2 * (xCount + 1)];//定义顶点            for (k = 0; k < xCount + 1; k++)//X轴平行方向上的点的定义            {                borderBackVertices[k].Position = new Vector3(k * cellWidth, minY, yCount * cellHeight);                borderBackVertices[k].Color = System.Drawing.Color.Aqua.ToArgb();            }            for (; k < 2 * (xCount + 1); k++)//高程图上的边界点的定义            {                Color color = bitmap.GetPixel((int)((k - xCount - 1) * cellWidth), (int)(yCount * cellHeight));//不能直接写死                float height = float.Parse(color.R.ToString()) + float.Parse(color.G.ToString()) + float.Parse(color.B.ToString());                height /= 10;                borderBackVertices[k].Position = new Vector3((k - xCount - 1) * cellWidth, height, yCount * cellHeight);                borderBackVertices[k].Color = System.Drawing.Color.Aqua.ToArgb();            }            borderBackVertexBuffer.SetData(borderBackVertices, 0, LockFlags.None);            borderBackIndexBuffer = new IndexBuffer(typeof(int),                6 * xCount * 1,                device,                Usage.WriteOnly,                Pool.Default);            borderBackIndices = new int[6 * xCount * 1];//初始化索引顶点            for (int j = 0; j < xCount; j++)            {                borderBackIndices[6 * (j)] = j;                borderBackIndices[6 * (j) + 1] = j + (xCount + 1);                borderBackIndices[6 * (j) + 2] = j + 1;                borderBackIndices[6 * (j) + 3] = j + 1;                borderBackIndices[6 * (j) + 4] = j + (xCount + 1);                borderBackIndices[6 * (j) + 5] = j + (xCount + 1) + 1;            }            borderBackIndexBuffer.SetData(borderBackIndices, 0, LockFlags.None);            int diff = yCount - xCount;            /**第3个四周边界**/            borderLeftVertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored),                2 * (yCount + 1),//四周的一个面封闭总共所需要的顶点的数目                device,                Usage.Dynamic | Usage.WriteOnly,                CustomVertex.PositionColored.Format,                Pool.Default);            borderLeftVertices = new CustomVertex.PositionColored[2 * (yCount + 1)];//定义顶点            for (k = 0; k < yCount + 1; k++)//Z轴平行方向上的点的定义            {                borderLeftVertices[k].Position = new Vector3(0, minY, k * cellHeight);                borderLeftVertices[k].Color = System.Drawing.Color.Aqua.ToArgb();            }            for (; k < 2 * (yCount + 1); k++)//高程图上的边界点的定义            {                Color color = bitmap.GetPixel(0, (int)((k - yCount - 1) * cellHeight));//边界点不能直接传进去写死,容易产生溢出的异常                float height = float.Parse(color.R.ToString()) + float.Parse(color.G.ToString()) + float.Parse(color.B.ToString());                height /= 10;                borderLeftVertices[k].Position = new Vector3(0, height, (k - yCount - 1) * cellHeight);                borderLeftVertices[k].Color = System.Drawing.Color.Aqua.ToArgb();            }            borderLeftVertexBuffer.SetData(borderLeftVertices, 0, LockFlags.None);            borderLeftIndexBuffer = new IndexBuffer(typeof(int),                6 * yCount * 1,                device,                Usage.WriteOnly,                Pool.Default);            borderLeftIndices = new int[6 * yCount * 1];//初始化索引顶点            for (int j = 0; j < yCount; j++)            {                borderLeftIndices[6 * (j)] = j;                borderLeftIndices[6 * (j) + 1] = j + (yCount + 1);                borderLeftIndices[6 * (j) + 2] = j + 1;                borderLeftIndices[6 * (j) + 3] = j + 1;                borderLeftIndices[6 * (j) + 4] = j + (yCount + 1);                borderLeftIndices[6 * (j) + 5] = j + (yCount + 1) + 1;            }            borderLeftIndexBuffer.SetData(borderLeftIndices, 0, LockFlags.None);            //MessageBox.Show(borderLeftIndices[0]+","+borderLeftIndices[1]+","+borderLeftIndices[2]);            /**第4个四周边界**/            borderRightVertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored),                2 * (yCount + 1),//四周的一个面封闭总共所需要的顶点的数目                device,                Usage.Dynamic | Usage.WriteOnly,                CustomVertex.PositionColored.Format,                Pool.Default);            borderRightVertices = new CustomVertex.PositionColored[2 * (yCount + 1)];//定义顶点            for (k = 0; k < yCount + 1; k++)//Z轴平行方向上的点的定义            {                borderRightVertices[k].Position = new Vector3(xCount * cellWidth, minY, k * cellHeight);                borderRightVertices[k].Color = System.Drawing.Color.Aqua.ToArgb();            }            for (; k < 2 * (yCount + 1); k++)//高程图上的边界点的定义            {                Color color = bitmap.GetPixel((int)(xCount * cellWidth), (int)((k - yCount - 1) * cellHeight));//边界点不能直接传进去写死,容易产生溢出和精度损失                float height = float.Parse(color.R.ToString()) + float.Parse(color.G.ToString()) + float.Parse(color.B.ToString());                height /= 10;                borderRightVertices[k].Position = new Vector3(xCount * cellWidth, height, (k - yCount - 1) * cellHeight);                borderRightVertices[k].Color = System.Drawing.Color.Aqua.ToArgb();            }            borderRightVertexBuffer.SetData(borderRightVertices, 0, LockFlags.None);            borderRightIndexBuffer = new IndexBuffer(typeof(int),                6 * yCount * 1,                device,                Usage.WriteOnly,                Pool.Default);            borderRightIndices = new int[6 * yCount * 1];//初始化索引顶点            for (int j = 0; j < yCount; j++)            {                borderRightIndices[6 * (j)] = j;                borderRightIndices[6 * (j) + 1] = j + (yCount + 1);                borderRightIndices[6 * (j) + 2] = j + 1;                borderRightIndices[6 * (j) + 3] = j + 1;                borderRightIndices[6 * (j) + 4] = j + (yCount + 1);                borderRightIndices[6 * (j) + 5] = j + (yCount + 1) + 1;            }            borderRightIndexBuffer.SetData(borderRightIndices, 0, LockFlags.None);            device.SamplerState[0].MagFilter = TextureFilter.Linear;//使用纹理滤波器进行线性滤波        }        private Vector3 CamPostion = new Vector3(0.0f, 0.0f, -100.0f);//定义摄像机位置        private Vector3 CamTarget = new Vector3(0.0f, 0.0f, 0.0f);//定义摄像机目标位置//         void SetupMatrices()//         {//             m_device.Transform.World = Matrix.RotationX((float)Math.PI/180)*Matrix.Translation(0,-20,0);//世界变换,下调为观察变换矩阵//             Matrix viewMatrix = Matrix.LookAtLH(CamPostion, CamTarget, new Vector3(0, 1, 0));//             m_device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 1.0f, 6500.0f);//             m_device.Transform.View = viewMatrix;//         }        public void Render()        {            if (m_device == null)                return;            m_device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.White, 1.0f, 0);            /*SetupMatrices();*/            m_device.Transform.World = Matrix.Scaling(8,8,8)*Matrix.Translation(250,0,250);//世界变换,下调为观察变换矩阵            m_device.Transform.View = Matrix.LookAtLH(CamPostion, CamTarget, new Vector3(0, 1, 0));            m_device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 1.0f, 6500.0f);                        m_device.BeginScene();            m_device.RenderState.FillMode = FillMode.Solid;            m_device.RenderState.CullMode = Cull.None;            m_device.RenderState.Lighting = false;            m_device.Material = skyboxMeshMaterials;//指定设备的材质            for (int i = 0; i < meshMaterials1.Length; i++)//Mesh中可能有多个3D图形,逐一显示            {                m_device.Material = meshMaterials1[i];//设定3D图形的材质                m_device.SetTexture(0, skyboxMeshTextures[i]);//设定3D图形的纹理                skyboxMesh.DrawSubset(i);            }            m_device.Transform.World = Matrix.Identity;            Matrix viewMatrix = Matrix.LookAtLH(CamPostion, CamTarget, new Vector3(0, 1, 0));            m_device.Transform.Projection = Matrix.PerspectiveFovLH(                (float)Math.PI / 4,                this.Width / this.Height,                1.0f,                6500.0f);            m_device.Transform.View = viewMatrix;            m_device.SetTexture(0, texture);//设置贴图            m_device.VertexFormat = CustomVertex.PositionTextured.Format;            m_device.SetStreamSource(0, vertexBuffer, 0);            m_device.Indices = indexBuffer;            m_device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, (xCount + 1) * (yCount + 1), 0, indices.Length / 3);            //m_device.Transform.World = Matrix.Translation(0.0f, 0.0f, 0.0f);//底部世界变换//             m_device.Material = bottomMaterial;//底部使用的材质// //             m_device.RenderState.DiffuseMaterialSource = ColorSource.Material;//             m_device.RenderState.AlphaBlendEnable = true;//             m_device.SetTexture(0, bottomTexture);//             //             m_device.SetStreamSource(0, bottomVertexBuffer, 0);//             m_device.VertexFormat = CustomVertex.PositionNormalTextured.Format;//             m_device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);                        /*第1个边界三角形*/            m_device.SetStreamSource(0, borderFrontVertexBuffer, 0);            m_device.VertexFormat = CustomVertex.PositionColored.Format;            m_device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 2 * (xCount + 1), 0, borderFrontIndices.Length / 3);            /*第2个边界三角形*/            m_device.SetStreamSource(0, borderBackVertexBuffer, 0);            m_device.VertexFormat = CustomVertex.PositionColored.Format;            m_device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 2 * (xCount + 1), 0, borderBackIndices.Length / 3);            /*第3个边界三角形*/            m_device.SetStreamSource(0, borderLeftVertexBuffer, 0);            m_device.VertexFormat = CustomVertex.PositionColored.Format;            m_device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 2 * (yCount + 1), 0, borderLeftIndices.Length / 3);            /*第4个边界三角形*/            m_device.SetStreamSource(0, borderRightVertexBuffer, 0);            m_device.VertexFormat = CustomVertex.PositionColored.Format;            m_device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 2 * (yCount + 1), 0, borderRightIndices.Length / 3);            m_device.EndScene();            m_device.Present();        }        private void OnKeyDown(object sender, KeyEventArgs e)        {            Vector4 tempV4;            Matrix currentView = m_device.Transform.View;//当前摄像机的视图矩阵            switch (e.KeyCode)            {                case Keys.Left:                    CamPostion.Subtract(CamTarget);                    tempV4 = Vector3.Transform(CamPostion, Matrix.RotationQuaternion(                            Quaternion.RotationAxis(new Vector3(currentView.M12, currentView.M22, currentView.M32), -angleY)));                    CamPostion.X = tempV4.X + CamTarget.X;                    CamPostion.Y = tempV4.Y + CamTarget.Y;                    CamPostion.Z = tempV4.Z + CamTarget.Z;                    break;                case Keys.Right:                    CamPostion.Subtract(CamTarget);                    tempV4 = Vector3.Transform(CamPostion, Matrix.RotationQuaternion(                            Quaternion.RotationAxis(new Vector3(currentView.M12, currentView.M22, currentView.M32), angleY)));                    CamPostion.X = tempV4.X + CamTarget.X;                    CamPostion.Y = tempV4.Y + CamTarget.Y;                    CamPostion.Z = tempV4.Z + CamTarget.Z;                    break;                case Keys.Up:                    CamPostion.Subtract(CamTarget);                    tempV4 = Vector3.Transform(CamPostion, Matrix.RotationQuaternion(                       Quaternion.RotationAxis(new Vector3(m_device.Transform.View.M11                       , m_device.Transform.View.M21, m_device.Transform.View.M31), -angleY)));                    CamPostion.X = tempV4.X + CamTarget.X;                    CamPostion.Y = tempV4.Y + CamTarget.Y;                    CamPostion.Z = tempV4.Z + CamTarget.Z;                    break;                case Keys.Down:                    CamPostion.Subtract(CamTarget);                    tempV4 = Vector3.Transform(CamPostion, Matrix.RotationQuaternion(                       Quaternion.RotationAxis(new Vector3(m_device.Transform.View.M11                       , m_device.Transform.View.M21, m_device.Transform.View.M31), angleY)));                    CamPostion.X = tempV4.X + CamTarget.X;                    CamPostion.Y = tempV4.Y + CamTarget.Y;                    CamPostion.Z = tempV4.Z + CamTarget.Z;                    break;                case Keys.Add:                    CamPostion.Subtract(CamTarget);                    CamPostion.Scale(0.95f);                    CamPostion.Add(CamTarget);                    break;                case Keys.Subtract:                    CamPostion.Subtract(CamTarget);                    CamPostion.Scale(1.05f);                    CamPostion.Add(CamTarget);                    break;            }            Matrix viewMatrix = Matrix.LookAtLH(CamPostion, CamTarget, new Vector3(0, 1, 0));            m_device.Transform.View = viewMatrix;            Render();        }        private void OnMouseDown(object sender, MouseEventArgs e)        {            if (e.Button == MouseButtons.Left)            {                mouseLastX = e.X;                mouseLastY = e.Y;                isRotateByMouse = true;            }            else if (e.Button == MouseButtons.Middle)            {                mouseLastX = e.X;                mouseLastY = e.Y;                isMoveByMouse = true;            }        }        private void OnMouseUp(object sender, MouseEventArgs e)        {            isRotateByMouse = false;            isMoveByMouse = false;        }        private void OnMouseMove(object sender, MouseEventArgs e)        {            if (isRotateByMouse)            {                Matrix currentView = m_device.Transform.View;//当前摄像机的视图矩阵                float tempAngleY = 2 * (float)(e.X - mouseLastX) / this.Width;                CamPostion.Subtract(CamTarget);                Vector4 tempV4 = Vector3.Transform(CamPostion, Matrix.RotationQuaternion(                    Quaternion.RotationAxis(new Vector3(currentView.M12, currentView.M22, currentView.M32), tempAngleY)));                CamPostion.X = tempV4.X;                CamPostion.Y = tempV4.Y;                CamPostion.Z = tempV4.Z;                float tempAngleX = 4 * (float)(e.Y - mouseLastY) / this.Height;                tempV4 = Vector3.Transform(CamPostion, Matrix.RotationQuaternion(                    Quaternion.RotationAxis(new Vector3(currentView.M11, currentView.M21, currentView.M31), tempAngleX)));                CamPostion.X = tempV4.X + CamTarget.X;                CamPostion.Y = tempV4.Y + CamTarget.Y;                CamPostion.Z = tempV4.Z + CamTarget.Z;                Matrix viewMatrix = Matrix.LookAtLH(CamPostion, CamTarget, new Vector3(0, 1, 0));                m_device.Transform.View = viewMatrix;                mouseLastX = e.X;                mouseLastY = e.Y;                Render();            }            else if (isMoveByMouse)            {                Matrix currentView = m_device.Transform.View;//当前摄像机的视图矩阵                float moveFactor = 0.01f;                CamTarget.X += -moveFactor * ((e.X - mouseLastX) * currentView.M11 - (e.Y - mouseLastY) * currentView.M12);                CamTarget.Y += -moveFactor * ((e.X - mouseLastX) * currentView.M21 - (e.Y - mouseLastY) * currentView.M22);                CamTarget.Z += -moveFactor * ((e.X - mouseLastX) * currentView.M31 - (e.Y - mouseLastY) * currentView.M32);                CamPostion.X += -moveFactor * ((e.X - mouseLastX) * currentView.M11 - (e.Y - mouseLastY) * currentView.M12);                CamPostion.Y += -moveFactor * ((e.X - mouseLastX) * currentView.M21 - (e.Y - mouseLastY) * currentView.M22);                CamPostion.Z += -moveFactor * ((e.X - mouseLastX) * currentView.M31 - (e.Y - mouseLastY) * currentView.M32);                Matrix viewMatrix = Matrix.LookAtLH(CamPostion, CamTarget, new Vector3(0, 1, 0));                m_device.Transform.View = viewMatrix;                mouseLastX = e.X;                mouseLastY = e.Y;                Render();            }        }        private void OnMouseWheel(object sender, MouseEventArgs e)        {            float scaleFactor = -(float)e.Delta / 2000 + 1f;            CamPostion.Subtract(CamTarget);            CamPostion.Scale(scaleFactor);            CamPostion.Add(CamTarget);            Matrix viewMatrix = Matrix.LookAtLH(CamPostion, CamTarget, new Vector3(0, 1, 0));            m_device.Transform.View = viewMatrix;            Render();        }        private void OnLoad(object sender, EventArgs e)        {            InitializeGraphics();            this.Show();            Render();        }        private void OnPaint(object sender, PaintEventArgs e)        {            this.Render();        }        private void OnResize(object sender, EventArgs e)        {            pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible);        }    }}

天空盒子

天空盒子的实现更加简单,这个可以完全通过代码来实现,需要准备几张天空360°无缝衔接的全景图,然后按照一定的顺组组合贴图即可。


建立一个立方体模型,为了增加渲染的效率,可以考虑只绘制一个基准面,然后利用这个基准面进行旋转平移变换就可以得到其他的面,绘制的时候,设置不同的纹理贴图即可。下面贴上几张天空盒子的效果图:




下面附上实现的核心代码:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using Microsoft.DirectX;using Microsoft.DirectX.Direct3D;namespace Test{    public partial class SkyBox : Form    {        private Device m_device = null;        bool pause = false;        VertexBuffer skyboxVertexBuffer = null;        Material skyboxMtrl;        float Angle = 0, ViewZ = -6.0f;        Texture skyboxFrontTexture = null;//定义skybox模型6个面的纹理变量        Texture skyboxBackTexture = null;        Texture skyboxTopTexture = null;        Texture skyboxBottomTexture = null;        Texture skyboxLeftTexture = null;        Texture skyboxRightTexture = null;        private float angleY = 0.0f;//定义绕Y轴旋转变量        private int mouseLastX, mouseLastY;//记录鼠标按下时的坐标位置        private bool isRotateByMouse = false;//记录是否由鼠标控制旋转        private bool isMoveByMouse = false;//记录是否由鼠标控制移动        public SkyBox()        {            InitializeComponent();        }        public bool InitializeGraphics()        {            try            {                PresentParameters presentParams = new PresentParameters();                presentParams.Windowed = true;//不是全屏显示,在一个窗口显示                presentParams.SwapEffect = SwapEffect.Discard; //后备缓存交换的方式                presentParams.EnableAutoDepthStencil = true; //允许使用自动深度模板测试                //深度缓冲区单元为16位二进制数                presentParams.AutoDepthStencilFormat = DepthFormat.D16;                m_device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);                //设置设备重置事件(device.DeviceReset)事件函数为this.OnResetDevice                m_device.DeviceReset += new System.EventHandler(this.OnResetDevice);                this.OnCreateDevice(m_device, null);//自定义方法,初始化Device的工作放到这个方法中                this.OnResetDevice(m_device, null);//调用设备重置事件(device.DeviceReset)事件函数            }//设备重置事件函数要设置Device参数,初始函数中必须调用该函数            catch (DirectXException)            {                return false;            }            return true;        }                public void OnCreateDevice(object sender, EventArgs e)        {            Device dev = (Device)sender;            skyboxVertexBuffer = new VertexBuffer(                typeof(CustomVertex.PositionNormalTextured),                 6,                 dev,                 0,                 CustomVertex.PositionNormalTextured.Format,                 Pool.Default);            skyboxVertexBuffer.Created += new System.EventHandler(this.OnCreateSkyBoxVertexBuffer);            this.OnCreateSkyBoxVertexBuffer(skyboxVertexBuffer, null);            skyboxMtrl = new Material();            skyboxMtrl.Diffuse = System.Drawing.Color.Yellow;//物体的颜色            skyboxMtrl.Ambient = System.Drawing.Color.Red;//反射环境光的颜色            skyboxFrontTexture = TextureLoader.FromFile(dev, @"F:\\workdir\\VC# Based DirectX\\skybox\\neg_z.bmp");            skyboxBackTexture = TextureLoader.FromFile(dev, @"F:\\workdir\\VC# Based DirectX\\skybox\\pos_z.bmp");            skyboxTopTexture = TextureLoader.FromFile(dev, @"F:\\workdir\\VC# Based DirectX\\skybox\\pos_y.bmp");            skyboxBottomTexture = TextureLoader.FromFile(dev, @"F:\\workdir\\VC# Based DirectX\\skybox\\neg_y.bmp");            skyboxLeftTexture = TextureLoader.FromFile(dev, @"F:\\workdir\\VC# Based DirectX\\skybox\\pos_x.bmp");            skyboxRightTexture = TextureLoader.FromFile(dev, @"F:\\workdir\\VC# Based DirectX\\skybox\\neg_x.bmp");        }        public void OnCreateSkyBoxVertexBuffer(object sender, EventArgs e)        {            CustomVertex.PositionNormalTextured[] verts =                        (CustomVertex.PositionNormalTextured[])skyboxVertexBuffer.Lock(0, 0);            verts[0].Position = new Vector3(-10.0f, -10.0f, 0.0f);  //顶点0位置            verts[0].Normal = new Vector3(0, 0, -1);        //顶点0法线            verts[0].Tu = 0.0f;          //顶点0纹理坐标Tu            verts[0].Tv = 1.0f;            verts[1].Position = new Vector3(-10.0f, 10.0f, 0.0f);    //顶点1位置            verts[1].Normal = new Vector3(0, 0, -1);  //顶点1法线            verts[1].Tu = 0.0f;        //顶点0纹理坐标Tu            verts[1].Tv = 0.0f;            verts[2].Position = new Vector3(10.0f, 10.0f, 0.0f);      //顶点2位置            verts[2].Normal = new Vector3(0, 0, -1);            verts[2].Tu = 1.0f;        //顶点0纹理坐标Tu            verts[2].Tv = 0.0f;            verts[3].Position = new Vector3(-10.0f, -10.0f, 0.0f);  //顶点3位置            verts[3].Normal = new Vector3(0, 0, -1);        //顶点3法线            verts[3].Tu = 0.0f;        //顶点0纹理坐标Tu            verts[3].Tv = 1.0f;            verts[4].Position = new Vector3(10.0f, 10.0f, 0.0f);    //顶点4位置            verts[4].Normal = new Vector3(0, 0, -1);            verts[4].Tu = 1.0f;        //顶点0纹理坐标Tu            verts[4].Tv = 0.0f;            verts[5].Position = new Vector3(10.0f, -10.0f, 0.0f);      //顶点5位置            verts[5].Normal = new Vector3(0, 0, -1);            verts[5].Tu = 1.0f;        //顶点0纹理坐标Tu            verts[5].Tv = 1.0f;            skyboxVertexBuffer.Unlock();        }        public void OnResetDevice(object sender, EventArgs e)        {            Device dev = (Device)sender;            dev.RenderState.CullMode = Cull.None;//没有背面剔除            m_device.RenderState.ZBufferEnable = true;//打开Z缓冲            m_device.RenderState.Lighting = false;//打开灯光            //SetupLights();//设置灯光            //m_device.SamplerState[0].MagFilter = TextureFilter.Linear;//使用线性滤波,结合处容易出现裂缝        }                public void Render()//渲染方法,本方法没有任何渲染代码,可认为是渲染方法的框架        {            if (m_device == null) //如果未建立设备对象,退出                return;            if (pause)                return;            m_device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.WhiteSmoke, 1.0f, 0);            m_device.BeginScene();//开始渲染            SetupMatrices();            m_device.RenderState.CullMode = Cull.None;            m_device.RenderState.FillMode = FillMode.Solid;            m_device.SetStreamSource(0, skyboxVertexBuffer, 0);            m_device.VertexFormat = CustomVertex.PositionNormalTextured.Format;            m_device.SetTexture(0, skyboxFrontTexture);            m_device.Transform.World =                 Matrix.Translation(0, 0, -10);//沿Z轴向观察者方向移动10个单位            m_device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);//正前面            m_device.SetTexture(0, skyboxBackTexture);            m_device.Transform.World =                 Matrix.RotationY((float)Math.PI) * Matrix.Translation(0, 0, 10);            m_device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);//正后面            m_device.SetTexture(0, skyboxRightTexture);            m_device.Transform.World =         Matrix.RotationY(-(float)Math.PI / 2) * Matrix.Translation(10, 0, 0);            m_device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);//右侧面            m_device.SetTexture(0, skyboxLeftTexture);            m_device.Transform.World =         Matrix.RotationY((float)Math.PI / 2) * Matrix.Translation(-10, 0, 0);            m_device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);//左侧面            m_device.SetTexture(0, skyboxTopTexture);            m_device.Transform.World =         Matrix.RotationX((float)Math.PI / 2) * Matrix.RotationY(-(float)Math.PI / 2) * Matrix.Translation(0, 10, 0);            m_device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);//上面            m_device.SetTexture(0, skyboxBottomTexture);            m_device.Transform.World =         Matrix.RotationX(-(float)Math.PI / 2) * Matrix.RotationY(-(float)Math.PI/2)*Matrix.Translation(0, -10, 0);            m_device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);//下面            m_device.EndScene();//渲染结束            m_device.Present();//更新显示区域,把后备缓存的D图形送到图形卡的显存中显示        }        private Vector3 CamPostion = new Vector3(0.0f, 0.0f, -5.0f);//定义摄像机位置        private Vector3 CamTarget = new Vector3(0.0f, 0.0f, 0.0f);//定义摄像机目标位置        private void SetupMatrices()//注意世界变换和观察变换参数可能要改变        {//             device.Transform.World = Matrix.RotationY(0);//世界变换矩阵//             Vector3 v1 = new Vector3(0.0f, 0.0f, -5.0f);//下句使v1点分别沿Y轴和X轴旋转//             v1.TransformCoordinate(Matrix.RotationYawPitchRoll(Angle, ViewZ, 0));//             device.Transform.View = Matrix.LookAtLH(v1, new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));//观察变换矩阵//             device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4,//                             this.Width/this.Height, 1.0f, 100.0f);//投影变换矩阵            Matrix viewMatrix = Matrix.LookAtLH(CamPostion, CamTarget, new Vector3(0, 1, 0));            m_device.Transform.Projection = Matrix.PerspectiveFovLH(                (float)Math.PI / 4,                 this.Width / this.Height,                 1.0f,                 6500.0f);            m_device.Transform.View = viewMatrix;        }        private void SetupLights()        {            m_device.Material = skyboxMtrl;            m_device.Lights[0].Type = LightType.Directional;//灯光类型            m_device.Lights[0].Diffuse = System.Drawing.Color.White;//光的颜色为白色            m_device.Lights[0].Direction = new Vector3(0, -2, 4);//灯光方向从观察者上方指向屏幕下方            m_device.Lights[0].Update();//更新灯光设置,创建第一盏灯光            m_device.Lights[0].Enabled = true;//使设置有效,下句设置环境光为白色            m_device.RenderState.Ambient = System.Drawing.Color.FromArgb(0x808080);        }        private void Form1_Load(object sender, EventArgs e)        {            InitializeGraphics();            this.Show();            Render();        }        private void Form1_Paint(object sender, PaintEventArgs e)        {            this.Render();        }        private void Form1_Resize(object sender, EventArgs e)        {            pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible);        }        private void OnKeyDown(object sender, KeyEventArgs e)        {            Vector4 tempV4;            Matrix currentView = m_device.Transform.View;//当前摄像机的视图矩阵            switch (e.KeyCode)            {                case Keys.Left:                    CamPostion.Subtract(CamTarget);                    tempV4 = Vector3.Transform(CamPostion, Matrix.RotationQuaternion(                            Quaternion.RotationAxis(new Vector3(currentView.M12, currentView.M22, currentView.M32), -angleY)));                    CamPostion.X = tempV4.X + CamTarget.X;                    CamPostion.Y = tempV4.Y + CamTarget.Y;                    CamPostion.Z = tempV4.Z + CamTarget.Z;                    break;                case Keys.Right:                    CamPostion.Subtract(CamTarget);                    tempV4 = Vector3.Transform(CamPostion, Matrix.RotationQuaternion(                            Quaternion.RotationAxis(new Vector3(currentView.M12, currentView.M22, currentView.M32), angleY)));                    CamPostion.X = tempV4.X + CamTarget.X;                    CamPostion.Y = tempV4.Y + CamTarget.Y;                    CamPostion.Z = tempV4.Z + CamTarget.Z;                    break;                case Keys.Up:                    CamPostion.Subtract(CamTarget);                    tempV4 = Vector3.Transform(CamPostion, Matrix.RotationQuaternion(                       Quaternion.RotationAxis(new Vector3(m_device.Transform.View.M11                       , m_device.Transform.View.M21, m_device.Transform.View.M31), -angleY)));                    CamPostion.X = tempV4.X + CamTarget.X;                    CamPostion.Y = tempV4.Y + CamTarget.Y;                    CamPostion.Z = tempV4.Z + CamTarget.Z;                    break;                case Keys.Down:                    CamPostion.Subtract(CamTarget);                    tempV4 = Vector3.Transform(CamPostion, Matrix.RotationQuaternion(                       Quaternion.RotationAxis(new Vector3(m_device.Transform.View.M11                       , m_device.Transform.View.M21, m_device.Transform.View.M31), angleY)));                    CamPostion.X = tempV4.X + CamTarget.X;                    CamPostion.Y = tempV4.Y + CamTarget.Y;                    CamPostion.Z = tempV4.Z + CamTarget.Z;                    break;                case Keys.Add:                    CamPostion.Subtract(CamTarget);                    CamPostion.Scale(0.95f);                    CamPostion.Add(CamTarget);                    break;                case Keys.Subtract:                    CamPostion.Subtract(CamTarget);                    CamPostion.Scale(1.05f);                    CamPostion.Add(CamTarget);                    break;            }            Matrix viewMatrix = Matrix.LookAtLH(CamPostion, CamTarget, new Vector3(0, 1, 0));            m_device.Transform.View = viewMatrix;            Render();        }        private void OnMouseDown(object sender, MouseEventArgs e)        {            if (e.Button == MouseButtons.Left)            {                mouseLastX = e.X;                mouseLastY = e.Y;                isRotateByMouse = true;            }            else if (e.Button == MouseButtons.Middle)            {                mouseLastX = e.X;                mouseLastY = e.Y;                isMoveByMouse = true;            }        }        private void OnMouseUp(object sender, MouseEventArgs e)        {            isRotateByMouse = false;            isMoveByMouse = false;        }        private void OnMouseMove(object sender, MouseEventArgs e)        {            if (isRotateByMouse)            {                Matrix currentView = m_device.Transform.View;//当前摄像机的视图矩阵                float tempAngleY = 2 * (float)(e.X - mouseLastX) / this.Width;                CamPostion.Subtract(CamTarget);                Vector4 tempV4 = Vector3.Transform(CamPostion, Matrix.RotationQuaternion(                    Quaternion.RotationAxis(new Vector3(currentView.M12, currentView.M22, currentView.M32), tempAngleY)));                CamPostion.X = tempV4.X;                CamPostion.Y = tempV4.Y;                CamPostion.Z = tempV4.Z;                float tempAngleX = 4 * (float)(e.Y - mouseLastY) / this.Height;                tempV4 = Vector3.Transform(CamPostion, Matrix.RotationQuaternion(                    Quaternion.RotationAxis(new Vector3(currentView.M11, currentView.M21, currentView.M31), tempAngleX)));                CamPostion.X = tempV4.X + CamTarget.X;                CamPostion.Y = tempV4.Y + CamTarget.Y;                CamPostion.Z = tempV4.Z + CamTarget.Z;                Matrix viewMatrix = Matrix.LookAtLH(CamPostion, CamTarget, new Vector3(0, 1, 0));                m_device.Transform.View = viewMatrix;                mouseLastX = e.X;                mouseLastY = e.Y;                Render();            }            else if (isMoveByMouse)            {                Matrix currentView = m_device.Transform.View;//当前摄像机的视图矩阵                float moveFactor = 0.01f;                CamTarget.X += -moveFactor * ((e.X - mouseLastX) * currentView.M11 - (e.Y - mouseLastY) * currentView.M12);                CamTarget.Y += -moveFactor * ((e.X - mouseLastX) * currentView.M21 - (e.Y - mouseLastY) * currentView.M22);                CamTarget.Z += -moveFactor * ((e.X - mouseLastX) * currentView.M31 - (e.Y - mouseLastY) * currentView.M32);                CamPostion.X += -moveFactor * ((e.X - mouseLastX) * currentView.M11 - (e.Y - mouseLastY) * currentView.M12);                CamPostion.Y += -moveFactor * ((e.X - mouseLastX) * currentView.M21 - (e.Y - mouseLastY) * currentView.M22);                CamPostion.Z += -moveFactor * ((e.X - mouseLastX) * currentView.M31 - (e.Y - mouseLastY) * currentView.M32);                Matrix viewMatrix = Matrix.LookAtLH(CamPostion, CamTarget, new Vector3(0, 1, 0));                m_device.Transform.View = viewMatrix;                mouseLastX = e.X;                mouseLastY = e.Y;                Render();            }        }        private void OnMouseWheel(object sender, MouseEventArgs e)        {            float scaleFactor = -(float)e.Delta / 2000 + 1f;            CamPostion.Subtract(CamTarget);            CamPostion.Scale(scaleFactor);            CamPostion.Add(CamTarget);            Matrix viewMatrix = Matrix.LookAtLH(CamPostion, CamTarget, new Vector3(0, 1, 0));            m_device.Transform.View = viewMatrix;            Render();        }    }}



1 0
原创粉丝点击