327 lines
10 KiB
C++
327 lines
10 KiB
C++
#include "vboteapot.h"
|
|
#include "teapotdata.h"
|
|
|
|
#include <GL/glew.h>
|
|
#include <GL/gl.h>
|
|
#include <cstdio>
|
|
#include <glm/glm.hpp>
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
#include <glm/gtc/matrix_inverse.hpp>
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
#include <glm/gtc/constants.hpp>
|
|
|
|
|
|
|
|
|
|
//set grid = 64, lidTransform = 4x4 identity matrix
|
|
VBOTeapot::VBOTeapot(int grid, mat4 lidTransform)
|
|
{
|
|
int verts = 32 * (grid + 1) * (grid + 1);
|
|
faces = grid * grid * 32;
|
|
|
|
|
|
float * v = new float[ verts * 3 ]; //vertex positions : vec3
|
|
float * n = new float[ verts * 3 ]; //vertex normals : vec3
|
|
float * tc = new float[ verts * 2 ]; //texture coordinates : vec2 (we don't use it at this point)
|
|
unsigned int * el = new unsigned int[faces * 6]; //indices for IBO
|
|
|
|
generatePatches(v, n, tc, el, grid);
|
|
|
|
|
|
|
|
|
|
glGenVertexArrays(1, &VAO);
|
|
glBindVertexArray(VAO);
|
|
|
|
glGenBuffers(1, &VBO_position);
|
|
glBindBuffer(GL_ARRAY_BUFFER, VBO_position);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * verts, v, GL_STATIC_DRAW);
|
|
|
|
glVertexAttribPointer(
|
|
0, //attr number = 0
|
|
3,
|
|
GL_FLOAT,
|
|
GL_FALSE,
|
|
0,
|
|
(void*)0);
|
|
glEnableVertexAttribArray(0); //attr number = 0
|
|
|
|
glGenBuffers(1, &VBO_normal);
|
|
glBindBuffer(GL_ARRAY_BUFFER, VBO_normal);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * verts, n, GL_STATIC_DRAW);
|
|
|
|
glVertexAttribPointer(
|
|
1,
|
|
3,
|
|
GL_FLOAT,
|
|
GL_FALSE,
|
|
0,
|
|
(void*)0);
|
|
glEnableVertexAttribArray(1);
|
|
|
|
glGenBuffers(1, &VBO_tex);
|
|
glBindBuffer(GL_ARRAY_BUFFER, VBO_tex);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 2 * verts, tc, GL_STATIC_DRAW);
|
|
|
|
glVertexAttribPointer(
|
|
2,
|
|
3,
|
|
GL_FLOAT,
|
|
GL_FALSE,
|
|
0,
|
|
(void*)0);
|
|
glEnableVertexAttribArray(2);
|
|
|
|
|
|
glGenBuffers(1, &IBO);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, faces * 6 * sizeof(GLuint), el, GL_STATIC_DRAW);
|
|
|
|
glBindVertexArray(0);
|
|
|
|
|
|
delete [] v;
|
|
delete [] n;
|
|
delete [] el;
|
|
delete [] tc;
|
|
|
|
|
|
}
|
|
|
|
void VBOTeapot::draw(ShaderProgram * shader, glm::mat4x4 proj_matrix, glm::mat4x4 view_matrix)
|
|
{
|
|
_model.glPushMatrix();
|
|
effectTransformations();
|
|
glBindVertexArray(VAO);
|
|
glm::mat4 mvpMatrix = proj_matrix * view_matrix * _model.getMatrix();
|
|
glUniformMatrix4fv(shader->uniform("mvp"), 1, GL_FALSE, glm::value_ptr(mvpMatrix));
|
|
glm::mat4 modelview = view_matrix * _model.getMatrix();
|
|
glUniform4fv(shader->uniform("LightLocation"), 1, glm::value_ptr(view_matrix * glm::vec4(50, 50, 50, 1)));
|
|
glUniformMatrix4fv(shader->uniform("ModelViewMatrix"), 1, GL_FALSE, glm::value_ptr(modelview));
|
|
glm::mat4 inverseModelView = glm::inverse(modelview);
|
|
glm::mat3 normalMatrix = glm::mat3(glm::transpose(inverseModelView));
|
|
glUniformMatrix3fv(shader->uniform("NormalMatrix"), 1, GL_FALSE, glm::value_ptr(normalMatrix));
|
|
|
|
int size;
|
|
glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
|
|
glDrawElements(GL_TRIANGLES, size / sizeof(GLuint), GL_UNSIGNED_INT, 0);
|
|
|
|
_model.glPopMatrix();
|
|
|
|
}
|
|
|
|
DrawableType VBOTeapot::getType()
|
|
{
|
|
return DrawableType::TEAPOT;
|
|
}
|
|
|
|
void VBOTeapot::generatePatches(float * v, float * n, float * tc, unsigned int* el, int grid) {
|
|
float * B = new float[4*(grid+1)]; // Pre-computed Bernstein basis functions
|
|
float * dB = new float[4*(grid+1)]; // Pre-computed derivitives of basis functions
|
|
|
|
int idx = 0, elIndex = 0, tcIndex = 0;
|
|
|
|
// Pre-compute the basis functions (Bernstein polynomials)
|
|
// and their derivatives
|
|
computeBasisFunctions(B, dB, grid);
|
|
|
|
// Build each patch
|
|
// The rim
|
|
buildPatchReflect(0, B, dB, v, n, tc, el, idx, elIndex, tcIndex, grid, true, true);
|
|
// The body
|
|
buildPatchReflect(1, B, dB, v, n, tc, el, idx, elIndex, tcIndex, grid, true, true);
|
|
buildPatchReflect(2, B, dB, v, n, tc, el, idx, elIndex, tcIndex, grid, true, true);
|
|
// The lid
|
|
buildPatchReflect(3, B, dB, v, n, tc, el, idx, elIndex, tcIndex, grid, true, true);
|
|
buildPatchReflect(4, B, dB, v, n, tc, el, idx, elIndex, tcIndex, grid, true, true);
|
|
// The bottom
|
|
buildPatchReflect(5, B, dB, v, n, tc, el, idx, elIndex, tcIndex, grid, true, true);
|
|
// The handle
|
|
buildPatchReflect(6, B, dB, v, n, tc, el, idx, elIndex, tcIndex, grid, false, true);
|
|
buildPatchReflect(7, B, dB, v, n, tc, el, idx, elIndex, tcIndex, grid, false, true);
|
|
// The spout
|
|
buildPatchReflect(8, B, dB, v, n, tc, el, idx, elIndex, tcIndex, grid, false, true);
|
|
buildPatchReflect(9, B, dB, v, n, tc, el, idx, elIndex, tcIndex, grid, false, true);
|
|
|
|
delete [] B;
|
|
delete [] dB;
|
|
}
|
|
|
|
void VBOTeapot::moveLid(int grid, float *v, mat4 lidTransform) {
|
|
|
|
int start = 3 * 12 * (grid+1) * (grid+1);
|
|
int end = 3 * 20 * (grid+1) * (grid+1);
|
|
|
|
for( int i = start; i < end; i+=3 )
|
|
{
|
|
vec4 vert = vec4(v[i], v[i+1], v[i+2], 1.0f );
|
|
vert = lidTransform * vert;
|
|
v[i] = vert.x;
|
|
v[i+1] = vert.y;
|
|
v[i+2] = vert.z;
|
|
}
|
|
}
|
|
|
|
void VBOTeapot::buildPatchReflect(int patchNum,
|
|
float *B, float *dB,
|
|
float *v, float *n,
|
|
float *tc, unsigned int *el,
|
|
int &index, int &elIndex, int &tcIndex, int grid,
|
|
bool reflectX, bool reflectY)
|
|
{
|
|
vec3 patch[4][4];
|
|
vec3 patchRevV[4][4];
|
|
getPatch(patchNum, patch, false);
|
|
getPatch(patchNum, patchRevV, true);
|
|
|
|
// Patch without modification
|
|
buildPatch(patch, B, dB, v, n, tc, el,
|
|
index, elIndex, tcIndex, grid, mat3(1.0f), true);
|
|
|
|
// Patch reflected in x
|
|
if( reflectX ) {
|
|
buildPatch(patchRevV, B, dB, v, n, tc, el,
|
|
index, elIndex, tcIndex, grid, mat3(vec3(-1.0f, 0.0f, 0.0f),
|
|
vec3(0.0f, 1.0f, 0.0f),
|
|
vec3(0.0f, 0.0f, 1.0f) ), false );
|
|
}
|
|
|
|
// Patch reflected in y
|
|
if( reflectY ) {
|
|
buildPatch(patchRevV, B, dB, v, n, tc, el,
|
|
index, elIndex, tcIndex, grid, mat3(vec3(1.0f, 0.0f, 0.0f),
|
|
vec3(0.0f, -1.0f, 0.0f),
|
|
vec3(0.0f, 0.0f, 1.0f) ), false );
|
|
}
|
|
|
|
// Patch reflected in x and y
|
|
if( reflectX && reflectY ) {
|
|
buildPatch(patch, B, dB, v, n, tc, el,
|
|
index, elIndex, tcIndex, grid, mat3(vec3(-1.0f, 0.0f, 0.0f),
|
|
vec3(0.0f, -1.0f, 0.0f),
|
|
vec3(0.0f, 0.0f, 1.0f) ), true );
|
|
}
|
|
}
|
|
|
|
void VBOTeapot::buildPatch(vec3 patch[][4],
|
|
float *B, float *dB,
|
|
float *v, float *n, float *tc,
|
|
unsigned int *el,
|
|
int &index, int &elIndex, int &tcIndex, int grid, mat3 reflect,
|
|
bool invertNormal)
|
|
{
|
|
int startIndex = index / 3;
|
|
float tcFactor = 1.0f / grid;
|
|
|
|
for( int i = 0; i <= grid; i++ )
|
|
{
|
|
for( int j = 0 ; j <= grid; j++)
|
|
{
|
|
vec3 pt = reflect * evaluate(i,j,B,patch);
|
|
vec3 norm = reflect * evaluateNormal(i,j,B,dB,patch);
|
|
if( invertNormal )
|
|
norm = -norm;
|
|
|
|
v[index] = pt.x;
|
|
v[index+1] = pt.y;
|
|
v[index+2] = pt.z;
|
|
|
|
n[index] = norm.x;
|
|
n[index+1] = norm.y;
|
|
n[index+2] = norm.z;
|
|
|
|
tc[tcIndex] = i * tcFactor;
|
|
tc[tcIndex+1] = j * tcFactor;
|
|
|
|
index += 3;
|
|
tcIndex += 2;
|
|
}
|
|
}
|
|
|
|
for( int i = 0; i < grid; i++ )
|
|
{
|
|
int iStart = i * (grid+1) + startIndex;
|
|
int nextiStart = (i+1) * (grid+1) + startIndex;
|
|
for( int j = 0; j < grid; j++)
|
|
{
|
|
el[elIndex] = iStart + j;
|
|
el[elIndex+1] = nextiStart + j + 1;
|
|
el[elIndex+2] = nextiStart + j;
|
|
|
|
el[elIndex+3] = iStart + j;
|
|
el[elIndex+4] = iStart + j + 1;
|
|
el[elIndex+5] = nextiStart + j + 1;
|
|
|
|
elIndex += 6;
|
|
}
|
|
}
|
|
}
|
|
|
|
void VBOTeapot::getPatch( int patchNum, vec3 patch[][4], bool reverseV )
|
|
{
|
|
for( int u = 0; u < 4; u++) { // Loop in u direction
|
|
for( int v = 0; v < 4; v++ ) { // Loop in v direction
|
|
if( reverseV ) {
|
|
patch[u][v] = vec3(
|
|
Teapot::cpdata[Teapot::patchdata[patchNum][u*4+(3-v)]][0],
|
|
Teapot::cpdata[Teapot::patchdata[patchNum][u*4+(3-v)]][1],
|
|
Teapot::cpdata[Teapot::patchdata[patchNum][u*4+(3-v)]][2]
|
|
);
|
|
} else {
|
|
patch[u][v] = vec3(
|
|
Teapot::cpdata[Teapot::patchdata[patchNum][u*4+v]][0],
|
|
Teapot::cpdata[Teapot::patchdata[patchNum][u*4+v]][1],
|
|
Teapot::cpdata[Teapot::patchdata[patchNum][u*4+v]][2]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void VBOTeapot::computeBasisFunctions( float * B, float * dB, int grid ) {
|
|
float inc = 1.0f / grid;
|
|
for( int i = 0; i <= grid; i++ )
|
|
{
|
|
float t = i * inc;
|
|
float tSqr = t * t;
|
|
float oneMinusT = (1.0f - t);
|
|
float oneMinusT2 = oneMinusT * oneMinusT;
|
|
|
|
B[i*4 + 0] = oneMinusT * oneMinusT2;
|
|
B[i*4 + 1] = 3.0f * oneMinusT2 * t;
|
|
B[i*4 + 2] = 3.0f * oneMinusT * tSqr;
|
|
B[i*4 + 3] = t * tSqr;
|
|
|
|
dB[i*4 + 0] = -3.0f * oneMinusT2;
|
|
dB[i*4 + 1] = -6.0f * t * oneMinusT + 3.0f * oneMinusT2;
|
|
dB[i*4 + 2] = -3.0f * tSqr + 6.0f * t * oneMinusT;
|
|
dB[i*4 + 3] = 3.0f * tSqr;
|
|
}
|
|
}
|
|
|
|
|
|
vec3 VBOTeapot::evaluate( int gridU, int gridV, float *B, vec3 patch[][4] )
|
|
{
|
|
vec3 p(0.0f,0.0f,0.0f);
|
|
for( int i = 0; i < 4; i++) {
|
|
for( int j = 0; j < 4; j++) {
|
|
p += patch[i][j] * B[gridU*4+i] * B[gridV*4+j];
|
|
}
|
|
}
|
|
return p;
|
|
}
|
|
|
|
vec3 VBOTeapot::evaluateNormal( int gridU, int gridV, float *B, float *dB, vec3 patch[][4] )
|
|
{
|
|
vec3 du(0.0f,0.0f,0.0f);
|
|
vec3 dv(0.0f,0.0f,0.0f);
|
|
|
|
for( int i = 0; i < 4; i++) {
|
|
for( int j = 0; j < 4; j++) {
|
|
du += patch[i][j] * dB[gridU*4+i] * B[gridV*4+j];
|
|
dv += patch[i][j] * B[gridU*4+i] * dB[gridV*4+j];
|
|
}
|
|
}
|
|
return glm::normalize( glm::cross( du, dv ) );
|
|
}
|