2012-02-07 3 views
0

Я новичок в 3D-графике, и я нашел ряд примеров по вращению, однако я считаю, что что-то не так с моим кодом для создания 3D-сетки или самого вращения. Я использую модифицированную версию primatives example for xna.3D Mesh Rotation

Example Image

Итак, по существу моя проблема сводится к тому, что я вращающейся вокруг красных х линий вместо синей линии х. В идеале я хочу повернуть, где встречаются синяя линия Y и линия Blue X. Слишком посмотреть на функцию вращения см. Ниже приведенный ниже класс микрометрического класса Microsoft и посмотреть 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;   
} 

Слегка модифицированная версия класса Microsoft Геометрических примитивный:

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); 

Добавляя «позиции» в углах квадрата, вы компенсируя геометрический центр квадрата из локального пространства координат сетки.

Во время вращения местное происхождение (и все вершины) всегда вращается вокруг оси, проходящей через мировое происхождение. Ваш код приносит местное пространство в линию с этой осью, но если ваша ось вращения находится вокруг геометрического центра (вместо локального начала), во время вращения требуется сдвиг трансляции.

Как правило, вы не добавляете «позицию» в такую ​​вершину (таким образом избегая этой проблемы вообще). Вы строите вершины вокруг начала координат симметрично в локальном пространстве и переводите их позже, куда бы вы ни захотели, чтобы они находились в мировом пространстве. Тогда это смещение вращения много легче иметь дело.

На первый взгляд мне кажется, что если вы удалите это количество позиции из угловых вершин, ваш код будет делать то, что вы ожидаете.

Надеюсь, что по крайней мере дать вам ключ, чтобы установить вас в правильном направлении.

Смежные вопросы