private void UpdateModelViewMatrix() // метод вызывается при измении свойств cameraAngle и cameraDistance { #region Обновление объектно-видовой матрицы --------------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { DMatrix4 modelMat = DMatrix4.Identity; RotateMatrix(ref modelMat, Rotation.X, Rotation.Y, Rotation.Z); ScaleMatrix(ref modelMat, Scale.X, Scale.Y, Scale.Z); gl.MatrixMode(OpenGL.GL_MODELVIEW); gl.LoadMatrix(modelMat.ToArray(true)); }); #endregion }
private void UpdateDisplayMode() // метод вызывается при измении свойств cameraAngle и cameraDistance { #region Обновление объектно-видовой матрицы --------------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { if (Wireframe) { gl.PolygonMode(OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_LINE); } else { gl.PolygonMode(OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_FILL); } }); #endregion }
private void UpdateModelViewMatrix() // метод вызывается при измении свойств cameraAngle и cameraDistance { #region Обновление объектно-видовой матрицы --------------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { gl.MatrixMode(OpenGL.GL_MODELVIEW); gl.LoadIdentity(); gl.Translate(Shift.X, Shift.Y, 0.0); gl.Rotate(Rotation.X, 1.0, 0.0, 0.0); gl.Rotate(Rotation.Y, 0.0, 1.0, 0.0); gl.Rotate(Rotation.Z, 0.0, 0.0, 1.0); gl.Translate(Position.X, Position.Y, Position.Z); gl.Scale(Scale.X, Scale.Y, Scale.Z); }); #endregion }
private void UpdateModelViewMatrix() // метод вызывается при измении свойств cameraAngle и cameraDistance { #region Обновление объектно-видовой матрицы --------------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { gl.MatrixMode(OpenGL.GL_MODELVIEW); var deg2rad = Math.PI / 180; // Вращается камера, а не сам объект double phi = deg2rad * cameraAngle.X; double teta = deg2rad * cameraAngle.Y; double psi = deg2rad * cameraAngle.Z; // матрицы поворота вокруг осей DMatrix3 RX = new DMatrix3(1, 0, 0, 0, Math.Cos(phi), -Math.Sin(phi), 0, Math.Sin(phi), Math.Cos(phi)); DMatrix3 RY = new DMatrix3(Math.Cos(teta), 0, Math.Sin(teta), 0, 1, 0, -Math.Sin(teta), 0, Math.Cos(teta)); DMatrix3 RZ = new DMatrix3(Math.Cos(psi), -Math.Sin(psi), 0, Math.Sin(psi), Math.Cos(psi), 0, 0, 0, 1); var cameraTransform = (RX * RY) * RZ; var cameraPosition = cameraTransform * new DVector3(0, 0, cameraDistance); var cameraUpDirection = cameraTransform * new DVector3(0, 1, 0); // Мировая матрица (преобразование локальной системы координат в мировую) mMatrix = DMatrix4.Identity; // нет никаких преобразований над объекта // Видовая матрица (переход из мировой системы координат к системе координат камеры) vMatrix = LookAt(DMatrix4.Identity, cameraPosition, DVector3.Zero, cameraUpDirection); // матрица ModelView var mvMatrix = vMatrix * mMatrix; gl.LoadMatrix(mvMatrix.ToArray(true)); //gl.Rotate(45, 1f, 0f, 0); //gl.Rotate(-45, 0f, 1f, 0); }); #endregion }
private void UpdateModelViewMatrix() // метод вызывается при измении свойств cameraAngle и cameraDistance { #region Обновление объектно-видовой матрицы --------------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { }); #endregion }
protected override void OnMainWindowLoad(object sender, EventArgs args) { base.VSPanelWidth = 260; base.ValueStorage.RightColWidth = 60; base.RenderDevice.VSync = 1; #region Обработчики событий мыши и клавиатуры ------------------------------------------------------- RenderDevice.MouseMoveWithLeftBtnDown += (s, e) => Rotation += new DVector3(e.MovDeltaY, e.MovDeltaX, 0); RenderDevice.MouseMoveWithRightBtnDown += (s, e) => { double W = base.RenderDevice.Width; double H = base.RenderDevice.Height; double AspectRatio = W / H; }; #endregion InclinedCylinder(); #region Инициализация OGL и параметров рендера ----------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { gl.FrontFace(OpenGL.GL_CCW); gl.Enable(OpenGL.GL_CULL_FACE); gl.CullFace(OpenGL.GL_BACK); gl.ClearColor(0.2f, 0.6f, 1.0f, 1.0f); gl.Enable(OpenGL.GL_DEPTH_TEST); gl.DepthFunc(OpenGL.GL_LEQUAL); gl.ClearDepth(1.0f); // 0 - ближе, 1 - далеко gl.ClearStencil(0); }); #endregion #region Инициализация буфера вершин ----------------------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { uint[] VertexVBOIDtempArray = new uint[1]; gl.GenBuffers(1, VertexVBOIDtempArray); VertexVBOID = VertexVBOIDtempArray[0]; uint[] IndexVBOIDtempArray = new uint[1]; gl.GenBuffers(1, IndexVBOIDtempArray); IndexVBOID = IndexVBOIDtempArray[0]; vertexShader = gl.CreateShader(OpenGL.GL_VERTEX_SHADER); gl.ShaderSource(vertexShader, ReadShader("VertexShader.vert")); gl.CompileShader(vertexShader); ShaderLog(gl, vertexShader); fragmentShader = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER); gl.ShaderSource(fragmentShader, ReadShader("FragmentShader.frag")); gl.CompileShader(fragmentShader); ShaderLog(gl, fragmentShader); shaderProgram = gl.CreateProgram(); gl.AttachShader(shaderProgram, vertexShader); gl.AttachShader(shaderProgram, fragmentShader); gl.LinkProgram(shaderProgram); ProgramLog(gl, shaderProgram); }, this); #endregion #region Уничтожение буфера вершин по завершению работы OGL ------------------------------------------ RenderDevice.Closed += (s, e) => // Событие выполняется в контексте потока OGL при завершении работы { var gl = e.gl; gl.DeleteBuffers(2, new uint[2] { VertexVBOID, IndexVBOID }); gl.DeleteShader(vertexShader); gl.DeleteShader(fragmentShader); gl.DeleteProgram(shaderProgram); }; #endregion #region Обновление матрицы проекции при изменении размеров окна и запуске приложения ---------------- RenderDevice.Resized += (s, e) => { var gl = e.gl; UpdateProjectionMatrix(gl); }; #endregion }
protected override void OnMainWindowLoad(object sender, EventArgs args) { base.ValueStorage.Font = new Font("Courier New", 12f); base.ValueStorage.ForeColor = Color.Black; base.ValueStorage.RowHeight = 30; base.ValueStorage.BackColor = Color.FromArgb(180, 180, 180); base.MainWindow.BackColor = Color.FromArgb(160, 160, 160); base.ValueStorage.RightColWidth = 70; base.VSPanelWidth = 480; base.VSPanelLeft = true; base.MainWindow.Size = new Size(960, 640); #region Обработчики событий мыши и клавиатуры ------------------------------------------------------- RenderDevice.MouseMoveWithLeftBtnDown += (s, e) => cameraAngle += new DVector3(-e.MovDeltaY, -e.MovDeltaX, 0); RenderDevice.MouseWheel += (s, e) => cameraDistance -= e.Delta / 10.0; #endregion // Как было отмеченно выше вся работа связанная с OGL должна выполнятся в одном потоке. Тут работа с OGL // осуществляется в отдельном потоке, а метод OnMainWindowLoad() является событием возбуждаемым потоком // пользовательского интерфейса (UI). Поэтой причине весь код ниже добавляется в диспетчер устройства // вывода (метод AddScheduleTask() объекта RenderDevice) и выполняется ассинхронно в контексте потока // OGL. Сам диспетчер является очередью типа FIFO (First In First Out - т.е. задания обрабатываются // строго в порядке их поступления) и гарантирует, что все задания добавленные в OnMainWindowLoad() // будут выполнены до первого вызова метода OnDeviceUpdate() (aka OnPaint) #region Инициализация OGL и параметров рендера ----------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { //gl.Disable(OpenGL.GL_DEPTH_TEST); gl.Enable(OpenGL.GL_DEPTH_TEST); gl.Enable(OpenGL.GL_CULL_FACE); gl.CullFace(OpenGL.GL_BACK); // отбросить полигоны, повёрнутые изнанкой gl.ClearColor(1, 1, 1, 0); gl.FrontFace(OpenGL.GL_CW); // обход вершин по часовой стрелки //gl.PolygonMode(OpenGL.GL_FRONT, OpenGL.GL_FILL); // закрашиваются полигоны, повёрнутые лицевой стороной gl.PolygonMode(OpenGL.GL_FRONT, OpenGL.GL_LINE); gl.PolygonMode(OpenGL.GL_BACK, OpenGL.GL_FILL); }); #endregion #region Загрузка и компиляция шейдера var errorhandler = new Action <string, object, object>((format, arg0, arg1) => { string errormessage = String.Format(format, arg0, arg1); Trace.WriteLine(errormessage); throw new Exception(errormessage); MessageBox.Show(errormessage, "SHADER CREATION ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); Application.Exit(); }); RenderDevice.AddScheduleTask((gl, s) => { var parameters = new int[1]; uint uit_ver = gl.CreateShader(OpenGL.GL_VERTEX_SHADER); uint uit_frag = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER); var compile_shader = new Action <uint>(shader => { gl.CompileShader(shader); // Проверяем была ли компиляция выполнена успешно gl.GetShader(shader, OpenGL.GL_COMPILE_STATUS, parameters); if (parameters[0] != OpenGL.GL_TRUE) { // В случае если компиляция не удалась пытаемся добиться от OGL // что именно ему не понравилось. Для этого вначале получаем длину // сообщения, выделим память под него, а затем уже запрашиваем // скопировать туда само сообщение. В случае C# это выглядит // немного иначе, но суть таже. gl.GetShader(shader, OpenGL.GL_INFO_LOG_LENGTH, parameters); StringBuilder strbuilder = new StringBuilder(parameters[0]); gl.GetShaderInfoLog(shader, parameters[0], IntPtr.Zero, strbuilder); errorhandler("OpenGL Error: ошибка во время компиляции {1}.\n{0}", strbuilder.ToString(), shader == uit_ver ? "VERTEX_SHADER" : shader == uit_frag ? "FRAGMENT_SHADER" : "??????????_SHADER"); } }); var shader_vert = HelpUtils.GetTextFileFromRes("shader.vert"); var shader_frag = HelpUtils.GetTextFileFromRes("shader.frag"); //return; gl.ShaderSource(uit_ver, shader_vert); gl.ShaderSource(uit_frag, shader_frag); compile_shader(uit_ver); compile_shader(uit_frag); program = gl.CreateProgram(); gl.AttachShader(program, uit_ver); gl.AttachShader(program, uit_frag); //gl.LinkProgram(program); gl.LinkProgram(program); gl.GetProgram(program, OpenGL.GL_LINK_STATUS, parameters); if (parameters[0] != OpenGL.GL_TRUE) { errorhandler("OpenGL Error: ошибка линковки програмы шейдера", null, null); } attrib_loc[0] = (uint)gl.GetAttribLocation(program, "position"); attrib_loc[1] = (uint)gl.GetAttribLocation(program, "normal"); uniform_loc[0] = (uint)gl.GetUniformLocation(program, "projection"); uniform_loc[1] = (uint)gl.GetUniformLocation(program, "view"); uniform_loc[2] = (uint)gl.GetUniformLocation(program, "model"); gl.UseProgram(program); }); #endregion #region Инициализация буфера вершин ----------------------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { gl.EnableClientState(OpenGL.GL_VERTEX_ARRAY); gl.EnableClientState(OpenGL.GL_NORMAL_ARRAY); gl.EnableClientState(OpenGL.GL_INDEX_ARRAY); gl.EnableClientState(OpenGL.GL_COLOR_ARRAY); gl.GenBuffers(buffers.Length, buffers); }, this); #endregion #region Уничтожение буфера вершин по завершению работы OGL ------------------------------------------ RenderDevice.Closed += (s, e) => // Событие выполняется в контексте потока OGL при завершении работы { var gl = e.gl; gl.DisableClientState(OpenGL.GL_VERTEX_ARRAY); gl.DisableClientState(OpenGL.GL_NORMAL_ARRAY); gl.DisableClientState(OpenGL.GL_INDEX_ARRAY); gl.DisableClientState(OpenGL.GL_COLOR_ARRAY); }; #endregion #region Обновление матрицы проекции при изменении размеров окна и запуске приложения ---------------- RenderDevice.Resized += (s, e) => { var gl = e.gl; gl.MatrixMode(OpenGL.GL_PROJECTION); pMatrix = Perspective(60, (double)e.Width / e.Height, 0.1, 100); gl.LoadMatrix(pMatrix.ToArray(true)); }; #endregion }
protected override void OnMainWindowLoad(object sender, EventArgs args) { base.VSPanelWidth = 260; base.ValueStorage.RightColWidth = 60; base.RenderDevice.VSync = 1; #region Обработчики событий мыши и клавиатуры ------------------------------------------------------- RenderDevice.MouseMoveWithLeftBtnDown += (s, e) => { }; RenderDevice.MouseMoveWithRightBtnDown += (s, e) => { }; RenderDevice.MouseLeftBtnDown += (s, e) => { DVector2 norm = NormalizeCoords(e.Location.X, e.Location.Y); double X = (norm.X - ShiftX) * Scale; double Y = (norm.Y - ShiftY) * Scale; text = $"{X} {Y}"; lock (locker) { vertices.Add(new Vertex2(X, Y)); } }; RenderDevice.MouseLeftBtnUp += (s, e) => { }; RenderDevice.MouseRightBtnDown += (s, e) => { DVector2 norm = NormalizeCoords(e.Location.X, e.Location.Y); double X = (norm.X - ShiftX) * Scale; double Y = (norm.Y - ShiftY) * Scale; foreach (Vertex2 v in vertices) { double dx = v.Point.X - X; double dy = v.Point.Y - Y; double r = Math.Sqrt(dx * dx + dy * dy); double radius = NormalizeDistance(VertexSize) * Scale; if (r < radius) { ActiveVertex = v; return; } } }; RenderDevice.MouseRightBtnUp += (s, e) => { ActiveVertex = null; Pos = new DVector2(0.0, 0.0); }; RenderDevice.MouseMove += (s, e) => { MousePosition = new DVector2(e.Location.X + e.MovDeltaX, e.Location.Y + e.MovDeltaY); if (ActiveVertex != null) { double dx = NormalizeDistance(e.MovDeltaX) * Scale; double dy = NormalizeDistance(e.MovDeltaY) * Scale; if (e.MovDeltaX < 0) { dx = -dx; } if (e.MovDeltaY > 0) { dy = -dy; } double newX = ActiveVertex.Point.X + dx; double newY = ActiveVertex.Point.Y + dy; ActiveVertex.Point = new DVector2(newX, newY); Pos = ActiveVertex.Point; } }; // Реализация управления клавиатурой RenderDevice.HotkeyRegister(Keys.Up, (s, e) => ShiftY += 0.05); RenderDevice.HotkeyRegister(Keys.Down, (s, e) => ShiftY -= 0.05); RenderDevice.HotkeyRegister(Keys.Left, (s, e) => ShiftX -= 0.05); RenderDevice.HotkeyRegister(Keys.Right, (s, e) => ShiftX += 0.05); RenderDevice.HotkeyRegister(KeyMod.Shift, Keys.Up, (s, e) => ShiftY += 0.1); RenderDevice.HotkeyRegister(KeyMod.Shift, Keys.Down, (s, e) => ShiftY -= 0.1); RenderDevice.HotkeyRegister(KeyMod.Shift, Keys.Left, (s, e) => ShiftX -= 0.1); RenderDevice.HotkeyRegister(KeyMod.Shift, Keys.Right, (s, e) => ShiftX += 0.1); RenderDevice.HotkeyRegister(Keys.C, (s, e) => { DVector2 vec = NormalizeCoords(MousePosition.X, MousePosition.Y); ShiftX = -vec.X + ShiftX; ShiftY = -vec.Y + ShiftY; }); RenderDevice.MouseWheel += (s, e) => { float DeltaScale = -e.Delta / 10000.0f; Scale += DeltaScale; }; RenderDevice.MouseMoveWithMiddleBtnDown += (s, e) => { double dx = NormalizeDistance(e.MovDeltaX); double dy = NormalizeDistance(e.MovDeltaY); if (e.MovDeltaX < 0) { dx = -dx; } if (e.MovDeltaY > 0) { dy = -dy; } ShiftX += dx; ShiftY += dy; }; #endregion spline = new CatmullRomSpline(vertices, false, 1.0 / ApproxLevel); #region Инициализация OGL и параметров рендера ----------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { gl.FrontFace(OpenGL.GL_CCW); gl.Enable(OpenGL.GL_CULL_FACE); gl.CullFace(OpenGL.GL_BACK); gl.ClearColor(0, 0, 0, 0); gl.Enable(OpenGL.GL_DEPTH_TEST); gl.DepthFunc(OpenGL.GL_LEQUAL); gl.ClearDepth(1.0f); // 0 - ближе, 1 - далеко gl.ClearStencil(0); }); #endregion #region Обновление матрицы проекции при изменении размеров окна и запуске приложения ---------------- RenderDevice.Resized += (s, e) => { var gl = e.gl; UpdateProjectionMatrix(gl); }; #endregion }
protected override void OnMainWindowLoad(object sender, EventArgs args) { base.VSPanelWidth = 260; base.ValueStorage.RightColWidth = 60; base.RenderDevice.VSync = 1; #region Обработчики событий мыши и клавиатуры ------------------------------------------------------- RenderDevice.MouseMoveWithLeftBtnDown += (s, e) => Rotation += new DVector3(e.MovDeltaY, e.MovDeltaX, 0); RenderDevice.MouseMoveWithRightBtnDown += (s, e) => { double W = base.RenderDevice.Width; double H = base.RenderDevice.Height; double AspectRatio = W / H; if (W > H) { ShiftX += ((double)e.MovDeltaX / W * 2) * AspectRatio; ShiftY -= (double)e.MovDeltaY / H * 2; } else { ShiftX += (double)e.MovDeltaX / W * 2; ShiftY -= ((double)e.MovDeltaY / H * 2) / AspectRatio; } }; #endregion // Как было отмеченно выше вся работа связанная с OGL должна выполнятся в одном потоке. Тут работа с OGL // осуществляется в отдельном потоке, а метод OnMainWindowLoad() является событием возбуждаемым потоком // пользовательского интерфейса (UI). Поэтой причине весь код ниже добавляется в диспетчер устройства // вывода (метод AddScheduleTask() объекта RenderDevice) и выполняется ассинхронно в контексте потока // OGL. Сам диспетчер является очередью типа FIFO (First In First Out - т.е. задания обрабатываются // строго в порядке их поступления) и гарантирует, что все задания добавленные в OnMainWindowLoad() // будут выполнены до первого вызова метода OnDeviceUpdate() (aka OnPaint) InclinedCylinder(); #region Инициализация OGL и параметров рендера ----------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { gl.FrontFace(OpenGL.GL_CCW); gl.Enable(OpenGL.GL_CULL_FACE); gl.CullFace(OpenGL.GL_BACK); gl.ClearColor(0, 0, 0, 0); gl.Enable(OpenGL.GL_DEPTH_TEST); gl.DepthFunc(OpenGL.GL_LEQUAL); gl.ClearDepth(1.0f); // 0 - ближе, 1 - далеко gl.ClearStencil(0); }); #endregion #region Инициализация буфера вершин ----------------------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { uint[] VertexVBOIDtempArray = new uint[1]; gl.GenBuffers(1, VertexVBOIDtempArray); VertexVBOID = VertexVBOIDtempArray[0]; uint[] IndexVBOIDtempArray = new uint[1]; gl.GenBuffers(1, IndexVBOIDtempArray); IndexVBOID = IndexVBOIDtempArray[0]; }, this); #endregion #region Уничтожение буфера вершин по завершению работы OGL ------------------------------------------ RenderDevice.Closed += (s, e) => // Событие выполняется в контексте потока OGL при завершении работы { var gl = e.gl; gl.DeleteBuffers(2, new uint[2] { VertexVBOID, IndexVBOID }); }; #endregion #region Обновление матрицы проекции при изменении размеров окна и запуске приложения ---------------- RenderDevice.Resized += (s, e) => { var gl = e.gl; UpdateProjectionMatrix(gl); }; #endregion }
protected override void OnMainWindowLoad(object sender, EventArgs args) { base.VSPanelWidth = 260; base.ValueStorage.RightColWidth = 60; base.RenderDevice.VSync = 1; #region Обработчики событий мыши и клавиатуры ------------------------------------------------------- RenderDevice.MouseMoveWithRightBtnDown += (s, e) => Rotation += new DVector3(e.MovDeltaY, e.MovDeltaX, 0); RenderDevice.MouseMoveWithMiddleBtnDown += (s, e) => { double H = base.RenderDevice.Height; double W = base.RenderDevice.Width; double AspectRatio = W / H; if (W > H) { Shift = new DVector2(Shift.X + 2 * e.MovDeltaX / W * AspectRatio, Shift.Y - 2 * (double)e.MovDeltaY / H); } else { Shift = new DVector2(Shift.X + 2 * e.MovDeltaX / W, Shift.Y - 2 * (double)e.MovDeltaY / H / AspectRatio); } }; RenderDevice.MouseLeftBtnDown += (s, e) => { DVector2 norm = NormalizeCoords(e.Location.X, e.Location.Y); double H = base.RenderDevice.Height; double W = base.RenderDevice.Width; double AspectRatio = W / H; double X, Y; if (W > H) { X = (norm.X) / AspectRatio; Y = norm.Y; } else { X = norm.X; Y = (norm.Y) * AspectRatio; } DVector4 mousePos = new DVector4(X, Y, 0.0, 0.0); lock (ActiveVertexLocker) { ActiveVertex = FindClosestVertex(transformationMatrix, mousePos); if (ActiveVertex != null) { ActiveVertexPosition = ActiveVertex.Point; } else { ActiveVertexPosition = DVector3.Zero; } } }; RenderDevice.MouseLeftBtnUp += (s, e) => { }; RenderDevice.MouseRightBtnDown += (s, e) => { }; RenderDevice.MouseRightBtnUp += (s, e) => { }; RenderDevice.MouseMove += (s, e) => { }; #endregion #region Инициализация OGL и параметров рендера ----------------------------------------------------- RenderDevice.AddScheduleTask((gl, s) => { gl.FrontFace(OpenGL.GL_CCW); gl.Enable(OpenGL.GL_CULL_FACE); gl.CullFace(OpenGL.GL_BACK); gl.ClearColor(0, 0, 0, 0); gl.Enable(OpenGL.GL_DEPTH_TEST); gl.DepthFunc(OpenGL.GL_LEQUAL); gl.ClearDepth(1.0f); // 0 - ближе, 1 - далеко gl.ClearStencil(0); }); #endregion #region Обновление матрицы проекции при изменении размеров окна и запуске приложения ---------------- RenderDevice.Resized += (s, e) => { var gl = e.gl; UpdateProjectionMatrix(gl); }; #endregion surface = new CoonsSurface(Prefix + ".txt"); surface.ComputeSurface(ApproxLevel); }