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(); } }}
- DirectX天空球和天空盒子模型
- DirectX下天空盒子的实现
- 【Unity3D】地形和天空盒子
- Direct3D学习(七):DirectX下天空盒子的实现
- XNA 天空盒子
- 天空盒子的绘制
- OSG 天空盒子
- Unity3D添加天空盒子
- 天空盒、天空穹和天空面
- 天空
- 天空
- 天空
- 天空
- 天空
- 关于sandy3D引擎 创建天空盒子模型等缝隙问题
- three.js 天空盒子使用方法
- (第九章)Unity3D-音频和天空盒子
- 云彩和天空
- Java的GUI发展-AWT/SWT/Swing
- vim简易教程
- python 迭代器
- 自己用到的SSH
- wordpress 添加修改 robots.txt
- DirectX天空球和天空盒子模型
- 捕捉Windows服务与WinForm的全局异常
- storyboard的简单应用
- Java this关键字总结
- redis中的数据结构基本的操作
- Codeforces Round #332 (Div. 2)C. Day at the Beach(好题,)
- C++11 利用const_cast和type_traits修改类成员常量的通用模板函数
- 重启压力测试APK
- 常见错误