Deforming a 3d Cube

Hey guys,

I’m trying to draw a 3D cube and then deform it using matrices. I’ve managed
to draw the cube, get it rotating, and even shear it. But I want to bend, twist,
and taper the object.

I know the matrix operations needed to do these, but I can’t figure out how
to execute it in code. My algorithm for twisting is

cos(theta(y)) 0 sin(theta(y)) 0
0 1 0 0
-sin(theta(y)) 0 cos(theta(y)) 0
0 0 0 1

times the vector containing x, y, z, w.

However I can’t figure out how to get the current vector for x, y, z, w
so that I can get the y value. I am assuming that I just use glMultMatrixf
to multiply the current matrix by the matrix mentioned about, right?
I used an array of vertices and glVertexPointer to feed these vertices
into glDrawArrays.

So I’ve figured out how to do it, I think. But I seem to have run into a problem.

Here is my program:


#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include<glm/glm.hpp>
#include <iostream>

#define WIDTH 600
#define HEIGHT 480
#define TIME_BETWEEN_TRANSFORMATIONS  7

using std::cerr;
using std::cout;
using glm::mat4;
using glm::vec4;

GLFWwindow* initializeWindow(const int width, const int height)
{
	//Initialize GLFW, and return NULL if glfwInit fails
	if (!glfwInit())
	{
		cerr << "Failed to initialize GLFW.
";
		return NULL;
	}

	//Sets glfwWindowHint vaules
	glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing

	GLFWwindow* window = glfwCreateWindow(width, height, "Assignment 1", NULL, NULL);

	if (window == NULL)
	{
		cerr << "Failed to create window.
";
		return NULL;
	}

	glfwMakeContextCurrent(window);

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glDisable(GL_CULL_FACE);
	glCullFace(GL_BACK);
	return window;

}

void drawCube()
{
	GLfloat vertices[] =
	{
		-1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1,
		1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1,
		-1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1,
		-1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1,
		-1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1,
		-1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1
	};

	GLfloat colors[] =
	{
		0.f, 0.5f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.f, 0.5f, 0.3f, 0.6f,
		1.f, 0.5f, 0.3f, 0.2f, 1.f, 0.6f, 0.f, 1.f, 1.f, 0.f, 0.9f, 0.1f,
		0.f, 0.f, 0.f, 0.1f, 0.9f, 1.f, 1.f, 1.f, 0.f, 0.5f, 0.6f, 0.f,
		0.6f, 0.5f, 0.6f, 0.8f, 0.9f, 0.2f, 0.3f, 0.2f, 1.f, 0.f, 0.8f, 0.f,
		0.f, 0.5f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.f, 0.5f, 0.3f, 0.6f,
		1.f, 0.5f, 0.3f, 1.f, 1.f, 1.f, 1.f, 0.7f, 1.f, 0.f, 0.9f, 0.1f
	};

	static float rotation = 0;

	glRotatef(rotation, 0.1f, 1.0f, 0.3f);

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_COLOR_ARRAY);
	glVertexPointer(4, GL_FLOAT, 0, vertices);
	glColorPointer(3, GL_FLOAT, 0, colors);

	glDrawArrays(GL_QUADS, 0, 24);

	glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
	rotation += 0.15f;
}

int transformationType(float currentTime, float rotateTime, float shearTime, float taperTime, float twistTime, float bendTime)
{
	if (currentTime < rotateTime) return 0;
	if (currentTime < shearTime) return 1;
	if (currentTime < taperTime) return 2;
	if (currentTime < twistTime) return 3;
	if (currentTime < bendTime) return 4;
	else return 0;
}

void drawShearedCube()
{
	GLfloat vertices[] =
	{
		-1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1,
		1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1,
		-1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1,
		-1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1,
		-1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1,
		-1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1
	};

	GLfloat colors[] =
	{
		0.f, 0.5f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.f, 0.5f, 0.3f, 0.6f,
		1.f, 0.5f, 0.3f, 0.2f, 1.f, 0.6f, 0.f, 1.f, 1.f, 0.f, 0.9f, 0.1f,
		0.f, 0.f, 0.f, 0.1f, 0.9f, 1.f, 1.f, 1.f, 0.f, 0.5f, 0.6f, 0.f,
		0.6f, 0.5f, 0.6f, 0.8f, 0.9f, 0.2f, 0.3f, 0.2f, 1.f, 0.f, 0.8f, 0.f,
		0.f, 0.5f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.f, 0.5f, 0.3f, 0.6f,
		1.f, 0.5f, 0.3f, 1.f, 1.f, 1.f, 1.f, 0.7f, 1.f, 0.f, 0.9f, 0.1f
	};

	static float rotation = 0;

	glRotatef(rotation, 0.1f, 1.0f, 0.3f);

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_COLOR_ARRAY);
	glVertexPointer(3, GL_FLOAT, 0, vertices);
	glColorPointer(3, GL_FLOAT, 0, colors);

	float m[] = {
		1, 0, 0, 0,
		.3, 1, 0, 0,
		0, 0, 1, 0,
		0, 0, 0, 1 };
	glMultMatrixf(m);

	glDrawArrays(GL_QUADS, 0, 24);

	glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
	rotation += 0.1f;
}

void drawTwistedCube()
{
	GLfloat vertices[] =
	{
		-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f,
		1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f,
		-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
		-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f,
		-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
		-1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f
	};

	GLfloat colors[] =
	{
		0.f, 0.5f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.f, 0.5f, 0.3f, 0.6f,
		1.f, 0.5f, 0.3f, 0.2f, 1.f, 0.6f, 0.f, 1.f, 1.f, 0.f, 0.9f, 0.1f,
		0.f, 0.f, 0.f, 0.1f, 0.9f, 1.f, 1.f, 1.f, 0.f, 0.5f, 0.6f, 0.f,
		0.6f, 0.5f, 0.6f, 0.8f, 0.9f, 0.2f, 0.3f, 0.2f, 1.f, 0.f, 0.8f, 0.f,
		0.f, 0.5f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.f, 0.5f, 0.3f, 0.6f,
		1.f, 0.5f, 0.3f, 1.f, 1.f, 1.f, 1.f, 0.7f, 1.f, 0.f, 0.9f, 0.1f
	};

	int i = 0;
	while (i < 71)
	{
		vec4 tempVector = vec4(vertices[i], vertices[i + 1], vertices[i + 2], vertices[i + 3]);
		mat4 twistMatrix = mat4(2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
		//mat4 twistMatrix = mat4(cos(.2*vertices[i + 1]), 0, sin(.2*vertices[i + 1]), 0, 0, 1, 0, 0, -sin(.2*vertices[i + 1]),
			//0, cos(.2*vertices[i + 1]), 0, 0, 0, 0, 1);
		
		tempVector = twistMatrix * tempVector;
		
		vertices[i] = tempVector[0];
		vertices[i + 1] = tempVector[1];
		vertices[i + 2] = tempVector[2];
		vertices[i + 3] = tempVector[3];


		i = i + 4;
	}

	cout << "START";
	for (int i = 0; i < 72; i++)
	{
		cout << vertices[i];
		if ((i % 4) == 3) cout << "
";
	}

	static float rotation = 0;

	glRotatef(rotation, 0.1f, 1.0f, 0.3f);

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_COLOR_ARRAY);
	glVertexPointer(4, GL_FLOAT, 0, vertices);
	glColorPointer(3, GL_FLOAT, 0, colors);

	glDrawArrays(GL_QUADS, 0, 24);

	glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
	rotation += 0.1f;
}

void display(GLFWwindow* window)
{
	//Sets up time variables
	float startTime, rotateTime, shearTime, taperTime, twistTime, bendTime;
	startTime = glfwGetTime();
	rotateTime = startTime + TIME_BETWEEN_TRANSFORMATIONS;
	shearTime = rotateTime + TIME_BETWEEN_TRANSFORMATIONS;
	taperTime = shearTime + TIME_BETWEEN_TRANSFORMATIONS;
	twistTime = taperTime + TIME_BETWEEN_TRANSFORMATIONS;
	bendTime = twistTime + TIME_BETWEEN_TRANSFORMATIONS;

	float translateValue = 0;

	while (!glfwWindowShouldClose(window))
	{
		// Scale to window size
		GLint windowWidth, windowHeight;
		glfwGetWindowSize(window, &windowWidth, &windowHeight);
		glViewport(0, 0, windowWidth, windowHeight);

		// Draw stuff
		glClearColor(0.0, 0.0, 0.0, 1.0);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		glMatrixMode(GL_PROJECTION_MATRIX);
		glLoadIdentity();
		gluPerspective(70, (double)windowWidth / (double)windowHeight, 0.1, 100);

		glMatrixMode(GL_MODELVIEW_MATRIX);
		glTranslatef(0, 0, translateValue);

		switch (transformationType(glfwGetTime(), rotateTime, shearTime, taperTime, twistTime, bendTime))
		{
		case 0:
			drawCube();
			break;
		case 1:
			drawTwistedCube();
			break;
		case 2:
			drawCube();
			break;
		case 3:
			drawCube();
			break;
		case 4:
			drawTwistedCube();
			break;
		}

		// Update Screen
		glfwSwapBuffers(window);

		// Check for any input, or window movement
		glfwPollEvents();

		if (translateValue > -5)
			translateValue -= 0.001f;
	}
}

int main()
{
	GLFWwindow* window = initializeWindow(WIDTH, HEIGHT);
	if (window != NULL)
	{
		display(window);
	}
	glfwDestroyWindow(window);
	glfwTerminate();
	return 0;
}

when I run drawTwistedCube() which, as it stands now should just scale the cube by a factor of 2,
it leaves 2 sides un-scaled and I can’t figure out why. Can anyone help me figure out why this is?

Thanks!

#faces * #vertices per face * #floats per vertex = 6 * 4 * 4 = 96
In other words: your loop bounds are too small and you are not transforming all positions.

Ooooh okay. Thanks. I turned the matrix into 4 points per vertex instead of 3 and forgot to increase the size of the loop accordingly.
One thing I don’t understand though, is the value placed in:


glDrawArrays(GL_QUADS, 0, 24);

I tried messing around with the value placed as the third argument and it seemed
to make little difference unless the number I provided was less than 24. But when
I changed my vertices to contain 4 numbers instead of 3, 24 was still sufficient.
Can anyone explain that to me? I tried reading the documentation and was still
confused afterwards.

Your cube has 24 vertices, independent of how many components the vectors to specify the positions have. Using a number larger than 24 means you are reading off the end of your arrays and just happen to be lucky that it does not crash/render garbage/melt your computer (the latter is a rare case though :wink: ) - still it’s a bug to tell OpenGL to render more vertices than you have data available for.

Ooh, that makes sense. Thanks!