#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();
и вы увидите, как это работает более четко: