C#选中模型移动类似于3dmax(附源码)

前段时间弄d3d,看完红书和基于Visual+C#的DirectX开发实例,就自己练习了下这个程序

sdk上面都有拾取,但是没有选中移动,最近的项目要用到,就简单仿了下3dmax的移动方式

选中物体,再选取需要移动的平面,效果如下:

移动

 

拾取代码中会有个小问题,就是会出现重复多选的问题,本例中是通过比较Intersect函数返回参数IntersectInformation中交点距离的最短值找出mesh的;大家可以用list的遍历找最小值,方法很多

然后是关于平面的移动,当选取完成之后。会出现三个完全透明的平面,物体就是根据隐形平面的u v值进行移动的;

重要代码如下:(我基本打成class类,后期工程的时候会加到dll中,这个只是演示,便于学习)

这个是:class类

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; namespace PickObject { public class Hawk_Class { public Device device; //Device public float Pan_Width, Pan_High; //pannel Size //初始化类 public Hawk_Class(Device device,float w,float h) { this.device = device; Pan_Width = w; Pan_High = h; } //寻找交点 public void Check_Point_Face(float Mouse_x, float Mouse_y, Vector3 Cam_Postion, Mesh Chech_Mesh, Matrix Chech_Mesh_Postion, out bool Check_Bool, out IntersectInformation Point_Inf) { //计算摄像机投影窗口上对应的点击位置坐标 Vector3 SVector = new Vector3(); SVector.X = 2 * Mouse_x / this.Pan_Width - 1; SVector.Y = -2 * Mouse_y / this.Pan_High + 1; SVector.Z = 1.0f / (float)Math.Tan(Math.PI / 8); //视图矩阵 Matrix viewMatrix = this.device.Transform.View; viewMatrix.Invert();//计算视图矩阵的逆矩阵 //射线位置 Vector3 rayPos = Vector3.TransformCoordinate(SVector, viewMatrix); //射线方向 Vector3 rayDir = Vector3.Subtract(rayPos, Cam_Postion); //碰撞检测 //将模型的世界矩阵进行逆变换 Matrix inverseWorld = Matrix.Invert(Chech_Mesh_Postion); Vector3 localRayPos = Vector3.TransformCoordinate(rayPos, inverseWorld); Vector3 localRayDir = Vector3.TransformNormal(rayDir, inverseWorld); IntersectInformation PI; bool result = Chech_Mesh.Intersect(localRayPos, localRayDir, out PI); Check_Bool = result; Point_Inf = PI; } //创建一个mesh类 public void Create_Mesh(Vector3[] pointVectors,out Mesh M_H) { Mesh meshObject; //定义顶点 CustomVertex.PositionColored[] arrayVertices = new CustomVertex.PositionColored[4]; //定义索引 Int16[] arrayIndices = new Int16[6]; //定义属性 AttributeRange attributeRange = new AttributeRange(); //实例化网格对象 meshObject = new Mesh(arrayIndices.Length / 3, arrayVertices.Length, MeshFlags.SystemMemory, CustomVertex.PositionColored.Format, device); //设置顶点坐标值 arrayVertices[0].Position = pointVectors[0]; arrayVertices[0].Color = Color.FromArgb(108, 255, 255, 255).ToArgb(); arrayVertices[1].Position = pointVectors[1]; arrayVertices[1].Color = Color.FromArgb(108, 255, 255, 255).ToArgb(); arrayVertices[2].Position = pointVectors[2]; arrayVertices[2].Color = Color.FromArgb(108, 255, 255, 255).ToArgb(); arrayVertices[3].Position = pointVectors[3]; arrayVertices[3].Color = Color.FromArgb(108, 255, 255, 255).ToArgb(); //设置索引,顶部三角形 arrayIndices[0] = 0; arrayIndices[1] = 1; arrayIndices[2] = 3; arrayIndices[3] = 3; arrayIndices[4] = 1; arrayIndices[5] = 2; //设置属性 attributeRange.AttributeId = 0; attributeRange.FaceStart = 0; attributeRange.FaceCount = arrayIndices.Length / 3; attributeRange.VertexStart = 0; attributeRange.VertexCount = arrayVertices.Length; //设置网格对象的索引缓冲和顶点缓冲数据 meshObject.VertexBuffer.SetData(arrayVertices, 0, LockFlags.None); meshObject.IndexBuffer.SetData(arrayIndices, 0, LockFlags.None); meshObject.SetAttributeTable(new AttributeRange[] { attributeRange }); M_H = meshObject; } public void Create_Mesh_Face(Vector3[] pointVectors, out Mesh M_H) { Mesh meshObject; //定义顶点 CustomVertex.PositionColored[] arrayVertices = new CustomVertex.PositionColored[3]; //定义索引 Int16[] arrayIndices = new Int16[3]; //定义属性 AttributeRange attributeRange = new AttributeRange(); //实例化网格对象 meshObject = new Mesh(arrayIndices.Length / 3, arrayVertices.Length, MeshFlags.SystemMemory, CustomVertex.PositionColored.Format, device); //设置顶点坐标值 arrayVertices[0].Position = pointVectors[0]; arrayVertices[0].Color = Color.FromArgb(0, 255, 255, 255).ToArgb(); arrayVertices[1].Position = pointVectors[1]; arrayVertices[1].Color = Color.FromArgb(0, 255, 255, 255).ToArgb(); arrayVertices[2].Position = pointVectors[2]; arrayVertices[2].Color = Color.FromArgb(0, 255, 255, 255).ToArgb(); //设置索引,顶部三角形 arrayIndices[0] = 0; arrayIndices[1] = 1; arrayIndices[2] = 2; //设置属性 attributeRange.AttributeId = 0; attributeRange.FaceStart = 0; attributeRange.FaceCount = arrayIndices.Length / 3; attributeRange.VertexStart = 0; attributeRange.VertexCount = arrayVertices.Length; //设置网格对象的索引缓冲和顶点缓冲数据 meshObject.VertexBuffer.SetData(arrayVertices, 0, LockFlags.None); meshObject.IndexBuffer.SetData(arrayIndices, 0, LockFlags.None); meshObject.SetAttributeTable(new AttributeRange[] { attributeRange }); M_H = meshObject; } //所有关于坐标的初始化 public void SetLine_and_Face(Mesh[] meshObjXYZ, Mesh[] checkface, out Material meshMaterialsXYZ, VertexBuffer _xyzLineVertexBuffer) { //三个标示的大平面 Vector3[] points = new Vector3[4]; points[0] = new Vector3(0f, 0f, 0f); points[1] = new Vector3(0f, 5f, 0f); points[2] = new Vector3(5f, 5f, 0f); points[3] = new Vector3(5f, 0f, 0f); Create_Mesh(points, out meshObjXYZ[0]); Vector3[] points1 = new Vector3[4]; points1[0] = new Vector3(0f, 0f, 0f); points1[1] = new Vector3(0f, 5f, 0f); points1[2] = new Vector3(0f, 5f, 5f); points1[3] = new Vector3(0f, 0f, 5f); Create_Mesh(points1, out meshObjXYZ[1]); Vector3[] points2 = new Vector3[4]; points2[0] = new Vector3(0f, 0f, 0f); points2[1] = new Vector3(0f, 0f, 5f); points2[2] = new Vector3(5f, 0f, 5f); points2[3] = new Vector3(5f, 0f, 0f); Create_Mesh(points2, out meshObjXYZ[2]); //三个标示的大平面其材质 Material temp = new Material(); temp.Diffuse = Color.FromArgb(108, 255, 255, 255); temp.Ambient = Color.White; temp.Specular = Color.White;//浅灰色 temp.SpecularSharpness = 1.0F; meshMaterialsXYZ = temp; //用于移动的三个大的透明平面 Vector3[] points3 = new Vector3[3]; points3[0] = new Vector3(-500f, -500f, 0f); points3[1] = new Vector3(-500f, 2000f, 0f); points3[2] = new Vector3(2000f, -500f, 0f); Create_Mesh_Face(points3, out checkface[0]); Vector3[] points4 = new Vector3[3]; points4[0] = new Vector3(0f, -500f, -500f); points4[1] = new Vector3(0f, 2000f, -500f); points4[2] = new Vector3(0f, -500f, 2000f); Create_Mesh_Face(points4, out checkface[1]); Vector3[] points5 = new Vector3[3]; points5[0] = new Vector3(-500f, 0f, -500f); points5[1] = new Vector3(-500f, 0f, 2000f); points5[2] = new Vector3(2000f, 0f, -500f); Create_Mesh_Face(points5, out checkface[2]); //三根XYZ坐标的数据生成 using (GraphicsStream data = _xyzLineVertexBuffer.Lock(0, 0, LockFlags.None)) { data.Write(new CustomVertex.PositionColored(0.0f, 0.0f, 0.0f, Color.Red.ToArgb())); data.Write(new CustomVertex.PositionColored(10.0f, 0.0f, 0.0f, Color.Red.ToArgb())); data.Write(new CustomVertex.PositionColored(0.0f, 0.0f, 0.0f, Color.Green.ToArgb())); data.Write(new CustomVertex.PositionColored(0.0f, 10.0f, 0.0f, Color.Green.ToArgb())); data.Write(new CustomVertex.PositionColored(0.0f, 0.0f, 0.0f, Color.White.ToArgb())); data.Write(new CustomVertex.PositionColored(0.0f, 0.0f, 10.0f, Color.White.ToArgb())); _xyzLineVertexBuffer.Unlock(); } } //给予一个mesh数组以及对应mesh位置的数组,确认鼠标选中的最近的mesh //(最后一个参数:<1>:选择哪个model,<2>:选择哪个平面) public int Select_Mesh_Fun(float Mouse_x, float Mouse_y,Vector3 Cam_Postion, Mesh[] Check_Mesh, Matrix[] Chech_Mesh_Postion,int flag) { int Lenth_Data = Check_Mesh.Length; int selected; IntersectInformation[] Pi = new IntersectInformation[3]; for (int i = 0; i < Lenth_Data; i++) { bool result; if(flag==99) Check_Point_Face(Mouse_x, Mouse_y, Cam_Postion, Check_Mesh[i], Chech_Mesh_Postion[i], out result, out Pi[i]); else Check_Point_Face(Mouse_x, Mouse_y, Cam_Postion, Check_Mesh[i], Chech_Mesh_Postion[flag], out result, out Pi[i]); if (!result) Pi[i].Dist = 9999.0f; } #region //找出最短的mesh float tempmin = Math.Min(Pi[0].Dist, Pi[1].Dist); if (tempmin == Pi[0].Dist); else selected = 1; tempmin = Math.Min(tempmin, Pi[2].Dist); if (tempmin == Pi[2].Dist) selected = 2; if (tempmin == 9999.0f) selected = 99; #endregion return selected; } } }

这个是对应loop吐出画面的函数:

device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.DarkSlateBlue, 1.0f, 0); //清除windows界面为深蓝色 device.BeginScene(); device.RenderState.CullMode = Cull.None;//显示里面的机构 device.Lights[0].Type = LightType.Directional; device.Lights[0].Diffuse = System.Drawing.Color.Red; device.Lights[0].Direction = new Vector3(-1.0f, 1.0f, 1.0f); device.Lights[0].Enabled = true; //打开灯光 device.Lights[1].Type = LightType.Directional; device.Lights[1].Diffuse = System.Drawing.Color.Green; device.Lights[1].Direction = new Vector3(1f, -1.0f, 1.0f); device.Lights[1].Enabled = true; //打开灯光 device.RenderState.Ambient = Color.SlateGray; device.SetRenderState(RenderStates.AlphaBlendEnable, true);//开启透明度 device.RenderState.SourceBlend = Blend.SourceAlpha; device.RenderState.DestinationBlend = Blend.InvSourceAlpha; //以实体形式绘制茶壶模型 device.RenderState.FillMode = FillMode.Solid; for (int i = 0; i < meshObj.Length; i++) { device.Transform.World = meshPosition[i]; if (i == selected) { device.RenderState.Lighting = false; // XYZ 라인 그리기 this.device.SetStreamSource(0, this._xyzLineVertexBuffer, 0); this.device.VertexFormat = CustomVertex.PositionColored.Format; this.device.DrawPrimitives(PrimitiveType.LineList, 0, 3); device.RenderState.Lighting = true; for (int j = 0; j < 3; j++)//选中模型的选中平面显示 { if (j == selectedFace) device.Material = meshMaterialsXYZ; else device.Material = new Material(); meshObjXYZ[j].DrawSubset(0); } meshMaterials[i].Diffuse = Color.FromArgb(48, 180, 168, 8);//选中的model透明 device.Material = meshMaterials[i]; meshObj[i].DrawSubset(0); continue; } device.RenderState.Lighting = true;//灯光设置 //设置当前材质 meshMaterials[i].Diffuse = Color.FromArgb(255, 180, 168, 8); device.Material = meshMaterials[i]; meshObj[i].DrawSubset(0); } if (selectedFace != 99)//如果选中屏幕 { device.Transform.World = checkfacePosition; checkface[1].DrawSubset(0); checkface[0].DrawSubset(0); checkface[2].DrawSubset(0); } device.EndScene();

还有一个具体会碰到的问题,就是刷新pannel.Invalidate();时候会出现闪屏的状况

查了些资料。应该这样解决最简单,原以为mfc有的问题会在C#解决,没想到还是这样

//重写 System.Windows.Forms.Panel类 public class DrawPanel : System.Windows.Forms.Panel { public DrawPanel() : base() { this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true); Location = new System.Drawing.Point(0, 0); Name = "drawpanel"; Size = new System.Drawing.Size(1024, 768); TabIndex = 5; } }

还有就是d3d GUI的应用,下面有时间弄了介绍,库是一个意大利小子写得

 

下面是程序的源码

https://download.csdn.net/download/hawk86104/2544380

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值