Безплатна камера, Блог на Иван Андреев
В тази статия ще създадем проста камера, която също ще ни спести известно време по-късно.
Ще създадем „свободна камера“, тоест камера, която не е прикрепена към никакъв обект, може свободно да се движи в триизмерното пространство и също така да се върти под произволен ъгъл около всяка координатна ос.
Ще внедрим камерата като компонент на играта, но тъй като не е необходимо да рисуваме камерата по никакъв начин, ще я наследим от GameComponent.
Основните параметри, които ще трябва да получим от камерата, са позицията на камерата (необходима е за някои модели осветителни тела) и матрицата на изгледа, която ще използваме навсякъде в нашите по-нататъшни приложения.
Също така беше възможно да преместя проекционната матрица в класа на камерата, но няма да го направя, защото не мисля, че е съвсем логично (въпреки че може и да греша).
Класът на камерата ще изглежда така:
клас FreeCamera : GameComponent
обществена Позиция на вектор3;
float turnSpeed = 1;
обществена FreeCamera( Игра игра, позиция на Vector3, LookAt на Vector3) : база (игра)
този .Position = позиция;
Изглед = Matrix .CreateLookAt(position, lookAt, Vector3 .Up);
обществено заменяне невалидна актуализация( GameTime gameTime)
int centerX = Game.GraphicsDevice.Viewport.Width / 2;
int centerY = Game.GraphicsDevice.Viewport.Height / 2;
MouseState mouse = Mouse.GetState();
Мишка .SetPosition(centerX, centerY);
float seconds = ( float )(gameTime.ElapsedGameTime.TotalSeconds);
float yaw = MathHelper .ToRadians((mouse.X - centerX) * turnSpeed *секунди);
плавна стъпка = MathHelper .ToRadians((mouse.Y — centerY) * turnSpeed * seconds);
ъгъл = нов Вектор3 (ъгъл.X + стъпка, ъгъл.Y + отклонение, ъгъл.Z);
Вектор3 напред = — Вектор3 .Normalize( нов Вектор3 (
( float ) Math .Sin(-angle.Y) * ( float ) Math .Cos(angle.X),
( float ) Math .Sin(angle.X),
( float ) Math .Cos(-angle.Y) * ( float ) Math .Cos(angle.X))
Вектор3 вляво = — Вектор3 .Normalize( нов Вектор3 (
( float ) Math .Cos(ъгъл.Y),
( float ) Math .Sin(angle.Y))
Състояние на KeyboardState = Keyboard .GetState();
if (state.IsKeyDown( Keys .Up))
Позиция += напред * скорост * секунди;
if (state.IsKeyDown( Keys .Down))
Позиция -= напред * скорост * секунди;
if (state.IsKeyDown( Keys .Left))
Позиция += ляво * скорост * секунди;
if (state.IsKeyDown( Keys .Right))
Позиция -= ляво * скорост * секунди;
Изглед = Матрица .CreateTranslation(-Position) *
Подробна реализация на този клас, описан в нашия курс «XNA за начинаещи», тук отбележете само някои основни моменти:
Задават се две переменни, отговарящи за скоростта на преместване и завъртане на камерата – скорост и turnSpeed съответно.
Първоначално се определя местоположението на ъгъла на завъртане на камерата в зависимост от смесването на показалеца на мишката от центъра на екрана (след този курсор отново се премества в центъра на екрана) и се определя новият ъгъл на завъртане спрямо всички координатни оси. С този углам се определят вектори Пред и Влево за текущото направление на камерата. В зависимост от нажатия клавищ на клавиатурата се случва сместването на позицията на камерата в посокавектори напред и наляво.
Отместването се изчислява от матрицата на изгледа.
Сега можете да свържете новия компонент в играта и да използвате матрицата за изглед, която се съдържа в камерата, за да изобразите сцената.
Ще бъде трудно да проверим нашата камера, когато има само един модел в цвета, нека напишем прост код, който ще нарисува много модели на различни места в триизмерния свят.
protected override void Initialize()
// ЗАДАЧИ: Добавете вашата инициализираща логика тук
Components.Add( new FPSCounter ( this ));
светлина = ново Светлина (това);
camera = new FreeCamera ( this , new Vector3 (0, 0, 3), Vector3 .Zero);
basicEffect = new BasicEffect(GraphicsDevice, null);
чайник = нов TeapotPrimitive(GraphicsDevice);
защитен отменяне невалидно теглене( GameTime gameTime)
GraphicsDevice.Clear(Color.CornflowerBlue);
Matrixview = camera.View;
Matrix proj = Matrix .CreatePerspectiveFieldOfView( MathHelper .ToRadians(45), GraphicsDevice.Viewport.AspectRatio, 0.1f, 10f);
// ЗАДАЧА: Добавете своя код за чертеж тук
basicEffect.World = Matrix.Identity;
basicEffect.AmbientLightColor = нов Вектор3(0.1f, 0.1f, 0.1f);
basicEffect.DirectionalLight0.Direction = Vector3.Zero-light.Position;
basicEffect.DirectionalLight0.DiffuseColor = нов Вектор3(0.6f, 0, 0.4f);
за ( int i = -2; i
за ( int j = -2; j
за ( int k = -2; k
Вектор3 поз = нов Вектор3 (i,j,k) * 2;
basicEffect.World = Matrix .CreateTranslation(pos);
basicEffect.DirectionalLight0.Direction = pos - light.Position;
Имайте предвид, че тъй като източникът на светлина е на 2 разстояние от началото, източникът на светлина е по-близо до началото, отколкото някои чайници. Въпреки че обикновено се счита, че източникът на насочена светлина (засега ще разгледаме източник на насочена светлина) е безкрайно отдалечен от сцената. По принцип няма нищо лошо в това, но ако искате да поправите този недостатък, можете просто да промените първоначалната позиция на източника на светлина на голяма (например на Vector3 (0,0,100)).
Също така си струва да се отбележи, че при нашите първоначални условия камерата по подразбиране е вътре в един от чайниците.
клас FreeCamera : GameComponent
обществена Позиция на вектор3;
float turnSpeed = 1;
обществена FreeCamera( Игра игра, позиция на Vector3, LookAt на Vector3) : база (игра)
този .Position = позиция;
Изглед = Matrix .CreateLookAt(position, lookAt, Vector3 .Up);
обществено заменяне невалидна актуализация( GameTime gameTime)
int centerX = Game.GraphicsDevice.Viewport.Width / 2;
int centerY = Game.GraphicsDevice.Viewport.Height / 2;
MouseState mouse = Mouse.GetState();
Мишка .SetPosition(centerX, centerY);
float seconds = ( float )(gameTime.ElapsedGameTime.TotalSeconds);
float yaw = MathHelper .ToRadians((mouse.X - centerX) * turnSpeed * секунди);
плавна стъпка = MathHelper .ToRadians((mouse.Y - centerY) * turnSpeed * секунди);
ъгъл = нов Вектор3(ъгъл.X + стъпка, ъгъл.Y + отклонение, ъгъл.Z);
Вектор3 напред = - Вектор3 .Normalize( нов Вектор3 (
( float ) Math .Sin(-angle.Y) * ( float ) Math .Cos(angle.X),
( float ) Math .Sin(angle.X),
( float ) Math .Cos(-angle.Y) * ( float ) Math .Cos(angle.X))
Вектор3 вляво = — Вектор3 .Normalize( нов Вектор3 (
( float ) Math .Cos(ъгъл.Y),
( float ) Math .Sin(angle.Y))
Състояние на KeyboardState = Keyboard.GetState();
if (state.IsKeyDown( Keys.Up))
Позиция += напред * скорост * секунди;
if (state.IsKeyDown( Keys.Down))
Позиция -= напред * скорост * секунди;
if (state.IsKeyDown( Keys.Left))
Позиция += ляво * скорост * секунди;
if (state.IsKeyDown( Keys.Right))
Позиция -= ляво * скорост * секунди;
Изглед = Матрица .CreateTranslation(-Position) *