2012-02-07 132 views
0

我对3D图形很陌生,我发现了很多旋转的例子,但是我相信我的代码用于创建三维网格或旋转本身。我正在使用primatives example for xna的修改版本。三维网格旋转

Example Image

所以基本上我的问题归结到我绕着红色的X线,而不是蓝色的X线。理想情况下,我想旋转蓝色Y线和蓝色X线相交处。看看旋转函数,看下面列出的微软类Geometric Primative,看看RotateX。

谢谢你的帮助。

下面是如何设置我的场景:

public RenderScene3D(short _depth, GraphicsDevice GD) : base(_depth) 
{ 
    PrimativeCollection = new List<GeometricPrimitive>(); 
    cameraPosition = new Vector3(0, 0, 2.5f); 
    fAspect = GD.Viewport.AspectRatio; 

    CameraWorld = Matrix.CreateTranslation(cameraPosition); 
    world = Matrix.CreateFromYawPitchRoll(0, 0, 0); 
    view = Matrix.CreateLookAt(cameraPosition, Vector3.Zero, Vector3.Up); 
    projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, fAspect, .01f, 500f); 
    // This serves as a base line for latter ray cursor calculations. 
    ScreenProjection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, fAspect, .01f, 2.5f); 
    graphicsDevice = GD;   
} 

微软的类几何灵长类动物的稍作修改的版本:

public abstract class GeometricPrimitive : IDisposable 
{ 
    #region Fields 

    // During the process of constructing a primitive model, vertex 
    // and index data is stored on the CPU in these managed lists. 
    protected List<VertexPositionNormal> vertices = new List<VertexPositionNormal>(); 
    protected List<ushort> indices = new List<ushort>(); 
    public Vector3 v3Position; 
    protected Matrix world; 
    protected Matrix worldPosition; 
    protected Matrix worldRotation; 

    // Once all the geometry has been specified, the InitializePrimitive 
    // method copies the vertex and index data into these buffers, which 
    // store it on the GPU ready for efficient rendering. 
    protected VertexBuffer vertexBuffer; 
    protected IndexBuffer indexBuffer; 
    protected BasicEffect basicEffect; 

    #endregion 

    #region Initialization 


    /// <summary> 
    /// Adds a new vertex to the primitive model. This should only be called 
    /// during the initialization process, before InitializePrimitive. 
    /// </summary> 
    protected void AddVertex(Vector3 _position, Vector3 normal) 
    { 
     vertices.Add(new VertexPositionNormal(_position, _position)); 
    } 


    /// <summary> 
    /// Adds a new index to the primitive model. This should only be called 
    /// during the initialization process, before InitializePrimitive. 
    /// </summary> 
    protected void AddIndex(int index) 
    { 
     if (index > ushort.MaxValue) 
      throw new ArgumentOutOfRangeException("index"); 

     indices.Add((ushort)index); 
    } 


    /// <summary> 
    /// Queries the index of the current vertex. This starts at 
    /// zero, and increments every time AddVertex is called. 
    /// </summary> 
    protected int CurrentVertex 
    { 
     get { return vertices.Count; } 
    } 


    /// <summary> 
    /// Once all the geometry has been specified by calling AddVertex and AddIndex, 
    /// this method copies the vertex and index data into GPU format buffers, ready 
    /// for efficient rendering. 
    public void InitializePrimitive(GraphicsDevice graphicsDevice) 
    { 
     // Create a vertex declaration, describing the format of our vertex data. 

     // Create a vertex buffer, and copy our vertex data into it. 
     vertexBuffer = new VertexBuffer(graphicsDevice, 
             typeof(VertexPositionNormal), 
             vertices.Count, BufferUsage.None); 

     vertexBuffer.SetData(vertices.ToArray()); 

     // Create an index buffer, and copy our index data into it. 
     indexBuffer = new IndexBuffer(graphicsDevice, typeof(ushort), 
             indices.Count, BufferUsage.None); 

     indexBuffer.SetData(indices.ToArray()); 

     // Create a BasicEffect, which will be used to render the primitive. 
     basicEffect = new BasicEffect(graphicsDevice); 

     basicEffect.EnableDefaultLighting(); 
     RotateX(0); 
     UpdateWorld(); 
    } 

    public void Move(Vector3 Position) 
    { 
     v3Position = Position; 
     worldPosition = Matrix.CreateTranslation(v3Position); 
    } 

    public void UpdateWorld() 
    { 
     world = worldRotation * worldPosition; 
    } 

    public void RotateX(float X) 
    { 
     Matrix rotation = worldPosition; 

     Matrix.CreateRotationX(X, out rotation); 
     worldRotation = rotation; 
    } 


    /// <summary> 
    /// Finalizer. 
    /// </summary> 
    ~GeometricPrimitive() 
    { 
     Dispose(false); 
    } 


    /// <summary> 
    /// Frees resources used by this object. 
    /// </summary> 
    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 


    /// <summary> 
    /// Frees resources used by this object. 
    /// </summary> 
    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      if (vertexBuffer != null) 
       vertexBuffer.Dispose(); 

      if (indexBuffer != null) 
       indexBuffer.Dispose(); 

      if (basicEffect != null) 
       basicEffect.Dispose(); 
     } 
    } 


    #endregion 

    #region Draw 


    /// <summary> 
    /// Draws the primitive model, using the specified effect. Unlike the other 
    /// Draw overload where you just specify the world/view/projection matrices 
    /// and color, this method does not set any renderstates, so you must make 
    /// sure all states are set to sensible values before you call it. 
    /// </summary> 
    public void Draw(Effect effect) 
    { 
     GraphicsDevice graphicsDevice = effect.GraphicsDevice; 

     // Set our vertex declaration, vertex buffer, and index buffer. 
     graphicsDevice.SetVertexBuffer(vertexBuffer); 

     graphicsDevice.Indices = indexBuffer;    


     foreach (EffectPass effectPass in effect.CurrentTechnique.Passes) 
     { 
      effectPass.Apply(); 

      int primitiveCount = indices.Count/3; 

      graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertices.Count, 0, primitiveCount); 

     } 
    } 


    /// <summary> 
    /// Draws the primitive model, using a BasicEffect shader with default 
    /// lighting. Unlike the other Draw overload where you specify a custom 
    /// effect, this method sets important renderstates to sensible values 
    /// for 3D model rendering, so you do not need to set these states before 
    /// you call it. 
    /// </summary> 
    public void Draw(Matrix view, Matrix projection, Color color) 
    { 
     // Set BasicEffect parameters. 
     basicEffect.World = world; 
     //Matrix worldMatrix = Matrix.CreateScale(0.0005f, 0.0005f, 0.0005f) * Matrix.CreateRotationY(MathHelper.Pi) * Matrix.CreateFromQuaternion(xwingRotation) * Matrix.CreateTranslation(xwingPosition); 
     //Matrix worldMatrix = Matrix.CreateScale(0.0005f, 0.0005f, 0.0005f) * Matrix.CreateRotationY(MathHelper.Pi) * Matrix.CreateFromQuaternion(xwingRotation) * Matrix.CreateTranslation(xwingPosition); 
     //Matrix test = view.Translation * new Vector3(0,0,0.001f); 
     basicEffect.View = view; 
     basicEffect.Projection = projection; 
     basicEffect.DiffuseColor = color.ToVector3(); 
     basicEffect.Alpha = 128.0f/color.A; 

     GraphicsDevice device = basicEffect.GraphicsDevice; 
     // Reset the fill mode renderstate. 
     device.DepthStencilState = DepthStencilState.Default; 

     if (color.A < 255) 
     { 
      // Set renderstates for alpha blended rendering. 
      device.BlendState = BlendState.AlphaBlend; 
     } 
     else 
     { 
      // Set renderstates for opaque rendering. 
      device.BlendState = BlendState.AlphaBlend; 
     } 

     // Draw the model, using BasicEffect. 
     Draw(basicEffect); 
    } 
} 

最后我的平方类别:

public class SquarePrimitive : GeometricPrimitive 
{ 
    public float size; 
    /// <summary> 
    /// Constructs a new square primitive, using default settings. 
    /// </summary> 
    public SquarePrimitive(Vector3 position, Vector3 _v3Rotation) 
     : this(position, _v3Rotation, 1) 
    { 

    } 

    /// <summary> 
    /// Constructs a new square primitive, with the specified size. 
    /// </summary> 
    public SquarePrimitive(Vector3 position, Vector3 _v3Rotation, float _size) 
    { 
     size = _size; 
     // Get two vectors perpendicular to the face normal and to each other. 
     Vector3 topLeft = new Vector3(-size, size, 0); 
     Vector3 topRight = new Vector3(size, size, 0); 
     Vector3 bottomLeft = new Vector3(-size, -size, 0); 
     Vector3 bottomRight = new Vector3(size, -size, 0); 

     // Six indices (two triangles) per face. 
     AddIndex(CurrentVertex + 0); 
     AddIndex(CurrentVertex + 1); 
     AddIndex(CurrentVertex + 2); 

     AddIndex(CurrentVertex + 0); 
     AddIndex(CurrentVertex + 2); 
     AddIndex(CurrentVertex + 3); 

     // Four vertices per face. 
     size = 0.1f; 
     AddVertex((position + topLeft), position); 
     AddVertex((position + topRight), position); 
     AddVertex((position + bottomRight), position); 
     AddVertex((position + bottomLeft), position); 

     Move(position); 
    } 
} 

回答

1

它以偏移(平移)网格的几何中心以使得期望的旋转点是在轴上,该轴贯穿世界原点,然后应用旋转,然后将其翻译回原来的位置。或者...修改您的代码以防止需要这样做。

您的代码中有足够的细微之处,我不得不随时随地提供一行代码,这对您很有用,但这里有一两个想法。

AddVertex((position + topLeft), position); 
    AddVertex((position + topRight), position); 
    AddVertex((position + bottomRight), position); 
    AddVertex((position + bottomLeft), position); 

通过添加“位置”到广场的角落,你抵消从网格的局部空间的原点方形的几何中心。

在旋转过程中,局部原点(和所有顶点)总是围绕穿过世界原点的轴旋转。您的代码将本地空间原点与该轴内联,但是您希望的旋转轴位于几何中心周围(而不是本地原点附近),因此在旋转过程中需要平移偏移。

通常情况下,您不会为此类顶点添加“位置”(从而完全避免该问题)。您可以在局部空间中对称地围绕原点构建顶点,然后将其中的一些点翻译成您希望它们在世界空间中的任何位置。那么旋转抵消是多了更容易处理。

乍一看,如果您从角落顶点删除了“位置”数量,您的代码将按照您的预期进行操作。

希望至少能给你提供一个线索,让你朝着正确的方向前进。