|
Grado en Ingeniería Informática
Realidad Virtual
Curso 2023/2024
|
Práctica 5
|
|
Color e
iluminación
|
|
Objetivos
|
|
En esta práctica se presenta un modelo de iluminación que permite
añadirle color a los objetos situados en la escena. El modelo
planteado se conoce como modelo de Phong o modelo ADS, ya que
calcula el color de cada punto como la suma de tres componentes:
ambiental, difusa y especular. El resultado final es similar al
presentado en la práctica anterior, pero dotando de color a los
cuerpos representados.

|
|
El modelo de iluminación de Phong
|
|
OpenGL utiliza el formato RGBA para representar el color. Esto permite describir un color por medio de un vector de 4 componentes.
Generalmente cada componente se representa por medio de un valor float normalizado. De esta forma, el color negro se
representa mediante el vector (0.0, 0.0, 0.0, 1.0) y el color blanco mediante el vector (1.0, 1.0, 1.0, 1.0). En las prácticas
anteriores el FragmentShader se limitaba a asignar el color rojo a todos los píxeles del fragmento. Para generar figuras
de colores diferentes una opción sencilla es introducir el color del objeto por medio de una variable uniforme. El problema
es que esto dibuja las figuras con un color plano, lo que resulta muy poco realista. Para generar un coloreado natural es
necesario estudiar la forma en la que la luz ilumina a las diferentes figuras. Es decir, es necesario plantear un modelo de
iluminación.
El modelo de iluminación de Phong fue propuesto por Bui Tuong Phong en su tesis doctoral, presentada en 1973 en la Universidad de Utah.
Este modelo constituye una mejora del modelo de Gouraud, que fue propuesto en 1971. Estos modelos se basan en calcular el color con
el que se ve un objeto como el resultado de la interacción de la luz (de un cierto color) con el material que forma el objeto (descrito
también por un color). Si los colores se expresan en coordenadas normalizadas, el resultado de iluminar un cuerpo de un color M
con una luz de un color L es
Color = M · L = (Mr, Mg, Mb, Ma) · (Lr, Lg, Lb, La)
= (Mr·Lr, Mg·Lg, Mb·Lb, Ma·La)
Esta ecuación permite modificar el color con el que se ve un objeto al modificar el color de la luz. Sin embargo sigue generando el
mismo color para todos los puntos del objeto (es decir, un color plano) lo que resulta antinatural. Para conseguir un coloreado
más natural se considera que el color final es la combinación de tres efectos: luz ambiental, luz difusa y luz especular.
La luz ambiental se considera como una luz que proviene de todas las direcciones y tras incidir en un punto se dispersa en todas las
direcciones. Este es el tipo de luz que ilumina la zona de sombra de un objeto (la zona de sombra nunca es totalmente negra) y su
fórmula corresponde a la descrita anteriormente.
La luz difusa se considera como una luz que proviene de una dirección concreta y tras incidir en un punto se dispersa en todas las
direcciones. El efecto de esta luz tiene en cuenta la dirección de incidencia, de manera que si incide verticalmente sobre el objeto
la iluminación es más intensa mientras que si incide de forma inclinada la intensidad es menor. El factor de incidencia se calcula
como el coseno del ángulo que forma la dirección de la luz (Ldir) con el vector normal a la superficie (N).
Si ambos vectores son unitarios el coseno corresponde al producto
escalar. El
efecto se calcula como:
Color = M · L · Intensidad = (M·L) * (Ldir·N)
La luz especular se considera como una luz que proviene de una dirección concreta y tras incidir en un punto se refleja, dispersándose
principalmente en la dirección reflejada. El efecto de esta luz tiene en cuenta la dirección de incidencia y la normal (para calcular
la dirección reflejada) y la posición del observador. Si la dirección reflejada coincide con la dirección en la que se encuentra el
observador la intensidad de este efecto será máxima mientras que si la dirección reflejada se separa de la dirección del observador
la intensidad disminuye. El factor de intensidad especular se calcula como el coseno del ángulo entre la dirección reflejada
(Reflect) y la
dirección del observador (Pos), elevado a un cierto coeficiente de brillo (Shininess).
Color = M · L · Intensidad = (M·L) * (Reflect·Pos)^Shininess
Reflect = 2· (Ldir·N) · N - Ldir
El color final en el que se dibuja cada punto es la suma de los tres efectos.
Color = Color_ambiental + Color_difuso + Color_especular
|
|
El programa gráfico
|
|
Para desarrollar el modelo de ilumniación de Phong es necesario calcular para cada píxel el valor de la normal a la superficie
y la posición del punto asociado a ese pixel. Estos vectores deben describirse en coordenadas del observador. Para obtener estos
vectores en cada pixel, el VertexShader debe generarlos como salidas asociadas a cada vértice de forma que el proceso de interpolación
genere los valores correspondientes a cada punto del fragmento. Por tanto, los atributos asociados a cada vértice deben ser su posición
y su normal. La salida gl_Position contiene la posición en coordenadas homogeneas (multiplicando por la matriz MVP como
vimos en la práctica anterior). Las salidas Position y Normal contienen los vectores de posición y normal en coordenadas
del observador (multiplicando en este caso por la matriz model-view).
#version 400
layout(location = 0) in vec3 VertexPosition;
layout(location = 1) in vec3 VertexNormal;
uniform mat4 MVP;
uniform mat4 ViewMatrix;
uniform mat4 ModelViewMatrix;
out vec3 Position;
out vec3 Normal;
void main()
{
vec4 n4 = ModelViewMatrix*vec4(VertexNormal, 0.0);
vec4 v4 = ModelViewMatrix*vec4(VertexPosition, 1.0);
Normal = vec3(n4);
Position = vec3(v4);
gl_Position = MVP * vec4(VertexPosition, 1.0);
}
|
El
FragmentShader debe desarrollar los calculos del modelo de
iluminación de Phong a partir de la interpolación de la posición y
la normal (en coordenadas del observador) y de las propiedades de la
luz y del material. Las propiedades de la luz se introducen por
medio de una variable uniforme (Light) que responde a una
estructura con cuatro campos (Ldir es la dirección de la
luz, La el color de la luz ambiental, Ld es el
color de la luz difusa y Ls es el color de la luz
especular). Las propiedades del material se introducen por medio de
una variable uniforme (Material) que responde a una
estructura con cuatro campos (Ka es el color del material
frente a la luz ambiental, Kd es el color frente a la luz
difusa, Ks es el color frente a la luz especular y
Shininess es el coeficiente de brillo). La función auxiliar
ads() desarrolla el modelo de Phong calculando los tres
efectos: ambiental, difusa y especular.
#version 400
in vec3 Position;
in vec3 Normal;
uniform mat4 ViewMatrix;
struct LightInfo
{
vec3 Ldir;
vec3 La;
vec3 Ld;
vec3 Ls;
};
uniform LightInfo Light;
struct MaterialInfo
{
vec3 Ka;
vec3 Kd;
vec3 Ks;
float Shininess;
};
uniform MaterialInfo Material;
out vec4 FragColor;
vec3 ads()
{
vec4 s4 = ViewMatrix*vec4(Light.Ldir, 0.0);
vec3 n = normalize(Normal);
vec3 v = normalize(-Position);
vec3 s = normalize(-vec3(s4));
vec3 r = reflect(-s, n);
float dRate = max(dot(s, n), 0.0);
float sRate = pow(max(dot(r, v), 0.0), Material.Shininess);
vec3 ambient = Light.La * Material.Ka;
vec3 difusse = Light.Ld * Material.Kd * dRate;
vec3 specular = Light.Ls * Material.Ks * sRate;
return ambient + difusse + specular;
}
void main()
{
vec3 Color = ads();
FragColor = vec4(Color,1.0);
}
|
|
|
La clase CGLight
|
|
Para describir las propiedades de la luz se va a crear una nueva
clase denominada CGLight.
La clase cuenta con los campos utilizados en el modelo de Phong. El
campo Ldir almacena la dirección de la luz en coordenadas
del modelo. Los campos La, Ld y Ls
contienen el color de las componentes ambiental, difusa y especular.
#pragma once
#include <glm/glm.hpp>
#include "CGShaderProgram.h"
class CGLight {
private:
glm::vec3 Ldir; // Light direction
glm::vec3 La; // Ambient intensity
glm::vec3 Ld; // Difusse intensity
glm::vec3 Ls; // Specular intensity
public:
CGLight();
void SetLightDirection(glm::vec3 d);
void SetAmbientLight(glm::vec3 a);
void SetDifusseLight(glm::vec3 d);
void SetSpecularLight(glm::vec3 s);
void SetUniforms(CGShaderProgram* program);
};
|
La clase consta de métodos Set..() para asignar el valor de
cada propiedad y del método SetUniforms() que asigna los
valores a la variable uniforme utilizada en el programa gráfico.
#include "CGLight.h"
#include <glm/glm.hpp>
//
// FUNCIÓN: CGLight::CGLight()
//
// PROPÓSITO: Construye una luz con los valores por defecto
//
CGLight::CGLight()
{
Ldir = glm::vec3(0.0f, 0.0f, -1.0f);
La = glm::vec3(1.0f, 1.0f, 1.0f);
Ld = glm::vec3(1.0f, 1.0f, 1.0f);
Ls = glm::vec3(0.0f, 0.0f, 0.0f);
}
//
// FUNCIÓN: CGLight::SetLightDirection(glm::vec3 d)
//
// PROPÓSITO: Asigna la dirección de la luz (expresada en coordenadas de modelo)
//
void CGLight::SetLightDirection(glm::vec3 d)
{
Ldir = d;
}
//
// FUNCIÓN: CGLight::SetAmbientLight(glm::vec3 a)
//
// PROPÓSITO: Asigna el color de la componente ambiental
//
void CGLight::SetAmbientLight(glm::vec3 a)
{
La = a;
}
//
// FUNCIÓN: CGLight::SetDifusseLight(glm::vec3 d)
//
// PROPÓSITO: Asigna el color de la componente difusa
//
void CGLight::SetDifusseLight(glm::vec3 d)
{
Ld = d;
}
//
// FUNCIÓN: CGLight::SetSpecularLight(glm::vec3 s)
//
// PROPÓSITO: Asigna el color de la componente especular
//
void CGLight::SetSpecularLight(glm::vec3 s)
{
Ls = s;
}
//
// FUNCIÓN: CGLight::SetUniforms(ShaderProgram* program)
//
// PROPÓSITO: Configura la luz en el programa gráfico
//
void CGLight::SetUniforms(CGShaderProgram* program)
{
program->SetUniformVec3("Light.Ldir", Ldir);
program->SetUniformVec3("Light.La", La);
program->SetUniformVec3("Light.Ld", Ld);
program->SetUniformVec3("Light.Ls", Ls);
}
|
|
|
La clase CGMaterial
|
|
Para describir las propiedades de los materiales se va a crear una nueva
clase denominada CGMaterial.
que almacena las propiedades utilizadas en el modelo de Phong. Los campos
Ka, Kd y Ks
contienen el color del material ante las fuentes de luz ambiental, difusa y especular,
lo que se conoce como reflectividad. El campo Shininess
contiene el factor de brillo, es decir, el exponente utilizado en el
cálculo de la componente especular.
#pragma once
#include <glm/glm.hpp>
#include "CGShaderProgram.h"
class CGMaterial {
private:
glm::vec3 Ka; // Reflectividad ambiental (color ante la luz ambiental)
glm::vec3 Kd; // Reflectividad difusa (color ante la luz difusa)
glm::vec3 Ks; // Reflectividad especular (color ante la luz especular)
GLfloat Shininess; // Factor de brillo (comportamiento ante la luz especular)
public:
CGMaterial();
void SetAmbientReflect(GLfloat r, GLfloat g, GLfloat b);
void SetDifusseReflect(GLfloat r, GLfloat g, GLfloat b);
void SetSpecularReflect(GLfloat r, GLfloat g, GLfloat b);
void SetShininess(GLfloat f);
void SetUniforms(CGShaderProgram* program);
};
|
Al igual que la clase CGLight, la clase
CGMaterial consta de métodos Set..() para asignar el valor de
cada propiedad y del método SetUniforms() que asigna los
valores a la variable uniforme utilizada en el programa gráfico.
#include "CGMaterial.h"
#include <GL/glew.h>
//
// FUNCIÓN: CGMaterial::CGMaterial()
//
// PROPÓSITO: Construye un material con los valores por defecto
//
CGMaterial::CGMaterial()
{
Ka = glm::vec3(1.0f, 1.0f, 1.0f);
Kd = glm::vec3(1.0f, 1.0f, 1.0f);
Ks = glm::vec3(0.8f, 0.8f, 0.8f);
Shininess = 16.0f;
}
//
// FUNCIÓN: CGMaterial::SetAmbientReflect(GLfloat r, GLfloat g, GLfloat b)
//
// PROPÓSITO: Asigna la reflectividad ambiental (color ante la luz ambiental)
//
void CGMaterial::SetAmbientReflect(GLfloat r, GLfloat g, GLfloat b)
{
Ka = glm::vec3(r, g, b);
}
//
// FUNCIÓN: CGMaterial::SetDifusseReflect(GLfloat r, GLfloat g, GLfloat b)
//
// PROPÓSITO: Asigna la reflectividad difusa (color ante la luz difusa)
//
void CGMaterial::SetDifusseReflect(GLfloat r, GLfloat g, GLfloat b)
{
Kd = glm::vec3(r, g, b);
}
//
// FUNCIÓN: CGMaterial::SetSpecularReflect(GLfloat r, GLfloat g, GLfloat b)
//
// PROPÓSITO: Asigna la reflectividad especular (color ante la luz especular)
//
void CGMaterial::SetSpecularReflect(GLfloat r, GLfloat g, GLfloat b)
{
Ks = glm::vec3(r, g, b);
}
//
// FUNCIÓN: CGMaterial::SetShininess(GLfloat f)
//
// PROPÓSITO: Asigna el factor de brillo (comportamiento ante la luz especular)
//
void CGMaterial::SetShininess(GLfloat f)
{
Shininess = f;
}
//
// FUNCIÓN: CGMaterial::SetUniforms(CGShaderProgram* program)
//
// PROPÓSITO: Configura las propiedades de material en el programa gráfico
//
void CGMaterial::SetUniforms(CGShaderProgram* program)
{
program->SetUniformVec3("Material.Ka", Ka);
program->SetUniformVec3("Material.Kd", Kd);
program->SetUniformVec3("Material.Ks", Ks);
program->SetUniformF("Material.Shininess", Shininess);
}
|
|
|
La clase CGFigure
|
|
Para considerar los efectos de iluminación es necesario añadir a las figuras la información respecto a las propiedades del material.
Tambien es necesario que las figuras almacenen el valor del vector normal (perpendicular) a la
superficie en cada vértice, además de la posición de cada vértice. Esto supone realizar cambios sobre la clase
CGFigure.
#pragma once
#include <GL/glew.h>
#include <glm/glm.hpp>
#include "CGMaterial.h"
#include "CGShaderProgram.h"
#define VERTEX_DATA 0
#define INDEX_DATA 1
#define NORMAL_DATA 2
//
// CLASE: CGFigure
//
// DESCRIPCIÓN: Clase abstracta que representa un objeto descrito mediante
// VAO para su renderizado mediante shaders
//
class CGFigure {
protected:
GLushort* indexes; // Array of indexes
GLfloat* vertices; // Array of vertices
GLfloat* normals; // Array of normals
GLuint numFaces; // Number of faces
GLuint numVertices; // Number of vertices
GLuint VBO[3];
GLuint VAO;
glm::mat4 location; // Model matrix
CGMaterial* material;
public:
~CGFigure();
void InitBuffers();
void SetMaterial(CGMaterial* mat);
void ResetLocation();
void Translate(glm::vec3 t);
void Rotate(GLfloat angle, glm::vec3 axis);
void Draw(CGShaderProgram* program, glm::mat4 projection, glm::mat4 view);
};
|
Los cambios en la clase CGFigure consisten en considerar un segundo atributo en el VAO
así como las propiedades de material. Esto requiere
modificar un poco el método InitBuffers() para incorporar el segundo atributo
asociado a los vectores normales. Para tratar la información
respecto al material se añade el método
SetMaterial() y
se modifica el método Draw() para asignar los valores a la variable uniforme correspondiente. También
hay que tener en cuenta que el programa gráfico necesita ahora no solo la matriz MVP sino tambien las
matrices ModelViewMatrix y ViewMatrix como variables uniformes.
#include "CGFigure.h"
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
//
// FUNCIÓN: CGFigure::~CGFigure()
//
// PROPÓSITO: Destructor de la figura
//
CGFigure::~CGFigure()
{
if (vertices != NULL) delete[] vertices;
if (indexes != NULL) delete[] indexes;
if (normals != NULL) delete[] normals;
// Delete vertex buffer objects
glDeleteBuffers(3, VBO);
glDeleteVertexArrays(1, &VAO);
}
//
// FUNCIÓN: CGFigure::InitBuffers()
//
// PROPÓSITO: Crea el VAO y los VBO y almacena todos los datos
// en la GPU.
//
void CGFigure::InitBuffers()
{
// Create the Vertex Array Object
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
// Create the Vertex Buffer Objects
glGenBuffers(3, VBO);
// Copy data to video memory
// Vertex data
int buffsize = sizeof(GLfloat) * numVertices * 3;
glBindBuffer(GL_ARRAY_BUFFER, VBO[VERTEX_DATA]);
glBufferData(GL_ARRAY_BUFFER, buffsize, vertices, GL_STATIC_DRAW);
// Normal data
glBindBuffer(GL_ARRAY_BUFFER, VBO[NORMAL_DATA]);
glBufferData(GL_ARRAY_BUFFER, buffsize, normals, GL_STATIC_DRAW);
// Indexes
buffsize = sizeof(GLushort) * numFaces * 3;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBO[INDEX_DATA]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffsize, indexes, GL_STATIC_DRAW);
delete[] vertices;
delete[] indexes;
delete[] normals;
vertices = NULL;
indexes = NULL;
normals = NULL;
glEnableVertexAttribArray(0); // Vertex position
glBindBuffer(GL_ARRAY_BUFFER, VBO[VERTEX_DATA]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1); // Vertex normals
glBindBuffer(GL_ARRAY_BUFFER, VBO[NORMAL_DATA]);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
}
//
// FUNCIÓN: CGFigure::SetMaterial(CGMaterial* m)
//
// PROPÓSITO: Asigna el material de la figura
//
void CGFigure::SetMaterial(CGMaterial* mat)
{
material = mat;
}
//
// FUNCIÓN: CGFigure::ResetLocation()
//
// PROPÓSITO: Asigna la posición inicial de la figura
//
void CGFigure::ResetLocation()
{
location = glm::mat4(1.0f);
}
//
// FUNCIÓN: CGFigure::Translate(glm::vec3 t)
//
// PROPÓSITO: Añade un desplazamiento a la matriz de posición de la figura
//
void CGFigure::Translate(glm::vec3 t)
{
location = glm::translate(location, t);
}
//
// FUNCIÓN: CGFigure::Rotate(GLfloat angle, glm::vec3 axis)
//
// PROPÓSITO: Añade una rotación a la matriz de posición de la figura
//
void CGFigure::Rotate(GLfloat angle, glm::vec3 axis)
{
location = glm::rotate(location, glm::radians(angle), axis);
}
//
// FUNCIÓN: CGFigure::Draw(CGShaderProgram * program, glm::mat4 proj, glm::mat4 view)
//
// PROPÓSITO: Dibuja la figura
//
void CGFigure::Draw(CGShaderProgram* program, glm::mat4 projection, glm::mat4 view)
{
glm::mat4 mvp = projection * view * location;
program->SetUniformMatrix4("MVP", mvp);
program->SetUniformMatrix4("ViewMatrix", view);
program->SetUniformMatrix4("ModelViewMatrix", view * location);
material->SetUniforms(program);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, numFaces * 3, GL_UNSIGNED_SHORT, NULL);
}
|
|
|
La clase CGScene
|
|
La escena a representar en el modelo se describe en la clase
CGScene. Respecto a la versión de la práctica anterior, la única
diferencia en la cabecera de la función es que se añade un campo
light que almacena la información de la fuente de luz
y los campos matg y material que almacenan los
materiales del suelo y de las figuras.
#pragma once
#include <GL/glew.h>
#include <glm/glm.hpp>
#include "CGShaderProgram.h"
#include "CGLight.h"
#include "CGMaterial.h"
#include "CGFigure.h"
class CGScene {
public:
CGScene();
~CGScene();
void Draw(CGShaderProgram* program, glm::mat4 proj, glm::mat4 view);
private:
CGFigure* ground;
CGFigure* fig0;
CGFigure* fig1;
CGFigure* fig2;
CGFigure* fig3;
CGFigure* fig4;
CGFigure* fig5;
CGLight* light;
CGMaterial* matg;
CGMaterial* material;
};
|
Con respecto al código, el constructor de la clase, además de
generar las figuras y posicionarlas, debe inicializar los valores de
la fuente de luz y de las propiedades de material de cada figura. El
método Draw() debe asignar las variables uniformes
asociadas a la luz además de realizar llamadas para dibujar los
objetos que forman parte de la escena.
#include "CGScene.h"
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "CGShaderProgram.h"
#include "CGFigure.h"
#include "CGLight.h"
#include "CGMaterial.h"
#include "CGCube.h"
#include "CGCone.h"
#include "CGCylinder.h"
#include "CGSphere.h"
#include "CGTorus.h"
#include "CGIcosahedron.h"
#include "CGGround.h"
//
// FUNCIÓN: CGScene::CGScene()
//
// PROPÓSITO: Construye el objeto que representa la escena
//
CGScene::CGScene()
{
glm::vec3 Ldir = glm::vec3(1.0f, -0.8f, -1.0f);
Ldir = glm::normalize(Ldir);
light = new CGLight();
light->SetLightDirection(Ldir);
light->SetAmbientLight(glm::vec3(0.2f, 0.2f, 0.2f));
light->SetDifusseLight(glm::vec3(0.8f, 0.8f, 0.8f));
light->SetSpecularLight(glm::vec3(1.0f, 1.0f, 1.0f));
matg = new CGMaterial();
matg->SetAmbientReflect(0.0f, 0.6f, 0.0f);
matg->SetDifusseReflect(0.0f, 0.6f, 0.0f);
matg->SetSpecularReflect(0.8f, 0.8f, 0.8f);
matg->SetShininess(16.0f);
material = new CGMaterial();
material->SetAmbientReflect(1.0f, 0.0f, 0.0f);
material->SetDifusseReflect(1.0f, 0.0f, 0.0f);
material->SetSpecularReflect(0.8f, 0.8f, 0.8f);
material->SetShininess(16.0f);
ground = new CGGround(50.0f, 50.0f);
ground->SetMaterial(matg);
fig0 = new CGCone(5, 20, 5.0f, 5.0f);
fig0->SetMaterial(material);
fig0->Translate(glm::vec3(25.0f, 5.0f, 25.0f));
fig0->Rotate(-90.0f, glm::vec3(1.0f, 0.0f, 0.0f));
fig1 = new CGCube(5.0f);
fig1->SetMaterial(material);
fig1->Translate(glm::vec3(-25.0f, 5.0f, 25.0f));
fig1->Rotate(-90.0f, glm::vec3(1.0f, 0.0f, 0.0f));
fig2 = new CGCylinder(20, 20, 5.0f, 5.0f);
fig2->SetMaterial(material);
fig2->Translate(glm::vec3(25.0f, 5.0f, 0.0f));
fig2->Rotate(90.0f, glm::vec3(1.0f, 0.0f, 0.0f));
fig3 = new CGTorus(20, 40, 3.0f, 5.0f);
fig3->SetMaterial(material);
fig3->Translate(glm::vec3(-25.0f, 8.0f, 0.0f));
fig4 = new CGSphere(20, 40, 8.0f);
fig4->SetMaterial(material);
fig4->Translate(glm::vec3(25.0f, 8.0f, -25.0f));
fig5 = new CGIcosahedron(5.0f);
fig5->SetMaterial(material);
fig5->Translate(glm::vec3(-25.0f, 8.0f, -25.0f));
}
//
// FUNCIÓN: CGScene3:~CGScene()
//
// PROPÓSITO: Destruye el objeto que representa la escena
//
CGScene::~CGScene()
{
delete ground;
delete fig0;
delete fig1;
delete fig2;
delete fig3;
delete fig4;
delete fig5;
delete light;
delete matg;
delete material;
}
//
// FUNCIÓN: CGScene::Draw()
//
// PROPÓSITO: Dibuja la escena
//
void CGScene::Draw(CGShaderProgram* program, glm::mat4 proj, glm::mat4 view)
{
light->SetUniforms(program);
ground->Draw(program, proj, view);
fig0->Draw(program, proj, view);
fig1->Draw(program, proj, view);
fig2->Draw(program, proj, view);
fig3->Draw(program, proj, view);
fig4->Draw(program, proj, view);
fig5->Draw(program, proj, view);
}
|
|
|
Figuras geométricas
|
|
Con respecto a las diferentes figuras geométricas, es necesario
modificar su código para incorporar a los atributos de los vértices
el valor del vector normal en cada vértice.
El código asociado al cubo
es el siguiente.
#include "CGCube.h"
#include <GL/glew.h>
#include "CGFigure.h"
///
/// FUNCION: CGCube::CGCube(GLfloat s)
///
/// PROPÓSITO: Construye un cubo de lado '2*s'
///
CGCube::CGCube(GLfloat s)
{
numFaces = 12; // Number of faces
numVertices = 24; // Number of vertices
GLfloat p_vertices[24][3] = {
{ +s, +s, +s }, // A0 // Positive X
{ +s, -s, +s }, // D0
{ +s, -s, -s }, // D1
{ +s, +s, -s }, // A1
{ -s, +s, +s }, // B0 // Positive Y
{ +s, +s, +s }, // A0
{ +s, +s, -s }, // A1
{ -s, +s, -s }, // B1
{ -s, -s, +s }, // C0 // Negative X
{ -s, +s, +s }, // B0
{ -s, +s, -s }, // B1
{ -s, -s, -s }, // C1
{ +s, -s, +s }, // D0 // Negative Y
{ -s, -s, +s }, // C0
{ -s, -s, -s }, // C1
{ +s, -s, -s }, // D1
{ +s, +s, +s }, // A0 // Positive Z
{ -s, +s, +s }, // B0
{ -s, -s, +s }, // C0
{ +s, -s, +s }, // D0
{ +s, +s, -s }, // A1 // Negative Z
{ +s, -s, -s }, // D1
{ -s, -s, -s }, // C1
{ -s, +s, -s } // B1
};
GLfloat p_normals[24][3] = {
{ 1.0f, 0.0f, 0.0f }, // Positive X // 0
{ 1.0f, 0.0f, 0.0f }, // Positive X // 1
{ 1.0f, 0.0f, 0.0f }, // Positive X // 2
{ 1.0f, 0.0f, 0.0f }, // Positive X // 3
{ 0.0f, 1.0f, 0.0f }, // Positive Y // 4
{ 0.0f, 1.0f, 0.0f }, // Positive Y // 5
{ 0.0f, 1.0f, 0.0f }, // Positive Y // 6
{ 0.0f, 1.0f, 0.0f }, // Positive Y // 7
{ -1.0f, 0.0f, 0.0f }, // Negative X // 8
{ -1.0f, 0.0f, 0.0f }, // Negative X // 9
{ -1.0f, 0.0f, 0.0f }, // Negative X // 10
{ -1.0f, 0.0f, 0.0f }, // Negative X // 11
{ 0.0f, -1.0f, 0.0f }, // Negative Y // 12
{ 0.0f, -1.0f, 0.0f }, // Negative Y // 13
{ 0.0f, -1.0f, 0.0f }, // Negative Y // 14
{ 0.0f, -1.0f, 0.0f }, // Negative Y // 15
{ 0.0f, 0.0f, 1.0f }, // Positive Z // 16
{ 0.0f, 0.0f, 1.0f }, // Positive Z // 17
{ 0.0f, 0.0f, 1.0f }, // Positive Z // 18
{ 0.0f, 0.0f, 1.0f }, // Positive Z // 19
{ 0.0f, 0.0f, -1.0f }, // Negative Z // 20
{ 0.0f, 0.0f, -1.0f }, // Negative Z // 21
{ 0.0f, 0.0f, -1.0f }, // Negative Z // 22
{ 0.0f, 0.0f, -1.0f } // Negative Z // 23
};
GLushort p_indexes[12][3] = { // Array of indexes
{ 0, 1, 2 },
{ 0, 2, 3 },
{ 4, 5, 6 },
{ 4, 6, 7 },
{ 8, 9, 10 },
{ 8, 10, 11 },
{ 12, 13, 14 },
{ 12, 14, 15 },
{ 16, 17, 18 },
{ 16, 18, 19 },
{ 20, 21, 22 },
{ 20, 22, 23 }
};
vertices = new GLfloat[numVertices * 3];
for (int i = 0; i < numVertices; i++)
for (int j = 0; j < 3; j++)
vertices[3 * i + j] = p_vertices[i][j];
normals = new GLfloat[numVertices * 3];
for (int i = 0; i < numVertices; i++)
for (int j = 0; j < 3; j++)
normals[3 * i + j] = p_normals[i][j];
indexes = new GLushort[numFaces * 3];
for (int i = 0; i < numFaces; i++)
for (int j = 0; j < 3; j++)
indexes[3 * i + j] = p_indexes[i][j];
InitBuffers();
}
|
El código del constructor del cono
es el siguiente.
#include "CGCone.h"
#include <GL/glew.h>
#include <math.h>
#include "CGFigure.h"
///
/// FUNCION: CGCone::CGCone(GLint p, GLint m, GLfloat h, GLfloat r)
///
/// PROPÓSITO: Construir un cono de radio 'r' y altura '2*h'
/// considerando las circunferencias formadas por 'm' puntos
/// y el cuerpo del cono dividido en 'p' rodajas.
///
CGCone::CGCone(GLint p, GLint m, GLfloat h, GLfloat r)
{
numFaces = 2 * p * m; // Number of faces
numVertices = (p + 1)*m + 2; // Number of vertices
vertices = new GLfloat[numVertices * 3];
normals = new GLfloat[numVertices * 3];
indexes = new GLushort[numFaces * 3];
double module = sqrt(4 * h*h + r*r);
double xyN = (GLfloat)(2 * h / module);
double zN = (GLfloat)(r / module);
int verticesIndex = 0;
int normalsIndex = 0;
// Centro de la base
vertices[0] = 0.0f;
vertices[1] = 0.0f;
vertices[2] = -h;
verticesIndex += 3;
normals[0] = 0.0f;
normals[1] = 0.0f;
normals[2] = -1.0f;
normalsIndex += 3;
// Vértices de la base
for (int i = 0; i <m; i++)
{
GLfloat x = (GLfloat)cos(glm::radians(360.0 * i / m));
GLfloat y = -(GLfloat)sin(glm::radians(360.0 * i / m));
vertices[verticesIndex] = x*r;
vertices[verticesIndex + 1] = y*r;
vertices[verticesIndex + 2] = -h;
verticesIndex += 3;
normals[normalsIndex] = 0.0f;
normals[normalsIndex+1] = 0.0f;
normals[normalsIndex+2] = -1.0f;
normalsIndex += 3;
}
// Extremo del cono
vertices[verticesIndex] = 0.0f;
vertices[verticesIndex + 1] = 0.0f;
vertices[verticesIndex + 2] = h;
verticesIndex += 3;
normals[normalsIndex] = 0.0f;
normals[normalsIndex+1] = 0.0f;
normals[normalsIndex+2] = 1.0f;
normalsIndex += 3;
// Vértices de los lados
for (int i = 1; i <= p; i++)
{
GLfloat xy = i*r / p;
GLfloat z = h - 2 * i*h / p;
for (int j = 0; j < m; j++)
{
GLfloat xN = (GLfloat)cos(glm::radians(360.0 * j / m));
GLfloat yN = (GLfloat)sin(glm::radians(360.0 * j / m));
GLfloat x = (GLfloat)(xN*xy);
GLfloat y = (GLfloat)(yN*xy);
vertices[verticesIndex] = x;
vertices[verticesIndex + 1] = y;
vertices[verticesIndex + 2] = z;
verticesIndex += 3;
normals[normalsIndex] = xN*xyN;
normals[normalsIndex + 1] = yN*xyN;
normals[normalsIndex + 2] = zN;
normalsIndex += 3;
}
}
int indicesIndex = 0;
// Base
for (int i = 0; i < m - 1; i++)
{
indexes[indicesIndex] = 0;
indexes[indicesIndex + 1] = i + 1;
indexes[indicesIndex + 2] = i + 2;
indicesIndex += 3;
}
indexes[indicesIndex] = 0;
indexes[indicesIndex + 1] = m;
indexes[indicesIndex + 2] = 1;
indicesIndex += 3;
// Extremo
for (int i = 0; i < m - 1; i++)
{
indexes[indicesIndex] = m + 1;
indexes[indicesIndex + 1] = m + 2 + i;
indexes[indicesIndex + 2] = m + 3 + i;
indicesIndex += 3;
}
indexes[indicesIndex] = m + 1;
indexes[indicesIndex + 1] = 2 * m + 1;
indexes[indicesIndex + 2] = m + 2;
indicesIndex += 3;
// Lados
for (int j = 1; j < p; j++)
{
for (int i = 0; i < m - 1; i++)
{
indexes[indicesIndex] = j*m + 2 + i;
indexes[indicesIndex + 1] = (j + 1)*m + 2 + i;
indexes[indicesIndex + 2] = (j + 1)*m + 3 + i;
indicesIndex += 3;
indexes[indicesIndex] = j*m + 2 + i;
indexes[indicesIndex + 1] = (j + 1)*m + 3 + i;
indexes[indicesIndex + 2] = j*m + 3 + i;
indicesIndex += 3;
}
indexes[indicesIndex] = (j + 1)*m + 1;
indexes[indicesIndex + 1] = (j + 2)*m + 1;
indexes[indicesIndex + 2] = (j + 1)*m + 2;
indicesIndex += 3;
indexes[indicesIndex] = (j + 1)*m + 1;
indexes[indicesIndex + 1] = (j + 1)*m + 2;
indexes[indicesIndex + 2] = j*m + 2;
indicesIndex += 3;
}
InitBuffers();
}
|
El constructor del cilindro
queda así:
#include "CGCylinder.h"
#include <GL/glew.h>
#include <math.h>
#include "CGFigure.h"
///
/// FUNCION: CGCylinder::CGCylinder(GLint p, GLint m, GLfloat r, GLfloat l)
///
/// PROPÓSITO: Construir un cilindro de radio 'r' y longitud '2*l'
/// considerando las circunferencias formadas por 'm' puntos
/// y el cuerpo del cilindro dividido en 'p' tambores.
///
/// Tapa1: (m+1) vertices, m triángulos
/// Tapa2: (m+1) vertices, m triángulos
/// Tambor: (p+1)*(m+1) vertices, 2*p*m triángulos
///
CGCylinder::CGCylinder(GLint p, GLint m, GLfloat r, GLfloat l)
{
numFaces = 2 * m * (p + 1); // Number of faces
numVertices = (m + 1)*(p + 3); // Number of vertices
vertices = new GLfloat[numVertices * 3];
normals = new GLfloat[numVertices * 3];
indexes = new GLushort[numFaces * 3];
int verticesIndex = 0;
int normalsIndex = 0;
int indexesIndex = 0;
/* northern polar cap*/
vertices[0] = 0.0f;
vertices[1] = 0.0f;
vertices[2] = l;
verticesIndex += 3;
normals[0] = 0.0f;
normals[1] = 0.0f;
normals[2] = 1.0f;
normalsIndex += 3;
for (int j = 0; j < m; j++)
{
GLfloat mCos = (GLfloat)cos(glm::radians(360.0 * j / m));
GLfloat mSin = (GLfloat)sin(glm::radians(360.0 * j / m));
vertices[verticesIndex] = mCos * r;
vertices[verticesIndex + 1] = mSin * r;
vertices[verticesIndex + 2] = l;
verticesIndex += 3;
normals[normalsIndex] = 0.0f;
normals[normalsIndex + 1] = 0.0f;
normals[normalsIndex + 2] = 1.0f;
normalsIndex += 3;
indexes[indexesIndex] = 0; // center
indexes[indexesIndex + 1] = j + 1;
indexes[indexesIndex + 2] = (j + 2>m ? 1 : j + 2);
indexesIndex += 3;
}
/* southern polar cap*/
vertices[verticesIndex] = 0.0f;
vertices[verticesIndex + 1] = 0.0f;
vertices[verticesIndex + 2] = -l;
verticesIndex += 3;
normals[normalsIndex] = 0.0f;
normals[normalsIndex + 1] = 0.0f;
normals[normalsIndex + 2] = -1.0f;
normalsIndex += 3;
for (int j = 0; j < m; j++)
{
GLfloat mCos = (GLfloat)cos(glm::radians(360.0 * j / m));
GLfloat mSin = (GLfloat)sin(glm::radians(360.0 * j / m));
vertices[verticesIndex] = mCos * r;
vertices[verticesIndex + 1] = -mSin * r;
vertices[verticesIndex + 2] = -l;
verticesIndex += 3;
normals[normalsIndex] = 0.0f;
normals[normalsIndex + 1] = 0.0f;
normals[normalsIndex + 2] = -1.0f;
normalsIndex += 3;
indexes[indexesIndex] = m + 1; // center
indexes[indexesIndex + 1] = j + m + 2;
indexes[indexesIndex + 2] = (j + 2>m ? m + 2 : j + m + 3);
indexesIndex += 3;
}
/* body */
for (int i = 0; i <= p; i++)
{
for (int j = 0; j <= m; j++)
{
GLfloat mCos = (GLfloat)cos(glm::radians(360.0 * j / m));
GLfloat mSin = (GLfloat)sin(glm::radians(360.0 * j / m));
vertices[verticesIndex] = mCos * r;
vertices[verticesIndex + 1] = mSin * r;
vertices[verticesIndex + 2] = l - 2 * l*i / p;
verticesIndex += 3;
normals[normalsIndex] = mCos;
normals[normalsIndex + 1] = mSin;
normals[normalsIndex + 2] = 0.0f;
normalsIndex += 3;
}
}
int base = 2 * m + 2;
for (int i = 0; i < p; i++)
{
for (int j = 0; j < m; j++)
{
indexes[indexesIndex] = base + (m + 1)*i + j;
indexes[indexesIndex + 1] = base + (m + 1)*(i + 1) + j;
indexes[indexesIndex + 2] = base + (m + 1)*(i + 1) + j + 1;
indexesIndex += 3;
indexes[indexesIndex] = base + (m + 1)*i + j;
indexes[indexesIndex + 1] = base + (m + 1)*(i + 1) + j + 1;
indexes[indexesIndex + 2] = base + (m + 1)*i + j + 1;
indexesIndex += 3;
}
}
InitBuffers();
}
|
El constructor de la esfera
sería este:
#include "CGSphere.h"
#include <GL/glew.h>
#include <math.h>
#include "CGFigure.h"
///
/// FUNCION: CGSphere::CGSphere(GLint p, GLint m, GLfloat r)
///
/// PROPÓSITO: Construye una espera de radio 'r' con 'p' paralelos
/// y 'm' meridianos
///
CGSphere::CGSphere(GLint p, GLint m, GLfloat r)
{
numFaces = 2 * m*(p - 1); // Number of faces
numVertices = (m + 1)*(p + 1); // Number of vertices
vertices = new GLfloat[numVertices * 3];
normals = new GLfloat[numVertices * 3];
indexes = new GLushort[numFaces * 3];
int verticesIndex = 0;
int normalsIndex = 0;
int indexesIndex = 0;
for (int j = 0; j <= m; j++)
{
normals[normalsIndex] = 0.0f;
normals[normalsIndex + 1] = 0.0f;
normals[normalsIndex + 2] = 1.0f;
normalsIndex += 3;
vertices[verticesIndex] = 0.0;
vertices[verticesIndex + 1] = 0.0f;
vertices[verticesIndex + 2] = r;
verticesIndex += 3;
}
for (int i = 1; i < p; i++)
{
for (int j = 0; j <= m; j++)
{
GLfloat pCos = (GLfloat)cos(glm::radians(180.0 * i / p));
GLfloat pSin = (GLfloat)sin(glm::radians(180.0 * i / p));
GLfloat mCos = (GLfloat)cos(glm::radians(360.0 * j / m));
GLfloat mSin = (GLfloat)sin(glm::radians(360.0 * j / m));
normals[normalsIndex] = pSin*mCos;
normals[normalsIndex + 1] = pSin*mSin;
normals[normalsIndex + 2] = pCos;
normalsIndex += 3;
vertices[verticesIndex] = pSin*mCos*r;
vertices[verticesIndex + 1] = pSin*mSin*r;
vertices[verticesIndex + 2] = pCos*r;
verticesIndex += 3;
}
}
/* southern polar cap*/
for (int j = 0; j <= m; j++)
{
normals[normalsIndex] = 0.0f;
normals[normalsIndex + 1] = 0.0f;
normals[normalsIndex + 2] = -1.0f;
normalsIndex += 3;
vertices[verticesIndex] = 0.0;
vertices[verticesIndex + 1] = 0.0f;
vertices[verticesIndex + 2] = -r;
verticesIndex += 3;
}
/* northern polar cap*/
for (int j = 0; j < m; j++)
{
indexes[indexesIndex] = j;
indexes[indexesIndex + 1] = m + j + 1;
indexes[indexesIndex + 2] = m + j + 2;
indexesIndex += 3;
}
for (int i = 1; i < p - 1; i++)
{
for (int j = 0; j < m; j++)
{
indexes[indexesIndex] = i*(m + 1) + j;
indexes[indexesIndex + 1] = (i + 1)*(m + 1) + j;
indexes[indexesIndex + 2] = i*(m + 1) + j + 1;
indexes[indexesIndex + 3] = (i + 1)*(m + 1) + j;
indexes[indexesIndex + 4] = (i + 1)*(m + 1) + j + 1;
indexes[indexesIndex + 5] = i*(m + 1) + j + 1;
indexesIndex += 6;
}
}
for (int j = 0; j < m; j++)
{
indexes[indexesIndex] = (p - 1)*(m + 1) + j;
indexes[indexesIndex + 1] = p*(m + 1) + j;
indexes[indexesIndex + 2] = (p - 1)*(m + 1) + j + 1;
indexesIndex += 3;
}
InitBuffers();
}
|
El código para construir un toro
es el siguiente.
#include "CGTorus.h"
#include <GL/glew.h>
#include <math.h>
#include "CGFigure.h"
//
// FUNCIÓN: CGTorus::CGTorus(GLint p, GLint m, GLfloat r0, GLfloat r1)
//
// PROPÓSITO: Crea un toro
//
// COMENTARIOS:
//
// 'p' es el número de capas en las que se divide el toro
// 'm' es el número de sectores en que se divide cada capa
// 'r0' es el radio interior del toro
// 'r1' es el radio exterior del toro
//
CGTorus::CGTorus(GLint p, GLint m, GLfloat r0, GLfloat r1)
{
numFaces = 2 * m * p; // Number of faces
numVertices = (m + 1)*(p + 1); // Number of vertices
vertices = new GLfloat[numVertices * 3];
normals = new GLfloat[numVertices * 3];
indexes = new GLushort[numFaces * 3];
int verticesIndex = 0;
int normalsIndex = 0;
int indexesIndex = 0;
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= p; j++)
{
GLfloat pCos = (GLfloat)cos(glm::radians(360.0 * j / p));
GLfloat pSin = (GLfloat)sin(glm::radians(360.0 * j / p));
GLfloat mCos = (GLfloat)cos(glm::radians(360.0 * i / m));
GLfloat mSin = (GLfloat)sin(glm::radians(360.0 * i / m));
vertices[verticesIndex] = (r1 + r0*pCos)*mCos;
vertices[verticesIndex + 1] = (r1 + r0*pCos)*mSin;
vertices[verticesIndex + 2] = r0*pSin;
verticesIndex += 3;
normals[normalsIndex] = pCos * mCos;
normals[normalsIndex + 1] = pCos * mSin;
normals[normalsIndex + 2] = pSin;
normalsIndex += 3;
}
}
for (int i = 0; i < m; i++)
{
for (int j = 0; j < p; j++)
{
indexes[indexesIndex] = (p + 1)*i + j;
indexes[indexesIndex + 1] = (p + 1)*(i + 1) + j;
indexes[indexesIndex + 2] = (p + 1)*(i + 1) + j + 1;
indexesIndex += 3;
indexes[indexesIndex] = (p + 1)*i + j;
indexes[indexesIndex + 1] = (p + 1)*(i + 1) + j + 1;
indexes[indexesIndex + 2] = (p + 1)*i + j + 1;
indexesIndex += 3;
}
}
InitBuffers();
}
|
El icosahedro
se construye con el siguiente código.
#include "CGIcosahedron.h"
#include <GL/glew.h>
#include <math.h>
#include "CGFigure.h"
//
// FUNCIÓN: CGIcosahedron::CGIcosahedron(GLfloat r)
//
// PROPÓSITO: Dibuja un icosaedro de arista '2r'
//
CGIcosahedron::CGIcosahedron(GLfloat r)
{
numFaces = 20; // Number of faces
numVertices = 60; // Number of vertices
vertices = new GLfloat[numVertices * 3];
normals = new GLfloat[numVertices * 3];
indexes = new GLushort[numFaces * 3];
GLfloat phi = (GLfloat)((1 + sqrt(5.0)) / 2.0);
GLfloat mod = (GLfloat)sqrt(6 + 9 * phi);
GLfloat p0M = (GLfloat)phi / mod;
GLfloat p1M = (GLfloat)(phi + 1) / mod;
GLfloat p2M = (GLfloat)(2 * phi + 1) / mod;
GLfloat A0[] = { 0, r*phi, r };
GLfloat A1[] = { 0, r*phi, -r };
GLfloat A2[] = { 0, -r*phi, -r };
GLfloat A3[] = { 0, -r*phi, r };
GLfloat B0[] = { r*phi, r, 0 };
GLfloat B1[] = { r*phi, -r, 0 };
GLfloat B2[] = { -r*phi, -r, 0 };
GLfloat B3[] = { -r*phi, r, 0 };
GLfloat C0[] = { r, 0, r*phi };
GLfloat C1[] = { r, 0, -r*phi };
GLfloat C2[] = { -r, 0, -r*phi };
GLfloat C3[] = { -r, 0, r*phi };
GLfloat N1[] = { -p0M, p2M, 0 };
GLfloat N2[] = { -p1M, p1M, p1M };
GLfloat N3[] = { 0, p0M, p2M };
GLfloat N4[] = { p1M, p1M, p1M };
GLfloat N5[] = { p0M, p2M, 0 };
GLfloat N6[] = { p2M, 0, -p0M };
GLfloat N7[] = { p2M, 0, p0M };
GLfloat N8[] = { p1M, -p1M, p1M };
GLfloat N9[] = { p0M, -p2M, 0 };
GLfloat N10[] = { p1M, -p1M, -p1M };
GLfloat N11[] = { p1M, p1M, -p1M };
GLfloat N12[] = { 0, -p0M, p2M };
GLfloat N13[] = { 0, p0M, -p2M };
GLfloat N14[] = { -p1M, p1M, -p1M };
GLfloat N15[] = { -p2M, 0, p0M };
GLfloat N16[] = { -p1M, -p1M, p1M };
GLfloat N17[] = { -p2M, 0, -p0M };
GLfloat N18[] = { 0, -p0M, -p2M };
GLfloat N19[] = { -p1M, -p1M, -p1M };
GLfloat N20[] = { -p0M, -p2M, 0 };
int normalsIndex = 0;
int verticesIndex = 0;
// face 1; vertex[1] = A0; normals[1]=N1;
vertices[verticesIndex] = A0[0];
vertices[verticesIndex + 1] = A0[1];
vertices[verticesIndex + 2] = A0[2];
verticesIndex += 3;
normals[normalsIndex] = N1[0];
normals[normalsIndex + 1] = N1[1];
normals[normalsIndex + 2] = N1[2];
normalsIndex += 3;
// face 1; vertex[2]=A1; normals[2]=N1;
vertices[verticesIndex] = A1[0];
vertices[verticesIndex + 1] = A1[1];
vertices[verticesIndex + 2] = A1[2];
verticesIndex += 3;
normals[normalsIndex] = N1[0];
normals[normalsIndex + 1] = N1[1];
normals[normalsIndex + 2] = N1[2];
normalsIndex += 3;
// face 1; vertex[3]=B3; normals[3]=N1;
vertices[verticesIndex] = B3[0];
vertices[verticesIndex + 1] = B3[1];
vertices[verticesIndex + 2] = B3[2];
verticesIndex += 3;
normals[normalsIndex] = N1[0];
normals[normalsIndex + 1] = N1[1];
normals[normalsIndex + 2] = N1[2];
normalsIndex += 3;
// face 2; vertex[1] = A0; normals[1]=N2;
vertices[verticesIndex] = A0[0];
vertices[verticesIndex + 1] = A0[1];
vertices[verticesIndex + 2] = A0[2];
verticesIndex += 3;
normals[normalsIndex] = N2[0];
normals[normalsIndex + 1] = N2[1];
normals[normalsIndex + 2] = N2[2];
normalsIndex += 3;
// face 2; vertex[2] = B3; normals[2]=N2;
vertices[verticesIndex] = B3[0];
vertices[verticesIndex + 1] = B3[1];
vertices[verticesIndex + 2] = B3[2];
verticesIndex += 3;
normals[normalsIndex] = N2[0];
normals[normalsIndex + 1] = N2[1];
normals[normalsIndex + 2] = N2[2];
normalsIndex += 3;
// face 2; vertex[3] = C3; normals[3]=N2;
vertices[verticesIndex] = C3[0];
vertices[verticesIndex + 1] = C3[1];
vertices[verticesIndex + 2] = C3[2];
verticesIndex += 3;
normals[normalsIndex] = N2[0];
normals[normalsIndex + 1] = N2[1];
normals[normalsIndex + 2] = N2[2];
normalsIndex += 3;
// face 3; vertex[1] = A0; normals[1]=N3;
vertices[verticesIndex] = A0[0];
vertices[verticesIndex + 1] = A0[1];
vertices[verticesIndex + 2] = A0[2];
verticesIndex += 3;
normals[normalsIndex] = N3[0];
normals[normalsIndex + 1] = N3[1];
normals[normalsIndex + 2] = N3[2];
normalsIndex += 3;
// face 3; vertex[2] = C3; normals[2]=N3;
vertices[verticesIndex] = C3[0];
vertices[verticesIndex + 1] = C3[1];
vertices[verticesIndex + 2] = C3[2];
verticesIndex += 3;
normals[normalsIndex] = N3[0];
normals[normalsIndex + 1] = N3[1];
normals[normalsIndex + 2] = N3[2];
normalsIndex += 3;
// face 3; vertex[3] = C0; normals[3]=N3;
vertices[verticesIndex] = C0[0];
vertices[verticesIndex + 1] = C0[1];
vertices[verticesIndex + 2] = C0[2];
verticesIndex += 3;
normals[normalsIndex] = N3[0];
normals[normalsIndex + 1] = N3[1];
normals[normalsIndex + 2] = N3[2];
normalsIndex += 3;
// face 4; vertex[1] = A0; normals[1]=N4;
vertices[verticesIndex] = A0[0];
vertices[verticesIndex + 1] = A0[1];
vertices[verticesIndex + 2] = A0[2];
verticesIndex += 3;
normals[normalsIndex] = N4[0];
normals[normalsIndex + 1] = N4[1];
normals[normalsIndex + 2] = N4[2];
normalsIndex += 3;
// face 4; vertex[2] = C0; normals[2]=N4;
vertices[verticesIndex] = C0[0];
vertices[verticesIndex + 1] = C0[1];
vertices[verticesIndex + 2] = C0[2];
verticesIndex += 3;
normals[normalsIndex] = N4[0];
normals[normalsIndex + 1] = N4[1];
normals[normalsIndex + 2] = N4[2];
normalsIndex += 3;
// face 4; vertex[3] = B0; normals[3]=N4;
vertices[verticesIndex] = B0[0];
vertices[verticesIndex + 1] = B0[1];
vertices[verticesIndex + 2] = B0[2];
verticesIndex += 3;
normals[normalsIndex] = N4[0];
normals[normalsIndex + 1] = N4[1];
normals[normalsIndex + 2] = N4[2];
normalsIndex += 3;
// face 5; vertex[1] = A0; normals[1]=N5;
vertices[verticesIndex] = A0[0];
vertices[verticesIndex + 1] = A0[1];
vertices[verticesIndex + 2] = A0[2];
verticesIndex += 3;
normals[normalsIndex] = N5[0];
normals[normalsIndex + 1] = N5[1];
normals[normalsIndex + 2] = N5[2];
normalsIndex += 3;
// face 5; vertex[2] = B0; normals[2]=N5;
vertices[verticesIndex] = B0[0];
vertices[verticesIndex + 1] = B0[1];
vertices[verticesIndex + 2] = B0[2];
verticesIndex += 3;
normals[normalsIndex] = N5[0];
normals[normalsIndex + 1] = N5[1];
normals[normalsIndex + 2] = N5[2];
normalsIndex += 3;
// face 5; vertex[3] = A1; normals[3]=N5;
vertices[verticesIndex] = A1[0];
vertices[verticesIndex + 1] = A1[1];
vertices[verticesIndex + 2] = A1[2];
verticesIndex += 3;
normals[normalsIndex] = N5[0];
normals[normalsIndex + 1] = N5[1];
normals[normalsIndex + 2] = N5[2];
normalsIndex += 3;
// face 6; vertex[1] = B1; normals[1]=N6;
vertices[verticesIndex] = B1[0];
vertices[verticesIndex + 1] = B1[1];
vertices[verticesIndex + 2] = B1[2];
verticesIndex += 3;
normals[normalsIndex] = N6[0];
normals[normalsIndex + 1] = N6[1];
normals[normalsIndex + 2] = N6[2];
normalsIndex += 3;
// face 6; vertex[2] = C1; normals[2]=N6;
vertices[verticesIndex] = C1[0];
vertices[verticesIndex + 1] = C1[1];
vertices[verticesIndex + 2] = C1[2];
verticesIndex += 3;
normals[normalsIndex] = N6[0];
normals[normalsIndex + 1] = N6[1];
normals[normalsIndex + 2] = N6[2];
normalsIndex += 3;
// face 6; vertex[3] = B0; normals[3]=N6;
vertices[verticesIndex] = B0[0];
vertices[verticesIndex + 1] = B0[1];
vertices[verticesIndex + 2] = B0[2];
verticesIndex += 3;
normals[normalsIndex] = N6[0];
normals[normalsIndex + 1] = N6[1];
normals[normalsIndex + 2] = N6[2];
normalsIndex += 3;
// face 7; vertex[1] = B1; normals[1]=N7;
vertices[verticesIndex] = B1[0];
vertices[verticesIndex + 1] = B1[1];
vertices[verticesIndex + 2] = B1[2];
verticesIndex += 3;
normals[normalsIndex] = N7[0];
normals[normalsIndex + 1] = N7[1];
normals[normalsIndex + 2] = N7[2];
normalsIndex += 3;
// face 7; vertex[2] = B0; normals[2]=N7;
vertices[verticesIndex] = B0[0];
vertices[verticesIndex + 1] = B0[1];
vertices[verticesIndex + 2] = B0[2];
verticesIndex += 3;
normals[normalsIndex] = N7[0];
normals[normalsIndex + 1] = N7[1];
normals[normalsIndex + 2] = N7[2];
normalsIndex += 3;
// face 7; vertex[3] = C0; normals[3]=N7;
vertices[verticesIndex] = C0[0];
vertices[verticesIndex + 1] = C0[1];
vertices[verticesIndex + 2] = C0[2];
verticesIndex += 3;
normals[normalsIndex] = N7[0];
normals[normalsIndex + 1] = N7[1];
normals[normalsIndex + 2] = N7[2];
normalsIndex += 3;
// face 8; vertex[1] = B1; normals[1]=N8;
vertices[verticesIndex] = B1[0];
vertices[verticesIndex + 1] = B1[1];
vertices[verticesIndex + 2] = B1[2];
verticesIndex += 3;
normals[normalsIndex] = N8[0];
normals[normalsIndex + 1] = N8[1];
normals[normalsIndex + 2] = N8[2];
normalsIndex += 3;
// face 8; vertex[2] = C0; normals[2]=N8;
vertices[verticesIndex] = C0[0];
vertices[verticesIndex + 1] = C0[1];
vertices[verticesIndex + 2] = C0[2];
verticesIndex += 3;
normals[normalsIndex] = N8[0];
normals[normalsIndex + 1] = N8[1];
normals[normalsIndex + 2] = N8[2];
normalsIndex += 3;
// face 8; vertex[3] = A3; normals[3]=N8;
vertices[verticesIndex] = A3[0];
vertices[verticesIndex + 1] = A3[1];
vertices[verticesIndex + 2] = A3[2];
verticesIndex += 3;
normals[normalsIndex] = N8[0];
normals[normalsIndex + 1] = N8[1];
normals[normalsIndex + 2] = N8[2];
normalsIndex += 3;
// face 9; vertex[1] = B1; normals[1]=N9;
vertices[verticesIndex] = B1[0];
vertices[verticesIndex + 1] = B1[1];
vertices[verticesIndex + 2] = B1[2];
verticesIndex += 3;
normals[normalsIndex] = N9[0];
normals[normalsIndex + 1] = N9[1];
normals[normalsIndex + 2] = N9[2];
normalsIndex += 3;
// face 9; vertex[2] = A3; normals[2]=N9;
vertices[verticesIndex] = A3[0];
vertices[verticesIndex + 1] = A3[1];
vertices[verticesIndex + 2] = A3[2];
verticesIndex += 3;
normals[normalsIndex] = N9[0];
normals[normalsIndex + 1] = N9[1];
normals[normalsIndex + 2] = N9[2];
normalsIndex += 3;
// face 9; vertex[3] = A2; normals[3]=N9;
vertices[verticesIndex] = A2[0];
vertices[verticesIndex + 1] = A2[1];
vertices[verticesIndex + 2] = A2[2];
verticesIndex += 3;
normals[normalsIndex] = N9[0];
normals[normalsIndex + 1] = N9[1];
normals[normalsIndex + 2] = N9[2];
normalsIndex += 3;
// face 10; vertex[1] = B1; normals[1]=N10;
vertices[verticesIndex] = B1[0];
vertices[verticesIndex + 1] = B1[1];
vertices[verticesIndex + 2] = B1[2];
verticesIndex += 3;
normals[normalsIndex] = N10[0];
normals[normalsIndex + 1] = N10[1];
normals[normalsIndex + 2] = N10[2];
normalsIndex += 3;
// face 10; vertex[2] = A2; normals[2]=N10;
vertices[verticesIndex] = A2[0];
vertices[verticesIndex + 1] = A2[1];
vertices[verticesIndex + 2] = A2[2];
verticesIndex += 3;
normals[normalsIndex] = N10[0];
normals[normalsIndex + 1] = N10[1];
normals[normalsIndex + 2] = N10[2];
normalsIndex += 3;
// face 10; vertex[3] = C1; normals[3]=N10;
vertices[verticesIndex] = C1[0];
vertices[verticesIndex + 1] = C1[1];
vertices[verticesIndex + 2] = C1[2];
verticesIndex += 3;
normals[normalsIndex] = N10[0];
normals[normalsIndex + 1] = N10[1];
normals[normalsIndex + 2] = N10[2];
normalsIndex += 3;
// face 11; vertex[1] = B0; normals[1]=N11;
vertices[verticesIndex] = B0[0];
vertices[verticesIndex + 1] = B0[1];
vertices[verticesIndex + 2] = B0[2];
verticesIndex += 3;
normals[normalsIndex] = N11[0];
normals[normalsIndex + 1] = N11[1];
normals[normalsIndex + 2] = N11[2];
normalsIndex += 3;
// face 11; vertex[2] = C1; normals[2]=N11;
vertices[verticesIndex] = C1[0];
vertices[verticesIndex + 1] = C1[1];
vertices[verticesIndex + 2] = C1[2];
verticesIndex += 3;
normals[normalsIndex] = N11[0];
normals[normalsIndex + 1] = N11[1];
normals[normalsIndex + 2] = N11[2];
normalsIndex += 3;
// face 11; vertex[3] = A1; normals[3]=N11;
vertices[verticesIndex] = A1[0];
vertices[verticesIndex + 1] = A1[1];
vertices[verticesIndex + 2] = A1[2];
verticesIndex += 3;
normals[normalsIndex] = N11[0];
normals[normalsIndex + 1] = N11[1];
normals[normalsIndex + 2] = N11[2];
normalsIndex += 3;
// face 12; vertex[1] = C0; normals[1]=N12;
vertices[verticesIndex] = C0[0];
vertices[verticesIndex + 1] = C0[1];
vertices[verticesIndex + 2] = C0[2];
verticesIndex += 3;
normals[normalsIndex] = N12[0];
normals[normalsIndex + 1] = N12[1];
normals[normalsIndex + 2] = N12[2];
normalsIndex += 3;
// face 12; vertex[2] = C3; normals[2]=N12;
vertices[verticesIndex] = C3[0];
vertices[verticesIndex + 1] = C3[1];
vertices[verticesIndex + 2] = C3[2];
verticesIndex += 3;
normals[normalsIndex] = N12[0];
normals[normalsIndex + 1] = N12[1];
normals[normalsIndex + 2] = N12[2];
normalsIndex += 3;
// face 12; vertex[3] = A3; normals[3]=N12;
vertices[verticesIndex] = A3[0];
vertices[verticesIndex + 1] = A3[1];
vertices[verticesIndex + 2] = A3[2];
verticesIndex += 3;
normals[normalsIndex] = N12[0];
normals[normalsIndex + 1] = N12[1];
normals[normalsIndex + 2] = N12[2];
normalsIndex += 3;
// face 13; vertex[1] = A1; normals[1]=N13;
vertices[verticesIndex] = A1[0];
vertices[verticesIndex + 1] = A1[1];
vertices[verticesIndex + 2] = A1[2];
verticesIndex += 3;
normals[normalsIndex] = N13[0];
normals[normalsIndex + 1] = N13[1];
normals[normalsIndex + 2] = N13[2];
normalsIndex += 3;
// face 13; vertex[2] = C1; normals[2]=N13;
vertices[verticesIndex] = C1[0];
vertices[verticesIndex + 1] = C1[1];
vertices[verticesIndex + 2] = C1[2];
verticesIndex += 3;
normals[normalsIndex] = N13[0];
normals[normalsIndex + 1] = N13[1];
normals[normalsIndex + 2] = N13[2];
normalsIndex += 3;
// face 13; vertex[3] = C2; normals[3]=N13;
vertices[verticesIndex] = C2[0];
vertices[verticesIndex + 1] = C2[1];
vertices[verticesIndex + 2] = C2[2];
verticesIndex += 3;
normals[normalsIndex] = N13[0];
normals[normalsIndex + 1] = N13[1];
normals[normalsIndex + 2] = N13[2];
normalsIndex += 3;
// face 14; vertex[1] = A1; normals[1]=N14;
vertices[verticesIndex] = A1[0];
vertices[verticesIndex + 1] = A1[1];
vertices[verticesIndex + 2] = A1[2];
verticesIndex += 3;
normals[normalsIndex] = N14[0];
normals[normalsIndex + 1] = N14[1];
normals[normalsIndex + 2] = N14[2];
normalsIndex += 3;
// face 14; vertex[2] = C2; normals[2]=N14;
vertices[verticesIndex] = C2[0];
vertices[verticesIndex + 1] = C2[1];
vertices[verticesIndex + 2] = C2[2];
verticesIndex += 3;
normals[normalsIndex] = N14[0];
normals[normalsIndex + 1] = N14[1];
normals[normalsIndex + 2] = N14[2];
normalsIndex += 3;
// face 14; vertex[3] = B3; normals[3]=N14;
vertices[verticesIndex] = B3[0];
vertices[verticesIndex + 1] = B3[1];
vertices[verticesIndex + 2] = B3[2];
verticesIndex += 3;
normals[normalsIndex] = N14[0];
normals[normalsIndex + 1] = N14[1];
normals[normalsIndex + 2] = N14[2];
normalsIndex += 3;
// face 15; vertex[1] = C3; normals[1]=N15;
vertices[verticesIndex] = C3[0];
vertices[verticesIndex + 1] = C3[1];
vertices[verticesIndex + 2] = C3[2];
verticesIndex += 3;
normals[normalsIndex] = N15[0];
normals[normalsIndex + 1] = N15[1];
normals[normalsIndex + 2] = N15[2];
normalsIndex += 3;
// face 15; vertex[2] = B3; normals[2]=N15;
vertices[verticesIndex] = B3[0];
vertices[verticesIndex + 1] = B3[1];
vertices[verticesIndex + 2] = B3[2];
verticesIndex += 3;
normals[normalsIndex] = N15[0];
normals[normalsIndex + 1] = N15[1];
normals[normalsIndex + 2] = N15[2];
normalsIndex += 3;
// face 15; vertex[3] = B2; normals[3]=N15;
vertices[verticesIndex] = B2[0];
vertices[verticesIndex + 1] = B2[1];
vertices[verticesIndex + 2] = B2[2];
verticesIndex += 3;
normals[normalsIndex] = N15[0];
normals[normalsIndex + 1] = N15[1];
normals[normalsIndex + 2] = N15[2];
normalsIndex += 3;
// face 16; vertex[1] = C3; normals[1]=N16;
vertices[verticesIndex] = C3[0];
vertices[verticesIndex + 1] = C3[1];
vertices[verticesIndex + 2] = C3[2];
verticesIndex += 3;
normals[normalsIndex] = N16[0];
normals[normalsIndex + 1] = N16[1];
normals[normalsIndex + 2] = N16[2];
normalsIndex += 3;
// face 16; vertex[2] = B2; normals[2]=N16;
vertices[verticesIndex] = B2[0];
vertices[verticesIndex + 1] = B2[1];
vertices[verticesIndex + 2] = B2[2];
verticesIndex += 3;
normals[normalsIndex] = N16[0];
normals[normalsIndex + 1] = N16[1];
normals[normalsIndex + 2] = N16[2];
normalsIndex += 3;
// face 16; vertex[3] = A3; normals[3]=N16;
vertices[verticesIndex] = A3[0];
vertices[verticesIndex + 1] = A3[1];
vertices[verticesIndex + 2] = A3[2];
verticesIndex += 3;
normals[normalsIndex] = N16[0];
normals[normalsIndex + 1] = N16[1];
normals[normalsIndex + 2] = N16[2];
normalsIndex += 3;
// face 17; vertex[1] = B3; normals[1]=N17;
vertices[verticesIndex] = B3[0];
vertices[verticesIndex + 1] = B3[1];
vertices[verticesIndex + 2] = B3[2];
verticesIndex += 3;
normals[normalsIndex] = N17[0];
normals[normalsIndex + 1] = N17[1];
normals[normalsIndex + 2] = N17[2];
normalsIndex += 3;
// face 17; vertex[2] = C2; normals[2]=N17;
vertices[verticesIndex] = C2[0];
vertices[verticesIndex + 1] = C2[1];
vertices[verticesIndex + 2] = C2[2];
verticesIndex += 3;
normals[normalsIndex] = N17[0];
normals[normalsIndex + 1] = N17[1];
normals[normalsIndex + 2] = N17[2];
normalsIndex += 3;
// face 17; vertex[3] = B2; normals[1]=N17;
vertices[verticesIndex] = B2[0];
vertices[verticesIndex + 1] = B2[1];
vertices[verticesIndex + 2] = B2[2];
verticesIndex += 3;
normals[normalsIndex] = N17[0];
normals[normalsIndex + 1] = N17[1];
normals[normalsIndex + 2] = N17[2];
normalsIndex += 3;
// face 18; vertex[1] = C2; normals[1]=N18;
vertices[verticesIndex] = C2[0];
vertices[verticesIndex + 1] = C2[1];
vertices[verticesIndex + 2] = C2[2];
verticesIndex += 3;
normals[normalsIndex] = N18[0];
normals[normalsIndex + 1] = N18[1];
normals[normalsIndex + 2] = N18[2];
normalsIndex += 3;
// face 18; vertex[2] = C1; normals[2]=N18;
vertices[verticesIndex] = C1[0];
vertices[verticesIndex + 1] = C1[1];
vertices[verticesIndex + 2] = C1[2];
verticesIndex += 3;
normals[normalsIndex] = N18[0];
normals[normalsIndex + 1] = N18[1];
normals[normalsIndex + 2] = N18[2];
normalsIndex += 3;
// face 18; vertex[3] = A2; normals[3]=N18;
vertices[verticesIndex] = A2[0];
vertices[verticesIndex + 1] = A2[1];
vertices[verticesIndex + 2] = A2[2];
verticesIndex += 3;
normals[normalsIndex] = N18[0];
normals[normalsIndex + 1] = N18[1];
normals[normalsIndex + 2] = N18[2];
normalsIndex += 3;
// face 19; vertex[1] = C2; normals[1]=N19;
vertices[verticesIndex] = C2[0];
vertices[verticesIndex + 1] = C2[1];
vertices[verticesIndex + 2] = C2[2];
verticesIndex += 3;
normals[normalsIndex] = N19[0];
normals[normalsIndex + 1] = N19[1];
normals[normalsIndex + 2] = N19[2];
normalsIndex += 3;
// face 19; vertex[2] = A2; normals[2]=N19;
vertices[verticesIndex] = A2[0];
vertices[verticesIndex + 1] = A2[1];
vertices[verticesIndex + 2] = A2[2];
verticesIndex += 3;
normals[normalsIndex] = N19[0];
normals[normalsIndex + 1] = N19[1];
normals[normalsIndex + 2] = N19[2];
normalsIndex += 3;
// face 19; vertex[3] = B2; normals[3]=N19;
vertices[verticesIndex] = B2[0];
vertices[verticesIndex + 1] = B2[1];
vertices[verticesIndex + 2] = B2[2];
verticesIndex += 3;
normals[normalsIndex] = N19[0];
normals[normalsIndex + 1] = N19[1];
normals[normalsIndex + 2] = N19[2];
normalsIndex += 3;
// face 20; vertex[1] = A2; normals[1]=N20;
vertices[verticesIndex] = A2[0];
vertices[verticesIndex + 1] = A2[1];
vertices[verticesIndex + 2] = A2[2];
verticesIndex += 3;
normals[normalsIndex] = N20[0];
normals[normalsIndex + 1] = N20[1];
normals[normalsIndex + 2] = N20[2];
normalsIndex += 3;
// face 20; vertex[2] = A3; normals[2]=N20;
vertices[verticesIndex] = A3[0];
vertices[verticesIndex + 1] = A3[1];
vertices[verticesIndex + 2] = A3[2];
verticesIndex += 3;
normals[normalsIndex] = N20[0];
normals[normalsIndex + 1] = N20[1];
normals[normalsIndex + 2] = N20[2];
normalsIndex += 3;
// face 20; vertex[3] = B2; normals[3]=N20;
vertices[verticesIndex] = B2[0];
vertices[verticesIndex + 1] = B2[1];
vertices[verticesIndex + 2] = B2[2];
verticesIndex += 3;
normals[normalsIndex] = N20[0];
normals[normalsIndex + 1] = N20[1];
normals[normalsIndex + 2] = N20[2];
normalsIndex += 3;
for (int i = 0; i < numVertices; i++) indexes[i] = i;
InitBuffers();
}
|
El rectángulo utilizado como suelo se describe así.
#include "CGGround.h"
#include <GL/glew.h>
#include "CGFigure.h"
///
/// FUNCION: CGGround::CGGround(GLfloat l1, GLfloat l2)
///
/// PROPÓSITO: Construye un rectángulo de lados 2*l1 y 2*l2.
///
CGGround::CGGround(GLfloat l1, GLfloat l2)
{
numFaces = 2; // Number of faces
numVertices = 4; // Number of vertices
GLfloat p_vertices[4][3] = {
{ l1, 0.0f, l2 },
{ l1, 0.0f, -l2 },
{ -l1, 0.0f, -l2 },
{ -l1, 0.0f, l2 }
};
GLfloat p_normals[4][3] = {
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f }
};
GLushort p_indexes[2][3] = {
{ 0, 1, 2 },
{ 0, 2, 3 }
};
vertices = new GLfloat[numVertices * 3];
for (int i = 0; i < numVertices; i++)
for (int j = 0; j < 3; j++)
vertices[3 * i + j] = p_vertices[i][j];
normals = new GLfloat[numVertices * 3];
for (int i = 0; i < numVertices; i++)
for (int j = 0; j < 3; j++)
normals[3 * i + j] = p_normals[i][j];
indexes = new GLushort[numFaces * 3];
for (int i = 0; i < numFaces; i++)
for (int j = 0; j < 3; j++)
indexes[3 * i + j] = p_indexes[i][j];
InitBuffers();
}
|
|
|