Сделай Сам Свою Работу на 5

Добавление интерактивности





Лабораторная работа №2. OpenGL

Стандарт OpenGL (Open Graphics Library - открытая графическая библиотека) был создан и утвержден как эффективный аппаратно-независимый интерфейс, пригодный для реализации на различных платформах. Для использования функций стандарта OpenGL в языке С# будет использоваться библиотека OpenTK, она является открытой и бесплатной.

Установка OpenTK и подключение к проекту.

Скачайте установщик OpenTK с официального сайта[1] и установите. Создайте новый проект Windows Forms Application так же, как в предыдущей лабораторной работе. Откройте SolutionExplorer, нажмите ПКМ по папке References -> Add Reference. В открывшемся окне выберите вкладку Browse и найдите библиотеки OpenTK.dll и OpenTK.GLControl.dll (По умолчанию dll лежат в папке Documents -> OpenTK -> 1.1 -> Binaries -> OpenTK - > Release). Откройте панель ToolBox, Нажмите ПКМ в свободной области -> Choose Items, на вкладке .NET Framework Components включите элемент GLControl, и добавьте его на форму. На форме появится черный прямоугольник.

Настройка окна вывода OpenGL и перспективной проекции.

Создайте новый класс GLgraphics. С помощью директивы using подключите OpenTK.

using OpenTK;

using OpenTK.Graphics.OpenGL;

Создайте функцию Setup c параметрами width и height – размерами окна для OpenGL.



public void Setup(int width, int height)

{

Вызовите функцию ClearColor, заливающую буфер экрана одним цветом. Функцией ShadeModel установите тип отрисовки полигонов с оттенками (smooth shading). Включите буфер глубины.

GL.ClearColor(Color.DarkGray);

GL.ShadeModel(ShadingModel.Smooth);

GL.Enable(EnableCap.DepthTest);

Создайте матрицу проекции, настройте ее согласно по размерам окна, и загрузите в контекст OpenGL. Для дополнительной информации про матрицу проекции прочитайте тут[2].

Matrix4 perspectiveMat = Matrix4.CreatePerspectiveFieldOfView(

MathHelper.PiOver4,

width / (float)height,

1,

64);

GL.MatrixMode(MatrixMode.Projection);

GL.LoadMatrix(ref perspectiveMat);

В классе GLgraphics создайте функцию Update(). Добавьте в нее строку, очищающую буферы.

public void Update()

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

В классе Form1 создайте экземпляр класса GLgraphics и инициализируйте конструктором по умолчанию.

public partial class Form1 : Form

{GLgraphics glgraphics = new GLgraphics();

Откройте свойства вашего glControl, откройте список доступных Events и двойным щелчком создайте метод Load, и в нем вызовите функцию Setup с размерами вашего glcontrol она в качестве параметров.



private void glControl1_Load(object sender, EventArgs e)

{glgraphics.Setup(glControl1.Width, glControl1.Height);

Аналогичным способом создайте метод Paint, и в нем вызовите метод Update.

private void glControl1_Paint(object sender, PaintEventArgs e)

{

glgraphics.Update();

glControl1.SwapBuffers();

}

Запустите программу. На данном этапе glContol должен окраситься в серый цвет.

Настройка позиции камеры и рисование тестового квадрата.

В классе GLgraphics создайте функцию drawTestQuad. Рисование примитивов в OpenGL начинается функцией glBenig(), за которой идут координаты вершин (вместе с координатами вершин могут идти цвет этих вершин, нормали, тестурные координаты), и заканчивается рисование функцией glEnd. OpenTK оборачивает вызовы функций на языке С в свои C# функции.

private void drawTestQuad()

{

GL.Begin(PrimitiveType.Quads);

GL.Color3(Color.Blue);

GL.Vertex3(-1.0f, -1.0f, -1.0f);

GL.Color3(Color.Red);

GL.Vertex3(-1.0f, 1.0f, -1.0f);

GL.Color3(Color.White);

GL.Vertex3(1.0f, 1.0f, -1.0f);

GL.Color3(Color.Green);

GL.Vertex3(1.0f, -1.0f, -1.0f);

GL.End();

}

Создайте функцию Render, в которой вызовите только что созданный метод drawTestQuad.

public void Render()

{

drawTestQuad();

}

Создайте переменные Vector3, в которых будет храниться параметры положения камеры.

class GLgraphics

{

Vector3 cameraPosition = new Vector3(2, 3, 4);

Vector3 cameraDirecton = new Vector3(0, 0, 0);

Vector3 cameraUp = new Vector3(0, 0, 1);

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

public void Update()

{

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

Matrix4 viewMat = Matrix4.LookAt(cameraPosition, cameraDirecton, cameraUp);

GL.MatrixMode(MatrixMode.Modelview);

GL.LoadMatrix(ref viewMat);

Render();

}

Запустите программу, на экране должен появиться квадрат, раскрашенный градиентом.

 

Добавление интерактивности



Для того, чтобы лучше почувствовать объем, нужно реализовать передвижение в пространстве. В данном пособии перемещение в пространстве будет реализовано следующим образом: Камера устремлена в центр координат и движется по окружающей сфере подобно спутнику.

Создайте в классе переменные для радиуса окружающей сферы и угла по широте и долготе.

public float latitude = 47.98f;

public float longitude = 60.41f;

public float radius = 5.385f;

В функции Update создайте вычисление текущей позиции камеры по радиусу и углам широты и долготы, для вычислений используйте формулы перехода от сферических координат к декартовым.

cameraPosition = new Vector3(

(float)(radius*Math.Cos(Math.PI/180.0f*latitude)*Math.Cos(Math.PI/180.0f*longitude)),

(float)(radius*Math.Cos(Math.PI/180.0f*latitude)*Math.Sin(Math.PI/180.0f*longitude)),

(float)(radius * Math.Sin(Math.PI / 180.0f * latitude)));

Откройте методы Events у расположенного на форме glContol и двойным щелчком создайте метод MouseMove. В методе пропишите преобразование координат текущего положения мыши в расстояние от центра изображения до текущего положения мыши, нормализуйте от -0.5 до 0.5, умножьте

private void glControl1_MouseMove(object sender, MouseEventArgs e)

{

float widthCoef = (e.X - glControl1.Width * 0.5f) / (float)glControl1.Width;

float heightCoef = (-e.Y + glControl1.Height * 0.5f) / (float)glControl1.Height;

glgraphics.latitude = heightCoef * 180;

glgraphics.longitude = widthCoef * 360;

}

 

Трансформация объекта

Трансформировать объекты принято в следующем порядке:

1. Масштабирование (функция scale);

2. Поворот (функция rotate);

3. Перемещение (функция translate).

Чтобы трансформация затрагивала только один объект, до трансформаций вызывается функция pushMatrix, а после отрисовки трансформированного объекта функция popMatrix. Для объектов, рисуемых после данного вызова, трансформации нужно применять заново. Отдельно можно уточнить функцию Rotate: в качестве параметров для нее используются угол, на который нужно повернуть рисуемый объект, и вектор, вокруг которого поворот происходит.

В функцию Render добавьте код, который рисует копию уже нарисованного квадрата с примененными к нему трансформациями.

drawTestQuad();

GL.PushMatrix();

GL.Translate(1, 1, 1);

GL.Rotate(45, Vector3.UnitZ);

GL.Scale(0.5f, 0.5f, 0.5f);

drawTestQuad();

GL.PopMatrix();

Результатом работы вашей программы должно быть подобное изображение.

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

В классе GLgraphics создайте переменную rotateAngle типа float. В функции Update ее увеличьте значение на константу, например, на 0.1. В методе Render используйте эту переменную в качестве значения угла поворота. Создайте функцию Application_Idle, которая будет заставлять вашу форму перерисовываться.

void Application_Idle(object sender, EventArgs e)

{

while (glControl1.IsIdle)

glControl1.Refresh();

}

В методе glcontrol_load подключите созданную нами функцию к событию формы idle.

Application.Idle += Application_Idle;

Наложение текстуры

Для наложения текстур на объекты используются текстурные координаты.

В классе GLgraphics создайте функцию loadTexture, которая загружает текстуру из изображения в память видеокарты. Результатом работы этой функции будет являться ID текстуры, который будет использоваться для того, чтобы указать, какую текстуру применять.

public int LoadTexture(String filePath)

{

try

{

Bitmap image = new Bitmap(filePath);

int texID = GL.GenTexture();

GL.BindTexture(TextureTarget.Texture2D, texID);

BitmapData data = image.LockBits(

new System.Drawing.Rectangle(0, 0, image.Width, image.Height),

ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

GL.TexImage2D(TextureTarget.Texture2D, 0,

PixelInternalFormat.Rgba, data.Width, data.Height, 0,

OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);

image.UnlockBits(data);

GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);

return texID;

}

catch (System.IO.FileNotFoundException е)

{

return -1;

}

}

Создайте список номеров текстур и инициализируйте конструктором по умолчанию.

public List<int> texturesIDs = new List<int>();

Скопируйте файл, который будете использовать в качестве текстуры, в папку с исполняемым файлом (.exe). Чтобы открыть папку с исполняемым файлом, откройте SolutionExplorer, нажмите по проекту ПКМ -> Open Folder in Windows Explorer. В открывшемся окне перейдете в папку bin -> Debug (или Release, если вы собираете Release версию). Скопируйте вашу текстуру в данную папку.

Загрузите текстуру с помощью написанной вами функции. Загрузить текстуру нужно один раз при запуске программы. Нет разницы в том, вызывать загрузку текстуры из класса Form1 или из класса GLgraphics. Например, при загрузке текстур внутри функции glControl_load код будет выглядеть так:

int texID = glgraphics.LoadTexture("texture_logo.png");

glgraphics.texturesIDs.Add(texID);

Создайте метод drawTextureQuad по аналогии с методом drawtextquad. Главным отличием является то, что в новой функции каждой вершине ставится в соответствие текстурная координата.

private void drawTexturedQuad()

{

GL.Enable(EnableCap.Texture2D);

GL.BindTexture(TextureTarget.Texture2D, texturesIDs[0]);

GL.Begin(PrimitiveType.Quads);

GL.Color3(Color.Blue);

GL.TexCoord2(0.0, 0.0);

GL.Vertex3(-1.0f, -1.0f, -1.0f);

GL.Color3(Color.Red);

GL.TexCoord2(0.0, 1.0);

GL.Vertex3(-1.0f, 1.0f, -1.0f);

GL.Color3(Color.White);

GL.TexCoord2(1.0, 1.0);

GL.Vertex3(1.0f, 1.0f, -1.0f);

GL.Color3(Color.Green);

GL.TexCoord2(1.0, 0.0);

GL.Vertex3(1.0f, -1.0f, -1.0f);

GL.End();

GL.Disable(EnableCap.Texture2D);

}

Вызовите функцию, рисующую текстурированный квадрат, в функции Render. Проверьте правильность отрисовки.

Освещение в OpenGL

Настройку освещения в OpenGL можно условно разделить на две части: настройка источников света и настройка материала освещаемых объектов. В данной лабораторной работе для всех объектов будет использоваться один и тот же материал для упрощения работы.

В OpenGL реализовано моделирование освещения точечными источниками света (до 8 источников света).

В классе GLgraphics создайте метод SetupLightning. Внутри метода включите расчет освещения, включите нулевой источник света, включите освещение, включите освещение освещение цветных вершин.

GL.Enable(EnableCap.Lighting);

GL.Enable(EnableCap.Light0);

GL.Enable(EnableCap.ColorMaterial);

Установите положение источника света.

Vector4 lightPosition = new Vector4(1.0f, 1.0f, 4.0f, 0.0f);

GL.Light(LightName.Light0, LightParameter.Position, lightPosition);

Установите ambient цвет источника – цвет, который будет иметь объект, не освещенный источником.

Vector4 ambientColor = new Vector4(0.2f, 0.2f, 0.2f, 1.0f);

GL.Light(LightName.Light0, LightParameter.Ambient, ambientColor);

Установите diffuse цвет источника – цвет, который будет иметь объект, освещенный источником.

Vector4 diffuseColor = new Vector4(0.6f, 0.6f, 0.6f, 1.0f, 1.0f);

GL.Light(LightName.Light0, LightParameter.Diffuse, diffuseColor);

Для создания бликов на поверхностях установите всем материалам зеркальную составляющую. Из-за большого значения диффузной составляющей зеркальную не будет видно до тех пор, пока она не примет очень большое значение. В данном пособии Specular компонента будет включена для всех объектов, но в настоящий проектах specular составляющая устанавливается для каждого материала отдельно.

Vector4 materialSpecular = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);

GL.Material(MaterialFace.Front, MaterialParameter.Specular, materialSpecular);

float materialShininess = 100;

GL.Material(MaterialFace.Front, MaterialParameter.Shininess, materialShininess);

Вызовите созданную функцию SetupLightning в методе Setup, посмотрите на цветной квадрат под разными углами. Квадрат с освещенной стороны должен изменять свой цвет в зависимости от угла просмотра, а с неосвещенной стороны быть темным и не менять свой цвет в зависимости от угла.

 








Не нашли, что искали? Воспользуйтесь поиском по сайту:



©2015 - 2024 stydopedia.ru Все материалы защищены законодательством РФ.