Камера перемещения и прокрутки проекции OpenTK

#c# #opengl #2d #opentk

#c# #opengl #2d #opentk

Вопрос:

Я пишу графический 2d-редактор и использую OpenTK в качестве движка рендеринга.
Я подумал, как можно перемещать и прокручивать камеру с помощью мыши, чтобы она выглядела так, как это делается в Photoshop.

Вот код, который у меня есть на данный момент.

  GL.Enable(EnableCap.Texture2D);
 GL.Enable(EnableCap.Blend);
 GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
  

  GL.MatrixMode(MatrixMode.Projection);
 GL.LoadIdentity(); 
 GL.Viewport(0, 0, 1024, 768);
  

 ///Part od drawing function
            ClassNodeField nField = NodeFieldsManager.GetByID(ID);

            int Rows    = 4000 / 128   1;
            int Columns = 4000 / 128   1;


            GL.ClearColor(Color.Silver); 
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            GL.Color3(200f, 200f, 200f);

            GL.Begin(BeginMode.Lines);


            for (int i = 0; i < Rows; i  )
            {
                GL.Vertex3(4000,     128 * i, 0);
                GL.Vertex3(4000,     128 * i, 0);
            }


            for (int i = 0; i < Columns; i  )
            {
                GL.Vertex3(128 * i, 4000, 0);
                GL.Vertex3(128 * i, 4000, 0);
            }

            GL.End();
/// end part of drawing function
  

она отлично работает, имея поле 4000 на 4000 пикселей для тестов. Я планирую использовать 45000 на 45000. И теперь мне нужно перемещаться по этому полю и прокручивать колесо мыши.
Помогите мне с тем, что я должен вызвать из OpenTK, чтобы переместить мою камеру и прокрутить ее.

Ответ №1:

Если я достаточно понимаю OpenGL, нет вызова для перемещения камеры. В результате вы создаете матрицу преобразования, которая выполняет всю работу за вас. Вы должны заглянуть в мировую матрицу.

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

Итак, перед вами 2 варианта: 1) попробуйте преобразовать этот вызов для работы с OpenTK:

 Matrix.CreateTranslation(location.x, location.y, 0f)
  

где местоположение относится к центру того места, куда вы хотите посмотреть. Другой вариант — просмотреть любую соответствующую документацию об OpenGL и OpenTK.

Комментарии:

1. Соответствующий вызов в OpenTK будет: Matrix4.CreateTranslation(location.x, location.y, 0.0f) .

2. ничего не произошло. При вызове этой функции. Где я должен это назвать?

3. @AlexeyGapon Эта функция создает только матрицу. Скорее всего, вы не использовали ее после этого. Этот учебник попадает в точку в отношении того, что делает матрица, и потока, который вам нужно будет реализовать. Что касается того, где это реализовать? В обновлении, но не в части рисования вашей программы. Кроме того, вы можете прочитать о камерах для 3D-игр. Просто помните, что разница между 3D и 2D теперь заключается в том, что для 2D все глубины установлены на одинаковую величину.

Ответ №2:

Хорошо, спасибо всем, я решил эту задачу. Треугольник всегда перемещается вместе с курсором мыши — но я думаю, что это не проблема, чтобы сделать это только при нажатии кнопки (с двумя переменными old translate и new translate).

 /*--------------------------------Program.cs------------------------------*/
    //Program.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows.Forms;

    namespace OpenTK_OrthoCamera
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
        }
    }


/*--------------------------------Form1.Designer.cs------------------------*/
    namespace OpenTK_OrthoCamera
    {
        partial class Form1
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;

            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing amp;amp; (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }

            #region Windows Form Designer generated code

            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.glControl1 = new OpenTK.GLControl();
                this.SuspendLayout();
                // 
                // glControl1
                // 
                this.glControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
                | System.Windows.Forms.AnchorStyles.Left) 
                | System.Windows.Forms.AnchorStyles.Right)));
                this.glControl1.BackColor = System.Drawing.Color.Black;
                this.glControl1.Location = new System.Drawing.Point(12, 12);
                this.glControl1.Name = "glControl1";
                this.glControl1.Size = new System.Drawing.Size(892, 521);
                this.glControl1.TabIndex = 0;
                this.glControl1.VSync = false;
                this.glControl1.Load  = new System.EventHandler(this.glControl1_Load);
                this.glControl1.Paint  = new System.Windows.Forms.PaintEventHandler(this.glControl1_Paint);
                this.glControl1.MouseMove  = new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseMove);
                this.glControl1.Resize  = new System.EventHandler(this.glControl1_Resize);
                this.glControl1.MouseWheel  = new System.Windows.Forms.MouseEventHandler(this.OnMouseWheel);
                // 
                // Form1
                // 
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.ClientSize = new System.Drawing.Size(916, 545);
                this.Controls.Add(this.glControl1);
                this.Name = "Form1";
                this.Text = "Form1";
                this.ResumeLayout(false);

            }


            #endregion

            private OpenTK.GLControl glControl1;
        }
    }

/*--------------------------------Form1.cs-------------------------------*/
    using OpenTK.Graphics.OpenGL;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;

    namespace OpenTK_OrthoCamera
    {
        public partial class Form1 : Form
        {
            bool loaded = false;

            float x = 0;
            float y = 0;
            float z = 0;


            public Form1()
            {
                InitializeComponent();
            }

            /// <summary>
            /// Loads Control
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void glControl1_Load(object sender, EventArgs e)
            {
                loaded = true;
                GL.ClearColor(Color.SkyBlue); // Yey! .NET Colors can be used directly!

                SetupViewport();
            }

            /// <summary>
            /// Setup the Viewport
            /// </summary>
            private void SetupViewport()
            {

                GL.MatrixMode(MatrixMode.Projection);
                GL.LoadIdentity();            

                int w = glControl1.Width;
                int h = glControl1.Height;

                float orthoW = w * (z   1);
                float orthoH = h * (z   1);

                GL.Ortho(0, orthoW, 0, orthoH, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
                GL.Viewport(0, 0, w, h); // Use all of the glControl painting area
            }



            /// <summary>
            /// Calculate Translation of  (X, Y, Z) - according to mouse input
            /// </summary>
            private void SetupCursorXYZ()
            {
                x =   PointToClient(Cursor.Position).X  * (z   1);
                y = (-PointToClient(Cursor.Position).Y   glControl1.Height) * (z   1); 
            }


            /// <summary>
            /// We need to setup each time our viewport and Ortho.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void glControl1_Resize(object sender, EventArgs e)
            {
                if (!loaded)
                    return;

                SetupViewport();
            }


            /// <summary>
            /// Paint The control.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void glControl1_Paint(object sender, PaintEventArgs e)
            {
                if (!loaded) // Play nice
                    return;

                GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

                GL.MatrixMode(MatrixMode.Modelview);
                GL.LoadIdentity();

                GL.Translate(x, y, 0); // position triangle according to our x variable

                GL.Color3(Color.Yellow);
                GL.Begin(BeginMode.Triangles);
                GL.Vertex2(10, 20);
                GL.Vertex2(100, 20);
                GL.Vertex2(100, 50);
                GL.End();

                glControl1.SwapBuffers();

            }

            /// <summary>
            /// The triangle will always move with the cursor. 
            /// But is is not a problem to make it only if mousebutton pressed. 
            /// And do some simple ath with old Translation and new translation.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void glControl1_MouseMove(object sender, MouseEventArgs e)
            {
                x = PointToClient(Cursor.Position).X  * (z   1);
                y = (-PointToClient(Cursor.Position).Y   glControl1.Height) * (z   1);

                SetupCursorXYZ();

                glControl1.Invalidate();
            }


            private void OnMouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
            {
                if (e.Delta > 0 amp;amp; z > 0) z -= 0.5f;
                if (e.Delta < 0 amp;amp; z < 5) z  = 0.5f;

                SetupCursorXYZ();

                SetupViewport();
                glControl1.Invalidate();
            }

        }
    }
  

Попробуйте. Это работает.

Ответ №3:

Попробуйте заменить код

 GL.Color3(Color.Yellow);
GL.Begin(BeginMode.Triangles);
GL.Vertex2(10, 20);
GL.Vertex2(100, 20);
GL.Vertex2(100, 50);
GL.End();
  

с этим

  GL.Color3(Color.Yellow);
            GL.Begin(BeginMode.Triangles);

            for (int i = -20; i < 20; i  )
                for (int j = -20; j < 20; j  )
                {
                    GL.Vertex2(10   i * 200 , 20   j *200);
                    GL.Vertex2(100   i * 200, 20   j * 200);
                    GL.Vertex2(100   i * 200, 50   j * 200);
                }
            GL.End();
  

и вы увидите, как это работает более четко: