|
Grado en Ingeniería Informática
Animación por Ordenador
Curso 2025/2026
|
Práctica 5b
|
|
Creación de una escena
|
|
Objetivos
|
|
Modificar el modelo 3D para considerar una escena formada por varios
objetos. Se añade una cámara que permite navegar por la escena y
generar la vista desde diferentes posicionies.
|
|
La clase GEGround
|
|
Para representar la escena se ha creado una nueva figura que
representa el suelo sobre el que se situarán los diferentes objetos.
Esta nueva figura, definida en la clase GEGround,
representa un rectángulo de lados 2·l1 y 2·l2.
#pragma once
#include "GEFigure.h"
class GEGround : public GEFigure
{
public:
GEGround(float l1, float l2);
};
|
El código de la clase describe simplemente dos triángulos que forman
el rectángulo.
#include "GEGround.h"
GEGround::GEGround(float l1, float l2)
{
vertices = {
{{ l1, 0.0f, l2 }},
{{ l1, 0.0f, -l2 } },
{{ -l1, 0.0f, -l2 }},
{{ -l1, 0.0f, l2 }}
};
indices = {
0, 1, 2,
0, 2, 3
};
}
|
|
|
Modificaciones de la clase GEFigure
|
|
El posicionamiento de los vértices de las figuras requieren tres
transformaciones: Model-View-Projection. La transformación
Model supone modificar la posición de los vértices desde el
sistema de referencia local, propio de cada figura, al sistema de
referencia del modelo, propio de la escena. Esto quiere decir que la
matriz de la transformación Model depende de cada figura.
Para incorporar esta característica se ha modificado la clase
GEFigure para añadir el campo location que contendrá
la matriz de la transformación Model. El método
update() recibirá ahora las matrices View
y Projection y deberá calcular el producto de las tres
matrices para asignar la variable uniforme MVP. Se han
añadido además varios métodos dedicados a modificar la matriz de la
transformación Model. El método resetLocation()
inicializa el campo location a la matriz unidad. El método
setLocation() asigna directamente el valor de esta matriz.
El método translate() añade una transformación de
traslación a la figura. El método rotate() añade una
transformación de rotación a la figura.
#pragma once
#include "GEGraphicsContext.h"
#include "GERenderingContext.h"
#include "GEVertex.h"
#include "GETransform.h"
#include "GEVertexBuffer.h"
#include "GEIndexBuffer.h"
#include "GEUniformBuffer.h"
#include "GEDescriptorSet.h"
#include <glm/glm.hpp>
#include <vector>
//
// CLASE: GEFigure
//
// DESCRIPCIÓN: Clase que describe una figura formada por una malla de vértices
//
class GEFigure
{
protected:
std::vector<GEVertex> vertices;
std::vector<uint16_t> indices;
glm::mat4 location;
public:
void initialize(GEGraphicsContext* gc, GERenderingContext* rc);
void destroy(GEGraphicsContext* gc);
void addCommands(VkCommandBuffer commandBuffer,
VkPipelineLayout pipelineLayout, int index);
void update(GEGraphicsContext* gc, uint32_t index,
glm::mat4 view, glm::mat4 projection);
void resetLocation();
void setLocation(glm::mat4 m);
void translate(glm::vec3 t);
void rotate(float angle, glm::vec3 axis);
private:
GEVertexBuffer* vbo;
GEIndexBuffer* ibo;
GEUniformBuffer* ubo;
GEDescriptorSet* dset;
};
|
El código de los métodos modificados es el siguiente:
//
// FUNCIÓN: GEFigure::initialize(GEGraphicsContext* gc, GERenderingContext* rc)
//
// PROPÓSITO: Crea la figura
//
void GEFigure::initialize(GEGraphicsContext* gc, GERenderingContext* rc)
{
size_t vertexSize = sizeof(GEVertex) * vertices.size();
vbo = new GEVertexBuffer(gc, vertexSize, vertices.data());
size_t indexSize = sizeof(indices[0]) * indices.size();
ibo = new GEIndexBuffer(gc, indexSize, indices.data());
size_t transformBufferSize = sizeof(GETransform);
ubo = new GEUniformBuffer(gc, rc->imageCount, transformBufferSize);
std::vector<GEUniformBuffer*> ubos(1);
ubos[0] = ubo;
dset = new GEDescriptorSet(gc, rc, ubos);
location = glm::mat4(1.0f);
}
//
// FUNCIÓN: GEFigure::update(...)
//
// PROPÓSITO: Actualiza las variables uniformes sobre una imagen del swapchain
//
void GEFigure::update(GEGraphicsContext* gc, uint32_t index, glm::mat4 view,
glm::mat4 projection)
{
GETransform transform;
transform.MVP = projection * view * location;
ubo->update(gc, index, sizeof(GETransform), &transform);
}
//
// FUNCIÓN: CAFigure::resetLocation()
//
// PROPÓSITO: Resetea la matriz de localización (Model).
//
void CAFigure::resetLocation()
{
location = glm::mat4(1.0f);
}
//
// FUNCIÓN: GEFigure::resetLocation()
//
// PROPÓSITO: Resetea la matriz de localización (Model).
//
void GEFigure::resetLocation()
{
location = glm::mat4(1.0f);
}
//
// FUNCIÓN: GEFigure::setLocation()
//
// PROPÓSITO: Resetea la matriz de localización (Model).
//
void GEFigure::setLocation(glm::mat4 m)
{
location = glm::mat4(m);
}
//
// FUNCIÓN: GEFigure::translate(glm::vec3 t)
//
// PROPÓSITO: Añade un desplazamiento la matriz de localización (Model).
//
void GEFigure::translate(glm::vec3 t)
{
location = glm::translate(location, t);
}
//
// FUNCIÓN: GEFigure::rotate(float angle, glm::vec3 axis)
//
// PROPÓSITO: Añade una rotación la matriz de localización (Model).
//
void GEFigure::rotate(float angle, glm::vec3 axis)
{
location = glm::rotate(location, glm::radians(angle), axis);
}
|
|
|
Descripción de la cámara
(clase GECamera)
|
|
Para poder desplazarse a través de la escena es necesario establecer
la posición y orientación del observador y realizar una
transformación del sistema de coordenadas entre el sistema de
coordenadas del modelo y el sistema de coordenadas del observador.
La posición del observador, en coordenadas del modelo, viene dada
por el vector pos. Los ejes de coordenadas del
observador, en coordenadas del modelo, vienen dados por los vectores
right, up y dir.
Para transformar las coordenadas del modelo en coordenadas del
observador el primer paso es realizar una traslación de (-pos).
De esta forma, el origen de coordenadas del modelo pasa a estar
situado en la posición (-pos) y el origen de
coordenadas del observador pasa a estar situado en la posición
(0,0,0).
Para completar la transformación del sistema de coordenadas es
necesario rotar los ejes. El resultado de esta rotación es que el
vector right debe convertirse en el vector unitario
del eje X en el sistema de coordenadas del observador, es decir, en
el vector (1,0,0); el vector up debe transformarse
en el vector unitario sobre el eje Y, es decir, en el vector
(0,1,0); y el vector dir debe convertirse en el
vector unitario sobre el eje Z, es decir, el vector (0,0,1). A
continuación se muestra el contenido de la matriz de rotación.
Esta matriz de transformación se puede generar utilizando la función
glm::lookAt(eye,center,up) incluida en la biblioteca GLM.
El primer argumento es la posición del observador. El segundo
argumento es la posición de un punto situado sobre el eje
dir. El tercer argumento de esta función es el vector
up.
Para controlar las propiedades del observador vamos a definir una
nueva clase que denominamos GECamera. Esta clase nos
permitirá almacenar la posición y orientación del observador y
moverlo libremente a través de la escena. La descripción de esta
clase se encuentra en el fichero GECamera.h.
Los miembros de la clase, descritos en su zona privada, almacenan
los valores de los vectores pos, right, up
y dir. También se incluyen los campos moveStep y
turnStep que contienen la magnitud de los desplazamientos y
giros a realizar en cada paso de la animación. Los campos
cosAngle y sinAngle almacenan el seno y coseno de
turnStep para que no sea necesario recalcularlos
constantemente. Los campos se completan con un conjunto de flags que
indican si se encuentra pulsada una tecla que activa un tipo de
movimiento de la cámara (turnLeftPressed, ...). La interfaz pública de la clase
GECamera
consta del constructor, setters y getters parta
los campos, métodos setMove..() y setTurn...() para
asignar los flags de los movimientos y giros de la cámara, métodos
move...() y turn...() para realizar los
movimientos y giros de la cámara, el método update() para
realizar los movimientos y giros en función de los flags activos y el método
getViewMatrix() que devuelve la matriz de transformación entre el
sistema de coordenadas del modelo y el sistema de coordenadas del
observador.
#pragma once
#include <glm/glm.hpp>
class GECamera {
public:
GECamera();
glm::mat4 getViewMatrix();
void setPosition(glm::vec3 pos);
void setDirection(glm::vec3 dir, glm::vec3 up);
void setMoveStep(float step);
void setTurnStep(float step);
glm::vec3 getPosition();
glm::vec3 getDirection();
glm::vec3 getUpDirection();
float getMoveStep();
float getTurnStep();
void update();
void setTurnLeft(bool flag);
void setTurnRight(bool flag);
void setTurnUp(bool flag);
void setTurnDown(bool flag);
void setTurnCW(bool flag);
void setTurnCCW(bool flag);
void setMoveLeft(bool flag);
void setMoveRight(bool flag);
void setMoveUp(bool flag);
void setMoveDown(bool flag);
private:
glm::vec3 Pos;
glm::vec3 Dir;
glm::vec3 Up;
glm::vec3 Right;
float moveStep;
float turnStep;
float cosAngle;
float sinAngle;
bool turnLeftPressed;
bool turnRightPressed;
bool turnUpPressed;
bool turnDownPressed;
bool turnCWPressed;
bool turnCCWPressed;
bool moveLeftPressed;
bool moveRightPressed;
bool moveUpPressed;
bool moveDownPressed;
void turnRight();
void turnLeft();
void turnUp();
void turnDown();
void turnCW();
void turnCCW();
void moveLeft();
void moveRight();
void moveUp();
void moveDown();
void moveFront();
void moveBack();
};
|
El desarrollo de la clase
GECamera se encuentra en el archivo
GECamera.cpp, que se muestra a continuación. El constructor de la
clase inicializa la posición y orientación del observador de manera
que coincide con el sistema de coordenadas del modelo. El método
getViewMatrix() desarrolla la transformación de los sistemas de
coordenadas. Para ello construye y apica la matriz de rotación a
partir de los valores de right, up
y dir y la traslación a partir de los valores de
pos. Los métodos get...() se limitan a
obtener los valores de los campos internos de la clase. Con respecto
a los métodos set...() es importante señalar que la
orientación se fija en un único método que solo asigna los valores
de dir y up. Se asume que estos
vectores son unitarios y perpendiculares entre sí. El vector
right se calcula como el producto vectorial entre
up y dir. Los métodos move...()
generan traslaciones de módulo moveStep sobre cada uno de
los ejes del sistema de coordenadas del observador. Esto supone
modificar el vector pos añadiendo un desplazamiento
de moveStep por el vector unitario de la traslación. Por
ejemplo, moveRight() genera un desplazamiento en la
dirección del eje X (vector right) y
moveFront() genera un desplazamiento hacia adelante (dirección
-Z, es decir, -dir). Los métodos turn...()
realizan giros de magnitud turnStep sobre cada uno de los
ejes del sistema de coordenadas. Para evitar que por problemas de
redondeo se pierda la ortogonalidad de los vectores right,
up y dir, los giros se calculan
sobre un único vector y el otro vector afectado se recalcula
mediante un producto vectorial. Los métodos turnLeft() y
turnRight() realizan giros respecto al eje Y. Los métodos
turnUp() y turnDown() realizan giros respecto al
eje X. Los métodos turnCW() y turnCCW() realizan
giros respecto al eje Z. Los métodos setMove...() y
setTurn...() asignan los flags de movimiento y se utilizarán
como respuesta a los eventos de teclado. El método update()
realiza las modificaciones en la posición y orientación de la cámara
en función de los flags activos.
#include "GECamera.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
//
// FUNCIÓN: GECamera::GECamera()
//
// PROPÓSITO: Construye una cámara
//
// COMENTARIOS:
// La posición inicial es (0,0,0).
// La orientación incial es el sistema de coordenadas del modelo
// El tamaño del paso inicial es 0.1
// El támaño del giro inicial es 1.0 grados
//
GECamera::GECamera()
{
Pos = glm::vec3(0.0f, 0.0f, 0.0f);
Dir = glm::vec3(0.0f, 0.0f, 1.0f);
Up = glm::vec3(0.0f, 1.0f, 0.0f);
Right = glm::vec3(1.0f, 0.0f, 0.0f);
moveStep = 0.1f;
turnStep = 1.0f;
cosAngle = (float)cos(glm::radians(turnStep));
sinAngle = (float)sin(glm::radians(turnStep));
turnLeftPressed = false;
turnRightPressed = false;
turnUpPressed = false;
turnDownPressed = false;
turnCWPressed = false;
turnCCWPressed = false;
moveLeftPressed = false;
moveRightPressed = false;
moveUpPressed = false;
moveDownPressed = false;
}
//
// FUNCIÓN: GECamera::getViewMatrix()
//
// PROPÓSITO: Obtiene la matriz View para situar la cámara.
//
glm::mat4 GECamera::getViewMatrix()
{
return glm::lookAt(Pos, Pos - Dir, Up);
}
//
// FUNCIÓN: GECamera::setPosition(glm::vec3 pos)
//
// PROPÓSITO: Asigna la posición de la cámara con respecto al sistema de coordenadas
// del modelo.
//
void GECamera::setPosition(glm::vec3 pos)
{
Pos = glm::vec3(pos);
}
//
// FUNCIÓN: GECamera::setDirection(glm::vec3 dir, glm::vec3 up)
//
// PROPÓSITO: Asigna la orientación de la cámara.
//
void GECamera::setDirection(glm::vec3 dir, glm::vec3 up)
{
Dir = glm::vec3(dir);
Up = glm::vec3(up);
Right = glm::cross(Up, Dir);
}
//
// FUNCIÓN: GECamera::setMoveStep(float step)
//
// PROPÓSITO: Asigna el avance en cada paso.
//
void GECamera::setMoveStep(float step)
{
moveStep = step;
}
//
// FUNCIÓN: GECamera::setTurnStep(float step)
//
// PROPÓSITO: Asigna el ángulo de giro en cada paso.
//
void GECamera::setTurnStep(float step)
{
turnStep = step;
cosAngle = (float)cos(glm::radians(turnStep));
sinAngle = (float)sin(glm::radians(turnStep));
}
//
// FUNCIÓN: GECamera::getPosition()
//
// PROPÓSITO: Obtiene la posición de la cámara.
//
glm::vec3 GECamera::getPosition()
{
return Pos;
}
//
// FUNCIÓN: GECamera::getDirection()
//
// PROPÓSITO: Obtiene la orientación de la cámara (eje Z).
//
glm::vec3 GECamera::getDirection()
{
return Dir;
}
//
// FUNCIÓN: GECamera::getUpDirection()
//
// PROPÓSITO: Obtiene la orientación cenital de la cámara (eje Y).
//
glm::vec3 GECamera::getUpDirection()
{
return Up;
}
//
// FUNCIÓN: GECamera::getMoveStep()
//
// PROPÓSITO: Obtiene el avance en cada paso.
//
float GECamera::getMoveStep()
{
return moveStep;
}
//
// FUNCIÓN: GECamera::getTurnStep()
//
// PROPÓSITO: Obtiene el ángulo de giro en cada paso.
//
float GECamera::getTurnStep()
{
return turnStep;
}
//
// FUNCIÓN: GECamera::update()
//
// PROPÓSITO: Actualiza la posición y orientación de la cámara
//
void GECamera::update()
{
if (turnLeftPressed && !turnRightPressed) turnLeft();
if (!turnLeftPressed && turnRightPressed) turnRight();
if (turnUpPressed && !turnDownPressed) turnUp();
if (!turnUpPressed && turnDownPressed) turnDown();
if (turnCWPressed && !turnCCWPressed) turnCW();
if (!turnCWPressed && turnCCWPressed) turnCCW();
if (moveLeftPressed && !moveRightPressed) moveLeft();
if (!moveLeftPressed && moveRightPressed) moveRight();
if (moveUpPressed && !moveDownPressed) moveUp();
if (!moveUpPressed && moveDownPressed) moveDown();
moveFront();
}
//
// FUNCIÓN: GECamera::moveFront()
//
// PROPÓSITO: Mueve el observador un paso (moveStep) en la dirección -Dir
//
void GECamera::moveFront()
{
Pos -= moveStep * Dir;
}
//
// FUNCIÓN: GECamera::moveBack()
//
// PROPÓSITO: Mueve el observador un paso (moveStep) hacia atrás en la dirección Dir
//
void GECamera::moveBack()
{
Pos += moveStep * Dir;
}
//
// FUNCIÓN: GECamera::moveLeft()
//
// PROPÓSITO: Mueve el observador un paso (moveStep) hacia la izquierda.
//
void GECamera::moveLeft()
{
Pos -= 0.1f * Right;
}
//
// FUNCIÓN: GECamera::moveRight()
//
// PROPÓSITO: Mueve el observador un paso (moveStep) hacia la derecha.
//
void GECamera::moveRight()
{
Pos += 0.1f * Right;
}
//
// FUNCIÓN: GECamera::moveUp()
//
// PROPÓSITO: Mueve el observador un paso (moveStep) hacia arriba.
//
void GECamera::moveUp()
{
Pos += 0.1f * Up;
}
//
// FUNCIÓN: GECamera::moveDown()
//
// PROPÓSITO: Mueve el observador un paso (moveStep) hacia abajo.
//
void GECamera::moveDown()
{
Pos -= 0.1f * Up;
}
//
// FUNCIÓN: GECamera::turnRight()
//
// PROPÓSITO: Rota el observador un paso (angleStep) hacia su derecha.
//
void GECamera::turnRight()
{
Dir.x = cosAngle * Dir.x - sinAngle * Right.x;
Dir.y = cosAngle * Dir.y - sinAngle * Right.y;
Dir.z = cosAngle * Dir.z - sinAngle * Right.z;
// Right = Up x Dir
Right = glm::cross(Up, Dir);
}
//
// FUNCIÓN: CACamera::turnLeft()
//
// PROPÓSITO: Rota el observador un paso (angleStep) hacia su izquierda.
//
void GECamera::turnLeft()
{
Dir.x = cosAngle * Dir.x + sinAngle * Right.x;
Dir.y = cosAngle * Dir.y + sinAngle * Right.y;
Dir.z = cosAngle * Dir.z + sinAngle * Right.z;
// Right = Up x Dir
Right = glm::cross(Up, Dir);
}
//
// FUNCIÓN: GECamera::turnUp()
//
// PROPÓSITO: Rota el observador un paso (angleStep) hacia arriba.
//
void GECamera::turnUp()
{
Dir.x = cosAngle * Dir.x - sinAngle * Up.x;
Dir.y = cosAngle * Dir.y - sinAngle * Up.y;
Dir.z = cosAngle * Dir.z - sinAngle * Up.z;
// Up = Dir x Right
Up = glm::cross(Dir, Right);
}
//
// FUNCIÓN: GECamera::turnDown()
//
// PROPÓSITO: Rota el observador un paso (angleStep) hacia abajo.
//
void GECamera::turnDown()
{
Dir.x = cosAngle * Dir.x + sinAngle * Up.x;
Dir.y = cosAngle * Dir.y + sinAngle * Up.y;
Dir.z = cosAngle * Dir.z + sinAngle * Up.z;
// Up = Dir x Right
Up = glm::cross(Dir, Right);
}
//
// FUNCIÓN: GECamera::turnCW()
//
// PROPÓSITO: Rota el observador un paso (angleStep) en sentido del reloj.
//
void GECamera::turnCW()
{
Up.x = cosAngle * Up.x + sinAngle * Right.x;
Up.y = cosAngle * Up.y + sinAngle * Right.y;
Up.z = cosAngle * Up.z + sinAngle * Right.z;
// Right = Up x Dir
Right = glm::cross(Up, Dir);
}
//
// FUNCIÓN: GECamera::turnCCW()
//
// PROPÓSITO: Rota el observador un paso (angleStep) en sentido contrario al reloj.
//
void GECamera::turnCCW()
{
Up.x = cosAngle * Up.x - sinAngle * Right.x;
Up.y = cosAngle * Up.y - sinAngle * Right.y;
Up.z = cosAngle * Up.z - sinAngle * Right.z;
// Right = Up x Dir
Right = glm::cross(Up, Dir);
}
//
// FUNCIÓN: GECamera::setTurnLeft(bool flag)
//
// PROPÓSITO: Activa o desactiva el giro a la izquierda
//
void GECamera::setTurnLeft(bool flag)
{
turnLeftPressed = flag;
}
//
// FUNCIÓN: GECamera::setTurnRight(bool flag)
//
// PROPÓSITO: Activa o desactiva el giro a la derecha
//
void GECamera::setTurnRight(bool flag)
{
turnRightPressed = flag;
}
//
// FUNCIÓN: GECamera::setTurnUp(bool flag)
//
// PROPÓSITO: Activa o desactiva el giro hacia arriba
//
void GECamera::setTurnUp(bool flag)
{
turnUpPressed = flag;
}
//
// FUNCIÓN: GECamera::setTurnDown(bool flag)
//
// PROPÓSITO: Activa o desactiva el giro hacia abajo
//
void GECamera::setTurnDown(bool flag)
{
turnDownPressed = flag;
}
//
// FUNCIÓN: GECamera::setTurnCW(bool flag)
//
// PROPÓSITO: Activa o desactiva el giro horario
//
void GECamera::setTurnCW(bool flag)
{
turnCWPressed = flag;
}
//
// FUNCIÓN: GECamera::setTurnCCW(bool flag)
//
// PROPÓSITO: Activa o desactiva el giro antihorario
//
void GECamera::setTurnCCW(bool flag)
{
turnCCWPressed = flag;
}
//
// FUNCIÓN: GECamera::setMoveLeft(bool flag)
//
// PROPÓSITO: Activa o desactiva el desplazamiento a la izquierda
//
void GECamera::setMoveLeft(bool flag)
{
moveLeftPressed = flag;
}
//
// FUNCIÓN: GECamera::setMoveRight(bool flag)
//
// PROPÓSITO: Activa o desactiva el desplazamiento a la derecha
//
void GECamera::setMoveRight(bool flag)
{
moveRightPressed = flag;
}
//
// FUNCIÓN: GECamera::setMoveUp(bool flag)
//
// PROPÓSITO: Activa o desactiva el desplazamiento hacia arriba
//
void GECamera::setMoveUp(bool flag)
{
moveUpPressed = flag;
}
//
// FUNCIÓN: GECamera::setMoveDown(bool flag)
//
// PROPÓSITO: Activa o desactiva el desplazamiento hacia abajo
//
void GECamera::setMoveDown(bool flag)
{
moveDownPressed = flag;
}
|
|
|
Modificaciones de la clase GEScene
|
|
La clase GEScene se va a modificar para
contener la cámara y el conjunto de figuras. En este caso no se va a
mutar entre las figuras sino que se va a modelar una escena formada por 7
figuras: el suelo, un cubo, un cono, un toro, un cilindro, un
icosahedro y una esfera. La cámara permitirá desplazarse por el
espacio, generando la imagen desde diferentes posiciones y
orientaciones.
El constructor de la clase es el encargado
de crear las figuras y posicionarlas. Los métodos
destroyBuffers(), addCommands() y update() se limitan a llamar a los
métodos correspondientes de todas las figuras que forman la escena.
#pragma once
#include "GEGraphicsContext.h"
#include "GEDrawingContext.h"
#include "GECommandContext.h"
#include "GERenderingContext.h"
#include "GEFigure.h"
#include "GECamera.h"
#include <vulkan/vulkan.h>
#include <glm/glm.hpp>
#include <vector>
//
// CLASE: GEScene
//
// DESCRIPCIÓN: Clase que describe una escena
//
class GEScene
{
private:
GERenderingContext* rc;
std::vector<GEFigure*> figures;
GECamera* camera;
glm::mat4 projection;
public:
GEScene(GEGraphicsContext* gc, GEDrawingContext* dc, GECommandContext* cc);
void destroy(GEGraphicsContext* gc);
void recreate(GEGraphicsContext* gc, GEDrawingContext* dc, GECommandContext* cc);
void update(GEGraphicsContext* gc, uint32_t index);
void key_action(int key, bool pressed);
void aspect_ratio(double aspect);
private:
void fillCommandBuffers(std::vector<VkCommandBuffer> commandBuffers);
GEPipelineConfig* createPipelineConfig(VkExtent2D extent);
};
|
A continuación se muestra el código de la clase.
#include "GEScene.h"
#include "GECube.h"
#include "GEPyramid.h"
#include "GECone.h"
#include "GECylinder.h"
#include "GESphere.h"
#include "GEDisk.h"
#include "GETorus.h"
#include "GEIcosahedron.h"
#include "GEGround.h"
#include "GETransform.h"
#include <windows.h>
#include "resource.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
//
// FUNCIÓN: GEScene::GEScene(GEGraphicsContext* gc, GEDrawingContext* dc)
//
// PROPÓSITO: Crea la escena
//
GEScene::GEScene(GEGraphicsContext* gc, GEDrawingContext* dc, GECommandContext* cc)
{
VkExtent2D extent = dc->getExtent();
double aspect = (double)extent.width / (double)extent.height;
aspect_ratio(aspect);
GEPipelineConfig* config = createPipelineConfig(dc->getExtent());
rc = new GERenderingContext(gc, dc, config);
this->camera = new GECamera();
this->camera->setPosition(glm::vec3(0.0f, 10.0f, 300.0f));
this->camera->setMoveStep(0.0f);
GEFigure* ground = new GEGround(50.0f, 50.0f);
ground->initialize(gc, rc);
GEFigure* fig1 = new GECone(5, 20, 5.0f, 5.0f);
fig1->initialize(gc, rc);
fig1->translate(glm::vec3(25.0f, 5.0f, 25.0f));
fig1->rotate(-90.0f, glm::vec3(1.0f, 0.0f, 0.0f));
GEFigure* fig2 = new GECube(5.0f);
fig2->initialize(gc, rc);
fig2->translate(glm::vec3(-25.0f, 5.0f, 25.0f));
fig2->rotate(-90.0f, glm::vec3(1.0f, 0.0f, 0.0f));
GEFigure* fig3 = new GECylinder(20, 20, 5.0f, 5.0f);
fig3->initialize(gc, rc);
fig3->translate(glm::vec3(25.0f, 5.0f, 0.0f));
fig3->rotate(90.0f, glm::vec3(1.0f, 0.0f, 0.0f));
GEFigure* fig4 = new GETorus(20, 40, 3.0f, 5.0f);
fig4->initialize(gc, rc);
fig4->translate(glm::vec3(-25.0f, 8.0f, 0.0f));
GEFigure* fig5 = new GESphere(20, 40, 8.0f);
fig5->initialize(gc, rc);
fig5->translate(glm::vec3(25.0f, 8.0f, -25.0f));
GEFigure* fig6 = new GEIcosahedron(5.0f);
fig6->initialize(gc, rc);
fig6->translate(glm::vec3(-25.0f, 8.0f, -25.0f));
figures.resize(7);
figures[0] = ground;
figures[1] = fig1;
figures[2] = fig2;
figures[3] = fig3;
figures[4] = fig4;
figures[5] = fig5;
figures[6] = fig6;
fillCommandBuffers(cc->commandBuffers);
}
//
// FUNCIÓN: GEScene::destroy(GEGraphicsContext* gc)
//
// PROPÓSITO: Reconstruye los componentes gráficos de la escena
//
void GEScene::destroy(GEGraphicsContext* gc)
{
rc->destroy(gc);
delete rc;
for (int i = 0; i < figures.size(); i++)
{
figures[i]->destroy(gc);
delete figures[i];
}
}
//
// FUNCIÓN: GEScene::recreate(GEGraphicsContext* gc, GEDrawingContext* dc)
//
// PROPÓSITO: Reconstruye los componentes gráficos de la escena
//
void GEScene::recreate(GEGraphicsContext* gc, GEDrawingContext* dc, GECommandContext* cc)
{
rc->destroy(gc);
GEPipelineConfig* config = createPipelineConfig(dc->getExtent());
this->rc = new GERenderingContext(gc, dc, config);
fillCommandBuffers(cc->commandBuffers);
}
//
// FUNCIÓN: GEScene::update(GEGraphicsContext* gc, uint32_t index)
//
// PROPÓSITO: Actualiza la información para generar la imagen
//
void GEScene::update(GEGraphicsContext* gc, uint32_t index)
{
camera->update();
glm::mat4 view = camera->getViewMatrix();
for (int i = 0; i < figures.size(); i++)
{
figures[i]->update(gc, index, view, projection);
}
}
//
// FUNCIÓN: GEScene::key_action(int key, bool pressed)
//
// PROPÓSITO: Respuesta a acciones de teclado
//
void GEScene::key_action(int key, bool pressed)
{
switch (key)
{
case GLFW_KEY_UP:
camera->setTurnDown(pressed);
break;
case GLFW_KEY_DOWN:
camera->setTurnUp(pressed);
break;
case GLFW_KEY_LEFT:
camera->setTurnCCW(pressed);
break;
case GLFW_KEY_RIGHT:
camera->setTurnCW(pressed);
break;
case GLFW_KEY_S:
camera->setMoveStep(0.0f);
break;
case GLFW_KEY_KP_ADD:
case GLFW_KEY_1:
camera->setMoveStep(camera->getMoveStep() + 0.1f);
break;
case GLFW_KEY_KP_SUBTRACT:
case GLFW_KEY_2:
camera->setMoveStep(camera->getMoveStep() - 0.1f);
break;
case GLFW_KEY_Q:
camera->setMoveUp(pressed);
break;
case GLFW_KEY_A:
camera->setMoveDown(pressed);
break;
case GLFW_KEY_O:
camera->setMoveLeft(pressed);
break;
case GLFW_KEY_P:
camera->setMoveRight(pressed);
break;
case GLFW_KEY_K:
camera->setTurnLeft(pressed);
break;
case GLFW_KEY_L:
camera->setTurnRight(pressed);
break;
}
}
//
// FUNCIÓN: GEScene::aspect_ratio(double)
//
// PROPÓSITO: Modifica la relación anchura/altura del modelo
//
void GEScene::aspect_ratio(double aspect)
{
constexpr double fov = glm::radians(30.0f);
double sin_fov = sin(fov);
double cos_fov = cos(fov);
float wHeight = (float)(sin_fov * 0.2 / cos_fov);
float wWidth = (float)(wHeight * aspect);
projection = glm::perspective((float)fov, (float)aspect, 0.2f, 400.0f);
projection[1][1] *= -1.0f;
}
//
// FUNCIÓN: CAScene::fillCommandBuffers(std::vector<VkCommandBuffer> commandBuffers)
//
// PROPÓSITO: Añade los comandos de renderizado al command buffer
//
void GEScene::fillCommandBuffers(std::vector<VkCommandBuffer> commandBuffers)
{
rc->startFillingCommandBuffers(commandBuffers);
for (int i = 0; i < commandBuffers.size(); i++)
{
for (int j = 0; j < figures.size(); j++)
{
figures[j]->addCommands(commandBuffers[i], rc->pipelineLayout, i);
}
}
rc->endFillingCommandBuffers(commandBuffers);
}
//
// FUNCIÓN: GEScene::createPipelineConfig()
//
// PROPÓSITO: Obtiene la configuración del pipeline de renderizado
//
GEPipelineConfig* GEScene::createPipelineConfig(VkExtent2D extent)
{
GEPipelineConfig* config = new GEPipelineConfig();
config->vertex_shader = IDR_HTML1;
config->fragment_shader = IDR_HTML2;
config->attrStride = sizeof(GEVertex);
config->attrOffsets.resize(1);
config->attrOffsets[0] = offsetof(GEVertex, pos);
config->attrFormats.resize(1);
config->attrFormats[0] = VK_FORMAT_R32G32B32_SFLOAT;
config->descriptorTypes.resize(1);
config->descriptorTypes[0] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
config->descriptorStages.resize(1);
config->descriptorStages[1] = VK_SHADER_STAGE_VERTEX_BIT;
config->depthTestEnable = VK_TRUE;
config->cullMode = VK_CULL_MODE_BACK_BIT;
config->extent = extent;
return config;
}
|
|
|
Aspecto final
|
|
El aspecto final de la aplicación muestra la escena y permite navegar por medio del teclado.
|
|