I want to create a rubiks cube where each side contains multiple cubes. So far I'm able to create the overall Cube. I now want to rotate one side of the cube to the left, to do this i create a new matrix and then bind the uniform to that matrix. This works fine, but if i do a second operation, like rotating a different side, I again create a new matrix with the rotation and bind the uniform to that matrix. After i draw my objects after the second rotation, my objects are reset to the initial matrix (rotations are reverted).
Code for the left rotation:
glm::mat4 spinLeft(glm::mat4 anim, GLuint shaderProgram, int i) {
if(i < 9) {
// createAnim(shaderProgram, anim);
if(nrRotations <= 900) {
anim = spinObj(anim, 1.0);
// cout << nrRotations << endl;
nrRotations += 1;
glUniformMatrix4fv(uniformAnim, 1, GL_FALSE, glm::value_ptr(anim));
}
}
return anim;
}
glm::mat4 spinObj(glm::mat4 anim, float orientation) {
float angle = 0.1f * orientation;
anim = glm::rotate(anim, glm::radians(angle), glm::vec3(0.0f, 0.0f, 2.0f));
return anim;
}
Code for the right rotation:
glm::mat4 spinRight(glm::mat4 anim, GLuint shaderProgram, int i) {
if(i == RIGHT || i == TOP_RIGHT || i == BOTTOM_RIGHT
|| i == RIGHT+9 || i == TOP_RIGHT+9 || i == BOTTOM_RIGHT+9
|| i == RIGHT+18 || i == TOP_RIGHT+18 || i == BOTTOM_RIGHT+18)
{
// createAnim(shaderProgram, anim);
if(nrRotations <= 900) {
anim = spinObj2(anim, 1.0);
// cout << nrRotations << endl;
nrRotations +=1;
glUniformMatrix4fv(uniformAnim, 1, GL_FALSE, glm::value_ptr(anim));
}
}
return anim;
}
glm::mat4 spinObj2(glm::mat4 anim, float orientation) {
float angle = 0.1f * orientation;
anim = glm::translate(anim, glm::vec3(0.0f, 0.0f, -2.1f) );
anim = glm::rotate(anim, glm::radians(angle), glm::vec3(1.0f, 0.0f, 0.0f));
anim = glm::translate(anim, -(glm::vec3(0.0f, 0.0f, -2.1f)) );
return anim;
}
Code responsible for drawing, the vtxArray is the array containing my cubes, which form the overall cube. With the createAnim function i bind a new matrix (which is simply the identity matrix). If i dont call the createAnim the cube is not reset to the initial cube, but i get the problem that all rows are rotating, and not just the 1 row i define.
for(int i = 0; i < arraySize; i+=1) {
createAnim(shaderProgram, anim);
if(move == 1) {
if(i < 9) {
anim2 = spinLeft(anim2, shaderProgram, i);
if(nrRotations == 900) {
move ++;
nrRotations = 0;
// anim = anim2;
}
}
} else if (move == 2) {
anim3 = spinRight(anim3,shaderProgram, i);
if (nrRotations == 900) {
move++;
nrRotations = 0;
}
}
glBufferData(GL_ARRAY_BUFFER, 6*36*4, &vtxArray[i], GL_STATIC_DRAW);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
I use 1 VBO and 1 VAO for this. I hope you understand the problem I'm having, let me know if more code or explanation is required.
You will want to take advantage of matrix multiplication. There are many good resources online about how matrix multiplication can be used to "chain" rotations sequentially and is part of the intuition behind how the MVP matrix is chained together from seperate model, view and projection matrices without losing any of the information in the process.
In brief:
iterate through all blocks in the Rubik's cube and filter the blocks that form the face you want to rotate (check if its position is a certain value)
apply a rotation to its model matrix with matrix multiplication
update uniform for block and draw
If you get stuck, here is an example based around the code from LearnOpenGL, which demonstrates chaining matrix multiplication:
#include <iostream>
#include <vector>
#include <algorithm>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/string_cast.hpp>
#include <learnopengl/camera.h>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
using std::vector;
using std::cout;
using std::endl;
using glm::mat4;
using glm::vec2;
using glm::vec3;
using glm::vec4;
using glm::perspective;
using glm::radians;
using glm::normalize;
void processInput(GLFWwindow *window);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
// grid dimensions
const unsigned int GRID_WIDTH = 600;
const unsigned int GRID_HEIGHT = 600;
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;
// timing
float deltaTime = 0.0f;
float lastFrame = 0.0f;
mat4 view;
mat4 projection;
float fov = 90.0f;
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
class Block {
public:
unsigned int shaderProgram;
unsigned int VBO, VAO;
mat4 model;
Block(vec3 pos=vec3(0,0,0)) {
model = translate(mat4(1.0), pos);
// scale it down a little bit to see the different blocks
model = scale(model, vec3(0.99, 0.99, 0.99));
float vertices[] = {
0.5, -0.5, -0.5, 0, 0, 1,// 1
-0.5, -0.5, -0.5, 0, 0, 1,// 0
0.5, 0.5, -0.5, 0, 0, 1,// 2
-0.5, -0.5, -0.5, 0, 0, 1,// 0
-0.5, 0.5, -0.5, 0, 0, 1,// 3
0.5, 0.5, -0.5, 0, 0, 1,// 2
-0.5, -0.5, 0.5, 0, 1, 0,// 0
0.5, -0.5, 0.5, 0, 1, 0,// 1
0.5, 0.5, 0.5, 0, 1, 0,// 2
0.5, 0.5, 0.5, 0, 1, 0,// 2
-0.5, 0.5, 0.5, 0, 1, 0,// 3
-0.5, -0.5, 0.5, 0, 1, 0,// 0
-0.5, 0.5, 0.5, 1, 0, 0,
-0.5, 0.5, -0.5, 1, 0, 0,
-0.5, -0.5, -0.5, 1, 0, 0,
-0.5, -0.5, -0.5, 1, 0, 0,
-0.5, -0.5, 0.5, 1, 0, 0,
-0.5, 0.5, 0.5, 1, 0, 0,
0.5, 0.5, -0.5, 1, 0.5, 0, // 1
0.5, 0.5, 0.5, 1, 0.5, 0, // 0
0.5, -0.5, -0.5, 1, 0.5, 0, // 2
0.5, 0.5, 0.5, 1, 0.5, 0, // 0
0.5, -0.5, 0.5, 1, 0.5, 0, // 3
0.5, -0.5, -0.5, 1, 0.5, 0, // 2
-0.5, -0.5, -0.5, 1, 1, 1,//0
0.5, -0.5, -0.5, 1, 1, 1,//1
0.5, -0.5, 0.5, 1, 1, 1,//2
0.5, -0.5, 0.5, 1, 1, 1,//2
-0.5, -0.5, 0.5, 1, 1, 1,//3
-0.5, -0.5, -0.5, 1, 1, 1,//0
0.5, 0.5, -0.5, 1, 1, 0, //1
-0.5, 0.5, -0.5, 1, 1, 0, //0
0.5, 0.5, 0.5, 1, 1, 0, //2
-0.5, 0.5, -0.5, 1, 1, 0, //0
-0.5, 0.5, 0.5, 1, 1, 0, //3
0.5, 0.5, 0.5, 1, 1, 0, //2
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aCol;\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"out vec4 outColor;\n"
"void main()\n"
"{\n"
" gl_Position = projection * view * model * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
" outColor = vec4(aCol,1.0f);\n"
"}\0";
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec4 outColor;\n"
"void main()\n"
"{\n"
" FragColor = outColor;\n"
"}\n\0";
// vertex shader
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// check for shader compile errors
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl;
}
// fragment shader
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// check for shader compile errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl;
}
// link shaders
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// check for linking errors
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
void setMatrix(std::string name, glm::mat4 mat) {
glUseProgram(shaderProgram);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
void draw() {
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
vec3 getPosition() {
return vec3(model[3]);
}
};
class Cube {
public:
vector<Block> blocks;
Cube() {
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
for (int z = -1; z <= 1; z++) {
blocks.push_back(Block(vec3(x,y,z)));
}
}
}
}
void draw(mat4 view, mat4 projection) {
for (int i = 0; i < blocks.size(); i++) {
blocks[i].setMatrix("model", blocks[i].model);
blocks[i].setMatrix("view", view);
blocks[i].setMatrix("projection", projection);
blocks[i].draw();
}
}
void rotate(std::string value, bool ccw) {
int index;
vec3 axis;
if (value == "x") {
index = 0;
axis = vec3(1.0f, 0.0f, 0.0f);
}
if (value == "y") {
index = 1;
axis = vec3(0.0f, 1.0f, 0.0f);
}
for (int i = 0; i < blocks.size(); i++) {
if (fabs(blocks[i].getPosition()[index] - 1.0f) < 0.1f ) {
// create rotation matrix
mat4 rotationMatrix = glm::rotate(mat4(1.0f), radians(ccw ? -90.0f : 90.0f), axis);
// multiply with current matrix
blocks[i].model = rotationMatrix * blocks[i].model;
}
}
}
};
Cube *rubiksCube;
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Rubik's Cube", NULL, NULL);
if (window == NULL)
{
cout << "Failed to create GLFW window" << endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetScrollCallback(window, scroll_callback);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
cout << "Failed to initialize GLAD" << endl;
return -1;
}
projection = perspective(radians(fov), (float)SCR_WIDTH/(float)SCR_HEIGHT, 0.1f, 1000.0f);
glClearColor(0.0, 0.0, 0.0, 1.0);
rubiksCube = new Cube();
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
while (!glfwWindowShouldClose(window))
{
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
processInput(window);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
rubiksCube->draw(camera.GetViewMatrix(), projection);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
delete rubiksCube;
return 0;
}
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime);
}
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos;
lastY = ypos;
camera.ProcessMouseMovement(xoffset, yoffset);
}
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
camera.ProcessMouseScroll(yoffset);
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_1 && action == 1) {
rubiksCube->rotate("x", true);
}
if (button == GLFW_MOUSE_BUTTON_3 && action == 1) {
rubiksCube->rotate("y", true);
}
if (button == GLFW_MOUSE_BUTTON_2 && action == 1) {
rubiksCube->rotate("x", false);
}
}
Output:
Related
I'm writing a simple 3D world in OpenGL, that can render various stuff. I'm relatively new to OpenGL, and might not notice something, but there's a really big problem with (I guess) fragment shader.
What it does is it ignores z-value and draws faces in order that they were given by index buffer. What I mean by that, is if there is, for example, conditional index buffer, and it contains triangle 1, triangle 2, and triangle 3, and they stand in a row in front of the camera, then triangle 3, regardless of it's z-value, will be drawn on top of other two, 'cause it's last.
As a result, I became this:
This image shows exactly what I mean. The front side behaves like it's transparent, relatively to the neighbor side, but in terms of transparency, it ignores the parallel side, 'cause they are drawn in such an order.
My code for camera:
PCamera::PCamera(GLFWwindow* projectWindow, float windowWidth, float windowHeight)
{
window = projectWindow;
wWidth = windowWidth;
wHeight = windowHeight;
Position = glm::vec3(0.f, 0.f, -10.f);
Rotation = glm::vec3(0.f, glm::pi<float>(), 0.f);
if (glfwRawMouseMotionSupported())
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
glfwGetCursorPos(window, &xposnormal, &yposnormal);
}
PCamera::~PCamera()
{
}
glm::mat4 PCamera::NavigateCamera()
{
double xpos, ypos;
int state;
glfwGetCursorPos(window, &xpos, &ypos);
state = glfwGetKey(window, GLFW_KEY_ESCAPE);
if (state == GLFW_PRESS)
{
bMouseControl = false;
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);
if ((state == GLFW_PRESS) && (bMouseControl == false))
{
bMouseControl = true;
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
glfwGetCursorPos(window, &xposnormal, &yposnormal);
}
if (bMouseControl)
{
glfwGetCursorPos(window, &xpos, &ypos);
Rotation.x += (float)(yposnormal - ypos) / -300.f;
Rotation.y += (float)(xposnormal - xpos) / -300.f;
glfwSetCursorPos(window, xposnormal, yposnormal);
}
glm::mat4 RTSMatrix = glm::rotate(UnitMatrix, Rotation.x, glm::vec3(1.f, 0.f, 0.f)) * glm::rotate(UnitMatrix, Rotation.y, glm::vec3(0.f, 1.f, 0.f));
glm::vec3 DeltaPosition(0.f, 0.f, 0.f);
state = glfwGetKey(window, GLFW_KEY_W);
if (state == GLFW_PRESS) DeltaPosition.z += 0.01f;
state = glfwGetKey(window, GLFW_KEY_S);
if (state == GLFW_PRESS) DeltaPosition.z -= 0.01f;
state = glfwGetKey(window, GLFW_KEY_A);
if (state == GLFW_PRESS) DeltaPosition.x += 0.01f;
state = glfwGetKey(window, GLFW_KEY_D);
if (state == GLFW_PRESS) DeltaPosition.x -= 0.01f;
state = glfwGetKey(window, GLFW_KEY_LEFT_SHIFT);
if (state == GLFW_PRESS) DeltaPosition.y -= 0.01f;
state = glfwGetKey(window, GLFW_KEY_SPACE);
if (state == GLFW_PRESS) DeltaPosition.y += 0.01f;
glm::vec4 D4Position(Position, 0.f);
glm::mat4 InverseRTSMatrix = glm::rotate(UnitMatrix, -Rotation.y, glm::vec3(0.f, 1.f, 0.f)) * glm::rotate(UnitMatrix, -Rotation.x, glm::vec3(1.f, 0.f, 0.f));
D4Position -= InverseRTSMatrix*glm::vec4(DeltaPosition, 0.0);
Position.x = D4Position.x;
Position.y = D4Position.y;
Position.z = D4Position.z;
RTSMatrix = RTSMatrix * glm::translate(UnitMatrix, -Position);
return RTSMatrix;
}
void PCamera::UpdateProjectionMatrix(float Angle, float windowWidth, float windowHeight)
{
ProjectionMatrix = glm::perspective(Angle, (GLfloat)windowWidth / (GLfloat)windowHeight, -1.0f, 1.0f);
}
Code for my renderer:
void PRenderer::Draw(PObject * Object)
{
Object->Bind();
glDrawElements(GL_TRIANGLES, Object->IBCount, GL_UNSIGNED_INT, nullptr);
}
Code of my main execution file:
PProject::PProject(PRenderer * Renderer)
{
ProjectRenderer = Renderer;
}
PProject::~PProject()
{
}
int PProject::Launch()
{
GLFWwindow* window;
if (!glfwInit()) return -1;
window = glfwCreateWindow(640, 480, "PhysMaker", NULL, NULL);
if (!window) { glfwTerminate(); return -1; }
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) return -1;
float pos[] =
{
-0.5, -0.5, -0.5, 1.0, 0.0, 0.0,
-0.5, -0.5, 0.5, 0.0, 1.0, 0.0,
-0.5, 0.5, 0.5, 0.0, 0.0, 1.0,
-0.5, 0.5, -0.5, 1.0, 0.0, 1.0,
0.5, 0.5, 0.5, 1.0, 0.0, 1.0,
0.5, -0.5, 0.5, 1.0, 1.0, 0.0,
0.5, -0.5, -0.5, 1.0, 0.0, 0.0,
0.5, 0.5, -0.5, 0.0, 1.0, 1.0,
0.5, -0.5, 0.5, 1.0, 0.0, 0.0,
-0.5, -0.5, 0.5, 0.0, 1.0, 0.0,
0.5, 0.5, 0.5, 0.0, 0.0, 1.0,
-0.5, 0.5, 0.5, 1.0, 0.0, 0.0
};
unsigned int ind[]
{
0, 1, 2,
2, 3, 0,
6, 5, 4,
4, 7, 6,
8, 9, 10,
9, 11, 10
};
PShader NewShader("Source/Shaders/Vertex.shader","Source/Shaders/Fragment.shader");
NewShader.Bind();
glfwGetWindowSize(window, &windowWidth, &windowHeight);
PCamera MainCamera(window, windowWidth, windowHeight);
PObject NewObject(pos, 24, ind, 18, 0);
ProjectRenderer->SceneObjects.insert(ProjectRenderer->SceneObjects.end(), &NewObject);
while (!glfwWindowShouldClose(window))
{
glfwGetWindowSize(window, &windowWidth, &windowHeight);
glViewport(0, 0, windowWidth, windowHeight);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
MainCamera.UpdateProjectionMatrix(45.f, windowWidth, windowHeight);
glm::mat4 translation = MainCamera.ProjectionMatrix * MainCamera.NavigateCamera();
glUniformMatrix4fv(glGetUniformLocation(NewShader.Shader_ID, "u_MVP"), 1, GL_FALSE, &translation[0][0]);
ProjectRenderer->Draw(&NewObject);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
Fragment and Vertex shaders:
#FRAGMENT
#version 330 core
out vec4 color;
in vec3 vertexColor;
void main()
{
color = vec4(vertexColor, 1.0);;
}
#VERTEX
#version 330 core
in layout(location = 0) vec3 position;
in layout(location = 1) vec3 Color;
out vec3 vertexColor;
uniform mat4 u_MVP;
void main()
{
gl_Position = (u_MVP * vec4(position, 1.f));
vertexColor = Color;
}
Maybe it's something wrong with perspective? Should I use depth, and how? I used it before, but it didn't help. It seems like it's something with the projection matrix. So, what's wrong?
You have to enable the Depth test. If the depth test is enabled, then the depth of of a fragment is tested against the depth of the sample being written to. If it fails, the fragment is discarded.
Depth test is a global state. It is sufficient to enable it once, before the application loop;
glEnable(GL_DEPTH_TEST);
Once the depth test is enabled, you have to clear the depth buffer, too:
(See glClear)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
I am simply trying to create a triangle in the center and rotate the camera around the center. (0,0,0). the code is whipped from multiple tutorial sources and i suspect the problem could be somewhere from the glm::perspective/lookat or gl:projection/model matrix before triangle draw calls.
because that's where my general confusion is at right now.
any help is greatly appreciated so i can move on with my life. thank you in advance.
//sudo g++ -o sdl main.cpp -lSDL2_image -lGL -lGLU -lglut -lX11 -lGLEW `sdl2-config --cflags --libs`
#include <iostream>
#include <GL/glew.h>
#include <glm/glm.hpp>
#include "glm/gtc/matrix_transform.hpp"
#include <glm/gtc/type_ptr.hpp>
#include <SDL2/SDL.h>
#include <string>
#include <GL/gl.h>
std::string programName = "SDL2/OpenGL";
SDL_Window *mainWindow;
SDL_GLContext mainContext;
void Calculate()
{
float radius = 2.0f;
float camX = sin(SDL_GetTicks()*0.001) * radius;
float camZ = cos(SDL_GetTicks()*0.001) * radius;
glm::mat4 perspecive_mat = glm::perspective(
45.0f, 1.0f / 1.0f, 0.1f, 100.0f );
glm::mat4 view_mat = glm::lookAt(
glm::vec3(camX, 0.0, camZ), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0) );
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(glm::value_ptr(perspecive_mat));
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(glm::value_ptr(view_mat));
}
void Render()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float vertexCoords[24] = { // Coordinates for the vertices of a cube.
1,1,1, 1,1,-1, 1,-1,-1, 1,-1,1,
-1,1,1, -1,1,-1, -1,-1,-1, -1,-1,1 };
float vertexColors[24] = { // An RGB color value for each vertex
1,1,1, 1,0,0, 1,1,0, 0,1,0,
0,0,1, 1,0,1, 0,0,0, 0,1,1 };
int elementArray[24] = { // Vertex numbers for the six faces.
0,1,2,3, 0,3,7,4, 0,4,5,1,
6,2,1,5, 6,5,4,7, 6,7,3,2 };
glVertexPointer( 3, GL_FLOAT, 0, vertexCoords );
glColorPointer( 3, GL_FLOAT, 0, vertexColors );
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
glDrawElements( GL_QUADS, 24, GL_UNSIGNED_INT, elementArray );
SDL_GL_SwapWindow(mainWindow);
}
bool Loop()
{
while (true ){
SDL_Event event;
while ( SDL_PollEvent( &event ) ){
switch ( event.type ){
case SDL_QUIT :
SDL_Quit();
return 0;
case SDL_KEYDOWN :
std::cout<<"Key Down"<<std::endl;
break;
case SDL_KEYUP :
std::cout<<"Key Up"<<std::endl;
break;
case SDL_MOUSEBUTTONDOWN :
case SDL_MOUSEBUTTONUP :
case SDL_MOUSEMOTION :
default :
break;
}
}
Calculate();
Render();
}
}
void CheckSDLError(int line = -1){
std::string error = SDL_GetError();
if (error != "")
{
std::cout << "SLD Error : " << error << std::endl;
if (line != -1)
std::cout << "\nLine : " << line << std::endl;
SDL_ClearError();
}
}
void Cleanup(){
SDL_GL_DeleteContext(mainContext);
SDL_DestroyWindow(mainWindow );
SDL_Quit();
}
int main(int argc, char *argv[]){
if (SDL_Init(SDL_INIT_VIDEO) < 0){
std::cout << "Failed to init SDL\n";
return false;
}
mainWindow = SDL_CreateWindow(programName.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,512, 512, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
if (!mainWindow )
{
std::cout << "Unable to create window\n"<< std::endl;;
CheckSDLError(__LINE__);
return false;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
mainContext = SDL_GL_CreateContext(mainWindow );
// This makes our buffer swap syncronized with the monitor's vertical refresh
// ( which means it enables v-sync)
// Setting this to 0 will disable V-sync
// Which means our application could run at unlimited fps
SDL_GL_SetSwapInterval(1);
// Init GLEW
glewExperimental = GL_TRUE;
glewInit();
// Enable blending so that we can have transparanet object
glEnable(GL_BLEND ) ;
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Enable depth testing so that closer triangles will hide the triangles farther away
glEnable( GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
Loop();
Cleanup();
return 0;
}
Note, that drawing by glBegin/glEnd sequences and the fixed function pipeline matrix stack is deprecated since decades.
Read about Fixed Function Pipeline and see Vertex Specification and Shader for a state of the art way of rendering.
If you want to use the deprecated way of drawing, then you have to use a compatibility profile context instead of a core profile context (see OpenGL Context):
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
Further note, that glm::lookAt and glm::perspective don't set any OpenGL states or even fixed function pipline matrices. glm - OpenGL Mathematics is a math library, to do calculations related to OpenGL. Both function return a 4*4 matrix.
You can use glLoadMatrixf to load a matrix return by a glm function to the OpenGL fixed function pipeline matrix stack:
#include <glm/glm.hpp>
#include "glm/gtc/matrix_transform.hpp"
#include <glm/gtc/type_ptr.hpp>
void Calculate()
{
float radius = 2.0f;
float camX = sin(SDL_GetTicks()*0.001) * radius;
float camZ = cos(SDL_GetTicks()*0.001) * radius;
glm::mat4 perspecive_mat = glm::perspective(
45.0f, 1.0f / 1.0f, 0.1f, 100.0f );
glm::mat4 view_mat = glm::lookAt(
glm::vec3(camX, 0.0, camZ), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0) );
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(glm::value_ptr(perspecive_mat));
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(glm::value_ptr(view_mat));
}
If you want to use a core profile, then you have to create a simple Shader program:
#include <string>
std::string sh_vert = R"(
#version 150 core
in vec3 v_pos;
in vec4 v_col;
out vec4 color;
uniform mat4 projection;
uniform mat4 view;
void main()
{
color = v_col;
gl_Position = projection * view * vec4(v_pos, 1.0);
}
)";
std::string sh_frag = R"(
#version 150 core
in vec4 color;
void main()
{
gl_FragColor = color;
}
)";
Compile and link the program:
#include <vector>
GLuint CreateShader(GLenum type, const char *code)
{
GLuint shaderObj = glCreateShader(type);
glShaderSource(shaderObj, 1, &code, nullptr);
glCompileShader(shaderObj);
GLint status = GL_TRUE;
glGetShaderiv(shaderObj, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
GLint logLen;
glGetShaderiv(shaderObj, GL_INFO_LOG_LENGTH, &logLen);
std::vector< char >log(logLen);
GLsizei written;
glGetShaderInfoLog(shaderObj, logLen, &written, log.data());
std::cout << "compile error:" << std::endl << log.data() << std::endl;
}
return shaderObj;
}
GLuint CreateProgram()
{
GLuint vShObj = CreateShader(GL_VERTEX_SHADER, sh_vert.c_str());
GLuint fShObj = CreateShader(GL_FRAGMENT_SHADER, sh_frag.c_str());
GLuint progObj = glCreateProgram();
glAttachShader(progObj, vShObj);
glAttachShader(progObj, fShObj);
glLinkProgram(progObj);
GLint status = GL_TRUE;
glGetProgramiv(progObj, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
GLint logLen;
glGetProgramiv(progObj, GL_INFO_LOG_LENGTH, &logLen);
std::vector< char >log(logLen);
GLsizei written;
glGetProgramInfoLog(progObj, logLen, &written, log.data());
std::cout << "link error:" << std::endl << log.data() << std::endl;
}
return progObj;
}
Get the attribute and uniform locations:
GLuint prog;
GLint pos_attr, col_attr, proj_loc, view_loc;
void Init()
{
prog = CreateProgram();
pos_attr = glGetAttribLocation(prog, "v_pos");
col_attr = glGetAttribLocation(prog, "v_col");
proj_loc = glGetUniformLocation(prog, "projection");
view_loc = glGetUniformLocation(prog, "view");
// ....
}
Create a Vertex Array Object:
GLuint vao;
void Init()
{
// ....
const std::vector<float> varray
{
// x y z red green blue
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f,
0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
};
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, varray.size()*sizeof(float), varray.data(), GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glVertexAttribPointer(pos_attr, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), 0);
glEnableVertexAttribArray(pos_attr);
glVertexAttribPointer(col_attr, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(col_attr);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
Installs the program object as part of current rendering state and set the uniform variables:
void Calculate()
{
float radius = 2.0f;
float camX = sin(SDL_GetTicks()*0.001) * radius;
float camZ = cos(SDL_GetTicks()*0.001) * radius;
glm::mat4 perspecive_mat = glm::perspective(
45.0f, 1.0f / 1.0f, 0.1f, 100.0f );
glm::mat4 view_mat = glm::lookAt(
glm::vec3(camX, 0.0, camZ), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0) );
glUseProgram(prog);
glUniformMatrix4fv(proj_loc, 1, GL_FALSE, glm::value_ptr(perspecive_mat));
glUniformMatrix4fv(view_loc, 1, GL_FALSE, glm::value_ptr(view_mat));
}
Finally draw the triangle:
void Render()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
SDL_GL_SwapWindow(mainWindow);
}
bool Loop()
{
Init();
while (true) {
// ....
Calculate();
Render();
}
}
I'm new to OpenGl and I was working on texturing. I want to draw one image on three sides and another image on other three sides of cube. I'm unable to do it. I want to know at what point in my code is cube being drawn on window?
This is my code:
#include "06_texturing.hpp"
#include "texture.hpp"
GLuint shaderProgram;
GLuint vbo[2], vao[2];
GLuint tex;
glm::mat4 rotation_matrix;
glm::mat4 projection_matrix;
glm::mat4 c_rotation_matrix;
glm::mat4 lookat_matrix;
glm::mat4 model_matrix;
glm::mat4 view_matrix;
glm::mat4 modelview_matrix;
glm::mat3 normal_matrix;
GLuint uModelViewMatrix;
GLuint viewMatrix;
GLuint normalMatrix;
//-----------------------------------------------------------------
//6 faces, 2 triangles/face, 3 vertices/triangle
const int num_vertices = 36;
glm::vec4 texCoordinates[8];
//Eight vertices in homogenous coordinates
glm::vec4 positions[8] = {
glm::vec4(-0.5, -0.5, 0.5, 1.0),
glm::vec4(-0.5, 0.5, 0.5, 1.0),
glm::vec4(0.5, 0.5, 0.5, 1.0),
glm::vec4(0.5, -0.5, 0.5, 1.0),
glm::vec4(-0.5, -0.5, -0.5, 1.0),
glm::vec4(-0.5, 0.5, -0.5, 1.0),
glm::vec4(0.5, 0.5, -0.5, 1.0),
glm::vec4(0.5, -0.5, -0.5, 1.0)
};
glm::vec4 normals[8] = {
glm::vec4(-0.5, -0.5, 0.5, 1.0),
glm::vec4(-0.5, 0.5, 0.5, 1.0),
glm::vec4(0.5, 0.5, 0.5, 1.0),
glm::vec4(0.5, -0.5, 0.5, 1.0),
glm::vec4(-0.5, -0.5, -0.5, 1.0),
glm::vec4(-0.5, 0.5, -0.5, 1.0),
glm::vec4(0.5, 0.5, -0.5, 1.0),
glm::vec4(0.5, -0.5, -0.5, 1.0)
};
//RGBA colors
glm::vec4 colors[8] = {
glm::vec4(0.0, 0.0, 0.0, 1.0),
glm::vec4(1.0, 0.0, 0.0, 1.0),
glm::vec4(1.0, 1.0, 0.0, 1.0),
glm::vec4(0.0, 1.0, 0.0, 1.0),
glm::vec4(0.0, 0.0, 1.0, 1.0),
glm::vec4(1.0, 0.0, 1.0, 1.0),
glm::vec4(1.0, 1.0, 1.0, 1.0),
glm::vec4(0.0, 1.0, 1.0, 1.0)
};
glm::vec2 t_coords[4] = {
glm::vec2( 0.0, 0.0),
glm::vec2( 0.0, 1.0),
glm::vec2( 1.0, 0.0),
glm::vec2( 1.0, 1.0)
};
glm::vec4 color(0.6, 0.6, 0.6, 1.0);
glm::vec4 black(0.1, 0.1, 0.1, 1.0);
glm::vec4 white(0.2, 0.7, 0.7, 1.0);
glm::vec4 red(1.0, 0.2, 0.2, 1.0);
glm::vec4 yellow(0.8, 0.8, 0.0, 1.0);
glm::vec4 green(0.2, 0.7, 0.2, 1.0);
glm::vec4 blue(0.2, 0.2, 0.7, 1.0);
int tri_idx=0;
glm::vec4 v_positions[num_vertices];
glm::vec4 v_colors[num_vertices];
glm::vec4 v_normals[num_vertices];
glm::vec2 tex_coords[num_vertices];
// quad generates two triangles for each face and assigns colors to the vertices
void quad(int a, int b, int c, int d, glm::vec4 color)
{
v_colors[tri_idx] = color; v_positions[tri_idx] = positions[a];
v_normals[tri_idx] = normals[a];
tex_coords[tri_idx] = t_coords[1];
tri_idx++;
v_colors[tri_idx] = color; v_positions[tri_idx] = positions[b];
v_normals[tri_idx] = normals[b];
tex_coords[tri_idx] = t_coords[0];
tri_idx++;
v_colors[tri_idx] = color; v_positions[tri_idx] = positions[c];
v_normals[tri_idx] = normals[c];
tex_coords[tri_idx] = t_coords[2];
tri_idx++;
v_colors[tri_idx] = color; v_positions[tri_idx] = positions[a];
v_normals[tri_idx] = normals[a];
tex_coords[tri_idx] = t_coords[1];
tri_idx++;
v_colors[tri_idx] = color; v_positions[tri_idx] = positions[c];
v_normals[tri_idx] = normals[c];
tex_coords[tri_idx] = t_coords[2];
tri_idx++;
v_colors[tri_idx] = color; v_positions[tri_idx] = positions[d];
v_normals[tri_idx] = normals[d];
tex_coords[tri_idx] = t_coords[3];
tri_idx++;
}
// generate 12 triangles: 36 vertices and 36 colors
void colorcube(void)
{
quad( 1, 0, 3, 2, red);
quad( 2, 3, 7, 6, green);
quad( 3, 0, 4, 7, white);
quad( 6, 5, 1, 2, yellow);
quad( 4, 5, 6, 7, black);
quad( 5, 4, 0, 1, blue);
}
//-----------------------------------------------------------------
void initBuffersGL(void)
{
// Load shaders and use the resulting shader program
std::string vertex_shader_file("06_vshader.glsl");
std::string fragment_shader_file("06_fshader.glsl");
std::vector<GLuint> shaderList;
shaderList.push_back(csX75::LoadShaderGL(GL_VERTEX_SHADER, vertex_shader_file));
shaderList.push_back(csX75::LoadShaderGL(GL_FRAGMENT_SHADER, fragment_shader_file));
shaderProgram = csX75::CreateProgramGL(shaderList);
glUseProgram( shaderProgram );
// getting the attributes from the shader program
GLuint vPosition = glGetAttribLocation( shaderProgram, "vPosition" );
GLuint vColor = glGetAttribLocation( shaderProgram, "vColor" );
GLuint vNormal = glGetAttribLocation( shaderProgram, "vNormal" );
GLuint texCoord = glGetAttribLocation( shaderProgram, "texCoord" );
uModelViewMatrix = glGetUniformLocation( shaderProgram, "uModelViewMatrix");
normalMatrix = glGetUniformLocation( shaderProgram, "normalMatrix");
viewMatrix = glGetUniformLocation( shaderProgram, "viewMatrix");
// Load Textures
GLuint tex=LoadTexture("images/all1.bmp",256,256);
GLuint tex2=LoadTexture("images/another.bmp",256,256);
glBindTexture(GL_TEXTURE_2D, tex);
//Ask GL for two Vertex Attribute Objects (vao) , one for the sphere and one for the wireframe
glGenVertexArrays (2, vao);
//Ask GL for two Vertex Buffer Object (vbo)
glGenBuffers (2, vbo);
//Set 0 as the current array to be used by binding it
glBindVertexArray (vao[0]);
//Set 0 as the current buffer to be used by binding it
glBindBuffer (GL_ARRAY_BUFFER, vbo[0]);
colorcube();
//Copy the points into the current buffer
glBufferData (GL_ARRAY_BUFFER, sizeof (v_positions) + sizeof(tex_coords) + sizeof(v_normals), NULL, GL_STATIC_DRAW);
glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(v_positions), v_positions );
glBufferSubData( GL_ARRAY_BUFFER, sizeof(v_positions), sizeof(tex_coords), tex_coords);
glBufferSubData( GL_ARRAY_BUFFER, sizeof(tex_coords)+sizeof(v_positions), sizeof(v_normals), v_normals );
// set up vertex array
//Position
glEnableVertexAttribArray( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );
//Textures
glEnableVertexAttribArray( texCoord );
glVertexAttribPointer( texCoord, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(v_positions)) );
//Normal
glEnableVertexAttribArray( vNormal );
glVertexAttribPointer( vNormal, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(v_positions)+sizeof(tex_coords)) );
}
void renderGL(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
rotation_matrix = glm::rotate(glm::mat4(1.0f), glm::radians(xrot), glm::vec3(1.0f,0.0f,0.0f));
rotation_matrix = glm::rotate(rotation_matrix, glm::radians(yrot), glm::vec3(0.0f,1.0f,0.0f));
rotation_matrix = glm::rotate(rotation_matrix, glm::radians(zrot), glm::vec3(0.0f,0.0f,1.0f));
model_matrix = rotation_matrix;
//Creating the lookat and the up vectors for the camera
c_rotation_matrix = glm::rotate(glm::mat4(1.0f), glm::radians(c_xrot), glm::vec3(1.0f,0.0f,0.0f));
c_rotation_matrix = glm::rotate(c_rotation_matrix, glm::radians(c_yrot), glm::vec3(0.0f,1.0f,0.0f));
c_rotation_matrix = glm::rotate(c_rotation_matrix, glm::radians(c_zrot), glm::vec3(0.0f,0.0f,1.0f));
glm::vec4 c_pos = glm::vec4(c_xpos,c_ypos,c_zpos, 1.0)*c_rotation_matrix;
glm::vec4 c_up = glm::vec4(c_up_x,c_up_y,c_up_z, 1.0)*c_rotation_matrix;
//Creating the lookat matrix
lookat_matrix = glm::lookAt(glm::vec3(c_pos),glm::vec3(0.0),glm::vec3(c_up));
//creating the projection matrix
projection_matrix = glm::frustum(-1.0, 1.0, -1.0, 1.0, 1.0, 5.0);
view_matrix = projection_matrix*lookat_matrix;
glUniformMatrix4fv(viewMatrix, 1, GL_FALSE, glm::value_ptr(view_matrix));
// Draw the sphere
modelview_matrix = view_matrix*model_matrix;
glUniformMatrix4fv(uModelViewMatrix, 1, GL_FALSE, glm::value_ptr(modelview_matrix));
normal_matrix = glm::transpose (glm::inverse(glm::mat3(modelview_matrix)));
glUniformMatrix3fv(normalMatrix, 1, GL_FALSE, glm::value_ptr(normal_matrix));
// glBindTexture(GL_TEXTURE_2D, tex);
glBindVertexArray (vao[0]);
glDrawArrays(GL_TRIANGLES, 0, num_vertices);
}
int main(int argc, char** argv)
{
//! The pointer to the GLFW window
GLFWwindow* window;
//! Setting up the GLFW Error callback
glfwSetErrorCallback(csX75::error_callback);
//! Initialize GLFW
if (!glfwInit())
return -1;
//We want OpenGL 4.0
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//This is for MacOSX - can be omitted otherwise
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
//We don't want the old OpenGL
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//! Create a windowed mode window and its OpenGL context
window = glfwCreateWindow(512, 512, "CS475/CS675 Tutorial 6: Texturing a cube", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
//! Make the window's context current
glfwMakeContextCurrent(window);
//Initialize GLEW
//Turn this on to get Shader based OpenGL
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err)
{
//Problem: glewInit failed, something is seriously wrong.
std::cerr<<"GLEW Init Failed : %s"<<std::endl;
}
//Keyboard Callback
glfwSetKeyCallback(window, csX75::key_callback);
//Framebuffer resize callback
glfwSetFramebufferSizeCallback(window, csX75::framebuffer_size_callback);
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
//Initialize GL state
csX75::initGL();
initBuffersGL();
// Loop until the user closes the window
while (glfwWindowShouldClose(window) == 0)
{
// Render here
renderGL();
// Swap front and back buffers
glfwSwapBuffers(window);
// Poll for and process events
glfwPollEvents();
}
glfwTerminate();
return 0;
}
I want to change in it to render different images on different sides.
If you want to use 2 completely different textures, in the fragment shader, then you have to bind the textures to 2 different texture units. The texture unit can be set by glActiveTexture:
GLuint tex=LoadTexture("images/all1.bmp",256,256);
GLuint tex2=LoadTexture("images/another.bmp",256,256);
int unit_tex0 = 0; // texture unit 0 and binding point 0
int unit_tex1 = 1; // texture unit 1 and binding point 1
glActiveTexture( GL_TEXTURE0 + unit_tex0 );
glBindTexture(GL_TEXTURE_2D, tex);
glActiveTexture( GL_TEXTURE0 + unit_tex1 );
glBindTexture(GL_TEXTURE_2D, tex2);
Further you have to declare 2 texture samplers in the fragment shader. The texture samplers have to be associated to the texture units. Since GLSL version 4.2 this can be done in the fragment shader by specifying binding points:
#version 420
layout (binding = 0) uniform sampler2D u_texture0;
layout (binding = 1) uniform sampler2D u_texture1;
Alternatively you can assign the texture unit index, to the texture sampler uniform by glUniform1i:
uniform sampler2D u_texture0;
uniform sampler2D u_texture1;
GLuint location_tex0 = glGetUniformLocation( shaderProgram, "u_texture0" );
GLuint location_tex1 = glGetUniformLocation( shaderProgram, "u_texture1" );
glUniform1i( location_tex0, unit_tex0 );
glUniform1i( location_tex1, unit_tex1 );
To distinguish between the sides of the cubes, you can use the built in vertex shader variable gl_VertexID.
Create a flat out variable of type int in the vertex shader and pass the vertex id to the fragment shader:
flat out int vertex_id;
void main()
{
.....
vertex_id = gl_VertexID;
.....
}
In the fragment shader yo can decide which texture you want to use by the id corresponding to the vertex coordinate. Note, you have 36 coordinates, the first 3 sides have the ids form 0 to 17 and the other the ids form 18 to 35:
flat in int vertex_id;
void main()
{
.....
if ( vertex_id < 18 )
fragColor = texture(u_texture0, vertUV);
else
fragColor = texture(u_texture1, vertUV);
.....
}
I have the sample code of drawing a cube. How can I draw other cubes at different positions (using translation matrices) to be able to draw a tetris of which's engine I have.
#include <glf.hpp>
#include <GL/freeglut.h>
#include <camera.h>
#define kEpsilon 1.0e-6f
#define kPI 3.1415926535897932384626433832795f
#define kHalfPI 1.5707963267948966192313216916398f
#define kTwoPI 2.0f*kPI
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
namespace
{
//path to shader files
std::string const SHADER_VERT_SOURCE("../GL3_init/Basic.vsh"); //// relative to
std::string const SHADER_FRAG_SOURCE("../GL3_init/Basic.fsh"); //// the executable path
//cube data
namespace cube {
// (6 faces)(2 triangles/face)(3 vertices/triangle)
const int NumVertices = 36;
glm::vec4 points[NumVertices];
glm::vec4 colors[NumVertices];
// Vertices positions of a unit cube centered at origin
glm::vec4 vertex_positions[8] = {
glm::vec4( -0.5, -0.5, 0.5, 1.0),
glm::vec4( -0.5, 0.5, 0.5, 1.0),
glm::vec4( 0.5, 0.5, 0.5, 1.0),
glm::vec4( 0.5, -0.5, 0.5, 1.0),
glm::vec4( -0.5, -0.5, -0.5, 1.0),
glm::vec4( -0.5, 0.5, -0.5, 1.0),
glm::vec4( 0.5, 0.5, -0.5, 1.0),
glm::vec4( 0.5, -0.5, -0.5, 1.0)
};
// RGBA colors
glm::vec4 vertex_colors[8] = {
glm::vec4( 0.0, 0.0, 0.0, 1.0),//black
glm::vec4( 1.0, 0.0, 0.0, 1.0),//red
glm::vec4( 1.0, 1.0, 0.0, 1.0),//yellow
glm::vec4( 0.0, 1.0, 0.0, 1.0),//green
glm::vec4( 0.0, 0.0, 1.0, 1.0),//blue
glm::vec4( 1.0, 0.0, 1.0, 1.0),//magenta
glm::vec4( 1.0, 1.0, 1.0, 1.0),//white
glm::vec4( 0.0, 1.0, 1.0, 1.0) //cyan
};
// quad() generates two triangles for each face and assigns colors to the vertices
int Index = 0;
void quad( int a, int b, int c, int d )
{
colors[Index] = vertex_colors[a]; points[Index] = vertex_positions[a]; Index++;
colors[Index] = vertex_colors[b]; points[Index] = vertex_positions[b]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertex_positions[c]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertex_positions[a]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertex_positions[c]; Index++;
colors[Index] = vertex_colors[d]; points[Index] = vertex_positions[d]; Index++;
}
// generate 12 triangles: 36 vertices and 36 colors
void colorcube()
{
quad( 1, 0, 3, 2 );
quad( 2, 3, 7, 6 );
quad( 3, 0, 4, 7 );
quad( 6, 5, 1, 2 );
quad( 4, 5, 6, 7 );
quad( 5, 4, 0, 1 );
}
}
//OpenGL Objects
GLuint vao;
GLuint buffer;
GLuint program;
//window
int width = 800;
int height = 600;
//MVP
glm::mat4 mProjection = glm::perspective(60.0f, float(width) / height, 0.1f, 1000.0f);
Camera camera(glm::vec3(0.0f, 1.0f,-3.0f), glm::vec3(0.0f,0.0f,0.0f), glm::vec3(0.0f,1.0f,0.0f), mProjection);
//uniform variables
GLuint uMVP;
}
//create, compile and link shaders
bool initProgram()
{
bool Validated(true);
GLuint VertShaderName = glf::createShader(GL_VERTEX_SHADER, SHADER_VERT_SOURCE);
GLuint FragShaderName = glf::createShader(GL_FRAGMENT_SHADER, SHADER_FRAG_SOURCE);
program = glCreateProgram();
glAttachShader(program, VertShaderName);
glAttachShader(program, FragShaderName);
glLinkProgram(program);
glDeleteShader(VertShaderName);
glDeleteShader(FragShaderName);
Validated = Validated && glf::checkProgram(program);
if(Validated)
{
glUseProgram(program);
//Associate uniforms
uMVP = glGetUniformLocation( program, "MVP");
Validated = Validated && glf::checkError("initProgram - stage");
}
}
// Create and initialize buffer object
bool initBuffer()
{
bool Validated(true);
glGenBuffers(1,&buffer);
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER, sizeof(cube::points) + sizeof(cube::colors),NULL,GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(cube::points), cube::points);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(cube::points), sizeof(cube::colors), cube::colors);
return Validated;
}
// Create and bind vertex array object. Set pointer to vertex attributes
bool initVertexArray()
{
bool Validated(true);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
GLuint vPosition = glGetAttribLocation( program,"vPosition" );
glEnableVertexAttribArray(vPosition);
glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, 0);
GLuint vColor = glGetAttribLocation( program, "vColor" );
glEnableVertexAttribArray( vColor );
glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(cube::points)) );
return Validated;
}
// Setup GL state
bool beginGL()
{
bool Validated(true);
//setup the cube
cube::colorcube();
Validated = initProgram();
if(Validated)
Validated = initBuffer();
if(Validated)
Validated = initVertexArray();
return Validated;
}
// Free memory
void endGL()
{
glDeleteBuffers(1,&buffer);
glDeleteProgram(program);
glDeleteVertexArrays(1, &vao);
}
///////////////////////////////////////////////////////////////////////////////
// Called to draw scene
void RenderScene(void)
{
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glClearBufferfv(GL_COLOR, 0, &glm::vec4(0.4f, 0.4f, 0.4f, 1.0f)[0]);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glEnable(GL_CULL_FACE);
glEnable(GL_MULTISAMPLE);
//glPolygonMode( GL_FRONT_AND_BACK, GL_LINE);
//setup Model View Projection
glm::mat4 mMVP = camera.getprojection()*camera.ViewMatrix();
glProgramUniformMatrix4fv(program, uMVP, 1, GL_FALSE, glm::value_ptr(mMVP));
//Draw Cube
glDrawArrays(GL_TRIANGLES,0,cube::NumVertices);
// Flush drawing commands
glutSwapBuffers();
// Refresh the Window
glutPostRedisplay();
glDisable(GL_MULTISAMPLE);
}
///////////////////////////////////////////////////////////////////////////////
// A normal ASCII key has been pressed.
// In this case, space bar is pressed
void KeyPressFunc(unsigned char key, int x, int y)
{
switch(key)
{
// controls for camera
// add up/down and left/right controls
case 'L': camera.slide(.2, 0, 0); break;// slide camera right
case 'L' + 32: camera.slide(-0.2, 0, 0); break; // slide camera left
case 'U': camera.slide(0, -0.2, 0); break;// slide camera down
case 'U' + 32: camera.slide(0, 0.2, 0); break; // slide camera up
case 'F': camera.slide(0,0, 0.2); break; // slide camera forward
case 'F' + 32: camera.slide(0,0,-0.2); break; //slide camera back
// add pitch controls
case 'P': camera.pitch(-1.0); break;
case 'P' + 32: camera.pitch( 1.0); break;
// add yaw controls
case 'Y': camera.yaw(-1.0); break;
case 'Y' + 32: camera.yaw( 1.0); break;
// add roll controls
case 'R': camera.roll(1.0); break;
case 'R' + 32: camera.roll(-1.0); break;
// close with Esc
case 27: exit(0); break;
}
}
//////////////////////////////////////////////////////////////////////////////
// Window has changed size, or has just been created. In either case, we need
// to use the window dimensions to set the viewport and the projection matrix.
void ChangeSize(int w, int h)
{
width = w; height = h;
glViewport(0, 0, w, h);
mProjection = glm::perspective(60.0f, float(width) / height, 0.1f, 1000.0f);
camera.setprojection(mProjection);
}
// Main entry point for GLUT based programs
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(width, height);
glutCreateWindow("3D Demo");
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return 1;
}
if(beginGL()){
glutReshapeFunc(ChangeSize);
glutKeyboardFunc(KeyPressFunc);
glutDisplayFunc(RenderScene);
glutCloseFunc(endGL);
glutMainLoop();
return 0;
}
return 1;
}
In RenderScene you can play with the following lines in order to draw multiple cubes :
glm::mat4 mMVP = camera.getprojection()*camera.ViewMatrix();
for(int i = 0; i < 10; i++)
{
glm::mat4 finalM = mMVP * a_function_that_creates_a_translation_matrix(x, y, z);
glProgramUniformMatrix4fv(program, uMVP, 1, GL_FALSE, glm::value_ptr(finalM));
glDrawArrays(GL_TRIANGLES,0,cube::NumVertices);
}
By taking away the ComputePositonOffsets() and AdjustVertexData() methods, I can display a single triangle, but I added some button functionality to spin it to see if there was more anywhere else in the screen, and I can't figure out why it generates a black screen.
#include <algorithm>
#include <string>
#include <vector>
#include <stdio.h>
#include <glload/gl_3_2_comp.h>
#include <GL/freeglut.h>
#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
double rotate_y = 0;
double rotate_x = 0;
GLuint CreateShader(GLenum eShaderType, const std::string &strShaderFile) {
GLuint shader = glCreateShader(eShaderType);
const char *strFileData = strShaderFile.c_str();
glShaderSource(shader, 1, &strFileData, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *strInfoLog = new GLchar[infoLogLength + 1];
glGetShaderInfoLog(shader, infoLogLength, NULL, strInfoLog);
const char *strShaderType = NULL;
switch (eShaderType) {
case GL_VERTEX_SHADER:
strShaderType = "vertex";
break;
case GL_GEOMETRY_SHADER:
strShaderType = "geometry";
break;
case GL_FRAGMENT_SHADER:
strShaderType = "fragment";
break;
}
fprintf(stderr, "Compile failure in %s shader:\n%s\n", strShaderType,strInfoLog);
delete[] strInfoLog;
}
return shader;
}
GLuint CreateProgram(const std::vector<GLuint> &shaderList) {
GLuint program = glCreateProgram();
for (size_t iLoop = 0; iLoop < shaderList.size(); iLoop++)
glAttachShader(program, shaderList[iLoop]);
glLinkProgram(program);
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *strInfoLog = new GLchar[infoLogLength + 1];
glGetProgramInfoLog(program, infoLogLength, NULL, strInfoLog);
fprintf(stderr, "Linker failure: %s\n", strInfoLog);
delete[] strInfoLog;
}
for (size_t iLoop = 0; iLoop < shaderList.size(); iLoop++)
glDetachShader(program, shaderList[iLoop]);
return program;
}
GLuint theProgram;
const std::string strVertexShader("#version 330\n"
"layout(location = 0) in vec4 position;\n"
"void main()\n"
"{\n"
" gl_Position = position;\n"
"}\n");
const std::string strFragmentShader("#version 330\n"
"out vec4 outputColor;\n"
"void main()\n"
"{\n"
" outputColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);\n"
"}\n");
void InitializeProgram() {
std::vector<GLuint> shaderList;
shaderList.push_back(CreateShader(GL_VERTEX_SHADER, strVertexShader));
shaderList.push_back(CreateShader(GL_FRAGMENT_SHADER, strFragmentShader));
theProgram = CreateProgram(shaderList);
std::for_each(shaderList.begin(), shaderList.end(), glDeleteShader);
}
const float vertexPositions2[] = { 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5,
0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5,
-0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5,
-0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5,
-0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5 };
GLuint positionBufferObject;
GLuint vao;
void InitializeVertexBuffer() {
glGenBuffers(1, &positionBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions2), vertexPositions2,
GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
void init() {
InitializeProgram();
InitializeVertexBuffer();
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
}
void ComputePositionOffsets(float &fXOffset, float &fYOffset) {
const float fLoopDuration = 5.0f;
const float fScale = 3.14159f * 2.0f / fLoopDuration;
float fElapsedTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
float fCurrTimeThroughLoop = fmodf(fElapsedTime, fLoopDuration);
fXOffset = cosf(fCurrTimeThroughLoop * fScale) * 0.5f;
fYOffset = sinf(fCurrTimeThroughLoop * fScale) * 0.5f;
}
void AdjustVertexData(float fXOffset, float fYOffset) {
std::vector<float> fNewData(ARRAY_COUNT(vertexPositions2));
memcpy(&fNewData[0], vertexPositions2, sizeof(vertexPositions2));
for (int iVertex = 0; iVertex < ARRAY_COUNT(vertexPositions2); iVertex +=
4) {
fNewData[iVertex] += fXOffset;
fNewData[iVertex + 1] += fYOffset;
}
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertexPositions2), &fNewData[0]);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
//Called to update the display.
//You should call glutSwapBuffers after all of your rendering to display what you rendered.
//If you need continuous updates of the screen, call glutPostRedisplay() at the end of the function.
void display() {
glUseProgram(theProgram);
float fXOffset = 0.0f, fYOffset = 0.0f;
ComputePositionOffsets(fXOffset, fYOffset);
AdjustVertexData(fXOffset, fYOffset);
//glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glRotatef(rotate_x, 1.0, 0.0, 0.0);
glRotatef(rotate_y, 0.0, 1.0, 0.0);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
GLubyte indices[] = { 0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4, 8, 9, 10, 10, 11,
8, 12, 13, 14, 14, 15, 12, 16, 17, 18, 18, 19, 16, 20, 21, 22, 22,
23, 20 }; // back
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glFlush();
glUseProgram(0);
glutSwapBuffers();
}
//Called whenever the window is resized. The new window size is given, in pixels.
//This is an opportunity to call glViewport or glScissor to keep up with the change in size.
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
}
//Called whenever a key on the keyboard was pressed.
//The key is given by the ''key'' parameter, which is in ASCII.
//It's often a good idea to have the escape key (ASCII value 27) call glutLeaveMainLoop() to
//exit the program.
void keyboard(unsigned char key, int x, int y) {
switch (key) {
case 27:
glutLeaveMainLoop();
return;
}
// Right arrow - increase rotation by 5 degree
if (key == GLUT_KEY_RIGHT) rotate_y += 5;
// Left arrow - decrease rotation by 5 degree
else if (key == GLUT_KEY_LEFT) rotate_y -= 5;
else if (key == GLUT_KEY_UP) rotate_x += 5;
else if (key == GLUT_KEY_DOWN) rotate_x -= 5;
// Request display update
glutPostRedisplay();
}
unsigned int defaults(unsigned int displayMode, int &width, int &height) {
return displayMode;
}
const float vertexPositions2[] = {0.5,0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,0.5,-0.5,-0.5,0.5,-0.5,-0.5,0.5,0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5,0.5,-0.5,0.5,-0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5};
I'm guessing that is a list of 3D vectors making up a cube, seeing as there are 24 (6 faces * 4 corners) indices used lower down in your code and all the values are either 0.5 or -0.5. However, you tell OpenGL that this is a list of vectors with 4 componenents, rather than 3:
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
It's quite unusual to set that second parameter to 4. If you set it to 3, OpenGL will fill in the w component to 1 for you. Try that. I think you will see a square if you do that.
On top of this, I don't see a perspective projection matrix anywhere. If you don't have one, you will get a 2D projection instead of a 3D one. Things won't appear the way you want them to. You'll want to get that in before you implement rotation and moving around.
These lines below will have no effect on your program, and they do not belong in a modern graphics program. They change the matrices in the fixed-function matrix stack, which you don't (and I think can't, since you're using GLSL 330) use in your shader. You have to define the matrices as uniform variables yourself.
glLoadIdentity();
glRotatef(rotate_x, 1.0, 0.0, 0.0);
glRotatef(rotate_y, 0.0, 1.0, 0.0);