XNA Primitives画线 2(3D空间)
在XNA Primitives画线 1(2D和微量反射)的Demo中有很多的问题,比如,画的点不够精确、要画的线太多的话也就需要更多的点,这样的话对机子的性能可能要求就有点过了。
其实做现在这个Demo的主要目标也就是为了提高精度,在3D环境中我们可以用一个像素表示一个点,因此精确度应该就高的多。在XNA中 PrimitiveType.LineList可以直接画线,也可以由画出的线组成我们要的圆等图形。
另外,我想要实现全3D效果的话,我要用这种方式才行。
因为GraphicsDevice可以绘制点、线和三角形,我们的需要就主要是画线。如,根据四个点的坐标就可以绘制一个坐标轴,下面就是绘制坐标轴的方法:
1 private void DrawCoordinate()
2 {
3 DrawLine(new Vector3(0 - Window.ClientBounds.Width / 2, 0, 0), new Vector3(Window.ClientBounds.Width / 2, 0, 0));
4 DrawLine(new Vector3( 0,0 - Window.ClientBounds.Width / 2, 0), new Vector3( 0,Window.ClientBounds.Width / 2, 0));
5 }
2 {
3 DrawLine(new Vector3(0 - Window.ClientBounds.Width / 2, 0, 0), new Vector3(Window.ClientBounds.Width / 2, 0, 0));
4 DrawLine(new Vector3( 0,0 - Window.ClientBounds.Width / 2, 0), new Vector3( 0,Window.ClientBounds.Width / 2, 0));
5 }
现在让我们来绘制圆,XNA Primitives画线 1中的圆是由一个个的点组成的所以看起来就比较粗糙。这里的圆是由一个一个的线段,所以我就写了一个画线的方法:
1 private void DrawLine(Vector3 point1, Vector3 point2)
2 {
3 VertexPositionColor[] vpcs = new VertexPositionColor[2];
4 vpcs[0] = new VertexPositionColor(point1, Color.White);
5 vpcs[1] = new VertexPositionColor(point2, Color.White);
6
7 vertexDecl = new VertexDeclaration(GraphicsDevice, VertexPositionColor.VertexElements);
8 GraphicsDevice.VertexDeclaration = vertexDecl;
9 BasicEffect effect = new BasicEffect(GraphicsDevice, null);
10 effect.View = view;
11 effect.Projection = projection;
12 effect.World = worldTrans;
13
14 effect.Begin();
15 foreach (EffectPass pass in effect.CurrentTechnique.Passes)
16 {
17 pass.Begin();
18 GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineList, vpcs, 0, 1);
19 pass.End();
20 }
21 effect.End();
22 }
2 {
3 VertexPositionColor[] vpcs = new VertexPositionColor[2];
4 vpcs[0] = new VertexPositionColor(point1, Color.White);
5 vpcs[1] = new VertexPositionColor(point2, Color.White);
6
7 vertexDecl = new VertexDeclaration(GraphicsDevice, VertexPositionColor.VertexElements);
8 GraphicsDevice.VertexDeclaration = vertexDecl;
9 BasicEffect effect = new BasicEffect(GraphicsDevice, null);
10 effect.View = view;
11 effect.Projection = projection;
12 effect.World = worldTrans;
13
14 effect.Begin();
15 foreach (EffectPass pass in effect.CurrentTechnique.Passes)
16 {
17 pass.Begin();
18 GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineList, vpcs, 0, 1);
19 pass.End();
20 }
21 effect.End();
22 }
在开始画圆之前,我们还要为我们要画的圆创建好它的顶点:
1 private Vector3[] CirlcePoint()
2 {
3 Vector3[] VertexPoints = new Vector3[120];
4 Vector2 point = new Vector2(200,0);
5 Matrix tranmatrix;
6 for (int i = 0; i < 120;i++)
7 {
8 tranmatrix = new Matrix((float)Math.Cos(MathHelper.ToRadians( 3)), (float)Math.Sin(MathHelper.ToRadians( 3)), 0, 0,
9 -1 * (float)Math.Sin(MathHelper.ToRadians( 3)), (float)Math.Cos(MathHelper.ToRadians( 3)), 0, 0,
10 0, 0, 0, 0,
11 0, 0, 0, 0
12 );
13 point = Vector2.Transform(point, tranmatrix);
14 VertexPoints[i] = new Vector3(point.X, point.Y, 0);
15 }
16 return VertexPoints;
17 }
2 {
3 Vector3[] VertexPoints = new Vector3[120];
4 Vector2 point = new Vector2(200,0);
5 Matrix tranmatrix;
6 for (int i = 0; i < 120;i++)
7 {
8 tranmatrix = new Matrix((float)Math.Cos(MathHelper.ToRadians( 3)), (float)Math.Sin(MathHelper.ToRadians( 3)), 0, 0,
9 -1 * (float)Math.Sin(MathHelper.ToRadians( 3)), (float)Math.Cos(MathHelper.ToRadians( 3)), 0, 0,
10 0, 0, 0, 0,
11 0, 0, 0, 0
12 );
13 point = Vector2.Transform(point, tranmatrix);
14 VertexPoints[i] = new Vector3(point.X, point.Y, 0);
15 }
16 return VertexPoints;
17 }
现在就开始画我们的圆了:
Code
看下效果
这个是比之前那个好的多吧。
剩下和就是主题部分了,其实原理我之前那个还是一样的。
1 private void DrawMyEffect()
2 {
3 if (points[points.Length - 1].Length() >200)
4 {
5 ArrayList al = new ArrayList();
6 foreach(Vector3 vec in points)
7 {
8 al.Add(vec);
9 }
10 al.Add(points[points.Length - 1]);
11 points = (Vector3[])al.ToArray(typeof(Vector3));
12 velocity = Vector3.Reflect(velocity, Vector3.Normalize(points[points.Length - 1]));
13 }
14
15 for( int i = 0; i < points.Length-1;i++)
16 {
17 DrawLine(points[i], points[i + 1]);
18 }
19 points[points.Length-1] += velocity;
20 }
2 {
3 if (points[points.Length - 1].Length() >200)
4 {
5 ArrayList al = new ArrayList();
6 foreach(Vector3 vec in points)
7 {
8 al.Add(vec);
9 }
10 al.Add(points[points.Length - 1]);
11 points = (Vector3[])al.ToArray(typeof(Vector3));
12 velocity = Vector3.Reflect(velocity, Vector3.Normalize(points[points.Length - 1]));
13 }
14
15 for( int i = 0; i < points.Length-1;i++)
16 {
17 DrawLine(points[i], points[i + 1]);
18 }
19 points[points.Length-1] += velocity;
20 }
效果如下:
顺便贴出其它用到的方法:
随机的起点和方向
1 private Vector3 GetRandomVector3()
2 {
3 Random rand=new Random(DateTime.Now.Second);
4 return new Vector3((float)rand.Next(-180, 180), (float)rand.Next(-180, 180),0);
5 }
6
7 private Vector3 GetRandomVelocity()
8 {
9 Random rand = new Random();
10 return new Vector3((float)rand.Next(-80, 80), (float)rand.Next(-80, 80), 0);
11 }
2 {
3 Random rand=new Random(DateTime.Now.Second);
4 return new Vector3((float)rand.Next(-180, 180), (float)rand.Next(-180, 180),0);
5 }
6
7 private Vector3 GetRandomVelocity()
8 {
9 Random rand = new Random();
10 return new Vector3((float)rand.Next(-80, 80), (float)rand.Next(-80, 80), 0);
11 }
初始化
1 protected override void Initialize()
2 {
3 IsMouseVisible = true;
4 view = Matrix.CreateLookAt(new Vector3(0, 0, 800), Vector3.Zero, Vector3.Up);
5 projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 4 / 3f, 1, 10000);
6 velocity = GetRandomVelocity();
7 startPosition = GetRandomVector3();
8 points = new Vector3[2];
9 points[0] = startPosition;
10 points[1] = startPosition + velocity;
11
12 base.Initialize();
13 }
2 {
3 IsMouseVisible = true;
4 view = Matrix.CreateLookAt(new Vector3(0, 0, 800), Vector3.Zero, Vector3.Up);
5 projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 4 / 3f, 1, 10000);
6 velocity = GetRandomVelocity();
7 startPosition = GetRandomVector3();
8 points = new Vector3[2];
9 points[0] = startPosition;
10 points[1] = startPosition + velocity;
11
12 base.Initialize();
13 }
键盘控制
1 private void HandelInput()
2 {
3 KeyboardState ks = Keyboard.GetState();
4 if (ks.IsKeyDown(Keys.W))
5 {
6 worldTrans *= Matrix.CreateRotationX(MathHelper.ToRadians(10f));
7 }
8 if (ks.IsKeyDown(Keys.S))
9 {
10 worldTrans *= Matrix.CreateRotationX(MathHelper.ToRadians(-10f));
11 }
12 if (ks.IsKeyDown(Keys.A))
13 {
14 worldTrans *= Matrix.CreateRotationY(MathHelper.ToRadians(10f));
15 }
16 if (ks.IsKeyDown(Keys.D))
17 {
18 worldTrans *= Matrix.CreateRotationY(MathHelper.ToRadians(-10f));
19 }
20 if (ks.IsKeyDown(Keys.Q))
21 {
22 worldTrans *= Matrix.CreateRotationZ(MathHelper.ToRadians(10f));
23 }
24 if (ks.IsKeyDown(Keys.E))
25 {
26 worldTrans *= Matrix.CreateRotationZ(MathHelper.ToRadians(-10f));
27 }
28
29 if (ks.IsKeyDown(Keys.Up))
30 {
31 view *= Matrix.CreateTranslation(new Vector3(0,0,20));
32 }
33 if (ks.IsKeyDown(Keys.Down))
34 {
35 view *= Matrix.CreateTranslation(new Vector3(0, 0, -20));
36 }
37 }
2 {
3 KeyboardState ks = Keyboard.GetState();
4 if (ks.IsKeyDown(Keys.W))
5 {
6 worldTrans *= Matrix.CreateRotationX(MathHelper.ToRadians(10f));
7 }
8 if (ks.IsKeyDown(Keys.S))
9 {
10 worldTrans *= Matrix.CreateRotationX(MathHelper.ToRadians(-10f));
11 }
12 if (ks.IsKeyDown(Keys.A))
13 {
14 worldTrans *= Matrix.CreateRotationY(MathHelper.ToRadians(10f));
15 }
16 if (ks.IsKeyDown(Keys.D))
17 {
18 worldTrans *= Matrix.CreateRotationY(MathHelper.ToRadians(-10f));
19 }
20 if (ks.IsKeyDown(Keys.Q))
21 {
22 worldTrans *= Matrix.CreateRotationZ(MathHelper.ToRadians(10f));
23 }
24 if (ks.IsKeyDown(Keys.E))
25 {
26 worldTrans *= Matrix.CreateRotationZ(MathHelper.ToRadians(-10f));
27 }
28
29 if (ks.IsKeyDown(Keys.Up))
30 {
31 view *= Matrix.CreateTranslation(new Vector3(0,0,20));
32 }
33 if (ks.IsKeyDown(Keys.Down))
34 {
35 view *= Matrix.CreateTranslation(new Vector3(0, 0, -20));
36 }
37 }
这里主要是在3D环境中画出的2D效果,本来想再将这个Demo做成3D效果的,可惜顶点没添加到好多的时候速度就已经很慢了,所以做成3D效果的话还不成形机子就死了,所以就免了。
现在更希望有高手能指教这里面的不足。