КОМПЬЮТЕРНАЯ ГРАФИКА ВРАЩЕНИЕ ФИГУРЫ. РГЗ Вращение 3D-фигуры. новосибирский государственный технический университет
Скачать 0.65 Mb.
|
МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ «НОВОСИБИРСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ» Кафедра вычислительной техники РАСЧЕТНО-ГРАФИЧЕСКОЕ ЗАДАНИЕ ПО ДИСЦИПЛИНЕ «КОМПЬЮТЕРНАЯ ГРАФИКА» «Вращение 3D-фигуры» Факультет: АВТФ Преподаватель: Дружинин А.И. Группа: АВТ-010 Студент: Королев А. Е., Евдокимова Е.А. Новосибирск, 2021 г. Задание: Построить объёмную фигуру, используя любую доступную графическую библиотеку. Задать возможность вращения фигуры с клавиатуры по всем трём осям (XYZ). Результаты работы программы: На следующих скриншотах представлено разнообразный поворот куба, а также его движение по осям Куб вид спереди: Движение вниз: Движение влево: Движение вверх: Д вижение по оси Z (уменьшение): Движение вправо: Вращение по оси Ox (↓): Вращение по оси Оу (←) : Исходные коды модулей проекта: using MathNet.Numerics.LinearAlgebra; using SFML.Graphics; using SFML.System; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CompGraph { internal class Square : Drawable { public Vector3f A { get => a; private set { a = value; Update(); } } private Vector3f a; public Vector3f B { get => b; private set { b = value; Update(); } } private Vector3f b; public Vector3f C { get => c; private set { c = value; Update(); } } private Vector3f c; public Vector3f D { get => d; private set { d = value; Update(); } } public bool IsShading { get; } public Color Color { get; } private Vector3f d; public float Xoffset { get; set; } = 150; public float Yoffset { get; set; } =150; public float Zoffset { get; set; } = 1700; public Vector3f this[int index] { get { switch (index) { case 0: return A; case 1: return B; case 2: return C; case 3: return D; } return new Vector3f(0, 0, 0); } set { switch (index) { case 0: A = value; break; case 1: B = value; break; case 2: C = value; break; case 3: D = value; break; }; } } public ConvexShape Shape { get; set; } void Update() { if (A != new Vector3f(0, 0, 0) && B != new Vector3f(0, 0, 0) && C != new Vector3f(0, 0, 0) && D != new Vector3f(0, 0, 0)) { Shape.SetPoint(0, GetProjection(A)); Shape.SetPoint(1, GetProjection(B)); Shape.SetPoint(2, GetProjection(C)); Shape.SetPoint(3, GetProjection(D)); } } public Square(Vector3f a, Vector3f b, Vector3f c, Vector3f d,bool isShading,Color color) { Shape = new ConvexShape(4); A = b; B = a; C = c; D = d; IsShading = isShading; Color = color; } private Vector2f GetProjection(Vector3f vector) { return new Vector2f(vector.X * ((Zoffset) / vector.Z) + Xoffset, vector.Y * ((Zoffset) / vector.Z) + Yoffset); } public void Rotate(float angle, Vector3f point, RotateDirection direction) { var matrixToOrigin = CreateMatrix.DenseOfArray { {1,0,0,point.X }, {0,1,0,point.Y }, {0,0,1,point.Z }, {0,0,0,1 }, }); var matrixFromOrigin = CreateMatrix.DenseOfArray { {1,0,0,-point.X }, {0,1,0,-point.Y }, {0,0,1,-point.Z }, {0,0,0,1 }, }); Matrix var a = matrixToOrigin * rotateMatrix * matrixFromOrigin * CreateVector.DenseOfArray(new float[] { A.X, A.Y, A.Z, 1 }); var b = matrixToOrigin * rotateMatrix * matrixFromOrigin * CreateVector.DenseOfArray(new float[] { B.X, B.Y, B.Z, 1 }); var c = matrixToOrigin * rotateMatrix * matrixFromOrigin * CreateVector.DenseOfArray(new float[] { C.X, C.Y, C.Z, 1 }); var d = matrixToOrigin * rotateMatrix * matrixFromOrigin * CreateVector.DenseOfArray(new float[] { D.X, D.Y, D.Z, 1 }); A = new Vector3f(a[0], a[1], a[2]); B = new Vector3f(b[0], b[1], b[2]); C = new Vector3f(c[0], c[1], c[2]); D = new Vector3f(d[0], d[1], d[2]); } private Matrix { Matrix switch (direction) { case (RotateDirection.Xaxis): rotateMatrix = CreateMatrix.DenseOfArray(new float[,] { {1,0,0,0 }, {0,MathF.Cos(angle),-MathF.Sin(angle),0 }, {0,MathF.Sin(angle),MathF.Cos(angle),0 }, {0,0,0,1 }, }); break; case (RotateDirection.Yaxis): rotateMatrix = CreateMatrix.DenseOfArray(new float[,] { {MathF.Cos(angle), 0, MathF.Sin(angle), 0 }, {0, 1, 0, 0 }, {-MathF.Sin(angle),0, MathF.Cos(angle), 0 }, {0, 0, 0, 1 }, }); break; case (RotateDirection.Zaxis): rotateMatrix = CreateMatrix.DenseOfArray(new float[,] { {MathF.Cos(angle), -MathF.Sin(angle), 0, 0 }, {MathF.Sin(angle), MathF.Cos(angle), 0, 0 }, {0, 0, 1, 0 }, {0, 0, 0, 1 }, }); break; } return rotateMatrix; } public void Draw(RenderTarget target, RenderStates states) { Vertex[] vertices; if (IsShading) { float factor = 200; vertices = new Vertex[] { new Vertex(Shape.GetPoint(0),new Color(0,Convert.ToByte(255-(255/factor *A.Z)),0,Convert.ToByte(255-(255/24 *A.Z)+10))), new Vertex(Shape.GetPoint(1),new Color(0,Convert.ToByte(255-(255/factor*B.Z)),0,Convert.ToByte(255-(255/24 *B.Z)+10))), new Vertex(Shape.GetPoint(2),new Color(0,Convert.ToByte(255-(255/factor *C.Z)),0,Convert.ToByte(255-(255/24 *C.Z)+10))), new Vertex(Shape.GetPoint(3),new Color(0,Convert.ToByte(255-(255/factor *D.Z)),0,Convert.ToByte(255-(255/24 *D.Z)+10))) }; } else { vertices = new Vertex[] { new Vertex(Shape.GetPoint(0),Color), new Vertex(Shape.GetPoint(1),Color), new Vertex(Shape.GetPoint(2),Color), new Vertex(Shape.GetPoint(3),Color) }; } target.Draw(vertices, PrimitiveType.Quads, states); } } } global using SFML.Graphics; global using SFML.System; global using SFML.Window; using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace CompGraph { public class Program { private static RenderWindow Window; public static Vector2i WindowSize { get; } = new Vector2i(1000, 1000); private static Cube Cube { get; set; } private static RotateDirection RotateDirection { get; set; } = RotateDirection.Xaxis; static void Main(string[] args) { //Настройка окна var settings = new ContextSettings(); settings.DepthBits = 24; settings.StencilBits = 8; settings.AntialiasingLevel = 16; Window = new RenderWindow(new VideoMode(Convert.ToUInt32(WindowSize.X), Convert.ToUInt32(WindowSize.Y)), "CG", Styles.Default, settings); Window.SetFramerateLimit(0); Window.SetVerticalSyncEnabled(true); Window.Closed += Win_close; Window.SetActive(); Window.KeyReleased += Window_KeyReleased; Cube = new Cube(new Vector3f(2, 1, 20), new Vector3f(6, 1, 20), new Vector3f(2, 5, 20), new Vector3f(6, 5, 20), new Vector3f(2, 1, 24), new Vector3f(6, 1, 24), new Vector3f(2, 5, 24), new Vector3f(6, 5, 24)); float angle = 0.02f; while (Window.IsOpen) { Cube.Rotate(angle,RotateDirection); Window.Draw(Cube); Window.Display(); Window.DispatchEvents(); Window.Clear(Color.Black); } } private static void Window_KeyReleased(object sender, KeyEventArgs e) { switch(e.Code) { case (Keyboard.Key.Up): Cube.Move(MoveDirection.Up); break; case (Keyboard.Key.Down): Cube.Move(MoveDirection.Down); break; case (Keyboard.Key.Left): Cube.Move(MoveDirection.Left); break; case (Keyboard.Key.Right): Cube.Move(MoveDirection.Right); break; case (Keyboard.Key.W): RotateDirection = RotateDirection.Yaxis; break; case (Keyboard.Key.S): RotateDirection = RotateDirection.Xaxis; break; case (Keyboard.Key.Add): Cube.Move(MoveDirection.ZoomIn); break; case (Keyboard.Key.Subtract): Cube.Move(MoveDirection.ZoomOut); break; } } private static void Win_close(object sender, EventArgs e) { Window.Close(); } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CompGraph { enum RotateDirection { Xaxis, Yaxis, Zaxis, } enum MoveDirection { Up, Left, Right, Down, ZoomIn, ZoomOut, } internal class Cube : Drawable { public Cube(Vector3f A, Vector3f B, Vector3f C, Vector3f D, Vector3f E, Vector3f F, Vector3f G, Vector3f H) { Square First = new Square(A, B, C, D, true, Color.Green); Square Second = new Square(A, B, E, F, true, Color.Green); Square Third = new Square(C, D, G, H, true, Color.Green); Square Fourth = new Square(A, C, E, G, true, Color.Green); Square Fifth = new Square(B, D, F, H, true, Color.Green); Square Sixth = new Square(E, F, G, H, true, Color.Green); Sides = new Square[] { First, Second, Third, Fourth, Fifth, Sixth }; Origin = new Vector3f((Sides[0][0].X + Sides[0][1].X) / 2, (Sides[0][0].Y + Sides[0][2].Y) / 2, (Sides[0][0].Z + Sides[2][2].Z) / 2); Square Y = new Square(Origin, Origin + new Vector3f(0.1f, 0, 0), Origin + new Vector3f(0, 5, 0), Origin + new Vector3f(0.1f, 5, 0), false, Color.Red); Square X = new Square(Origin, Origin + new Vector3f(0, 0.1f, 0), Origin + new Vector3f(5, 0, 0), Origin + new Vector3f(5, 0.1f, 0), false, Color.Blue); Square Z = new Square(Origin, Origin + new Vector3f(0.1f, 0, 0), Origin + new Vector3f(0, 0, 15), Origin + new Vector3f(0.1f,0,15), false, Color.Yellow); Sides = new Square[] { First, Second, Third, Fourth, Fifth, Sixth,X,Y,Z }; } private Vector3f Origin { get; set; } Square[] Sides = new Square[6]; public void Move(MoveDirection direction) { foreach (var side in Sides) { for (int count = 0; count < 4; count++) { switch (direction) { case (MoveDirection.Up): side.Yoffset -= 10; break; case (MoveDirection.Down): side.Yoffset += 10; break; case (MoveDirection.Left): side.Xoffset -= 10; break; case (MoveDirection.Right): side.Xoffset += 10; break; case (MoveDirection.ZoomIn): side.Zoffset += 10; break; case (MoveDirection.ZoomOut): side.Zoffset -= 10; break; } } } // Origin = new Vector3f((Sides[0][0].X + Sides[0][1].X) / 2, (Sides[0][0].Y + Sides[0][2].Y) / 2, (Sides[0][0].Z + Sides[2][2].Z) / 2);++ } public void Rotate(float angle, RotateDirection direction) { for (int i = 0; i < Sides.Length-3; i++) { Square s = Sides[i]; s.Rotate(angle, Origin, direction); } } void Drawable.Draw(RenderTarget target, RenderStates states) { var a = Sides.ToList(); a.Sort(CompareSquare); a.Reverse(); foreach (var s in a) target.Draw(s, states); } private int CompareSquare(Square a, Square b) { float aSum = a.A.Z + a.B.Z + a.C.Z + a.D.Z; float bSum = b.A.Z + b.B.Z + b.C.Z + b.D.Z; if (aSum > bSum) return 1; else if (aSum != bSum) return -1; else { var aMin = (new float[] { a.A.Z, a.B.Z, a.C.Z, a.D.Z }).Min(); var bMin = (new float[] { b.A.Z, b.B.Z, b.C.Z, b.D.Z }).Min(); if (aMin > bMin) return 1; else if (aMin != bMin) return -1; else return 0; } } } } |