3D Mesh Вращение - PullRequest
       5

3D Mesh Вращение

0 голосов
/ 07 февраля 2012

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

Example Image

Так что, по сути, моя проблема сводится к тому, что я вращаюсь вокруг красногоЛиния х вместо синей линии х.В идеале я хочу повернуть туда, где сливаются синяя линия Y и синяя линия X.Также посмотрите на функцию поворота, посмотрите на приведенный ниже класс Microsoft Geometric Pritive и посмотрите на 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 Geometric Pritive:

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 Ответ

1 голос
/ 07 февраля 2012

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

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

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

Добавляя 'position' к углам квадрата, вы смещаете геометрический центр квадрата от локального космического начала сетки.

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

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

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

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

...