Opengl 3d player movement - c++

I need to make a simple game, and I ran into a little problem. I have a camera class with keyboard input, but now I'm trying to make a player class which will draw the "player" (in my case it's a box for now) and then monitor keyboard input. And the whole problem is that I don't understand at all how to make this box move because it has a lot of coordinates...
At the moment the camera file looks like this:
void Camera::Matrix(float FOVdeg, float nearPlane, float farPlane, Shader& shader, const char* uniform)
{
glm::mat4 view = glm::mat4(1.0f);
glm::mat4 projection = glm::mat4(1.0f);
view = glm::lookAt(Position, Position + Orientation, Up);
projection = glm::perspective(glm::radians(FOVdeg), (float)(width / height), nearPlane, farPlane);
glUniformMatrix4fv(glGetUniformLocation(shader.ID, uniform), 1, GL_FALSE, glm::value_ptr(projection * view));
}
void Camera::Inputs(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
{
Position += speed * Orientation;
}
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
{
Position += speed * -glm::normalize(glm::cross(Orientation, Up));
}
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
{
Position += speed * -Orientation;
}
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
{
Position += speed * glm::normalize(glm::cross(Orientation, Up));
}
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
{
Position += speed * Up;
}
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
{
Position += speed * -Up;
}
}
Player file:
GLfloat Vertices[] =
{ // COORDINATES / COLORS / TexCoord
0.1f, 1.0f, -0.1f, 0.83f, 0.70f, 0.44f, 0.3f, 0.0f, // 0
0.1f, 1.0f, -0.9f, 0.83f, 0.70f, 0.44f, 1.0f, 1.0f, // 1
0.9f, 1.0f, -0.9f, 0.83f, 0.70f, 0.44f, 1.0f, 0.0f, // 2
0.9f, 1.0f, -0.1f, 0.83f, 0.70f, 0.44f, 0.0f, 0.0f, // 3
0.1f, 2.8f, -0.1f, 0.83f, 0.70f, 0.44f, 0.0f, 0.0f, // 4
0.1f, 2.8f, -0.9f, 0.83f, 0.70f, 0.44f, 1.0f, 0.0f, // 5
0.9f, 2.8f, -0.9f, 0.83f, 0.70f, 0.44f, 1.0f, 1.0f, // 6
0.9f, 2.8f, -0.1f, 0.83f, 0.70f, 0.44f, 0.0f, 1.0f, // 7
};
GLuint Indices[] =
{
0, 1, 2,
2, 3, 0,
4, 5, 6,
6, 7, 4,
0, 4, 1,
1, 5, 4,
1, 5, 2,
2, 6, 5,
2, 6, 3,
3, 7, 6,
3, 7, 0,
0, 4, 7,
};
void Player::Initialization()
{
VAO2.Bind();
VBO VBO2(Vertices, sizeof(Vertices));
EBO EBO2(Indices, sizeof(Indices));
VAO2.LinkAttrib(VBO2, 0, 3, GL_FLOAT, 8 * sizeof(float), (void*)0);
VAO2.LinkAttrib(VBO2, 1, 3, GL_FLOAT, 8 * sizeof(float), (void*)(3 * sizeof(float)));
VAO2.LinkAttrib(VBO2, 2, 2, GL_FLOAT, 8 * sizeof(float), (void*)(6 * sizeof(float)));
VAO2.Unbind();
VBO2.Unbind();
EBO2.Unbind();
glEnable(GL_DEPTH_TEST);
}
void Player::PlayerDraw()
{
VAO2.Bind();
glDrawElements(GL_TRIANGLES, sizeof(Indices) / sizeof(int), GL_UNSIGNED_INT, 0);
}

Related

What is causing this cube to not render?

When running the program, the camera seems to work fine and I can manipulate the clear colour but the cube itself will not render.
Here's my code:
(The camera and renderer objects are both declared in their respective header files along with their methods)
Main.cpp
#include <GL/glew.h>
#include "Shapes.h"
#include "Renderer.h"
#include "Camera.h"
int main()
{
Renderer* renderer = new Renderer(800, 800, (const char*)"OpenGL Sample Test", glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
GLFWwindow* window = renderer->getWindow();
Block* cube = new Block(renderer);
cube->setColourTint(glm::vec4(0.3f, 0.0f, 0.4f, 1.0f));
while (!glfwWindowShouldClose(window))
{
renderer->updateRender();
cube->rotate((float)glfwGetTime() * glm::radians(50.0f), glm::vec3(0.5f, 0.5f, 0.0f));
}
delete renderer;
return 0;
}
Renderer.cpp
#include "Renderer.h"
#include "Shapes.h"
Renderer::Renderer(int Window_X, int Window_Y, const char* Window_Title, glm::vec4 ClearColour)
{
Renderer::renderList = new std::vector<Shape*>;
Renderer::clearColour = ClearColour;
Renderer::WINDOW_X = Window_X;
Renderer::WINDOW_Y = Window_Y;
Renderer::WINDOW_TITLE = Window_Title;
createWindow();
std::cout << "Running OpenGL extension checks... ";
GLenum glewTest = glewInit();
if (GLEW_OK != glewTest)
{
std::cout << "FAILED";
std::cout << (const char*)glewGetErrorString(glewTest) << std::endl;
glfwDestroyWindow(window);
}
else
{
std::cout << "OK" << std::endl;
glfwMakeContextCurrent(window);
}
//OPENGL//
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, Window_X, Window_Y);
Renderer::shader = new Shader("Vertex.glsl", "Fragment.glsl"); //Create the shaders
Renderer::camera = new Camera(Window_X, Window_Y, glm::vec3(0.0f, 0.0f, 2.0f));
Renderer::modelMatrixShaderLocation = glGetUniformLocation(shader->ID, "model"); //Grab the name of the uniform of the model matrix
Renderer::fragmentColourTintLocation = glGetUniformLocation(shader->ID, "colourTint");
glCheckError();
}
void Renderer::createWindow()
{
//Define OpenGL Version | Create Window
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
std::cout << "Creating GLFW Window... ";
Renderer::window = glfwCreateWindow(WINDOW_X, WINDOW_Y, WINDOW_TITLE, NULL, NULL);
if (window == NULL)
{
std::cout << "ERROR: GLFW WINDOW FAILED TO INSTANTIATE" << std::endl;
glfwTerminate();
}
else
{
std::cout << "OK" << std::endl;
glfwMakeContextCurrent(window);
//Key Callbacks
glfwSetKeyCallback(window, key_callback);
glfwSetWindowCloseCallback(window, close_callback);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
}
}
bool Renderer::updateRender()
{
glClearColor(clearColour.r, clearColour.g, clearColour.b, clearColour.a); //Add background color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Clear the color and depth back buffers
shader->use(); //Bind to the shader program
for (int i = 0; i < renderList->size(); i++)
{
Shape* current = renderList->at(i);
current->clearMatrix();
}
//Refresh the projection matrix
//projection = glm::mat4(1.0f);
//projection = glm::perspective(glm::radians(45.0f), (float)WINDOW_X / (float)WINDOW_Y, 0.1f, 100.0f);
//shader->setMat4("projection", projection);
glCheckError();
for (int i = 0; i < renderList->size(); i++) //Update matrix of each renderable object
{
Shape* current = renderList->at(i);
glUniformMatrix4fv(modelMatrixShaderLocation, 1, GL_FALSE, glm::value_ptr(current->getPosition()));
glUniform4f(fragmentColourTintLocation, current->getColourTint().r, current->getColourTint().g, current->getColourTint().b, current->getColourTint().a);
glBindVertexArray(current->getVAO());
std::cout << "Drawing: " << current << " : " << current->getVAO() << std::endl;
glDrawElements(GL_TRIANGLES, current->getIndicesStride(), GL_UNSIGNED_INT, 0);
glCheckError();
}
camera->Inputs(window); //Process camera input
//Camera Matrix updating
camera->Matrix(45.0f, 0.1f, 100.0f, shader, "camMatrix");
glfwSwapBuffers(window);
glfwPollEvents();
if (glCheckError() != NULL)
{
return true;
}
else
{
return false;
}
}
Renderer::~Renderer()
{
for (int i = 0; i < renderList->size(); i++)
{
Shape* current = renderList->at(i);
glDeleteVertexArrays(1, current->getVAOAddress());
glDeleteBuffers(1, current->getVBOAddress());
glDeleteBuffers(1, current->getEBOAddress());
delete current;
}
glfwDestroyWindow(window);
glfwTerminate();
glDeleteProgram(shader->ID);
delete renderList;
delete shader;
delete camera;
}
GLFWwindow* Renderer::getWindow()
{
return window;
}
void Renderer::push_Renderer(Shape* Renderable_Object)
{
renderList->push_back(Renderable_Object);
}
void Renderer::updateClearColour(glm::vec4 ClearColour)
{
clearColour = ClearColour;
}
Camera.cpp
#include "Camera.h"
Camera::Camera(int width, int height, glm::vec3 position)
{
Camera::width = width;
Camera::height = height;
Position = position;
}
void Camera::Matrix(float FOVdeg, float nearPlane, float farPlane, Shader* shader, const char* uniform)
{
//Matrix Magic
glm::mat4 view = glm::mat4(1.0f);
glm::mat4 projection = glm::mat4(1.0f);
view = glm::lookAt(Position, Position + Orientation, Up);
projection = glm::perspective(glm::radians(FOVdeg), (float)(width / height), nearPlane, farPlane);
//std::cout << "XYZ: " << Position.x << " : " << Position.y << " : " << Position.z << std::endl;
glUniformMatrix4fv(glGetUniformLocation(shader->ID, uniform), 1, GL_FALSE, glm::value_ptr(projection * view));
}
void Camera::Inputs(GLFWwindow* window)
{
//Basic Camera Controls
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
{
Position += speed * Orientation;
}
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
{
Position += speed * -glm::normalize(glm::cross(Orientation, Up));
}
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
{
Position += speed * -Orientation;
}
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
{
Position += speed * glm::normalize(glm::cross(Orientation, Up));
}
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
{
Position += speed * Up;
}
if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS)
{
Position += speed * -Up;
}
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
{
speed = 0.4f;
}
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_RELEASE)
{
speed = 0.1f;
}
//Mouse Control
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) //Hide cursor when left mouse button is pressed
{
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
double MouseX;
double MouseY;
glfwGetCursorPos(window, &MouseX, &MouseY);
float rotX = sensitivity * (float)(MouseY - (height / 2)) / height;
float rotY = sensitivity * (float)(MouseX - (height / 2)) / height;
glm::vec3 newOrientation = glm::rotate(Orientation, glm::radians(-rotX), glm::normalize(glm::cross(Orientation, Up)));
if (!((glm::angle(newOrientation, Up) <= glm::radians(5.0f)) or (glm::angle(newOrientation, -Up) <= glm::radians(5.0f))))
{
Orientation = newOrientation;
}
Orientation = glm::rotate(Orientation, glm::radians(-rotY), Up);
glfwSetCursorPos(window, (width / 2), (height / 2));
}
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE) //Show cursor when left mouse button is released
{
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
}
Shapes.h
#pragma once
#ifndef SHAPES_H
#define SHAPES_H
#include "Renderer.h"
#include <GL/glew.h>
#include <glm.hpp>
#include <gtc/type_ptr.hpp>
#include <gtx/rotate_vector.hpp>
#include <gtx/vector_angle.hpp>
inline void GeneralVao(GLuint &VAO, GLuint &VBO, GLuint &EBO, GLint* indices, GLfloat* vertices, GLsizeiptr sizeofidef, GLsizeiptr sizeofvdef)
{
//bind the Vertex Array Object first, then bind and set vertex buffer, and then configure vertex attributes(s).
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
//EBO
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeofidef, indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeofvdef, vertices, GL_STATIC_DRAW);
//Position Attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);
//Colour Attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
//unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
class Shape
{
protected:
GLfloat* vertices = NULL;
GLint* indices = NULL;
virtual void constructVao() = 0;
GLuint VAO = NULL, VBO = NULL, EBO = NULL;
glm::mat4 ModelMatrix = glm::mat4(1.0f);
glm::vec4 colourTint = glm::vec4(1.0f);
public:
GLuint getVAO()
{
return VAO;
}
glm::vec4 getColourTint()
{
return colourTint;
}
void setColourTint(glm::vec4 Colour)
{
colourTint = Colour;
}
//Addresses
GLuint* getVAOAddress()
{
return &VAO;
}
GLuint* getVBOAddress()
{
return &VBO;
}
GLuint* getEBOAddress()
{
return &EBO;
}
//
void setPosition(glm::mat4 Matrix)
{
ModelMatrix = Matrix;
}
void rotate(glm::f32 angle, glm::vec3 axis) //Rotates by an angle (floating point) and an axis (vector3)
{
ModelMatrix = glm::rotate(ModelMatrix, angle, axis);
}
void scale(glm::vec3 ScaleFactor3)
{
ModelMatrix = glm::scale(ModelMatrix, ScaleFactor3);
}
void move(glm::vec3 Vector)
{
ModelMatrix = glm::translate(ModelMatrix, Vector);
}
void clearMatrix()
{
ModelMatrix = glm::mat4(1.0f);
}
virtual GLsizei getIndicesStride() = 0;
glm::mat4 getPosition()
{
return ModelMatrix;
}
virtual ~Shape()
{
}
};
class Pyramid : public Shape
{
private:
GLfloat vdef[30] = {
//Position Colour
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, //Front Bottom Left | 0
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, //Front Bottom Right | 1
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, //Back Bottom Left | 2
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, //Back Bottom Right | 3
0.0f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f //Top | 4
};
GLint idef[18] = {
//Bottom
0, 2, 3,
3, 1, 0,
//Front
1, 4, 0 ,
//Left
0, 4, 2,
//Right
1, 4, 3,
//Back
3, 4, 2
};
public:
Pyramid(Renderer* renderer)
{
indices = idef;
vertices = vdef;
constructVao();
renderer->push_Renderer(this);
}
void constructVao()
{
GeneralVao(VAO, VBO, EBO, idef, vdef, sizeof(idef), sizeof(vdef));
}
GLsizei getIndicesStride()
{
return sizeof(idef) / sizeof(GLint);
}
virtual ~Pyramid()
{
}
};
class Block : public Shape
{
private:
GLfloat vdef[48] = {
//Position Colour
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, //Front Bottom Left | 0
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, //Front Bottom Right | 1
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, //Back Bottom Left | 2
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, //Back Bottom Right | 3
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, //Front Top Left | 4
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, //Front Top Right | 5
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, //Back Top Left | 6
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, //Back Top Right | 7
};
GLint idef[36] = {
//Bottom
0, 1, 3,
3, 2, 0,
//Front
1, 0, 4,
4, 5, 1,
//Left
0, 2, 6,
6, 4, 0,
//Right
1, 3, 7,
7, 5, 1,
//Top
4, 5, 7,
7, 6, 4,
//Back
2, 3, 5,
5, 5, 2
};
public:
Block(Renderer* renderer)
{
indices = idef;
vertices = vdef;
setColourTint(glm::vec4(0.3, 0.0, 1.0, 1.0));
constructVao();
renderer->push_Renderer(this);
}
void constructVao()
{
GeneralVao(VAO, VBO, EBO, idef, vdef, (GLsizeiptr)sizeof(idef), (GLsizeiptr)sizeof(vdef));
}
GLsizei getIndicesStride()
{
return sizeof(idef) / sizeof(GLint);
}
virtual ~Block()
{
}
};
#endif
Vertex.glsl
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
uniform mat4 model;
uniform mat4 camMatrix;
out vec3 ourColor;
void main()
{
gl_Position = camMatrix * model * vec4(aPos, 1.0);
ourColor = aColor;
}
Fragment.glsl
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
uniform vec4 colourTint;
void main()
{
FragColor.a = colourTint.a;
FragColor.rgb = ((FragColor.rgb - colourTint.rgb) / FragColor.rgb) * 100;
}
I found the issue.
Turns out it worked, just the cube was unexpectedly black along with the clearcolor.

Blank screen when running and no errors

Ran the code and no errors. A blank screen appear. Can't see where I went wrong after I edited this section of the code.
Trying to integrate a planet system of 4 planets and 1 sun. The program was running and showing the system, but once I edited this section of the code. It became blank screen.
planetsystem.cpp
#include <string>
using namespace std; // to avoid having to use std::
#define GLEW_STATIC // include GLEW as a static library
#include <GLEW/glew.h> // include GLEW
#include <GLFW/glfw3.h> // include GLFW (which includes the OpenGL header)
#include <glm/glm.hpp> // include GLM (ideally should only use the GLM headers that are actually used)
#include <glm/gtx/transform.hpp>
using namespace glm; // to avoid having to use glm::
#include "shader.h"
#include "camera.h"
#define PI 3.14159265
#define MAX_SLICES 50
#define MIN_SLICES 8
#define MAX_VERTICES (MAX_SLICES+2)*3 // a triangle fan should have a minimum of 3 vertices
#define CIRCLE_RADIUS 3.0
#define WINDOW_WIDTH 1000
#define WINDOW_HEIGHT 1000
// struct for vertex attributes
struct Vertex
{
GLfloat position[3];
GLfloat color[3];
};
// global variables
GLfloat g_vertices_circle[MAX_VERTICES] = {
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f
};
GLfloat g_colors_circle[MAX_VERTICES] = {
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f
};
GLuint g_slices = MAX_SLICES; // number of circle slices
Vertex g_vertices[] = {
// vertex 1
-0.5f, 0.5f, 0.5f, // position
1.0f, 0.0f, 1.0f, // colour
// vertex 2
-0.5f, -0.5f, 0.5f, // position
1.0f, 0.0f, 0.0f, // colour
// vertex 3
0.5f, 0.5f, 0.5f, // position
1.0f, 1.0f, 1.0f, // colour
// vertex 4
0.5f, -0.5f, 0.5f, // position
1.0f, 1.0f, 0.0f, // colour
// vertex 5
-0.5f, 0.5f, -0.5f, // position
0.0f, 0.0f, 1.0f, // colour
// vertex 6
-0.5f, -0.5f, -0.5f,// position
0.0f, 0.0f, 0.0f, // colour
// vertex 7
0.5f, 0.5f, -0.5f, // position
0.0f, 1.0f, 1.0f, // colour
// vertex 8
0.5f, -0.5f, -0.5f, // position
0.0f, 1.0f, 0.0f, // colour
};
GLuint g_indices[] = {
0, 1, 2, // triangle 1
2, 1, 3, // triangle 2
4, 5, 0, // triangle 3
0, 5, 1, // ...
2, 3, 6,
6, 3, 7,
4, 0, 6,
6, 0, 2,
1, 5, 3,
3, 5, 7,
5, 4, 7,
7, 4, 6, // triangle 12
};
GLuint g_IBO = 0; // index buffer object identifier
GLuint g_VBO[3]; // vertex buffer object identifier
GLuint g_VAO[2]; // vertex array object identifier
GLuint g_shaderProgramID = 0; // shader program identifier
GLuint g_MVP_Index = 0; // location in shader
GLuint g_alphaIndex; // for transparency of 4th planet
glm::mat4 g_modelMatrix[5]; // planets object model matrices
glm::mat4 g_modelMatrixCircle[5];// circle model matrices
glm::mat4 g_modelMatrixSubPlanets[5];// object matrices for sub-planets (moon, disc etc)
glm::mat4 g_viewMatrix; // view matrix
glm::mat4 g_projectionMatrix; // projection matrix
Camera g_camera; // camera
float g_orbitSpeed[5] = { 0.3f, 0.5f, 0.4f, 0.2f, 0.1f }; // for speed of rotation around sun
float g_rotationSpeed[5] = { 0.07f, 0.7f, 3.0f, 5.0f, 1.0f }; // for speed of rotation on own axis
float g_scaleSize[5] = { 0.5f, 0.5f, 0.5f, 0.5f, 0.5f }; // for scaling the orbiting planets
float g_axisOfRotation[5] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, }; // for offsetting the axis of rotation
float g_alpha = 0.5f; // transparency of 4th planet
bool g_enableAnimation = true;
void generate_circle()
{
float angle = PI * 2 / static_cast<float>(g_slices); // used to generate x and y coordinates
float scale_factor = static_cast<float>(WINDOW_HEIGHT) / WINDOW_WIDTH; // scale to make it a circle instead of an elipse
int index = 0; // vertex index
g_vertices_circle[3] = CIRCLE_RADIUS * scale_factor; // set x coordinate of vertex 1
// generate vertex coordinates for triangle fan
for (int i = 2; i < g_slices + 2; i++)
{
// multiply by 3 because a vertex has x, y, z coordinates
index = i * 3;
g_vertices_circle[index] = CIRCLE_RADIUS * cos(angle) * scale_factor;
g_vertices_circle[index + 1] = CIRCLE_RADIUS * sin(angle);
g_vertices_circle[index + 2] = 0.0f;
//Color for edges. See stackoverflow
g_colors_circle[index] = 1.0f;
g_colors_circle[index + 1] = 0.0f;
g_colors_circle[index + 2] = 0.0f;
// update to next angle
angle += PI * 2 / static_cast<float>(g_slices);
}
// Gets rid of line from middle of circle
g_vertices_circle[0] = g_vertices_circle[3];
g_vertices_circle[1] = g_vertices_circle[4];
g_vertices_circle[2] = g_vertices_circle[5];
}
static void init(GLFWwindow* window)
{
glClearColor(0.0, 0.0, 0.0, 1.0); // set clear background colour
glEnable(GL_DEPTH_TEST); // enable depth buffer test
glEnable(GL_BLEND);
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
// create and compile our GLSL program from the shader files
g_shaderProgramID = loadShaders("MVP_VS.vert", "ColorFS.frag");
// find the location of shader variables
GLuint positionIndex = glGetAttribLocation(g_shaderProgramID, "aPosition");
GLuint colorIndex = glGetAttribLocation(g_shaderProgramID, "aColor");
g_MVP_Index = glGetUniformLocation(g_shaderProgramID, "uModelViewProjectionMatrix");
g_alphaIndex = glGetUniformLocation(g_shaderProgramID, "uAlpha");
// initialise model matrix to the identity matrix
g_modelMatrix[0] = g_modelMatrix[1] = g_modelMatrix[2] = g_modelMatrix[3] = g_modelMatrix[4] = glm::mat4(1.0f);
g_modelMatrixCircle[0] = g_modelMatrixCircle[1] = g_modelMatrixCircle[2] = g_modelMatrixCircle[3] = g_modelMatrixCircle[4] = glm::mat4(1.0f);
g_modelMatrixSubPlanets[2] = g_modelMatrixSubPlanets[3] = glm::mat4(1.0f);;
// set camera's view matrix
g_camera.setViewMatrix(glm::vec3(0, 3, 14), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
int width, height;
glfwGetFramebufferSize(window, &width, &height);
float aspectRatio = static_cast<float>(width) / height;
// set camera's projection matrix
g_camera.setProjectionMatrix(g_projectionMatrix);
// initialise projection matrix
g_projectionMatrix = glm::perspective(45.0f, aspectRatio, 0.1f, 100.0f);
// generate identifier for VBO and copy data to GPU
glGenBuffers(1, &g_VBO[0]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices), g_vertices, GL_STATIC_DRAW);
// generate identifier for IBO and copy data to GPU
glGenBuffers(1, &g_IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_indices), g_indices, GL_STATIC_DRAW);
// generate identifiers for VAO
glGenVertexArrays(1, &g_VAO[0]);
// create VAO and specify VBO data
glBindVertexArray(g_VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO);
// interleaved attributes
glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
glVertexAttribPointer(colorIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, color)));
glEnableVertexAttribArray(positionIndex); // enable vertex attributes
glEnableVertexAttribArray(colorIndex);
/*------------------------Circle----------------------*/
// generate vertices of triangle fan
generate_circle();
// create VBO and buffer the data
glGenBuffers(1, &g_VBO[1]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_vertices_circle, GL_STATIC_DRAW);
glGenBuffers(1, &g_VBO[2]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_colors_circle, GL_STATIC_DRAW);
// create VAO and specify VBO data
glGenVertexArrays(1, &g_VAO[1]);
glBindVertexArray(g_VAO[1]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[1]);
glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
glVertexAttribPointer(colorIndex, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
glEnableVertexAttribArray(positionIndex); // enable vertex attributes
glEnableVertexAttribArray(colorIndex);
/*----------------------------------------------------*/
}
//Generates a random value between 0.1 and 0.9
double generateRandomFloat(float min, float max)
{
return min + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / (max - min)));
}
// function used to update the scene
static void update_scene()
{
// static variables for rotation angles
static float orbitAngle[5] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, };
static float rotationAngle[5] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
float scaleFactor = 0.05;
orbitAngle[0] += g_orbitSpeed[0] * scaleFactor;
orbitAngle[1] += g_orbitSpeed[1] * scaleFactor;
orbitAngle[2] += g_orbitSpeed[2] * scaleFactor;
orbitAngle[3] += g_orbitSpeed[3] * scaleFactor;
orbitAngle[4] += g_orbitSpeed[4] * scaleFactor;
// update rotation angles
rotationAngle[0] += g_rotationSpeed[0] * scaleFactor;
rotationAngle[1] += g_rotationSpeed[1] * scaleFactor;
rotationAngle[2] += g_rotationSpeed[2] * scaleFactor;
rotationAngle[3] += g_rotationSpeed[3] * scaleFactor;
rotationAngle[4] += g_rotationSpeed[4] * scaleFactor;
// update model matrix (planets)
g_modelMatrix[0] = glm::rotate(rotationAngle[0], glm::vec3(0.0f, 1.0f, 0.0f));
g_modelMatrix[1] = glm::translate(glm::vec3(g_axisOfRotation[1], 0.0f, 0.0f)) //moves the axis of rotation along x-axis
* glm::rotate(orbitAngle[1], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::translate(glm::vec3(2.0f, 0.0f, 0.0f))
* glm::rotate(rotationAngle[1], glm::vec3(0.0f, -1.0f, 0.0f)) //enables rotation on own axis. try comment
* glm::rotate(glm::radians(45.0f), glm::vec3(1.0f, 0.0f, 0.0f)) //rotates into a diamond shape
* glm::rotate(glm::radians(45.0f), glm::vec3(0.0f, 0.0f, 1.0f)) //rotates into a diamond shape
* glm::scale(glm::vec3(g_scaleSize[1], g_scaleSize[1], g_scaleSize[1]));
g_modelMatrix[2] = glm::translate(glm::vec3(g_axisOfRotation[2], 0.0f, 0.0f))
* glm::rotate(orbitAngle[2], glm::vec3(0.0f, -1.0f, 0.0f))
* glm::translate(glm::vec3(4.0f, 0.0f, 0.0f))
* glm::rotate(rotationAngle[2], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::scale(glm::vec3(g_scaleSize[2], g_scaleSize[2], g_scaleSize[2]));
g_modelMatrix[3] = glm::translate(glm::vec3(g_axisOfRotation[3], 0.0f, 0.0f))
* glm::rotate(orbitAngle[3], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::translate(glm::vec3(6.0f, 0.0f, 0.0f))
* glm::rotate(rotationAngle[3], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::scale(glm::vec3(g_scaleSize[3], g_scaleSize[3], g_scaleSize[3]));
g_modelMatrix[4] = glm::translate(glm::vec3(g_axisOfRotation[4], 0.0f, 0.0f))
* glm::rotate(orbitAngle[4], glm::vec3(0.0f, -1.0f, 0.0f)) // -y changes orbit to clock-wise
* glm::translate(glm::vec3(8.0f, 0.0f, 0.0f))
* glm::rotate(rotationAngle[4], glm::vec3(0.0f, -1.0f, 0.0f))
* glm::scale(glm::vec3(g_scaleSize[4], g_scaleSize[4], g_scaleSize[4]));
// update model matrix (orbit paths ie.circles)
g_modelMatrixCircle[1] = glm::translate(glm::vec3(g_axisOfRotation[1], 0.0f, 0.0f)) * glm::scale(glm::vec3(0.68f, 0.68f, 0.68f)) * glm::rotate(glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
g_modelMatrixCircle[2] = glm::translate(glm::vec3(g_axisOfRotation[2], 0.0f, 0.0f)) * glm::scale(glm::vec3(1.35f, 1.35f, 1.35f)) * glm::rotate(glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
g_modelMatrixCircle[3] = glm::translate(glm::vec3(g_axisOfRotation[3], 0.0f, 0.0f)) * glm::scale(glm::vec3(2.0f, 2.0f, 2.0f)) * glm::rotate(glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
g_modelMatrixCircle[4] = glm::translate(glm::vec3(g_axisOfRotation[4], 0.0f, 0.0f)) * glm::scale(glm::vec3(2.7f, 2.7f, 2.7f)) * glm::rotate(glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
// update model matrix (mini planets eg. moon)
g_modelMatrixSubPlanets[2] = glm::translate(glm::vec3(g_axisOfRotation[1], 0.0f, 0.0f))
* glm::scale(glm::vec3(0.35f, 0.35f, 0.35f))
* glm::rotate(glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
g_modelMatrixSubPlanets[3] = glm::translate(glm::vec3(g_axisOfRotation[3], 0.0f, 0.0f))
* glm::rotate(orbitAngle[3], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::translate(glm::vec3(6.0f, 0.0f, 0.0f))
* glm::rotate(rotationAngle[3], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::scale(glm::vec3(g_scaleSize[3], g_scaleSize[3], g_scaleSize[3]));
}
// function used to render the scene
static void render_scene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear colour buffer and depth buffer
glUseProgram(g_shaderProgramID); // use the shaders associated with the shader program
glm::mat4 MVP = glm::mat4(1.0f); //ModelViewProjection matrix to be shared. Initialized to identity
//Circle 1
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrixCircle[1];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glBindVertexArray(g_VAO[1]); // make VAO active
glDrawArrays(GL_LINE_LOOP, 0, g_slices + 2); // display the vertices based on the primitive type
//Circle 2
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrixCircle[2];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawArrays(GL_LINE_LOOP, 0, g_slices + 2); // display the vertices based on the primitive type
//Circle 3
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrixCircle[3];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawArrays(GL_LINE_LOOP, 0, g_slices + 2); // display the vertices based on the primitive type
//Circle 4
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrixCircle[4];;
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawArrays(GL_LINE_LOOP, 0, g_slices + 2); // display the vertices based on the primitive type
// Circle for Object 2
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[2] * g_modelMatrixSubPlanets[2];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawArrays(GL_TRIANGLE_FAN, 0, g_slices + 2); // display the vertices based on the primitive type
glBindVertexArray(g_VAO[0]); // make VAO active
// Object 1
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[0];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
// Object 2
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[1];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
// Object 3
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[2];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
// Object 4
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[3];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glUniform1fv(g_alphaIndex,1, &g_alpha);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
// Object 5
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[4];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
// Moon for Object 3
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrixSubPlanets[3] * g_modelMatrix[4];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
glFlush(); // flush the pipeline
}
static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
{
// variables to store mouse cursor coordinates
static double previous_xpos = xpos;
static double previous_ypos = ypos;
double delta_x = xpos - previous_xpos;
double delta_y = ypos - previous_ypos;
// pass mouse movement to camera class
g_camera.updateYaw(delta_x);
g_camera.updatePitch(delta_y);
// update previous mouse coordinates
previous_xpos = xpos;
previous_ypos = ypos;
}
// key press or release callback function
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
// quit if the ESCAPE key was press
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
{
// set flag to close the window
glfwSetWindowShouldClose(window, GL_TRUE);
return;
}
// toggle animation
else if (key == GLFW_KEY_P && action == GLFW_PRESS) {
static int count = 1;
if (count % 2 == 0)
g_enableAnimation = true;
else
g_enableAnimation = false;
count++;
}
// render in perspective view
else if (key == GLFW_KEY_1 && action == GLFW_PRESS) {
cout << "Perspective-View" << endl << endl;
// set camera's view matrix
g_camera.setViewMatrix(glm::vec3(0, 3, 14), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
render_scene();
}
// render from top view
else if (key == GLFW_KEY_2 && action == GLFW_PRESS) {
cout << "Top-View" << endl << endl;
// set camera's view matrix
g_camera.setViewMatrix(glm::vec3(0, 15, 0), glm::vec3(0, 0, 0), glm::vec3(0, 0,-1));
render_scene();
}
// Randomize size, orbit speed, axis rotation speed of planets
else if (key == GLFW_KEY_R && action == GLFW_PRESS) {
// Randomize planet size
g_scaleSize[1] = generateRandomFloat(0.1, 0.75);
g_scaleSize[2] = generateRandomFloat(0.1, 0.75);
g_scaleSize[3] = generateRandomFloat(0.1, 0.75);
g_scaleSize[4] = generateRandomFloat(0.1, 0.75);
// Randomize speed of rotation (on planets own axis)
g_rotationSpeed[1] = generateRandomFloat(0.1, 2.0);
g_rotationSpeed[2] = generateRandomFloat(0.1, 2.0);
g_rotationSpeed[3] = generateRandomFloat(0.1, 2.0);
g_rotationSpeed[4] = generateRandomFloat(0.1, 2.0);
// Randomize speed of rotation around sun
g_orbitSpeed[1] = generateRandomFloat(0.1, 0.7);
g_orbitSpeed[2] = generateRandomFloat(0.1, 0.7);
g_orbitSpeed[3] = generateRandomFloat(0.1, 0.7);
g_orbitSpeed[4] = generateRandomFloat(0.1, 0.7);
// Randomize offset for axis of rotation
g_axisOfRotation[1] = generateRandomFloat(-0.5, 0.5);
g_axisOfRotation[2] = generateRandomFloat(-0.5, 0.5);
g_axisOfRotation[3] = generateRandomFloat(-0.5, 0.5);
g_axisOfRotation[4] = generateRandomFloat(-0.5, 0.5);
// Display info for each planet
cout << "PLANET 1 - \tSize: " << g_scaleSize[1] << "\tSpeed: " << g_rotationSpeed[1]
<< "\tOrbit Speed: " << g_orbitSpeed[1] << "\tAxis offset: " << g_axisOfRotation[1] << endl;
cout << "PLANET 2 - \tSize: " << g_scaleSize[2] << "\tSpeed: " << g_rotationSpeed[2]
<< "\tOrbit Speed: " << g_orbitSpeed[2] << "\tAxis offset: " << g_axisOfRotation[2] << endl;
cout << "PLANET 3 - \tSize: " << g_scaleSize[3] << "\tSpeed: " << g_rotationSpeed[3]
<< "\tOrbit Speed: " << g_orbitSpeed[3] << "\tAxis offset: " << g_axisOfRotation[3] << endl;
cout << "PLANET 4 - \tSize: " << g_scaleSize[4] << "\tSpeed: " << g_rotationSpeed[4]
<< "\tOrbit Speed: " << g_orbitSpeed[4] << "\tAxis offset: " << g_axisOfRotation[4] << endl;
cout << endl;
render_scene();
}
}
// error callback function
static void error_callback(int error, const char* description)
{
cerr << description << endl; // output error description
}
int main(void)
{
GLFWwindow* window = NULL; // pointer to a GLFW window handle
glfwSetErrorCallback(error_callback); // set error callback function
// initialise GLFW
if (!glfwInit())
{
// if failed to initialise GLFW
exit(EXIT_FAILURE);
}
// minimum OpenGL version 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// create a window and its OpenGL context
window = glfwCreateWindow(1000, 1000, "Assessment 1", NULL, NULL);
// if failed to create window
if (window == NULL)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window); // set window context as the current context
glfwSwapInterval(1); // swap buffer interval
// initialise GLEW
if (glewInit() != GLEW_OK)
{
// if failed to initialise GLEW
cerr << "GLEW initialisation failed" << endl;
exit(EXIT_FAILURE);
}
// set key callback function
glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, cursor_position_callback);
// use sticky mode to avoid missing state changes from polling
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// use mouse to move camera, hence use disable cursor mode
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// initialise rendering states
init(window);
// variables for simple time management
float lastUpdateTime = glfwGetTime();
float currentTime = lastUpdateTime;
// the rendering loop
while (!glfwWindowShouldClose(window))
{
currentTime = glfwGetTime();
g_camera.update(window); // update camera
// only update if more than 0.02 seconds since last update
if (currentTime - lastUpdateTime > 0.02)
{
if (g_enableAnimation) { update_scene(); } // update the scene
render_scene(); // render the scene
glfwSwapBuffers(window); // swap buffers
glfwPollEvents(); // poll for events
lastUpdateTime = currentTime; // update last update time
}
}
// clean up
glDeleteProgram(g_shaderProgramID);
glDeleteBuffers(1, &g_IBO);
glDeleteBuffers(1, &g_VBO[0]);
glDeleteBuffers(1, &g_VBO[1]);
glDeleteVertexArrays(1, &g_VAO[0]);
glDeleteVertexArrays(1, &g_VAO[1]);
// close the window and terminate GLFW
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
color.frag
#version 330 core
// interpolated values from the vertex shaders
in vec3 vColor;
// uniform input data
uniform vec3 uAlpha;
// output data
out vec4 fColor;
void main()
{
// set output color
fColor = vec4(uAlpha,1);
}
There are 3 issues. The 1st one is a copy/past issue. g_projectionMatrix has to be set before it is passed to Camera::setProjectionMatrix:
// initialise projection matrix
g_projectionMatrix = glm::perspective(glm::radians(45.0f), aspectRatio, 0.1f, 100.0f);
// set camera's projection matrix
g_camera.setProjectionMatrix(g_projectionMatrix);
The 2nd issue is a logical issue. The index buffer (ELEMENT_ARRAY_BUFFER) binding is stored within the Vertex Array Object. So the Vertex Array Object has to be bound before the index buffer:
// generate identifier for VBO and copy data to GPU
glGenBuffers(1, &g_VBO[0]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices), g_vertices, GL_STATIC_DRAW);
# Bind vertex array object before element array buffer!
// generate identifiers for VAO
glGenVertexArrays(1, &g_VAO[0]);
// create VAO and specify VBO data
glBindVertexArray(g_VAO[0]);
// generate identifier for IBO and copy data to GPU
glGenBuffers(1, &g_IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_indices), g_indices, GL_STATIC_DRAW);
// interleaved attributes
glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
glVertexAttribPointer(colorIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, color)));
glEnableVertexAttribArray(positionIndex); // enable vertex attributes
glEnableVertexAttribArray(colorIndex);
Note, in compare to the index buffer, the array buffer binding is a global state.
Each attribute which is stated in the VAOs state vector may refer to a different ARRAY_BUFFER. This reference is stored when glVertexAttribPointer is called. Then the buffer which is currently bound to the target ARRAY_BUFFER is associated to the attribute and the name (value) of the object is stored in the state vector of the VAO.
But the index buffer is a state of the VAO. When a buffer is bound to the target ELEMENT_ARRAY_BUFFER, then this buffer is associated to the vertex array object which is currently bound.
Furthermore, I suppose the type of uAlpha ahs to be float, because it is set by glUniform1fv. The final color is fColor = vec4(vColor, uAlpha);:
Fragment shader
#version 330 core
// interpolated values from the vertex shaders
in vec3 vColor;
// uniform input data
uniform float uAlpha;
// output data
out vec4 fColor;
void main()
{
// set output color
fColor = vec4(vColor, uAlpha);
}

how to detect mouse event in opengl isometric scene (from learnopengl.com)

I'm going through learnopengl.com and trying to make a 3d isometric scene.
I've got it working quite nicely so far.
But something not in the learnopengl course is how to detect mouse clicks in 3d space.
I'm using instanced drawing using a vector of mat4 for drawing each cube of the world.
What I would like to do next is click on each cube and modify it (for now just change the z position).
I've found some articles on using glReadPixels but because of my isometric projection, the x &/or y co-ordinates don't seem correct.
Also, since i'm using instanced drawing, i'm not sure how i will figure out which instance in the vector was clicked on.
My code is on git hub here.
And here is the main class I'm using for drawing the cubes:
#include "worldTile.h"
worldTile::worldTile() : drawable("instance.shader.vs", "instance.shader.fs")
{
drawType = GL_STATIC_DRAW;
baseModel = glm::mat4(1.0f);
baseModel = glm::rotate(baseModel, glm::radians(-45.0f), glm::vec3(1.0f, 0.0f, 0.0f));
baseModel = glm::rotate(baseModel, glm::radians(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
baseModel = glm::rotate(baseModel, glm::radians(-45.0f), glm::vec3(0.0f, 0.0f, 1.0f));
}
worldTile::~worldTile()
{
cleanup();
}
void worldTile::cleanup()
{
}
void worldTile::setup()
{
float blockSize = 0.81f;
int worldSize = 2;
// 50 gives 15-16fps using drawElements
// 50 gives 480fps using drawElementsInstanced
// 50 gives 380fps using matrix drawElementsInstanced
for (int i = 0; i < worldSize; i++)
{
for (int j = 0; j < worldSize; j++)
{
float xPos = i * blockSize;
float yPos = j * blockSize;
glm::mat4 model = baseModel;
model = glm::translate(baseModel, glm::vec3(xPos, yPos, 0.0f));
modelMatrices.push_back(model);
if (i != 0)
{
model = glm::translate(baseModel, glm::vec3(-xPos, yPos, 0.0f));
modelMatrices.push_back(model);
}
if (j != 0)
{
model = glm::translate(baseModel, glm::vec3(xPos, -yPos, 0.0f));
modelMatrices.push_back(model);
}
if (i != 0 && j != 0)
{
model = glm::translate(baseModel, glm::vec3(-xPos, -yPos, 0.0f));
modelMatrices.push_back(model);
}
}
}
//modelMatrices[0] = glm::translate(modelMatrices[0], glm::vec3(0, 0, 0.2f));
colors = {
glm::vec3(0.55f, 0.71f, 0.29f), // 0 top green
glm::vec3(0.49f, 0.64f, 0.26f), // 1 front green
glm::vec3(0.45f, 0.59f, 0.24f), // 2 side green
glm::vec3(0.68f, 0.51f, 0.34f), // 3 brown
glm::vec3(0.73f, 0.55f, 0.36f), // 4 front brown
glm::vec3(0.62f, 0.47f, 0.35f), // 5 side brown
};
vertices = {
// top face
-0.4f, -0.4f, 0.1f, // 0
0.4f, -0.4f, 0.1f,
0.4f, 0.4f, 0.1f,
-0.4f, 0.4f, 0.1f,
// bottom face
-0.4f, -0.4f, -0.1f, // 4
0.4f, -0.4f, -0.1f,
0.4f, 0.4f, -0.1f,
-0.4f, 0.4f, -0.1f,
// left face - bottom
-0.4f, 0.4f, 0.0f, // 8
-0.4f, 0.4f, -0.1f,
-0.4f, -0.4f, -0.1f,
-0.4f, -0.4f, 0.0f,
// left face - top
-0.4f, 0.4f, 0.1f, // 12
-0.4f, 0.4f, -0.0f,
-0.4f, -0.4f, -0.0f,
-0.4f, -0.4f, 0.1f,
// right face - bottom
0.4f, 0.4f, 0.0f, // 16
0.4f, 0.4f, -0.1f,
0.4f, -0.4f, -0.1f,
0.4f, -0.4f, 0.0f,
// right face - top
0.4f, 0.4f, 0.1f, // 20
0.4f, 0.4f, -0.0f,
0.4f, -0.4f, -0.0f,
0.4f, -0.4f, 0.1f,
// left side face - bottom
-0.4f, -0.4f, -0.1f, // 24
0.4f, -0.4f, -0.1f,
0.4f, -0.4f, 0.0f,
-0.4f, -0.4f, 0.0f,
// left side face - top
-0.4f, -0.4f, -0.0f, // 28
0.4f, -0.4f, -0.0f,
0.4f, -0.4f, 0.1f,
-0.4f, -0.4f, 0.1f,
// back face - bottom
-0.4f, 0.4f, -0.1f, // 32
0.4f, 0.4f, -0.1f,
0.4f, 0.4f, 0.0f,
-0.4f, 0.4f, 0.0f,
// back face - top
-0.4f, 0.4f, -0.0f, // 36
0.4f, 0.4f, -0.0f,
0.4f, 0.4f, 0.1f,
-0.4f, 0.4f, 0.1f,
};
indices = { // note that we start from 0!
0, 1, 3, // first Triangle
1, 2, 3, // second Triangle
4, 5, 7,
5, 6, 7,
8,9,11,
9,10,11,
12,13,15,
13,14,15,
16,17,19,
17,18,19,
20,21,23,
21,22,23,
24,25,27,
25,26,27,
28,29,31,
29,30,31,
32,33,35,
33,34,35,
36,37,39,
37,38,39,
};
std::cout << "world title draw type" << std::endl;
glGenVertexArrays(1, VAO);
glGenBuffers(1, VBO);
glGenBuffers(1, EBO); // for index drawing
glGenBuffers(1, &matrixBuffer);
reloadBuffers();
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glEnableVertexAttribArray(5);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
// color attribute
//glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(3 * sizeof(float)));
// matrix attribute
// set attribute pointers for matrix (4 times vec4)
glBindBuffer(GL_ARRAY_BUFFER, matrixBuffer);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)0);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(1 * sizeof(glm::vec4)));
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(2 * sizeof(glm::vec4)));
glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(3 * sizeof(glm::vec4)));
glVertexAttribDivisor(2, 1);
glVertexAttribDivisor(3, 1);
glVertexAttribDivisor(4, 1);
glVertexAttribDivisor(5, 1);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
ourShader.use();
ourShader.setVec3("colors", 6, colors.data());
}
bool mouseDown = false;
glm::mat4 aProjection = glm::mat4(1.0f);
glm::mat4 aView = glm::mat4(1.0f);
void worldTile::processInput(GLFWwindow* window)
{
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE && mouseDown == true)
{
std::cout << "Mouse button released" << std::endl;
mouseDown = false;
}
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS && mouseDown == false)
{
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
//ypos = 600 - ypos;
mouseDown = true;
unsigned char pixeldata[4];
GLfloat depth;
// reading pixel data at current cursor position ...
glReadBuffer(GL_COLOR_ATTACHMENT1); // read from second framebuffer layer
glReadPixels(xpos, 600 - ypos, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixeldata);
glReadPixels(xpos, 600 - ypos, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
glm::vec4 viewport = glm::vec4(0, 0, 800, 600);
glm::vec3 wincoord = glm::vec3(xpos, 600 - ypos, depth);
glm::mat4 baseModel = glm::mat4(1.0f);
baseModel = glm::rotate(baseModel, glm::radians(-45.0f), glm::vec3(1.0f, 0.0f, 0.0f));
glm::vec3 objcoord = glm::unProject(wincoord, baseModel, aProjection, viewport);
printf("Coordinates in object space: %f, %f, %f\n", objcoord.x, objcoord.y, objcoord.z);
int modelIndex = 0;
// TODO: find out which model from modelMatrices was clicked on
modelMatrices[0] = glm::translate(modelMatrices[0], glm::vec3(0, 0, 0.2f));
glBindBuffer(GL_ARRAY_BUFFER, matrixBuffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::mat4), &modelMatrices.data()[0]);
//glBufferData(GL_ARRAY_BUFFER, modelMatrices.size() * sizeof(glm::mat4), &modelMatrices.data()[0], drawType);
// convert pixel color back to (int)ID ...
//unsigned int m_trackedID = (pixeldata[0] << 0) | (pixeldata[1] << 8) | (pixeldata[2] << 16) | (pixeldata[3] << 24);
// ------------
//std::cout << "Mouse button pressed: " << xpos << "-" << ypos << " - " << depth << " - " << m_trackedID << std::endl;
}
if (isPressed(window, GLFW_KEY_Z))
{
for (int i = 0; i < 40; i++)
{
int index = i * 4;
vertices[index] -= 0.01f;
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferSubData(GL_ARRAY_BUFFER, index * sizeof(float), sizeof(float), &vertices[index]);
}
}
else if (isPressed(window, GLFW_KEY_X))
{
for (int i = 0; i < 40; i++)
{
int index = i * 4;
vertices[index] += 0.01f;
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferSubData(GL_ARRAY_BUFFER, index * sizeof(float), sizeof(float), &vertices[index]);
}
}
}
void worldTile::draw(glm::mat4& currentModel, glm::mat4& currentProjection, glm::mat4& currentView)
{
ourShader.use();
ourShader.setMat4("projection", currentProjection);
ourShader.setMat4("view", currentView);
aProjection = currentProjection;
aView = currentView;
glBindVertexArray(VAO[0]);
glDrawElementsInstanced(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0, modelMatrices.size());
}
void worldTile::reloadBuffers()
{
glBindVertexArray(VAO[0]);
// load vertex buffers
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), drawType);
// load index buffers
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), drawType);
// load matrix buffer
glBindBuffer(GL_ARRAY_BUFFER, matrixBuffer);
glBufferData(GL_ARRAY_BUFFER, modelMatrices.size() * sizeof(glm::mat4), &modelMatrices.data()[0], drawType);
}
Any help is much appreciated.
I've figured it out.
I have to do to opposite of any translations and rotations i've done on my scene and models when calling unproject.
So i have the following as the model being passed into unproject:
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(0, 0, zoffset));
model = glm::rotate(model, glm::radians(-45.0f), glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, glm::radians(-45.0f), glm::vec3(0.0f, 0.0f, 1.0f));
glm::vec3 objcoord = glm::unProject(wincoord, model, aProjection, viewport);
I've also had to pass the scene projection, and zoffset (for zooming) to my model.
I also have an extra vector which keeps track of all my object's world positions so after i call unproject, I can use the calculated work coordinates to figure out which cube i clicked on. It's a bit of extra work, but it works. I can clean it up to use a clever algorithm or something to figure out which cube was selected.
But this is the basics of what i've done.

How do I get my OpenGL camera to point downwards?

I am trying to integrate 2 programs together.
One has a planet system (with moving cubes)
The other has code for a moving camera. It can also pan around
I have managed to put both of them together. The view of the planet system can be toggled to show
Perspective view (when '1' is pressed)
Top-view (when '2' is pressed)
I am having problems with my top-view (when 2 is pressed). It is not pointing at the planet system. It is right above the planets but not looking downwards. I want to point the camera downwards such that it looks like this
I have unsuccessfully been playing with this section of code (below) to get the camera to look down. More specifically, the coordinates in the g_camera.setViewMatrix function.
// render from top view
else if (key == GLFW_KEY_2 && action == GLFW_PRESS) {
cout << "Top-View" << endl << endl;
// set camera's view matrix
g_camera.setViewMatrix(glm::vec3(0, 15, 0), glm::vec3(0, 0, 0), glm::vec3(1, 0, 0));
//g_viewMatrix = glm::lookAt(glm::vec3(0, 15, 0), glm::vec3(0, 0, 0), glm::vec3(1, 0, 0));
render_scene();
}
Before I integrated the camera code, I used this look at function.
g_viewMatrix = glm::lookAt(glm::vec3(0, 15, 0), glm::vec3(0, 0, 0), glm::vec3(1, 0, 0));
However, when I plugged these same vectors for the g_camera.setViewMatrix function, it did not point in the same direction.
Another problem I have:
The red oval is actually a circle. How do I get it to appear as a circle instead of an oval? I integrated the code for the circle from another program. In that program, it was a perfect circle.
Here is my code
#include <cstdio> // for C++ i/o
#include <iostream>
#include <string>
#include <cstddef>
using namespace std; // to avoid having to use std::
#define GLEW_STATIC // include GLEW as a static library
#include <GLEW/glew.h> // include GLEW
#include <GLFW/glfw3.h> // include GLFW (which includes the OpenGL header)
#include <glm/glm.hpp> // include GLM (ideally should only use the GLM headers that are actually used)
#include <glm/gtx/transform.hpp>
using namespace glm; // to avoid having to use glm::
#include "shader.h"
#include "camera.h"
#define PI 3.14159265
#define MAX_SLICES 50
#define MIN_SLICES 8
#define MAX_VERTICES (MAX_SLICES+2)*3 // a triangle fan should have a minimum of 3 vertices
#define CIRCLE_RADIUS 3.0
#define WINDOW_WIDTH 1500
#define WINDOW_HEIGHT 800
// struct for vertex attributes
struct Vertex
{
GLfloat position[3];
GLfloat color[3];
};
// global variables
GLfloat g_vertices_circle[MAX_VERTICES] = {
0.0f, 0.0f, 0.0f, // try adjusting this value to get rid of red line
0.0f, 0.0f, 0.0f
};
GLfloat g_colors_circle[MAX_VERTICES] = {
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f
};
GLuint g_slices = MAX_SLICES; // number of circle slices
Vertex g_vertices[] = {
// vertex 1
-0.5f, 0.5f, 0.5f, // position
1.0f, 0.0f, 1.0f, // colour
// vertex 2
-0.5f, -0.5f, 0.5f, // position
1.0f, 0.0f, 0.0f, // colour
// vertex 3
0.5f, 0.5f, 0.5f, // position
1.0f, 1.0f, 1.0f, // colour
// vertex 4
0.5f, -0.5f, 0.5f, // position
1.0f, 1.0f, 0.0f, // colour
// vertex 5
-0.5f, 0.5f, -0.5f, // position
0.0f, 0.0f, 1.0f, // colour
// vertex 6
-0.5f, -0.5f, -0.5f,// position
0.0f, 0.0f, 0.0f, // colour
// vertex 7
0.5f, 0.5f, -0.5f, // position
0.0f, 1.0f, 1.0f, // colour
// vertex 8
0.5f, -0.5f, -0.5f, // position
0.0f, 1.0f, 0.0f, // colour
};
GLuint g_indices[] = {
0, 1, 2, // triangle 1
2, 1, 3, // triangle 2
4, 5, 0, // triangle 3
0, 5, 1, // ...
2, 3, 6,
6, 3, 7,
4, 0, 6,
6, 0, 2,
1, 5, 3,
3, 5, 7,
5, 4, 7,
7, 4, 6, // triangle 12
};
GLuint g_IBO = 0; // index buffer object identifier
GLuint g_VBO[3]; // vertex buffer object identifier
GLuint g_VAO[2]; // vertex array object identifier
GLuint g_shaderProgramID = 0; // shader program identifier
GLuint g_MVP_Index = 0; // location in shader
glm::mat4 g_modelMatrix[5]; // planets object model matrices
glm::mat4 g_modelMatrixCircle[5];// circle model matrices
glm::mat4 g_modelMatrixSubPlanets[5];// object matrices for sub-planets (moon, disc etc)
glm::mat4 g_viewMatrix; // view matrix
glm::mat4 g_projectionMatrix; // projection matrix
Camera g_camera; // camera
float g_orbitSpeed[5] = { 0.3f, 1.0f, 0.7f, 0.9f, 1.2f }; // for speed of rotation around sun
float g_rotationSpeed[5] = { 0.07f, 0.7f, 3.0f, 5.0f, 1.0f }; // for speed of rotation on own axis
float g_scaleSize[5] = { 0.5f, 0.5f, 0.5f, 0.5f, 0.5f }; // for scaling the orbiting planets
float g_axisOfRotation[5] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, }; // for offsetting the axis of rotation
void generate_circle()
{
float angle = PI * 2 / static_cast<float>(g_slices); // used to generate x and y coordinates
float scale_factor = static_cast<float>(WINDOW_HEIGHT) / WINDOW_WIDTH; // scale to make it a circle instead of an elipse
int index = 0; // vertex index
g_vertices_circle[3] = CIRCLE_RADIUS * scale_factor; // set x coordinate of vertex 1
// generate vertex coordinates for triangle fan
for (int i = 2; i < g_slices + 2; i++)
{
// multiply by 3 because a vertex has x, y, z coordinates
index = i * 3;
g_vertices_circle[index] = CIRCLE_RADIUS * cos(angle) * scale_factor;
g_vertices_circle[index + 1] = CIRCLE_RADIUS * sin(angle);
g_vertices_circle[index + 2] = 0.0f;
//Color for edges. See stackoverflow
g_colors_circle[index] = 1.0f;
g_colors_circle[index + 1] = 0.0f;
g_colors_circle[index + 2] = 0.0f;
// update to next angle
angle += PI * 2 / static_cast<float>(g_slices);
}
// Gets rid of line from middle of circle
g_vertices_circle[0] = g_vertices_circle[3];
g_vertices_circle[1] = g_vertices_circle[4];
g_vertices_circle[2] = g_vertices_circle[5];
}
static void init(GLFWwindow* window)
{
glClearColor(0.0, 0.0, 0.0, 1.0); // set clear background colour
glEnable(GL_DEPTH_TEST); // enable depth buffer test
// create and compile our GLSL program from the shader files
g_shaderProgramID = loadShaders("MVP_VS.vert", "ColorFS.frag");
// find the location of shader variables
GLuint positionIndex = glGetAttribLocation(g_shaderProgramID, "aPosition");
GLuint colorIndex = glGetAttribLocation(g_shaderProgramID, "aColor");
g_MVP_Index = glGetUniformLocation(g_shaderProgramID, "uModelViewProjectionMatrix");
// initialise model matrix to the identity matrix
g_modelMatrix[0] = g_modelMatrix[1] = g_modelMatrix[2] = g_modelMatrix[3] = g_modelMatrix[4] = glm::mat4(1.0f);
g_modelMatrixCircle[0] = g_modelMatrixCircle[1] = glm::mat4(1.0f);
g_modelMatrixSubPlanets[3] = glm::mat4(1.0f);;
// initialise view matrix
//g_viewMatrix = glm::lookAt(glm::vec3(10, 3, 8), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)); //perspective
// set camera's view matrix
//g_camera.setViewMatrix(glm::vec3(10, 3, 8), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
g_camera.setViewMatrix(glm::vec3(0, 3, 14), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
int width, height;
glfwGetFramebufferSize(window, &width, &height);
float aspectRatio = static_cast<float>(width) / height;
// set camera's projection matrix
g_camera.setProjectionMatrix(glm::perspective(45.0f, aspectRatio, 0.1f, 100.0f));
// initialise projection matrix
g_projectionMatrix = glm::perspective(45.0f, aspectRatio, 0.1f, 100.0f);
// generate identifier for VBO and copy data to GPU
glGenBuffers(1, &g_VBO[0]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices), g_vertices, GL_STATIC_DRAW);
// generate identifier for IBO and copy data to GPU
glGenBuffers(1, &g_IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_indices), g_indices, GL_STATIC_DRAW);
// generate identifiers for VAO
glGenVertexArrays(1, &g_VAO[0]);
// create VAO and specify VBO data
glBindVertexArray(g_VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO);
// interleaved attributes
glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
glVertexAttribPointer(colorIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, color)));
glEnableVertexAttribArray(positionIndex); // enable vertex attributes
glEnableVertexAttribArray(colorIndex);
/*------------------------Circle----------------------*/
// generate vertices of triangle fan
generate_circle();
// create VBO and buffer the data
glGenBuffers(1, &g_VBO[1]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_vertices_circle, GL_STATIC_DRAW);
glGenBuffers(1, &g_VBO[2]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_colors_circle, GL_STATIC_DRAW);
// create VAO and specify VBO data
glGenVertexArrays(1, &g_VAO[1]);
glBindVertexArray(g_VAO[1]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[1]);
glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
glVertexAttribPointer(colorIndex, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
/*----------------------------------------------------*/
glEnableVertexAttribArray(positionIndex); // enable vertex attributes
glEnableVertexAttribArray(colorIndex);
}
//Generates a random value between 0.1 and 0.9
double generateRandomFloat(float min, float max)
{
return min + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / (max - min)));
}
// function used to update the scene
static void update_scene()
{
// static variables for rotation angles
static float orbitAngle[5] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, };
static float rotationAngle[5] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
float scaleFactor = 0.05;
orbitAngle[0] += g_orbitSpeed[0] * scaleFactor;
orbitAngle[1] += g_orbitSpeed[1] * scaleFactor;
orbitAngle[2] += g_orbitSpeed[2] * scaleFactor;
orbitAngle[3] += g_orbitSpeed[3] * scaleFactor;
orbitAngle[4] += g_orbitSpeed[4] * scaleFactor;
// update rotation angles
rotationAngle[0] += g_rotationSpeed[0] * scaleFactor;
rotationAngle[1] += g_rotationSpeed[1] * scaleFactor;
rotationAngle[2] += g_rotationSpeed[2] * scaleFactor;
rotationAngle[3] += g_rotationSpeed[3] * scaleFactor;
rotationAngle[4] += g_rotationSpeed[4] * scaleFactor;
// update model matrix (planets)
g_modelMatrix[0] = glm::rotate(rotationAngle[0], glm::vec3(0.0f, 1.0f, 0.0f));
g_modelMatrix[1] = glm::translate(glm::vec3(g_axisOfRotation[1], 0.0f, 0.0f)) //moves the axis of rotation along x-axis
* glm::rotate(orbitAngle[1], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::translate(glm::vec3(2.0f, 0.0f, 0.0f))
* glm::rotate(rotationAngle[1], glm::vec3(0.0f, -1.0f, 0.0f)) //enables rotation on own axis. try comment
* glm::rotate(glm::radians(45.0f), glm::vec3(1.0f, 0.0f, 0.0f)) //rotates into a diamond shape
* glm::rotate(glm::radians(45.0f), glm::vec3(0.0f, 0.0f, 1.0f)) //rotates into a diamond shape
* glm::scale(glm::vec3(g_scaleSize[1], g_scaleSize[1], g_scaleSize[1]));
g_modelMatrix[2] = glm::translate(glm::vec3(g_axisOfRotation[2], 0.0f, 0.0f))
* glm::rotate(orbitAngle[2], glm::vec3(0.0f, -1.0f, 0.0f))
* glm::translate(glm::vec3(4.0f, 0.0f, 0.0f))
* glm::rotate(rotationAngle[2], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::scale(glm::vec3(g_scaleSize[2], g_scaleSize[2], g_scaleSize[2]));
g_modelMatrix[3] = glm::translate(glm::vec3(g_axisOfRotation[3], 0.0f, 0.0f))
* glm::rotate(orbitAngle[3], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::translate(glm::vec3(6.0f, 0.0f, 0.0f))
* glm::rotate(rotationAngle[3], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::scale(glm::vec3(g_scaleSize[3], g_scaleSize[3], g_scaleSize[3]));
g_modelMatrix[4] = glm::translate(glm::vec3(g_axisOfRotation[4], 0.0f, 0.0f))
* glm::rotate(orbitAngle[4], glm::vec3(0.0f, -1.0f, 0.0f)) // -y changes orbit to clock-wise
* glm::translate(glm::vec3(8.0f, 0.0f, 0.0f))
* glm::rotate(rotationAngle[4], glm::vec3(0.0f, -1.0f, 0.0f))
* glm::scale(glm::vec3(g_scaleSize[4], g_scaleSize[4], g_scaleSize[4]));
// update model matrix (orbit paths ie.circles)
g_modelMatrixCircle[1] = glm::rotate(glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
// update model matrix (mini planets eg. moon)
g_modelMatrixSubPlanets[3] = glm::translate(glm::vec3(g_axisOfRotation[3], 0.0f, 0.0f))
* glm::rotate(orbitAngle[3], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::translate(glm::vec3(6.0f, 0.0f, 0.0f))
* glm::rotate(rotationAngle[3], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::scale(glm::vec3(g_scaleSize[3], g_scaleSize[3], g_scaleSize[3]));
}
// function used to render the scene
static void render_scene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear colour buffer and depth buffer
glUseProgram(g_shaderProgramID); // use the shaders associated with the shader program
glm::mat4 MVP = glm::mat4(1.0f); //ModelViewProjection matrix to be shared. Initialized to identity
//Circle 1
//MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrixCircle[1];
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrixCircle[1];
//MVP = g_camera.getViewMatrix() * g_modelMatrixCircle[1];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glBindVertexArray(g_VAO[1]); // make VAO active
glDrawArrays(GL_LINE_LOOP, 0, g_slices + 2); // display the vertices based on the primitive type
glBindVertexArray(g_VAO[0]); // make VAO active
// Object 1
//MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[0];
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[0];
// set uniform model transformation matrix
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
// Object 2
//MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[1];
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[1];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
// Object 3
//MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[2];
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[2];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
// Object 4
//MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[3];
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[3];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
// Object 5
//MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[4];
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[4];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
// Moon for Object 3
//MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrixSubPlanets[3] * g_modelMatrix[4];
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrixSubPlanets[3] * g_modelMatrix[4];
glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
glFlush(); // flush the pipeline
}
static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
{
// variables to store mouse cursor coordinates
static double previous_xpos = xpos;
static double previous_ypos = ypos;
double delta_x = xpos - previous_xpos;
double delta_y = ypos - previous_ypos;
// pass mouse movement to camera class
g_camera.updateYaw(delta_x);
g_camera.updatePitch(delta_y);
// update previous mouse coordinates
previous_xpos = xpos;
previous_ypos = ypos;
}
// key press or release callback function
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
// quit if the ESCAPE key was press
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
{
// set flag to close the window
glfwSetWindowShouldClose(window, GL_TRUE);
return;
}
// render in perspective view
else if (key == GLFW_KEY_1 && action == GLFW_PRESS) {
cout << "Perspective-View" << endl << endl;
// set camera's view matrix
g_camera.setViewMatrix(glm::vec3(0, 3, 14), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
//g_viewMatrix = glm::lookAt(glm::vec3(10, 3, 8), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
render_scene();
}
// render from top view
else if (key == GLFW_KEY_2 && action == GLFW_PRESS) {
cout << "Top-View" << endl << endl;
// set camera's view matrix
g_camera.setViewMatrix(glm::vec3(0, 15, 0), glm::vec3(0, 0, 0), glm::vec3(1, 0, 0));
//g_viewMatrix = glm::lookAt(glm::vec3(0, 15, 0), glm::vec3(0, 0, 0), glm::vec3(1, 0, 0));
render_scene();
}
// render from eye-level view
else if (key == GLFW_KEY_3 && action == GLFW_PRESS) {
cout << "Eye-level View" << endl << endl;
// set camera's view matrix
g_camera.setViewMatrix(glm::vec3(0, 0, 10), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
//g_viewMatrix = glm::lookAt(glm::vec3(0, 0, 10), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
render_scene();
}
// Randomize size, orbit speed, axis rotation speed of planets
else if (key == GLFW_KEY_R && action == GLFW_PRESS) {
// Randomize planet size
g_scaleSize[1] = generateRandomFloat(0.1, 0.75);
g_scaleSize[2] = generateRandomFloat(0.1, 0.75);
g_scaleSize[3] = generateRandomFloat(0.1, 0.75);
g_scaleSize[4] = generateRandomFloat(0.1, 0.75);
// Randomize speed of rotation (on planets own axis)
g_rotationSpeed[1] = generateRandomFloat(0.1, 10.0);
g_rotationSpeed[2] = generateRandomFloat(0.1, 10.0);
g_rotationSpeed[3] = generateRandomFloat(0.1, 10.0);
g_rotationSpeed[4] = generateRandomFloat(0.1, 10.0);
// Randomize speed of rotation around sun
g_orbitSpeed[1] = generateRandomFloat(0.1, 1.2);
g_orbitSpeed[2] = generateRandomFloat(0.1, 1.2);
g_orbitSpeed[3] = generateRandomFloat(0.1, 1.2);
g_orbitSpeed[4] = generateRandomFloat(0.1, 1.2);
// Randomize offset for axis of rotation
g_axisOfRotation[1] = generateRandomFloat(-0.5, 0.5);
g_axisOfRotation[2] = generateRandomFloat(-0.5, 0.5);
g_axisOfRotation[3] = generateRandomFloat(-0.5, 0.5);
g_axisOfRotation[4] = generateRandomFloat(-0.5, 0.5);
// Display info for each planet
cout << "PLANET 1 - \tSize: " << g_scaleSize[1] << "\tSpeed: " << g_rotationSpeed[1]
<< "\tOrbit Speed: " << g_orbitSpeed[1] << "\tAxis offset: " << g_axisOfRotation[1] << endl;
cout << "PLANET 2 - \tSize: " << g_scaleSize[2] << "\tSpeed: " << g_rotationSpeed[2]
<< "\tOrbit Speed: " << g_orbitSpeed[2] << "\tAxis offset: " << g_axisOfRotation[2] << endl;
cout << "PLANET 3 - \tSize: " << g_scaleSize[3] << "\tSpeed: " << g_rotationSpeed[3]
<< "\tOrbit Speed: " << g_orbitSpeed[3] << "\tAxis offset: " << g_axisOfRotation[3] << endl;
cout << "PLANET 4 - \tSize: " << g_scaleSize[4] << "\tSpeed: " << g_rotationSpeed[4]
<< "\tOrbit Speed: " << g_orbitSpeed[4] << "\tAxis offset: " << g_axisOfRotation[4] << endl;
cout << endl;
render_scene();
}
}
// error callback function
static void error_callback(int error, const char* description)
{
cerr << description << endl; // output error description
}
int main(void)
{
GLFWwindow* window = NULL; // pointer to a GLFW window handle
glfwSetErrorCallback(error_callback); // set error callback function
// initialise GLFW
if (!glfwInit())
{
// if failed to initialise GLFW
exit(EXIT_FAILURE);
}
// minimum OpenGL version 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// create a window and its OpenGL context
window = glfwCreateWindow(1500, 1000, "Assignment 2", NULL, NULL);
// if failed to create window
if (window == NULL)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window); // set window context as the current context
glfwSwapInterval(1); // swap buffer interval
// initialise GLEW
if (glewInit() != GLEW_OK)
{
// if failed to initialise GLEW
cerr << "GLEW initialisation failed" << endl;
exit(EXIT_FAILURE);
}
// set key callback function
glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, cursor_position_callback);
// use sticky mode to avoid missing state changes from polling
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// use mouse to move camera, hence use disable cursor mode
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// initialise rendering states
init(window);
// variables for simple time management
float lastUpdateTime = glfwGetTime();
float currentTime = lastUpdateTime;
// the rendering loop
while (!glfwWindowShouldClose(window))
{
currentTime = glfwGetTime();
g_camera.update(window); // update camera
// only update if more than 0.02 seconds since last update
if (currentTime - lastUpdateTime > 0.02)
{
update_scene(); // update the scene
render_scene(); // render the scene
glfwSwapBuffers(window); // swap buffers
glfwPollEvents(); // poll for events
lastUpdateTime = currentTime; // update last update time
}
}
// clean up
glDeleteProgram(g_shaderProgramID);
glDeleteBuffers(1, &g_IBO);
glDeleteBuffers(1, &g_VBO[0]);
glDeleteBuffers(1, &g_VBO[1]);
glDeleteVertexArrays(1, &g_VAO[0]);
glDeleteVertexArrays(1, &g_VAO[1]);
// close the window and terminate GLFW
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
Camera.cpp
#include "Camera.h"
Camera::Camera()
{
// initialise camera member variables
mPosition = glm::vec3(0.0f, 0.0f, 1.0f);
mLookAt = glm::vec3(0.0f, 0.0f, 0.0f);
mUp = glm::vec3(0.0f, 1.0f, 0.0f);
mYaw = 0.0f;
mPitch = 0.0f;
mViewMatrix = glm::lookAt(mPosition, mLookAt, mUp);
mProjectionMatrix = glm::perspective(45.0f, 1.5f, 0.1f, 100.0f);
}
Camera::~Camera()
{}
void Camera::update(GLFWwindow* window)
{
// variables to store forward/back and strafe movement
float moveForward = 0;
float strafeRight = 0;
// update variables based on keyboard input
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
moveForward += MOVEMENT_SENSITIVITY;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
moveForward -= MOVEMENT_SENSITIVITY;
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
strafeRight -= MOVEMENT_SENSITIVITY;
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
strafeRight += MOVEMENT_SENSITIVITY;
// rotate the respective unit vectors about the y-axis
glm::vec3 rotatedForwardVec = glm::rotateY(glm::vec3(0.0f, 0.0f, -1.0f), mYaw);
glm::vec3 rotatedRightVec = glm::rotateY(glm::vec3(1.0f, 0.0f, 0.0f), mYaw);
// rotate the rotated forward vector about the rotated right vector
rotatedForwardVec = glm::vec3(glm::rotate(mPitch, rotatedRightVec)*glm::vec4(rotatedForwardVec, 0.0f));
// update position, look-at and up vectors
mPosition += rotatedForwardVec * moveForward + rotatedRightVec * strafeRight;
mLookAt = mPosition + rotatedForwardVec;
mUp = glm::cross(rotatedRightVec, rotatedForwardVec);
// compute the new view matrix
mViewMatrix = glm::lookAt(mPosition, mLookAt, mUp);
}
void Camera::updateYaw(float yaw)
{
mYaw -= yaw * ROTATION_SENSITIVITY;
}
void Camera::updatePitch(float pitch)
{
mPitch -= pitch * ROTATION_SENSITIVITY;
}
void Camera::setViewMatrix(glm::vec3 position, glm::vec3 lookAt, glm::vec3 up)
{
mPosition = position;
mLookAt = lookAt;
mUp = up;
mViewMatrix = glm::lookAt(mPosition, mLookAt, mUp);
}
void Camera::setProjectionMatrix(glm::mat4& matrix)
{
mProjectionMatrix = matrix;
}
glm::mat4 Camera::getViewMatrix()
{
return mViewMatrix;
}
glm::mat4 Camera::getProjectionMatrix()
{
return mProjectionMatrix;
}
Camera.h
#ifndef __CAMERA_H
#define __CAMERA_H
#include <GLFW/glfw3.h> // include GLFW (which includes the OpenGL header)
#include <glm/glm.hpp> // include GLM (ideally should only use the GLM headers that are actually used)
#include <glm/gtx/transform.hpp>
#include <glm/gtx/rotate_vector.hpp>
using namespace glm; // to avoid having to use glm::
#define MOVEMENT_SENSITIVITY 0.0005f // camera movement sensitivity
#define ROTATION_SENSITIVITY 0.001f // camera rotation sensitivity
class Camera {
public:
Camera();
~Camera();
void update(GLFWwindow* window);
void updateYaw(float yaw);
void updatePitch(float pitch);
void setViewMatrix(glm::vec3 position, glm::vec3 lookAt, glm::vec3 up);
void setProjectionMatrix(glm::mat4& matrix);
glm::mat4 getViewMatrix();
glm::mat4 getProjectionMatrix();
private:
float mYaw;
float mPitch;
glm::vec3 mPosition;
glm::vec3 mLookAt;
glm::vec3 mUp;
glm::mat4 mViewMatrix;
glm::mat4 mProjectionMatrix;
};
#endif
Vertex shader
#version 330 core
// input data (different for all executions of this shader)
in vec3 aPosition;
in vec3 aColor;
// ModelViewProjection matrix
uniform mat4 uModelViewProjectionMatrix;
// output data (will be interpolated for each fragment)
out vec3 vColor;
void main()
{
// set vertex position
gl_Position = uModelViewProjectionMatrix * vec4(aPosition, 1.0);
// the color of each vertex will be interpolated
// to produce the color of each fragment
vColor = aColor;
}
You have to map from world coordinates to viewport cooordinates
x y z
--------
1 0 0 | x' = x
0 0 1 | y' = z
0 -1 0 | z' = -y
Use this to see the scene from above:
g_camera.setViewMatrix(glm::vec3(0, 15.0f, 0), glm::vec3(0, 0, 0), glm::vec3(0, 0, -1.0f));
To pane, zoom and orbit the view you have to set up translation and rotation matrices and you have to concatenate (multiply)
them with the view matrix.
Add members to the class Camerato store the translation and rotation angles:
glm::vec3 _move;
float _angX;
float _angY;
Adapt the method Camera::update to sum up the translation and rotation angles:
#define MOVEMENT_SENSITIVITY 0.01f
#define ZOOM_SENSITIVITY 0.1f
#define ROTATION_SENSITIVITY 1.0f
void Camera::update(GLFWwindow* window)
{
if ( glfwGetKey( window, GLFW_KEY_A ) == GLFW_PRESS ) _move[0] -= MOVEMENT_SENSITIVITY;
if ( glfwGetKey( window, GLFW_KEY_D ) == GLFW_PRESS ) _move[0] += MOVEMENT_SENSITIVITY;
if ( glfwGetKey( window, GLFW_KEY_S ) == GLFW_PRESS ) _move[1] -= MOVEMENT_SENSITIVITY;
if ( glfwGetKey( window, GLFW_KEY_W ) == GLFW_PRESS ) _move[1] += MOVEMENT_SENSITIVITY;
if ( glfwGetKey( window, GLFW_KEY_PAGE_DOWN ) == GLFW_PRESS ) _move[2] -= ZOOM_SENSITIVITY;
if ( glfwGetKey( window, GLFW_KEY_PAGE_UP ) == GLFW_PRESS ) _move[2] += ZOOM_SENSITIVITY;
if ( glfwGetKey( window, GLFW_KEY_UP ) == GLFW_PRESS ) _angX -= ROTATION_SENSITIVITY;
if ( glfwGetKey( window, GLFW_KEY_DOWN ) == GLFW_PRESS ) _angX += ROTATION_SENSITIVITY;
if ( glfwGetKey( window, GLFW_KEY_RIGHT ) == GLFW_PRESS ) _angY -= ROTATION_SENSITIVITY;
if ( glfwGetKey( window, GLFW_KEY_LEFT ) == GLFW_PRESS ) _angY += ROTATION_SENSITIVITY;
}
Note, you have to adjust the sensitivity and the buttons or even other kinds of input to your needs. To get a clearly defined behavior you should execute the update method in a time discrete process.
Set up the translation matrix and the rotation matrices in the methode Camera::getViewMatrix and concatenate them to the view matrix:
glm::mat4 Camera::getViewMatrix()
{
glm::mat4 rotX = glm::rotate( _angX * (float)PI / 180.0f, glm::vec3( mViewMatrix[0] ) );
glm::mat4 rotY = glm::rotate( _angY * (float)PI / 180.0f, glm::vec3( mViewMatrix[1] ) );
glm::mat4 trans = glm::translate( glm::mat4( 1.0 ), _move );
return trans * mViewMatrix * rotX * rotY;
}

Weird OpenGL Texture Display

I am drawing a 3D cube with texture and i get sth like this. I dont exactly know what is wrong ;/
http://i.stack.imgur.com/081nl.png
Vectors for texturecord
vec2(0.0f, 0.0f),
vec2(1.0f, 0.0f),
vec2(1.0f, 1.0f),
vec2(0.0f, 1.0f),
....
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 9));
....
glUniform1i(glGetUniformLocation(program, "mySampler"), 0);
....
color = texture(myTextureSampler,UV); //SHADER CODE
To load first example i used:
SDL_Surface* textures;
textures = SDL_LoadBMP(filename);
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, textures->w, textures->h, 0, GL_RGB, GL_UNSIGNED_BYTE, textures->pixels);
To second pics i used :
int width, height;
GLubyte * data;
FILE * file;
file = fopen(filename, "rb");
if (file == NULL) return 0;
width = 128;
height = 128;
data = (GLubyte *)malloc(width * height * 3);
//int size = fseek(file,);
fread(data, width * height * 3, 1, file);
fclose(file);
for (int i = 0; i < width * height; ++i)
{
int index = i * 3;
unsigned char B, R;
B = data[index];
R = data[index + 2];
data[index] = R;
data[index + 2] = B;
}
glActiveTexture(GL_TEXTURE0);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, data);
The both doesnt work correct;// any ideas?
Complete program:
main.cpp:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <fstream>
#include <GL\glew.h> // UP
#include <GL\glut.h>
#include <GLFW\glfw3.h>
#include <glm\gtc\matrix_transform.hpp>
#include <glm\gtx\transform.hpp>
#include <SDL.h>
using namespace glm;
GLuint LoadTexture(const char * filename)
{
int width, height;
GLubyte * data;
FILE * file;
file = fopen(filename, "rb");
if (file == NULL) return 0;
width = 128;
height = 128;
data = (GLubyte *)malloc(width * height * 3);
//int size = fseek(file,);
fread(data, width * height * 3, 1, file);
fclose(file);
for (int i = 0; i < width * height; ++i)
{
int index = i * 3;
unsigned char B, R;
B = data[index];
R = data[index + 2];
data[index] = R;
data[index + 2] = B;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glActiveTexture(GL_TEXTURE0);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
//free(data);
return texture;
/**
SDL_Surface* textures;
textures = SDL_LoadBMP(filename);
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, textures->w, textures->h, 0, GL_RGB, GL_UNSIGNED_BYTE, textures->pixels);
return texture;
**/
}
std::string LoadFileToString(const char* filepath){
std::string fileData = "";
std::ifstream stream(filepath, std::ios::in);
if (stream.is_open()){
std::string line = "";
while (getline(stream, line)){
fileData += "\n" + line;
}
stream.close();
}
return fileData;
}
GLuint LoadShaders(const char*VertShaderPath, const char* fragShaderPath){
GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
std::string vertShaderSource = LoadFileToString(VertShaderPath);
std::string fragShaderSource = LoadFileToString(fragShaderPath);
const char* rawVertShaderSource = vertShaderSource.c_str();
const char* rawfragShaderSource = fragShaderSource.c_str();
glShaderSource(vertShader, 1, &rawVertShaderSource, NULL);
glShaderSource(fragShader, 1, &rawfragShaderSource, NULL);
glCompileShader(vertShader);
glCompileShader(fragShader);
GLuint program = glCreateProgram();
glAttachShader(program, vertShader);
glAttachShader(program, fragShader);
glLinkProgram(program);
return program;
}
const float movementspeed = 0.01f;
class Camera{
vec3 position;
vec3 viewDirection;
const vec3 UP;
vec2 oldmouseposition;
public:
Camera();
mat4 getWorldToViewMatrix() const;
void mouseUpdate(const vec2 &newMousePosition);
void moveForward();
void moveBackWard();
void left();
void right();
void up();
void down();
};
Camera::Camera() :viewDirection(0.0f, 0.0f, -1.0f), UP(0.0f, 1.0f, 0.0f){}
void Camera::mouseUpdate(const vec2 &newMousePosition){
glm::vec2 mouseDelta = newMousePosition - oldmouseposition;
if (glm::length(mouseDelta) >10.0f)
{
oldmouseposition = newMousePosition;
return;
}
viewDirection = glm::mat3(glm::rotate(-mouseDelta.x*0.5f, UP)) * viewDirection;
oldmouseposition = newMousePosition;
}
void Camera::moveForward(){
position -= movementspeed *viewDirection;
}
void Camera::moveBackWard(){
position += movementspeed *viewDirection;
}
void Camera::left(){
glm::vec3 strafeDirection = glm::cross(viewDirection, UP);
position += movementspeed *strafeDirection;
}
void Camera::right(){
glm::vec3 strafeDirection = glm::cross(viewDirection, UP);
position += -movementspeed *strafeDirection;
}
void Camera::up(){
position += movementspeed *UP;
}
void Camera::down(){
position += -movementspeed *UP;
}
mat4 Camera::getWorldToViewMatrix() const {
return lookAt(position, position - viewDirection, UP);
}
int main(int argc, char ** argv)
{
if (!glfwInit())
exit(EXIT_FAILURE);
GLFWwindow* window;
window = glfwCreateWindow(640, 480, "My 3D World", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glewExperimental = true;
if (glewInit() != GLEW_OK){
glfwTerminate();
exit(EXIT_FAILURE);
}
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
GLuint program = LoadShaders("vertex.wss", "fragment.fss"); // shadersprogram
struct Vertex{
glm::vec3 position;
glm::vec3 color;
glm::vec2 texture;
glm::vec3 normal;
};
Vertex verts[] = {
vec3(-1.0f, +1.0f, +1.0f), // 0
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(+1.0f, +1.0f, +1.0f), // 1
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(+1.0f, +1.0f, -1.0f), // 2
vec3(1.0f, 0.0f, 0.0f), // Colour
vec2(1.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, +1.0f, -1.0f), // 3
vec3(0.0f, 0.0f, 0.0f), // Colour
vec2(0.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, +1.0f, -1.0f), // 4
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(0.0f, 0.0f),
vec3(0.0f, -1.0f, 0.0f), //normal
vec3(+1.0f, +1.0f, -1.0f), // 5
vec3(1.0f, 0.0f, 0.0f), // Colour
vec2(1.0f, 0.0f),
vec3(0.0f, -1.0f, 0.0f), //normal
vec3(+1.0f, -1.0f, -1.0f), //
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(1.0f, 1.0f),
vec3(0.0f, -1.0f, 0.0f), //normal
vec3(-1.0f, -1.0f, -1.0f), // 7
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(0.0f, 1.0f),
vec3(0.0f, -1.0f, 0.0f), //normal
vec3(+1.0f, +1.0f, -1.0f), // 8
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(0.0f, 0.0f),
vec3(0.0f, 0.0f, -1.0f), //normal
vec3(+1.0f, +1.0f, +1.0f), // 9
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(1.0f, 0.0f),
vec3(0.0f, 0.0f, -1.0f), //normal
vec3(+1.0f, -1.0f, +1.0f), // 10
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(1.0f, 1.0f),
vec3(0.0f, 0.0f, -1.0f), //normal
vec3(+1.0f, -1.0f, -1.0f), // 11
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(0.0f, 1.0f),
vec3(0.0f, 0.0f, -1.0f), //normal
vec3(-1.0f, +1.0f, +1.0f), // 12
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, +1.0f, -1.0f), // 13
vec3(1.0f, 0.0f, 0.0f), // Colour
vec2(1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, -1.0f, -1.0f), // 14
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(1.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, -1.0f, +1.0f), // 15
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(0.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(+1.0f, +1.0f, +1.0f), // 16
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, +1.0f, +1.0f), // 17
vec3(1.0f, 0.0f, 1.0f), // Colour
vec2(1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, -1.0f, +1.0f), // 18
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(1.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(+1.0f, -1.0f, +1.0f), // 19
vec3(1.0f, 0.0f, 1.0f), // Colour
vec2(0.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(+1.0f, -1.0f, -1.0f), // 20
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, -1.0f, -1.0f), // 21
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, -1.0f, +1.0f), // 22
vec3(0.0f, 1.0f, 1.0f), // Colour
vec2(1.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(+1.0f, -1.0f, +1.0f), // 23
vec3(1.0f, 1.0f, 0.0f), // Colour
vec2(0.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f) //normal
};
GLushort indices[] = {
0, 1, 2, 0, 2, 3, // Top
4, 5, 6, 4, 6, 7, // Front
8, 9, 10, 8, 10, 11, // Right
12, 13, 14, 12, 14, 15, // Left
16, 17, 18, 16, 18, 19, // Back
20, 22, 21, 20, 23, 22 // Bottom
};
////////VAO niepotrzebne
////////VBO
GLuint vboID;
glGenBuffers(1, &vboID);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
GLuint indexbuff;
glGenBuffers(1, &indexbuff);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexbuff);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);
//////
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, LoadTexture("block"));
Camera camera;
while (!glfwWindowShouldClose(window))
{
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glUseProgram(program);
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS){
camera.moveForward();
}
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS){
camera.moveBackWard();
}
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS){
camera.left();
}
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS){
camera.right();
}
if (glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS){
camera.up();
}
if (glfwGetKey(window, GLFW_KEY_F) == GLFW_PRESS){
camera.down();
}
if (xpos > 0 && xpos < 640 && ypos>0 && ypos < 400){
camera.mouseUpdate(vec2(float(xpos / 50), float(ypos / 50)));
std::cout << "pos x: " << xpos << "pos y: " << ypos << std::endl;
}
// textures
glUniform1i(glGetUniformLocation(program, "mySampler"), 0);
//AMBIENT LIGHT
GLint ambientlightlocation = glGetUniformLocation(program, "ambientLight");
vec3 ambientLight(0.3f, 0.3f, 0.3f);
glUniform3fv(ambientlightlocation, 1, &ambientLight[0]);
//Light
GLint lightlocation = glGetUniformLocation(program, "lightPosition");
vec3 lightposition(1.0f, 1.0f, -3.75f);
glUniform3fv(lightlocation, 1, &lightposition[0]);
GLint fullTransformMatrixUniformLocation = glGetUniformLocation(program, "fullTransformMatrix");
mat4 fullTransformMatrix;
mat4 projectionMatrix = perspective(90.0f, (480.0f / 640.0f), 0.1f, 5.0f);
mat4 worldToProjectionMatrix = projectionMatrix* camera.getWorldToViewMatrix();
//CUBE 1 tak sie robi gdyby sie roznily
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (void*)0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 3));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 6));
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 9));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexbuff);
mat4 cube1WorldMatrix = translate(vec3(1.0f, 0.0f, -3.75f)) * rotate(0.0f, vec3(0.0f, 1.0f, 1.0f));
fullTransformMatrix = worldToProjectionMatrix *cube1WorldMatrix;
glUniformMatrix4fv(fullTransformMatrixUniformLocation, 1, GL_FALSE, &fullTransformMatrix[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0);
// CUBE 2 gdyby byly rozne
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (void*)0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 3));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 6));
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 9));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexbuff);
mat4 cube2WorldMatrix = translate(vec3(-3.0f, 0.0f, -3.75f)) * rotate(126.0f, vec3(1.0f, 0.0f, 0.0f));
fullTransformMatrix = worldToProjectionMatrix *cube2WorldMatrix;
glUniformMatrix4fv(fullTransformMatrixUniformLocation, 1, GL_FALSE, &fullTransformMatrix[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
fragment.fss:
#version 330 core
out vec4 color;
in vec3 theColor;
in vec2 UV;
uniform sampler2D myTextureSampler;
void main()
{
color = texture(myTextureSampler,UV);
//texture(myTextureSampler,UV);
// * vec4(theColor,1.0);
}
vertex.wss:
#version 330 core
layout(location=0) in vec3 in_pos;
layout(location=1) in vec3 vertexColor;
layout(location=2) in vec2 vertexUV;
layout(location=3) in vec3 normal;
uniform mat4 fullTransformMatrix;
uniform vec3 ambientLight;
uniform vec3 lightPosition;
out vec3 theColor;
out vec2 UV;
void main()
{
vec4 v = vec4(in_pos, 1.0);
gl_Position = fullTransformMatrix* v;
vec3 lightVector = normalize(lightPosition-normal);
float brightness = dot(lightVector,normal);
theColor = vertexColor * vec3( brightness, brightness, brightness);// * ambientLight;
UV = vertexUV;
}
If you want to load compressed images you'll need a proper decoder.
Your LoadTexture() function was assuming everything passed in
is an uncompressed, tightly-packed blob of RGB triplets, which is...not a good assumption :)
Here's an example using stb_image and a screenshot PNG:
GLuint LoadTexture(const char * filename)
{
int width = 0, height = 0, n = 0;
unsigned char* data = stbi_load
(
filename,
&width,
&height,
&n,
3
);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glActiveTexture(GL_TEXTURE0);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free( data );
return texture;
}
All together:
#include <iostream>
#include <cstdarg>
#include <GL\glew.h>
#include <GLFW\glfw3.h>
#define GLM_FORCE_RADIANS
#include <glm\gtc\matrix_transform.hpp>
#include <glm\gtx\transform.hpp>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
using namespace glm;
struct Program
{
static GLuint Load( const char* shader, ... )
{
GLuint prog = glCreateProgram();
va_list args;
va_start( args, shader );
while( shader )
{
const GLenum type = va_arg( args, GLenum );
AttachShader( prog, type, shader );
shader = va_arg( args, const char* );
}
va_end( args );
glLinkProgram( prog );
CheckStatus( prog );
return prog;
}
private:
static void CheckStatus( GLuint obj )
{
GLint status = GL_FALSE;
if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
if( status == GL_TRUE ) return;
GLchar log[ 1 << 15 ] = { 0 };
if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
std::cerr << log << std::endl;
exit( EXIT_FAILURE );
}
static void AttachShader( GLuint program, GLenum type, const char* src )
{
GLuint shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );
CheckStatus( shader );
glAttachShader( program, shader );
glDeleteShader( shader );
}
};
#define GLSL(version, shader) "#version " #version "\n" #shader
const char* vert = GLSL
(
330 core,
layout(location=0) in vec3 in_pos;
layout(location=1) in vec3 vertexColor;
layout(location=2) in vec2 vertexUV;
layout(location=3) in vec3 normal;
uniform mat4 fullTransformMatrix;
uniform vec3 ambientLight;
uniform vec3 lightPosition;
out vec3 theColor;
out vec2 UV;
void main()
{
vec4 v = vec4(in_pos, 1.0);
gl_Position = fullTransformMatrix* v;
vec3 lightVector = normalize(lightPosition-normal);
float brightness = dot(lightVector,normal);
theColor = vertexColor * vec3( brightness, brightness, brightness);// * ambientLight;
UV = vertexUV;
}
);
const char* frag = GLSL
(
330 core,
out vec4 color;
in vec3 theColor;
in vec2 UV;
uniform sampler2D mySampler;
void main()
{
color = texture(mySampler,UV);
}
);
GLuint LoadTexture(const char * filename)
{
int width = 0, height = 0, n = 0;
unsigned char* data = stbi_load
(
filename,
&width,
&height,
&n,
3
);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glActiveTexture(GL_TEXTURE0);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free( data );
return texture;
}
const float movementspeed = 0.01f;
class Camera{
vec3 position;
vec3 viewDirection;
const vec3 UP;
vec2 oldmouseposition;
public:
Camera();
mat4 getWorldToViewMatrix() const;
void mouseUpdate(const vec2 &newMousePosition);
void moveForward();
void moveBackWard();
void left();
void right();
void up();
void down();
};
Camera::Camera() :viewDirection(0.0f, 0.0f, -1.0f), UP(0.0f, 1.0f, 0.0f){}
void Camera::mouseUpdate(const vec2 &newMousePosition){
glm::vec2 mouseDelta = newMousePosition - oldmouseposition;
if (glm::length(mouseDelta) >10.0f)
{
oldmouseposition = newMousePosition;
return;
}
viewDirection = glm::mat3(glm::rotate(-mouseDelta.x*0.5f, UP)) * viewDirection;
oldmouseposition = newMousePosition;
}
void Camera::moveForward(){
position -= movementspeed *viewDirection;
}
void Camera::moveBackWard(){
position += movementspeed *viewDirection;
}
void Camera::left(){
glm::vec3 strafeDirection = glm::cross(viewDirection, UP);
position += movementspeed *strafeDirection;
}
void Camera::right(){
glm::vec3 strafeDirection = glm::cross(viewDirection, UP);
position += -movementspeed *strafeDirection;
}
void Camera::up(){
position += movementspeed *UP;
}
void Camera::down(){
position += -movementspeed *UP;
}
mat4 Camera::getWorldToViewMatrix() const {
return lookAt(position, position - viewDirection, UP);
}
int main(int argc, char ** argv)
{
if (!glfwInit())
exit(EXIT_FAILURE);
GLFWwindow* window;
window = glfwCreateWindow(640, 480, "My 3D World", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glewExperimental = true;
if (glewInit() != GLEW_OK){
glfwTerminate();
exit(EXIT_FAILURE);
}
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
GLuint program = Program::Load
(
vert, GL_VERTEX_SHADER,
frag, GL_FRAGMENT_SHADER,
NULL
);
struct Vertex{
glm::vec3 position;
glm::vec3 color;
glm::vec2 texture;
glm::vec3 normal;
};
Vertex verts[] = {
vec3(-1.0f, +1.0f, +1.0f), // 0
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(+1.0f, +1.0f, +1.0f), // 1
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(+1.0f, +1.0f, -1.0f), // 2
vec3(1.0f, 0.0f, 0.0f), // Colour
vec2(1.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, +1.0f, -1.0f), // 3
vec3(0.0f, 0.0f, 0.0f), // Colour
vec2(0.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, +1.0f, -1.0f), // 4
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(0.0f, 0.0f),
vec3(0.0f, -1.0f, 0.0f), //normal
vec3(+1.0f, +1.0f, -1.0f), // 5
vec3(1.0f, 0.0f, 0.0f), // Colour
vec2(1.0f, 0.0f),
vec3(0.0f, -1.0f, 0.0f), //normal
vec3(+1.0f, -1.0f, -1.0f), //
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(1.0f, 1.0f),
vec3(0.0f, -1.0f, 0.0f), //normal
vec3(-1.0f, -1.0f, -1.0f), // 7
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(0.0f, 1.0f),
vec3(0.0f, -1.0f, 0.0f), //normal
vec3(+1.0f, +1.0f, -1.0f), // 8
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(0.0f, 0.0f),
vec3(0.0f, 0.0f, -1.0f), //normal
vec3(+1.0f, +1.0f, +1.0f), // 9
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(1.0f, 0.0f),
vec3(0.0f, 0.0f, -1.0f), //normal
vec3(+1.0f, -1.0f, +1.0f), // 10
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(1.0f, 1.0f),
vec3(0.0f, 0.0f, -1.0f), //normal
vec3(+1.0f, -1.0f, -1.0f), // 11
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(0.0f, 1.0f),
vec3(0.0f, 0.0f, -1.0f), //normal
vec3(-1.0f, +1.0f, +1.0f), // 12
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, +1.0f, -1.0f), // 13
vec3(1.0f, 0.0f, 0.0f), // Colour
vec2(1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, -1.0f, -1.0f), // 14
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(1.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, -1.0f, +1.0f), // 15
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(0.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(+1.0f, +1.0f, +1.0f), // 16
vec3(0.0f, 0.0f, 1.0f), // Colour
vec2(0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, +1.0f, +1.0f), // 17
vec3(1.0f, 0.0f, 1.0f), // Colour
vec2(1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, -1.0f, +1.0f), // 18
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(1.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(+1.0f, -1.0f, +1.0f), // 19
vec3(1.0f, 0.0f, 1.0f), // Colour
vec2(0.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(+1.0f, -1.0f, -1.0f), // 20
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, -1.0f, -1.0f), // 21
vec3(0.0f, 1.0f, 0.0f), // Colour
vec2(1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(-1.0f, -1.0f, +1.0f), // 22
vec3(0.0f, 1.0f, 1.0f), // Colour
vec2(1.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f), //normal
vec3(+1.0f, -1.0f, +1.0f), // 23
vec3(1.0f, 1.0f, 0.0f), // Colour
vec2(0.0f, 1.0f),
vec3(0.0f, 1.0f, 0.0f) //normal
};
GLushort indices[] = {
0, 1, 2, 0, 2, 3, // Top
4, 5, 6, 4, 6, 7, // Front
8, 9, 10, 8, 10, 11, // Right
12, 13, 14, 12, 14, 15, // Left
16, 17, 18, 16, 18, 19, // Back
20, 22, 21, 20, 23, 22 // Bottom
};
////////VAO niepotrzebne
////////VBO
GLuint vboID;
glGenBuffers(1, &vboID);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
GLuint indexbuff;
glGenBuffers(1, &indexbuff);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexbuff);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);
//////
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, LoadTexture("TADdR.png"));
Camera camera;
while (!glfwWindowShouldClose(window))
{
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glUseProgram(program);
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS){
camera.moveForward();
}
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS){
camera.moveBackWard();
}
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS){
camera.left();
}
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS){
camera.right();
}
if (glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS){
camera.up();
}
if (glfwGetKey(window, GLFW_KEY_F) == GLFW_PRESS){
camera.down();
}
if (xpos > 0 && xpos < 640 && ypos>0 && ypos < 400){
camera.mouseUpdate(vec2(float(xpos / 50), float(ypos / 50)));
std::cout << "pos x: " << xpos << "pos y: " << ypos << std::endl;
}
// textures
glUniform1i(glGetUniformLocation(program, "mySampler"), 0);
//AMBIENT LIGHT
GLint ambientlightlocation = glGetUniformLocation(program, "ambientLight");
vec3 ambientLight(0.3f, 0.3f, 0.3f);
glUniform3fv(ambientlightlocation, 1, &ambientLight[0]);
//Light
GLint lightlocation = glGetUniformLocation(program, "lightPosition");
vec3 lightposition(1.0f, 1.0f, -3.75f);
glUniform3fv(lightlocation, 1, &lightposition[0]);
GLint fullTransformMatrixUniformLocation = glGetUniformLocation(program, "fullTransformMatrix");
mat4 fullTransformMatrix;
mat4 projectionMatrix = perspective( glm::radians( 90.0f ), (480.0f / 640.0f), 0.1f, 5.0f);
mat4 worldToProjectionMatrix = projectionMatrix* camera.getWorldToViewMatrix();
//CUBE 1 tak sie robi gdyby sie roznily
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (void*)0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 3));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 6));
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 9));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexbuff);
mat4 cube1WorldMatrix = translate(vec3(1.0f, 0.0f, -3.75f)) * rotate(0.0f, vec3(0.0f, 1.0f, 1.0f));
fullTransformMatrix = worldToProjectionMatrix *cube1WorldMatrix;
glUniformMatrix4fv(fullTransformMatrixUniformLocation, 1, GL_FALSE, &fullTransformMatrix[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0);
// CUBE 2 gdyby byly rozne
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (void*)0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 3));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 6));
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, (char*)(sizeof(float) * 9));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexbuff);
mat4 cube2WorldMatrix = translate(vec3(-3.0f, 0.0f, -3.75f)) * rotate(126.0f, vec3(1.0f, 0.0f, 0.0f));
fullTransformMatrix = worldToProjectionMatrix *cube2WorldMatrix;
glUniformMatrix4fv(fullTransformMatrixUniformLocation, 1, GL_FALSE, &fullTransformMatrix[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}