OpenTK - 如何按给定角度旋转对象

时间:2011-12-18 19:40:51

标签: c# opengl rotation opentk trackball

我正在使用http://viewport3d.com/trackball.htm上的教程来编写轨迹球。我有轴和角度计算,但因为我只是OpenTK和OpenGL的初学者,我不知道如何将旋转应用于对象。有什么帮助吗?

代码由几个文件组成,这里有两个最重要的文件。

Trackball.cs

using System;
using System.Windows.Forms;
using OpenTK;
using OpenTK.Graphics.OpenGL;

namespace _038trackball
{
  public partial class Form1
  {
    #region Camera attributes

    /// <summary>
    /// Current camera position.
    /// </summary>
    private Vector3 eye = new Vector3( 0.0f, 0.0f, 10.0f );

    /// <summary>
    /// Current point to look at.
    /// </summary>
    private Vector3 pointAt = Vector3.Zero;

    /// <summary>
    /// Current "up" vector.
    /// </summary>
    private Vector3 up = Vector3.UnitY;

    /// <summary>
    /// Vertical field-of-view angle in radians.
    /// </summary>
    private float fov = 1.0f;

    /// <summary>
    /// Camera's far point.
    /// </summary>
    private float far = 200.0f;

    #endregion

    protected Vector3d v1 = new Vector3d(0, 0, 0);
    protected Vector3d v2 = new Vector3d(0, 0, 0);
    protected float theta = 0;
    /// <summary>
    /// Sets up a projective viewport
    /// </summary>
    private void SetupViewport ()
    {
      int width  = glControl1.Width;
      int height = glControl1.Height;

      // 1. set ViewPort transform:
      GL.Viewport( 0, 0, width, height );

      // 2. set projection matrix
      GL.MatrixMode( MatrixMode.Projection );
      Matrix4 proj = Matrix4.CreatePerspectiveFieldOfView( fov, (float)width / (float)height, 0.1f, far );
      GL.LoadMatrix( ref proj );
    }

    /// <summary>
    /// Setup of a camera called for every frame prior to any rendering.
    /// </summary>
    private void SetCamera ()
    {
      // !!!{{ TODO: add camera setup here

      SetupViewport();

      GL.MatrixMode( MatrixMode.Modelview );
      Matrix4 modelview = Matrix4.CreateTranslation(-center) *
                          Matrix4.Scale(1.0f / diameter) *
                          Matrix4.CreateTranslation(0.0f, 0.0f, -1.5f);
      GL.LoadMatrix( ref modelview );

      // !!!}}
    }

    private void ResetCamera ()
    {
      // !!!{{ TODO: add camera reset code here
      // !!!}}

    }

    /// <summary>
    /// Rendering of one frame.
    /// </summary>
    private void Render ()
    {
      if ( !loaded ) return;

      frameCounter++;
      GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
      GL.ShadeModel( ShadingModel.Flat );
      GL.PolygonMode( MaterialFace.Front, PolygonMode.Fill );
      GL.Enable( EnableCap.CullFace );

      SetCamera();

      RenderScene();

      glControl1.SwapBuffers();
    }

    public void glControl1_MouseDown ( object sender, MouseEventArgs e )
    {
        Cursor.Current = Cursors.Hand;

        double x = MousePosition.X * 1.0 / (glControl1.Width * 1.0 / 2);
        double y = MousePosition.Y * 1.0 / (glControl1.Height * 1.0 / 2);
        x = x - 1;
        y = 1 - y;
        double z2 = 1 - x * x - y * y;
        double z = z2 > 0 ? Math.Sqrt(z2) : 0;
        v1 = new Vector3d(x, y, z);
        v1.Normalize();
        //labelFile.Text = String.Format("{0}, {1}, {2}, {3}, {4}, {5}, {6}", x, y, z, MousePosition.X, MousePosition.Y, glControl1.Width, glControl1.Height);
    }

    private void glControl1_MouseUp ( object sender, MouseEventArgs e )
    {
        Cursor.Current = Cursors.Default;

        double x = MousePosition.X * 1.0 / (glControl1.Width * 1.0 / 2);
        double y = MousePosition.Y * 1.0 / (glControl1.Height * 1.0 / 2);
        x = x - 1;
        y = 1 - y;
        double z2 = 1 - x * x - y * y;
        double z = z2 > 0 ? Math.Sqrt(z2) : 0;
        v2 = new Vector3d(x, y, z);
        v2.Normalize();

        Vector3d axis = Vector3d.Cross(v1, v2);
        float theta = (float) Vector3d.CalculateAngle(v1, v2);

        // Here sholud be smoething

        //labelFile.Text = String.Format("{0}, {1}", axis, theta);
    }

    private void glControl1_MouseMove ( object sender, MouseEventArgs e )
    {
      // !!!{{ TODO: add the event handler here
      // !!!}}

    }

    private void glControl1_MouseWheel ( object sender, MouseEventArgs e )
    {
      // !!!{{ TODO: add the event handler here
      // HINT: for most mouses, e.delta / 120 is the number of wheel clicks, +/- indicated the direction

      // !!!}}
    }

    private void glControl1_KeyDown ( object sender, KeyEventArgs e )
    {
      // !!!{{ TODO: add the event handler here
      // !!!}}
    }

    private void glControl1_KeyUp ( object sender, KeyEventArgs e )
    {
      // !!!{{ TODO: add the event handler here
      // !!!}}
    }

    private void buttonReset_Click ( object sender, EventArgs e )
    {
      // !!!{{ TODO: add the event handler here

      ResetCamera();

      // !!!}}
    }
  }
}

和Form1.cs

using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using Scene3D;

namespace _038trackball
{
  public partial class Form1 : Form
  {
    /// <summary>
    /// Scene read from file.
    /// </summary>
    protected SceneBrep scene = new SceneBrep();

    /// <summary>
    /// Scene center point.
    /// </summary>
    protected Vector3 center = Vector3.Zero;

    /// <summary>
    /// Scene diameter.
    /// </summary>
    protected float diameter = 3.5f;

    /// <summary>
    /// GLControl guard flag.
    /// </summary>
    bool loaded = false;

    /// <summary>
    /// Are we allowed to use VBO?
    /// </summary>
    bool useVBO = true;

    #region OpenGL globals

    private uint[] VBOid = new uint[ 2 ];       // vertex array (colors, normals, coords), index array
    private int stride = 0;                     // stride for vertex array

    #endregion

    #region FPS counter

    long lastFpsTime = 0L;
    int frameCounter = 0;
    long triangleCounter = 0L;

    #endregion

    public Form1 ()
    {
      InitializeComponent();
    }

    private void glControl1_Load ( object sender, EventArgs e )
    {
      loaded = true;

      // OpenGL init code:
      GL.ClearColor( Color.DarkBlue );
      GL.Enable( EnableCap.DepthTest );
      GL.ShadeModel( ShadingModel.Flat );

      // VBO init:
      GL.GenBuffers( 2, VBOid );
      if ( GL.GetError() != ErrorCode.NoError )
        useVBO = false;

      SetupViewport();

      Application.Idle += new EventHandler( Application_Idle );      
      comboTrackballType.SelectedIndex = 0;
    }

    private void glControl1_Resize ( object sender, EventArgs e )
    {
      if ( !loaded ) return;

      SetupViewport();
      glControl1.Invalidate();
    }

    private void glControl1_Paint ( object sender, PaintEventArgs e )
    {
      Render();
    }

    private void buttonOpen_Click ( object sender, EventArgs e )
    {
      OpenFileDialog ofd = new OpenFileDialog();

      ofd.Title = "Open Scene File";
      ofd.Filter = "Wavefront OBJ Files|*.obj" +
          "|All scene types|*.obj";

      ofd.FilterIndex = 1;
      ofd.FileName = "";
      if ( ofd.ShowDialog() != DialogResult.OK )
        return;

      WavefrontObj objReader = new WavefrontObj();
      objReader.MirrorConversion = false;
      StreamReader reader = new StreamReader( new FileStream( ofd.FileName, FileMode.Open ) );
      int faces = objReader.ReadBrep( reader, scene );
      reader.Close();
      scene.BuildCornerTable();
      diameter = scene.GetDiameter( out center );
      scene.GenerateColors( 12 );
      ResetCamera();

      //labelFile.Text = String.Format("{0}: {1} faces, {2}, {3}, {4}, {5}", ofd.SafeFileName, faces, theta, v1.X, x, y);
      PrepareDataBuffers();
      glControl1.Invalidate();
    }

    /// <summary>
    /// Prepare VBO content and upload it to the GPU.
    /// </summary>
    private void PrepareDataBuffers ()
    {
      if ( useVBO &&
           scene != null &&
           scene.Triangles > 0 )
      {
        GL.EnableClientState( ArrayCap.VertexArray );
        if ( scene.Normals > 0 )
          GL.EnableClientState( ArrayCap.NormalArray );
        GL.EnableClientState( ArrayCap.ColorArray );

        // Vertex array: color [normal] coord
        GL.BindBuffer( BufferTarget.ArrayBuffer, VBOid[ 0 ] );
        int vertexBufferSize = scene.VertexBufferSize( true, false, true, true );
        GL.BufferData( BufferTarget.ArrayBuffer, (IntPtr)vertexBufferSize, IntPtr.Zero, BufferUsageHint.StaticDraw );
        IntPtr videoMemoryPtr = GL.MapBuffer( BufferTarget.ArrayBuffer, BufferAccess.WriteOnly );
        unsafe
        {
          stride = scene.FillVertexBuffer( (float*)videoMemoryPtr.ToPointer(), true, false, true, true );
        }
        GL.UnmapBuffer( BufferTarget.ArrayBuffer );
        GL.BindBuffer( BufferTarget.ArrayBuffer, 0 );

        // Index buffer
        GL.BindBuffer( BufferTarget.ElementArrayBuffer, VBOid[ 1 ] );
        GL.BufferData( BufferTarget.ElementArrayBuffer, (IntPtr)(scene.Triangles * 3 * sizeof( uint )), IntPtr.Zero, BufferUsageHint.StaticDraw );
        videoMemoryPtr = GL.MapBuffer( BufferTarget.ElementArrayBuffer, BufferAccess.WriteOnly );
        unsafe
        {
          scene.FillIndexBuffer( (uint*)videoMemoryPtr.ToPointer() );
        }
        GL.UnmapBuffer( BufferTarget.ElementArrayBuffer );
        GL.BindBuffer( BufferTarget.ElementArrayBuffer, 0 );
      }
      else
      {
        GL.DisableClientState( ArrayCap.VertexArray );
        GL.DisableClientState( ArrayCap.NormalArray );
        GL.DisableClientState( ArrayCap.ColorArray );

        if ( useVBO )
        {
          GL.BindBuffer( BufferTarget.ArrayBuffer, VBOid[ 0 ] );
          GL.BufferData( BufferTarget.ArrayBuffer, (IntPtr)0, IntPtr.Zero, BufferUsageHint.StaticDraw );
          GL.BindBuffer( BufferTarget.ArrayBuffer, 0 );
          GL.BindBuffer( BufferTarget.ElementArrayBuffer, VBOid[ 1 ] );
          GL.BufferData( BufferTarget.ElementArrayBuffer, (IntPtr)0, IntPtr.Zero, BufferUsageHint.StaticDraw );
          GL.BindBuffer( BufferTarget.ElementArrayBuffer, 0 );
        }
      }
    }
  }
}

2 个答案:

答案 0 :(得分:0)

在设置ModelView矩阵的地方,将Matrix4.CreateRotation乘以指定对象的旋转。

答案 1 :(得分:-2)

对单个对象应用转换:

GL.PushMatrix();
GL.Translate(X, 0f, 0f); // My object is moving along the X axis
GL.Rotate(AngleX, 0.0f, 1.0f, 0.0f); // Also it rotates alongs its 

... put here all the code necessary to draw your object

GL.PopMatrix();