Эта публикация перенесена в раздел уроков по адресу Урок по созданию класса Камеры. К ней прикреплена новая отдельная ветка комментариев форума, которую вы можетет найти после текста публикации. Обсуждение публикации рекуомендуется вести по новому адресу, который указан выше.
В этом уроке мы научимся создавать класс - камера. Для этого мы сначала попробуем разобраться с командой библиотеки Glu - GluLookAt. В нашем случаи Glu.gluLookAt.Она принимает три набора аргументов, которые задают точку наблюдения, прицельную точку (точку, на которую направлена камера) и направление, которое следует считать верхним.
Вроде бы все просто. Теперь создадим отдельный класс в нашем приложении - Camera. Сразу подключим пространства и создадим Vertex3D - структуру, где будут храниться X,Y,Z векторов.
/*http://esate.ru, OniKy*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tao.FreeGlut;
using Tao.OpenGl;
using Tao.Platform.Windows;
namespace Engine
{
class Camera
{
private struct Vector3D
{
public float x, y, z;
};
}
}
[spoiler] Объявим вектора которые будем использовать:
/*http://esate.ru, OniKy*/
private Vector3D mPos; //Вектор позиции камеры
private Vector3D mView; //Куда смотрит камера
private Vector3D mUp; //Вектор верхнего направления
private Vector3D mStrafe;//Вектор для стрейфа (движения влево и вправо) камеры.
Далее мы создадим метод, который будет нам возвращать перпендикулярный вектор от 3ех переданных векторов. Два любых вектора образуют плоскость, от которого мы и ищем перпендикуляр. Это все нам понадобиться для того чтоб мы смогли реализовать Стрейф.
/*http://esate.ru, OniKy*/
private Vector3D Cross(Vector3D vV1, Vector3D vV2, Vector3D vVector2)
{
Vector3D vNormal;
Vector3D vVector1;
vVector1.x = vV1.x - vV2.x;
vVector1.y = vV1.y - vV2.y;
vVector1.z = vV1.z - vV2.z;
// Если у нас есть 2 вектора (вектор взгляда и вертикальный вектор),
// у нас есть плоскость, от которой мы можем вычислить угол в 90 градусов.
// Рассчет cross'a прост, но его сложно запомнить с первого раза.
// Значение X для вектора = (V1.y * V2.z) - (V1.z * V2.y)
vNormal.x = ((vVector1.y * vVector2.z) - (vVector1.z * vVector2.y));
// Значение Y = (V1.z * V2.x) - (V1.x * V2.z)
vNormal.y = ((vVector1.z * vVector2.x) - (vVector1.x * vVector2.z));
// Значение Z = (V1.x * V2.y) - (V1.y * V2.x)
vNormal.z = ((vVector1.x * vVector2.y) - (vVector1.y * vVector2.x));
// *ВАЖНО* Вы не можете менять этот порядок, иначе ничего не будет работать.
// Должно быть именно так, как здесь. Просто запомните, если вы ищите Х, вы не
// используете значение X двух векторов, и то же самое для Y и Z. Заметьте,
// вы рассчитываете значение из двух других осей, и никогда из той же самой.
// Итак, зачем всё это? Нам нужно найти ось, вокруг которой вращаться. Вращение камеры
// влево и вправо простое - вертикальная ось всегда (0,1,0).
// Вращение камеры вверх и вниз отличается, так как оно происходит вне
// глобальных осей. Достаньте себе книгу по линейной алгебре, если у вас
// её ещё нет, она вам пригодится.
// вернем результат.
return vNormal;
}
Далее создадим два метода который будут работать над векторами - Magnitude и Normalize.
Magnitude - Возвращает величину вектора.
/*http://esate.ru, OniKy*/
private float Magnitude(Vector3D vNormal)
{
// Это даст нам величину нашей нормали,
// т.е. длину вектора. Мы используем эту информацию для нормализации
// вектора. Вот формула: magnitude = sqrt(V.x^2 + V.y^2 + V.z^2) где V - вектор.
return (float)Math.Sqrt((vNormal.x * vNormal.x) +
(vNormal.y * vNormal.y) +
(vNormal.z * vNormal.z));
}
и Normalize - Возвращает нормализированный вектор, длинна которого==1, это делает все рассчеты проще.
/*http://esate.ru, OniKy*/
private Vector3D Normalize(Vector3D vVector)
{
// Вы спросите, для чего эта ф-я? Мы должны убедиться, что наш вектор нормализирован.
// Вектор нормализирован - значит, его длинна равна 1. Например,
// вектор (2,0,0) после нормализации будет (1,0,0).
// Вычислим величину нормали
float magnitude = Magnitude(vVector);
// Теперь у нас есть величина, и мы можем разделить наш вектор на его величину.
// Это сделает длинну вектора равной единице, так с ним будет легче работать.
vVector.x = vVector.x / magnitude;
vVector.y = vVector.y / magnitude;
vVector.z = vVector.z / magnitude;
return vVector;
}
И так, теперь начнем работать с глобальными методами, которые мы сможем вызвать. Для начала нам нужно установить позицию, взгляд и вертикальный вектор камеры, в этом нам поможет следующий метод:
Теперь дадим возможность крутить камеру вокруг своей оси, аля вид от 1го лица =). Передовая в метод переменную speed, будем управлять силой поворота, а также и направлением, если положительная переменная, то вправо, а отрицательная, как вы уже догадались, налево =).
Если сделали вид от первого лица, то сделаем и от 3го =). Чтобы реализовать вращение камеры, мы будем использовать axis-angle вращение. Я должен предупредить, что формулы для рассчета вращения не очень просты, но занимают не много кода. Axis-angle вращение позволяет нам вращать точку в пространстве вокруг нужной оси. Это значит, что мы можем взять нашу точку взгляда (m_vView) и вращать вокруг нашей позиции. Чтобы лучше понять следующие рассчеты, советую вам посмотреть детальное описание: http://astronomy.swin.edu.au/~pbourke/geometry/rotate/
Также это функция реализована чтоб в переменную angle вы передавали угол в градусах.
/*http://esate.ru, OniKy*/
public void Rotate_Position(float angle, float x, float y, float z)
{
mPos.x = mPos.x - mView.x;
mPos.y = mPos.y - mView.y;
mPos.z = mPos.z - mView.z;
Vector3D vVector = mPos;
Vector3D AVector;
float SinA = (float)Math.Sin(Math.PI * angle / 180.0);
float CosA = (float)Math.Cos(Math.PI * angle / 180.0);
// Найдем новую позицию X для вращаемой точки
AVector.x = (CosA + (1 - CosA) * x * x) * vVector.x;
AVector.x += ((1 - CosA) * x * y - z * SinA) * vVector.y;
AVector.x += ((1 - CosA) * x * z + y * SinA) * vVector.z;
// Найдем позицию Y
AVector.y = ((1 - CosA) * x * y + z * SinA) * vVector.x;
AVector.y += (CosA + (1 - CosA) * y * y) * vVector.y;
AVector.y += ((1 - CosA) * y * z - x * SinA) * vVector.z;
// И позицию Z
AVector.z = ((1 - CosA) * x * z - y * SinA) * vVector.x;
AVector.z += ((1 - CosA) * y * z + x * SinA) * vVector.y;
AVector.z += (CosA + (1 - CosA) * z * z) * vVector.z;
mPos.x = mView.x + AVector.x;
mPos.y = mView.y + AVector.y;
mPos.z = mView.z + AVector.z;
}
Займемся перемещением камеры =). Самое первое как вы поняли, нам нужна возможность перемещать камеру вперед и назад в зависимости куда смотрит камера. Следующий метод позволит нам это делать =).
Ну и конечно нужен метод который у нас будет обновлять взгляд и позицию камеры:
/*http://esate.ru, OniKy*/
public void Look()
{
Glu.gluLookAt(mPos.x, mPos.y, mPos.z, //Нами ранее обсуждаемая команда =)
mView.x, mView.y, mView.z,
mUp.x, mUp.y, mUp.z);
}
И так, на всякий случай еще допишем методы который смогут получать позиции в пространстве как и камеры, так и взгляда:
/*http://esate.ru, OniKy*/
public double getPosX() //Возвращает позицию камеры по Х
{
return mPos.x;
}
public double getPosY() //Возвращает позицию камеры по Y
{
return mPos.y;
}
public double getPosZ() //Возвращает позицию камеры по Z
{
return mPos.z;
}
public double getViewX() //Возвращает позицию взгляда по Х
{
return mView.x;
}
public double getViewY() //Возвращает позицию взгляда по Y
{
return mView.y;
}
public double getViewZ() //Возвращает позицию взгляда по Z
{
return mView.z;
}
Ну вот и все =) Класс написан, и может быть использован. Как же его применять? Итак. Создадим новый проект. Объявим нужные нам библиотеки и пространства имен, добавим SimpleOpenGlControl и переименуем его в AnT. Также добавим Timer. Сразу объявим новый наш класс:
/*http://esate.ru, OniKy*/
Camera cam = new Camera();
Вот и собственно все =) На данном примере мы сделали возможность перемещаться по сцене как в редакторе моделей 3ds Max, можно использовать это также в играх типа Стратегий. Спасибо всем =)</cut>
Понравилась публикация? Сохраните ее, чтобы вернуться к изучению материала!
0
2798
17.01.2011
27
Внимание!
Эта публикация перенесена в раздел уроков по адресу Урок по созданию класса Камеры. К ней прикреплена новая отдельная ветка комментариев форума, которую вы можетет найти после текста публикации. Обсуждение публикации рекуомендуется вести по новому адресу, который указан выше.
Отличный урок, рекомендую вам перенести его в блог «новые уроки...». Для этого надо присоединится к блогу (), потом отредактировать урок и указать публичный блог для публикации.
Извини, в уроке вроде не хватает объявления некоторых переменных: MatrixColorOX MatrixColorOZ MatrixColorOY… mouseRotate mouseMove myMouseYcoord myMouseXcoordVar rot_cam_X… и т.д.
И было бы классно исходники к уроку приложить).(на почту ANVI скинуть он зальет)
урок класный, но думаю что та часть где ты камеру прикручиваешь лишняя, надо было просто словами написать что менять надо для поворота, и все бы поняли, хотя для ленивых это даже плюс
Для чайников (таких как я) — недостающие переменные: private void DrawGrid(int x, float quad_size) { //x - количество или длина сетки, quad_size - размер клетки
D:\пользователь\Documents\Visual Studio 2008\Projects\курсовая\курсовая\camera.cs(17,30): error CS0523: Struct member 'camera.Vector3D.mPos' of type 'camera.Vector3D' causes a cycle in the struct layout это ппц какой то
я наверно уже всех достал, но все же, я решил все со своими ошибками. теперь пытаюсь реализовать приближение и удаление камеры за счет колесика, но ни как не получается обработать это событие
Стоит ли переходить на Windows 10?Windows 10 установлена на каждый 3-й компьютер. Какие плюсы от перехода? DirectX 12 работает только в Windows 10?
Как установить Windows 10?Как бесплатно и легально скачать? Как записать и установить с последними обновлениями?
Сохраните страницу!
Регистрация
Регистрируясь, вы принимаете правила сайта. Если вы не получили код подтв. регистрации - не
забудьте проверить папку спам.
×
Восстановление пароля
Пожалуйста, заполните поля, после чего вы получите код подтверждения на ваш Email. Если код не пришел в течении нескольких минут - проверьте папку спам.
×
Авторизация
Авторизуйтесь с помощью соц. сети или с помощью аккаунта на сайте:
MatrixColorOX
MatrixColorOZ
MatrixColorOY…
mouseRotate
mouseMove
myMouseYcoord
myMouseXcoordVar
rot_cam_X… и т.д.
И было бы классно исходники к уроку приложить).(на почту ANVI скинуть он зальет)
private void DrawGrid(int x, float quad_size)
{
//x - количество или длина сетки, quad_size - размер клетки
float[] MatrixColorOX = {1,0,0,1};
float[] MatrixColorOY = {0,1,0,1};
float[] MatrixColorOZ = {0,0,1,1};
...
Далее:
bool mouseRotate, mouseMove = false;
int myMouseYcoord, myMouseXcoord, myMouseXcoordVar, myMouseYcoordVar;
float rot_cam_X;
private void AnT_MouseDown(object sender, MouseEventArgs e)
{
....
все лень делать, но как то пытаюсь бороться с этим =))
D:\пользователь\Documents\Visual Studio 2008\Projects\курсовая\курсовая\camera.cs(17,30): error CS0523: Struct member 'camera.Vector3D.mPos' of type 'camera.Vector3D' causes a cycle in the struct layout
это ппц какой то
может быть вы правда исходники дадите, чтобы было понятно, где ошибка?
Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_AMBIENT_AND_DIFFUSE, MatrixOXOYColor);
Ошибка на MatrixOXOYColor.
Она не где не обьявлялась. Что делать?
Просто черное окно.
Таймер включен.