Related
I am trying to build a code that uses OpenGL and shaders that adds texture to a square pyramid. After I added the functions to add the texture, ran the code but instead of rendering, I get a console window giving me the following error:
INFO: OpenGL Version: 4.4.0 NVIDIA 512.15
ERROR::SHADER::VERTEX::COMPILATION_FAILED
0(2) : error C1503: undefined variable "cameraPosition"
0(2) : error C1503: undefined variable "cameraPosition"
0(2) : error C1503: undefined variable "cameraPosition"
0(2) : error C1035: assignment of incompatible types
I have tried copying and pasting the cameraPosition variable from the bottom of my code to one of my main functions that has the gl_Position variable. But that did not solve the problem. Do I need to change the vec3 to vec4 somewhere or do I need to copy and paste the cameraPostion variable and definition somewhere else? Here is my code:
#include <iostream> // cout, cerr
#include <cstdlib> // EXIT_FAILURE
#include <GL/glew.h> // GLEW library
#include <GLFW/glfw3.h> // GLFW library
// GLM Math Header inclusions
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <SOIL2.h> // SOIL2 library
using namespace std; // Standard namespace
/*Shader program Macro*/
#ifndef GLSL
#define GLSL(Version, Source) "#version " #Version " core \n" #Source
#endif
// Input Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
// Declare View Matrix
glm::mat4 viewMatrix;
// Initialize FOV
GLfloat fov = 45.f;
// Define Camera Attributes
glm::vec3 cameraPosition = glm::vec3(0.f, 0.f, 3.f);
glm::vec3 target = glm::vec3(0.f, 0.f, 0.f);
glm::vec3 cameraDirection = glm::normalize(cameraPosition - target);
glm::vec3 worldUp = glm::vec3(0.f, 1.f, 0.f);
glm::vec3 cameraRight = glm::normalize(glm::cross(worldUp, cameraDirection));
glm::vec3 cameraUp = glm::normalize(glm::cross(cameraDirection, cameraRight));
glm::vec3 cameraFront = glm::normalize(glm::vec3(0.f, 0.f, -1.f));
// Declare target prototype
glm::vec3 getTarget();
// Camera transformation prototype
void TransformCamera();
// Boolean for keys and mouse buttons
bool keys[1024], mouseButtons[3];
// Boolean to check camera transformations
bool isPanning = false, isOrbiting = false;
// Radius, Pitch, and Yaw
GLfloat radius = 3.f, rawYaw = 0.f, rawPitch = 0.f, degYaw, degPitch;
GLfloat deltaTime = 0.f, lastFrame = 0.f;
GLfloat lastX = 400, lastY = 300, xChange, yChange;
bool firstMouseMove = true; // Detect inititial mouse movement
void initCamera();
// Unnamed namespace
namespace
{
const char* const WINDOW_TITLE = "Basic Camera Movement"; // Macro for window title
// Variables for window width and height
int WINDOW_WIDTH = 800;
int WINDOW_HEIGHT = 600;
// Stores the GL data relative to a given mesh
struct GLMesh
{
GLuint vao; // Handle for the vertex array object
GLuint vbos[2]; // Handles for the vertex buffer objects
GLuint nIndices; // Number of indices of the mesh
};
// Main GLFW window
GLFWwindow* gWindow = nullptr;
// Triangle mesh data
GLMesh gMesh;
// Shader program
GLuint gProgramId;
}
/* User-defined Function prototypes to:
* initialize the program, set the window size,
* redraw graphics on the window when resized,
* and render graphics on the screen
*/
bool UInitialize(int, char* [], GLFWwindow** window);
void UResizeWindow(GLFWwindow* window, int width, int height);
void UProcessInput(GLFWwindow* window);
void UCreateMesh(GLMesh& mesh);
void UDestroyMesh(GLMesh& mesh);
void URender();
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint& programId);
void UDestroyShaderProgram(GLuint programId);
/* Vertex Shader Source Code*/
const GLchar* vertexShaderSource = GLSL(440,
layout(location = 0) in vec3 position; // Vertex data from Vertex Attrib Pointer 0
layout(location = 1) in vec3 color; // Color data from Vertex Attrib Pointer 1
layout(location = 2) in vec2 texture; // Texture data from Vertex Attrib Pointer 2
out vec3 vertexColor; // variable to transfer color data to the fragment shader
out vec3 vertexTexture;
//Global variables for the transform matrices
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform sampler2D myTexture; // Sampler
void main()
{
gl_Position = projection * view * model * vec4(cameraPosition.x, cameraPosition.y, cameraPosition.z, 1.0f); // transforms vertices to clip coordinates
vertexColor = color; // references incoming color data
vertexTexture = texture;
}
);
/* Fragment Shader Source Code*/
const GLchar* fragmentShaderSource = GLSL(440,
in vec3 vertexColor; // Variable to hold incoming color data from vertex shader
out vec3 fragmentColor;
out vec3 fragmentTexture;
void main()
{
fragmentColor = texture(myTexture, textTexture);
fragmentTexture = vec2(vertexTexture);
}
);
int main(int argc, char* argv[])
{
if (!UInitialize(argc, argv, &gWindow))
return EXIT_FAILURE;
// Create the mesh
UCreateMesh(gMesh); // Calls the function to create the Vertex Buffer Object
// Create the shader program
if (!UCreateShaderProgram(vertexShaderSource, fragmentShaderSource, gProgramId))
return EXIT_FAILURE;
// Sets the background color of the window to black (it will be implicitely used by glClear)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Set input call back functions
glfwSetKeyCallback(gWindow, key_callback);
glfwSetCursorPosCallback(gWindow, cursor_position_callback);
glfwSetMouseButtonCallback(gWindow, mouse_button_callback);
glfwSetScrollCallback(gWindow, scroll_callback);
// render loop
// -----------
while (!glfwWindowShouldClose(gWindow))
{
// Set delta time
GLfloat currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
// Resize window and graphics simultaneously
glfwGetFramebufferSize(gWindow, &WINDOW_WIDTH, &WINDOW_HEIGHT);
// input
// -----
UProcessInput(gWindow);
// Render this frame
URender();
glfwPollEvents();
// Poll camera transformations
TransformCamera();
}
// Release mesh data
UDestroyMesh(gMesh);
// Release shader program
UDestroyShaderProgram(gProgramId);
exit(EXIT_SUCCESS); // Terminates the program successfully
}
// Initialize GLFW, GLEW, and create a window
bool UInitialize(int argc, char* argv[], GLFWwindow** window)
{
// GLFW: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// GLFW: window creation
// ---------------------
* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE, NULL, NULL);
if (*window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return false;
}
glfwMakeContextCurrent(*window);
glfwSetFramebufferSizeCallback(*window, UResizeWindow);
// GLEW: initialize
// ----------------
// Note: if using GLEW version 1.13 or earlier
glewExperimental = GL_TRUE;
GLenum GlewInitResult = glewInit();
if (GLEW_OK != GlewInitResult)
{
std::cerr << glewGetErrorString(GlewInitResult) << std::endl;
return false;
}
// Displays GPU OpenGL version
cout << "INFO: OpenGL Version: " << glGetString(GL_VERSION) << endl;
return true;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
void UProcessInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
float cameraSpeed = 2.5 * deltaTime;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
cameraPosition += cameraSpeed * cameraFront;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
cameraPosition -= cameraSpeed * cameraFront;
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
cameraPosition -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
cameraPosition += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
cameraPosition -= cameraSpeed * cameraUp;
if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
cameraPosition += cameraSpeed * cameraUp;
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
void UResizeWindow(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
// Functioned called to render a frame
void URender()
{
// Enable z-depth
glEnable(GL_DEPTH_TEST);
// Wireframe mode
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// Clear the frame and z buffers
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 1. Scales the object by 2
glm::mat4 scale = glm::scale(glm::vec3(1.0f, 1.0f, 1.0f));
// 2. Rotates shape by 15 degrees in the x axis
glm::mat4 rotation = glm::rotate(45.0f, glm::vec3(1.0, 1.0f, 1.0f));
// 3. Place object at the origin
glm::mat4 translation = glm::translate(glm::vec3(0.0f, 0.0f, 0.0f));
// Model matrix: transformations are applied right-to-left order
glm::mat4 model = translation * rotation * scale;
// Transforms the camera: move the camera back (z axis)
glm::mat4 view = glm::lookAt(cameraPosition, getTarget(), worldUp);
// Creates a perspective projection
glm::mat4 projection = glm::perspective(fov, (GLfloat)WINDOW_WIDTH / (GLfloat)WINDOW_HEIGHT, 0.1f, 100.0f);
// Set the shader to be used
glUseProgram(gProgramId);
// Retrieves and passes transform matrices to the Shader program
GLint modelLoc = glGetUniformLocation(gProgramId, "model");
GLint viewLoc = glGetUniformLocation(gProgramId, "view");
GLint projLoc = glGetUniformLocation(gProgramId, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
GLuint crateTexture = {1};
glBindTexture(GL_TEXTURE_2D, crateTexture);
// Activate the VBOs contained within the mesh's VAO
glBindVertexArray(gMesh.vao);
// Draws the triangles
glDrawElements(GL_TRIANGLES, gMesh.nIndices, GL_UNSIGNED_SHORT, NULL); // Draws the triangle
// Deactivate the Vertex Array Object
glBindVertexArray(0);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
glfwSwapBuffers(gWindow); // Flips the the back buffer with the front buffer every frame.
}
// Implements the UCreateMesh function
void UCreateMesh(GLMesh& mesh)
{
// Position and Color data
GLfloat verts[] = {
0.0f, 1.0f, 0.0f, // Top Center Vertex 0
1.0f, 0.0f, 0.0f, 1.0f, // Red
0.5f, 1.0f, // UV
-1.0f, -1.0f, 1.0f, // Bottom Left Vertex 1
0.0f, 1.0f, 0.0f, 1.0f, // Green
0.0f, 0.0f, // UV
1.0f, -1.0f, 1.0f, // Bottom Right Vertex 2
0.0f, 0.0f, 1.0f, 1.0f, // Blue
1.0f, 0.0f, // UV
1.0f, -1.0f, -1.0f, // Bottom Back Right Vertex 3
1.0f, 0.0f, 1.0f, 1.0f, // Magenta
0.0f, 0.0f, // UV
-1.0f, -1.0f, -1.0f, // Bottom Back Left Vertex 4
1.0f, 1.0f, 0.0f, 1.0f, // Yellow
1.0f, 0.0f // UV
};
// Index data to share position data
GLushort indices[] = {
// Sides
0, 1, 2, // Triangle 1
0 ,2, 3, // Triangle 2
0, 3, 1, // Triangle 3
0, 3, 4, // Triangle 4
// Base
1, 2, 3, // Triangle 5
1, 4, 3 // Triangle 6
};
const GLuint floatsPerVertex = 3;
const GLuint floatsPerColor = 4;
const GLuint floatsPerTexture = 2;
glGenVertexArrays(1, &mesh.vao); // we can also generate multiple VAOs or buffers at the same time
glBindVertexArray(mesh.vao);
// Create 2 buffers: first one for the vertex data; second one for the indices
glGenBuffers(2, mesh.vbos);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbos[0]); // Activates the buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); // Sends vertex or coordinate data to the GPU
mesh.nIndices = sizeof(indices) / sizeof(indices[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Strides between vertex coordinates is 6 (x, y, z, r, g, b, a). A tightly packed stride is 0.
GLint stride = sizeof(float) * (floatsPerVertex + floatsPerColor);// The number of floats before each
// Create Vertex Attribute Pointers
glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, floatsPerColor, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float) * floatsPerVertex));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, floatsPerTexture, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float) * floatsPerTexture));
glEnableVertexAttribArray(2);
// Load textures
int crateTexWidth, crateTexHeight, gridTexWidth, gridTexHeight;
unsigned char* crateImage = SOIL_load_image("crate.png", &crateTexWidth, &crateTexHeight, 0, SOIL_LOAD_RGB);
unsigned char* gridImage = SOIL_load_image("crate.png", &gridTexWidth, &gridTexHeight, 0, SOIL_LOAD_RGB);
// Generate Textures
GLuint crateTexture = {1};
glGenTextures(1, &crateTexture);
glBindTexture(GL_TEXTURE_2D, crateTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, crateTexWidth, crateTexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, crateImage);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(crateImage);
glBindTexture(GL_TEXTURE_2D, 0);
// Generate Textures
GLuint gridTexture;
glGenTextures(1, &gridTexture);
glBindTexture(GL_TEXTURE_2D, gridTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, gridTexWidth, gridTexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, gridImage);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(gridImage);
glBindTexture(GL_TEXTURE_2D, 0);
}
void UDestroyMesh(GLMesh& mesh)
{
glDeleteVertexArrays(1, &mesh.vao);
glDeleteBuffers(2, mesh.vbos);
}
// Implements the UCreateShaders function
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint& programId)
{
// Compilation and linkage error reporting
int success = 0;
char infoLog[512];
// Create a Shader program object.
programId = glCreateProgram();
// Create the vertex and fragment shader objects
GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
// Retrive the shader source
glShaderSource(vertexShaderId, 1, &vtxShaderSource, NULL);
glShaderSource(fragmentShaderId, 1, &fragShaderSource, NULL);
// Compile the vertex shader, and print compilation errors (if any)
glCompileShader(vertexShaderId); // compile the vertex shader
// check for shader compile errors
glGetShaderiv(vertexShaderId, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShaderId, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
return false;
}
glCompileShader(fragmentShaderId); // compile the fragment shader
// check for shader compile errors
glGetShaderiv(fragmentShaderId, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShaderId, sizeof(infoLog), NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
return false;
}
// Attached compiled shaders to the shader program
glAttachShader(programId, vertexShaderId);
glAttachShader(programId, fragmentShaderId);
glLinkProgram(programId); // links the shader program
// check for linking errors
glGetProgramiv(programId, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(programId, sizeof(infoLog), NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
return false;
}
glUseProgram(programId); // Uses the shader program
return true;
}
void UDestroyShaderProgram(GLuint programId)
{
glDeleteProgram(programId);
}
// Define Input Callback functions
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
// Display ASCII Keycode
//cout << "ASCII: " << key << endl;
if (action == GLFW_PRESS)
keys[key] = true;
else if (action == GLFW_RELEASE)
keys[key] = false;
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
/*
// Display scroll offset
if (yoffset > 0)
cout << "Scroll Up: ";
if (yoffset < 0)
cout << "Scroll Down: ";
cout << yoffset << endl;
*/
// Clamp FOV
if (fov >= 1.f && fov <= 45.f)
fov -= yoffset * 0.01f;
//Default FOV
if (fov < 1.f)
fov = 1.f;
if (fov > 45.f)
fov = 45.f;
}
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) {
// Display mouse x and y coordinates
// cout << "Mouse X: " << xpos << endl;
// cout << "Mouse Y: " << ypos << endl;
if (firstMouseMove) {
lastX = xpos;
lastY = ypos;
firstMouseMove = false;
}
// Calculate cursor offset
xChange = xpos - lastX;
yChange = lastY - ypos;
lastX = xpos;
lastY = ypos;
// Pan camera
if (isPanning) {
if (cameraPosition.z < 0.f)
cameraFront.z = 1.f;
else
cameraFront.z = -1.f;
GLfloat cameraSpeed = xChange * deltaTime;
cameraPosition += cameraSpeed * cameraRight;
cameraSpeed = yChange * deltaTime;
cameraPosition += cameraSpeed * cameraUp;
}
// Orbit camera
if (isOrbiting) {
rawYaw += xChange;
rawPitch += yChange;
// Convert Yaw and Pitch to degrees
degYaw = glm::radians(rawYaw);
// degPitch = glm::radians(rawPitch)
degPitch = glm::clamp(glm::radians(rawPitch), -glm::pi<float>() / 2.f + .1f, glm::pi<float>() / 2.f - .1f);
// Azimuth Altitude formula
cameraPosition.x = target.x + radius * cosf(degPitch) * sin(degYaw);
cameraPosition.y = target.y + radius * sinf(degPitch);
cameraPosition.z = target.z + radius * cosf(degPitch) * cosf(degYaw);
}
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
/*
// Detect mouse button clicks
if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
cout << "LMB clicked!" << endl;
if (button == GLFW_MOUSE_BUTTON_MIDDLE && action == GLFW_PRESS)
cout << "MMB clicked!" << endl;
if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
cout << "RMB clicked!" << endl;
*/
if (action == GLFW_PRESS)
mouseButtons[button] = true;
else if (action == GLFW_RELEASE)
mouseButtons[button] = false;
}
// Define getTarget function
glm::vec3 getTarget() {
if (isPanning)
target = cameraPosition + cameraFront;
return target;
}
// Define TransformCamera function
void TransformCamera() {
// Pan camera
if (keys[GLFW_KEY_LEFT_ALT] && mouseButtons[GLFW_MOUSE_BUTTON_MIDDLE])
isPanning = true;
else
isPanning = false;
// Orbit camera
if ((mouseButtons[GLFW_MOUSE_BUTTON_LEFT]))
isOrbiting = true;
else
isOrbiting = false;
// Reset camera
if (keys[GLFW_KEY_F])
initCamera();
}
void initCamera() {
cameraPosition = glm::vec3(0.f, 0.f, 3.f);
target = glm::vec3(0.f, 0.f, 0.f);
cameraDirection = glm::normalize(cameraPosition - target);
worldUp = glm::vec3(0.f, 1.f, 0.f);
cameraRight = glm::normalize(glm::cross(worldUp, cameraDirection));
cameraUp = glm::normalize(glm::cross(cameraDirection, cameraRight));
cameraFront = glm::normalize(glm::vec3(0.f, 0.f, -1.f));
}
You never actually bother to declare/define a cameraPosition (presumably) uniform in your vertex shader or set its value via an appropriate glUniform*() call.
...not that you'd really want to since then every vertex would end up being set to the same position and you'd end up with a dot somewhere (maybe) on screen.
Rather,
gl_Position = projection * view * model * vec4(cameraPosition.x, cameraPosition.y, cameraPosition.z, 1.0f);
should probably be:
gl_Position = projection * view * model * vec4(position, 1.0);
...so all your fancy geometry in verts actually has some chance of being sensibly displayed.
I'm trying to make the colours on a shape darken, and then brighten periodically. The way I thought of to do it was to use a uniform variable that changes periodically from 0 to 1 and back and multiply it by the inputted colours to form the output colour. I have a uniform variable ublackness which does that.
A check of whether it can be located always returns -1, however the previous variables and the next variable work as intended. I know the name is correct, and I know it is being used because with the multiplication there, the screen is black (presumably because the colours are getting multiplied by 0 or something) but without it it displays fine. Here is the relevant code in the cpp file
GLuint positionIndex = glGetAttribLocation(g_shaderProgramID, "aPosition");
GLuint colorIndex = glGetAttribLocation(g_shaderProgramID, "aColor");
shadeIndex = glGetUniformLocation(g_shaderProgramID, "ublackness");
if (shadeIndex = -1)
{
cout << "it didn't work" << endl;
}
g_MVP_Index = glGetUniformLocation(g_shaderProgramID, "uModelViewProjectionMatrix");
And here is the relevant fragment shader file.
#version 330 core
// interpolated values from the vertex shaders
in vec3 vColor;
//thing
uniform float ublackness;
// output data
out vec3 fColor;
void main()
{
// set output color
fColor = vColor * ublackness;
}
And in case anyone tells me to use the vertex shader instead, I've tried that with the same results. I have also tried sending a vec3, and creating a temp vec3 and setting its colors to vcolor * blackness then outputting that.
I've also heard that nvidia graphics cards affect how functions like glUniform1f work, and I use that function, but that didn't seem relevant because it doesn't even get to that part of the code with a valid index. In case it is relevant, however, I have a NVIDIA Geforce GTX 1080. I've also heard that you need to use glUseProgram to get glGetUniformLocation to work, however the other functions work without it, and ublackness still doesn't work with it, so I didn't bother leaving it in. It is still used when rendering, however.
I highlighted the code I thought was relevant, but in case more is needed, here is all the main cpp code:
#include <cstdio> // for C++ i/o
#include <iostream>
#include <string>
#include <time.h>
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"
// struct for vertex attributes
struct Vertex
{
GLfloat position[3];
GLfloat color[3];
};
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 = 0; // vertex buffer object identifier
GLuint g_VAO = 0; // vertex array object identifier
GLuint g_shaderProgramID = 0; // shader program identifier
GLuint g_MVP_Index = 0; // location in shader
GLuint shadeIndex = 0;
glm::mat4 g_modelMatrix[6]; // object's model matrix
glm::mat4 g_viewMatrix; // view matrix
glm::mat4 g_projectionMatrix; // projection matrix
float translation[6];
float scaling[6];
float rotation[6];
float totalRotation[6];
float orbit[6];
float totalOrbit[6];
float totalShade = 1;
int shadeChange = 1;
// 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
glBindVertexArray(g_VAO); // make VAO active
for (int i = 0; i < 5; i++)
{
g_modelMatrix[i] = glm::rotate(totalOrbit[i], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::translate(glm::vec3(translation[i], 0.0f, 0.0f))
* glm::rotate(totalRotation[i], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::scale(glm::vec3(scaling[i], scaling[i], scaling[i]));
glm::mat4 MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[i];
// 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
}
g_modelMatrix[5] = glm::rotate(totalOrbit[5], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::translate(glm::vec3(translation[5], 0.0f, 0.0f))
* glm::rotate(totalOrbit[5], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::translate(glm::vec3(0.4, 0.0f, 0.0f))
* glm::rotate(totalRotation[5], glm::vec3(0.0f, 1.0f, 0.0f))
* glm::scale(glm::vec3(scaling[5], scaling[5], scaling[5]));
glm::mat4 MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[5];
// 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
//glm::mat4 MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[0];
// set uniform model transformation matrix
//glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
glFlush(); // flush the pipeline
}
// error callback function
static void error_callback(int error, const char* description)
{
cerr << description << endl; // output error description
}
// 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;
}
}
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("VertexShader.vert", "FragShader.frag");
// find the location of shader variables
GLuint positionIndex = glGetAttribLocation(g_shaderProgramID, "aPosition");
GLuint colorIndex = glGetAttribLocation(g_shaderProgramID, "aColor");
shadeIndex = glGetUniformLocation(g_shaderProgramID, "ublackness");
if (shadeIndex = -1)
{
cout << "it didn't work" << endl;
}
g_MVP_Index = glGetUniformLocation(g_shaderProgramID, "uModelViewProjectionMatrix");
srand(time(NULL));
// initialise model matrix to the identity matrix
g_modelMatrix[0] = glm::mat4(1.0f); //sun
scaling[0] = 0.5f * (100 + ((rand() % 100)))/100;
translation[0] = 0.0f;
rotation[0] = 1.0f * (100 + ((rand() % 100))) / 100;
orbit[0] = 0.0f;
g_modelMatrix[1] = glm::mat4(1.0f); //tilted planet
scaling[1] = 0.1f * (100 + ((rand() % 100))) / 100;
translation[1] = 0.7f * (100 + ((rand() % 15))) / 100;
rotation[1] = 1.0f * (100 + ((rand() % 100))) / 100;
orbit[1] = 0.3f * (100 + ((rand() % 100))) / 100;
g_modelMatrix[2] = glm::mat4(1.0f); //ringed planet
scaling[2] = 0.1f * (100 + ((rand() % 100))) / 100;
translation[2] = 1.5f * (100 + ((rand() % 15))) / 100;
rotation[2] = 1.0f * (100 + ((rand() % 100))) / 100;
orbit[2] = 0.3f * (100 + ((rand() % 100))) / 100;
g_modelMatrix[3] = glm::mat4(1.0f); //moon planet
scaling[3] = 0.1f * (100 + ((rand() % 100))) / 100;
translation[3] = 2.8f * (100 + ((rand() % 15))) / 100;
rotation[3] = 1.0f * (100 + ((rand() % 100))) / 100;
orbit[3] = 0.3f * (100 + ((rand() % 100))) / 100;
g_modelMatrix[4] = glm::mat4(1.0f); //fading planet
scaling[4] = 0.1f * (100 + ((rand() % 100))) / 100;
translation[4] = 4.0f * (100 + ((rand() % 15))) / 100;
rotation[4] = 1.0f * (100 + ((rand() % 100))) / 100;
orbit[4] = 0.3f * (100 + ((rand() % 100))) / 100;
g_modelMatrix[5] = glm::mat4(1.0f); //moon
scaling[5] = 0.02f * (100 + ((rand() % 100))) / 100;
translation[5] = translation[3];
rotation[5] = 1.0f * (100 + ((rand() % 100))) / 100;
orbit[5] = orbit[3];
g_viewMatrix = glm::lookAt(glm::vec3(0, 6, 1), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
int width, height;
glfwGetFramebufferSize(window, &width, &height);
float aspectRatio = static_cast<float>(width) / height;
g_projectionMatrix = glm::perspective(45.0f, aspectRatio, 0.1f, 100.0f);
// generate identifier for VBO and copy data to GPU
glGenBuffers(1, &g_VBO);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO);
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);
// create VAO and specify VBO data
glBindVertexArray(g_VAO);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO);
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);
}
static void update_scene(GLFWwindow* window, float frameTime)
{
// declare variables to transform the object
for (int i = 0; i < 6; i++)
{
totalOrbit[i] += orbit[i] * frameTime;
totalRotation[i] += rotation[i] * frameTime;
}
if (totalShade = 1)
{
shadeChange = -0.05f;
}
else if (totalShade = 0)
{
shadeChange = 0.05f;
}
totalShade += shadeChange;
glUniform1f(shadeIndex, totalShade);
}
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(800, 600, "Creating a Window", 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);
/*
// if not using key or mouse callback functions
// use sticky mode to avoid missing state changes from polling
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
glfwSetInputMode(window, GLFW_STICKY_MOUSE_BUTTONS, GL_TRUE);
*/
// initialise rendering states
init(window);
double lastUpdateTime = glfwGetTime(); // last update time
double elapsedTime = lastUpdateTime; // time elapsed since last update
float frameTime = 0.0f; // frame time
int frameCount = 0;
// the rendering loop
while (!glfwWindowShouldClose(window))
{
update_scene(window, frameTime); // update the scene
render_scene(); // render the scene
glfwSwapBuffers(window); // swap buffers
glfwPollEvents(); // poll for events
frameCount++;
elapsedTime = glfwGetTime() - lastUpdateTime; // current time - last update time
if (elapsedTime >= 1.0f) // if time since last update >= to 1 second
{
frameTime = static_cast<float>(1.0f / frameCount); // calculate frame time
string str = "FPS = " + to_string(frameCount) + "; FT = " + to_string(frameTime);
glfwSetWindowTitle(window, str.c_str()); // update window title
frameCount = 0; // reset frame count
lastUpdateTime += elapsedTime; // update last update time
}
}
// clean up
glDeleteProgram(g_shaderProgramID);
glDeleteBuffers(1, &g_IBO);
glDeleteBuffers(1, &g_VBO);
glDeleteVertexArrays(1, &g_VAO);
// close the window and terminate GLFW
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
here is all the vertex shader code:
#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;
}
And here is all the shader cpp code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
#define GLEW_STATIC // include GLEW as a static library
#include <GLEW/glew.h> // include GLEW
#include "shader.h"
// function to load shaders
GLuint loadShaders(const string vertexShaderFile, const string fragmentShaderFile)
{
GLint status; // for checking compile and linking status
// load vertex shader code from file
string vertexShaderCode; // to store shader code
ifstream vertexShaderStream(vertexShaderFile, ios::in); // open file stream
// check whether file stream was successfully opened
if(vertexShaderStream.is_open())
{
// read from stream line by line and append it to shader code
string line = "";
while(getline(vertexShaderStream, line))
vertexShaderCode += line + "\n";
vertexShaderStream.close(); // no longer need file stream
}
else
{
// output error message and exit
cout << "Failed to open vertex shader file - " << vertexShaderFile << endl;
exit(EXIT_FAILURE);
}
// load fragment shader code from file
string fragmentShaderCode; // to store shader code
ifstream fragmentShaderStream(fragmentShaderFile, ios::in); // open file stream
// check whether file stream was successfully opened
if(fragmentShaderStream.is_open())
{
// read from stream line by line and append it to shader code
string line = "";
while(getline(fragmentShaderStream, line))
fragmentShaderCode += line + "\n";
fragmentShaderStream.close(); // no longer need file stream
}
else
{
// output error message and exit
cout << "Failed to open fragment shader file - " << fragmentShaderFile << endl;
exit(EXIT_FAILURE);
}
// create shader objects
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// provide source code for shaders
const GLchar* vShaderCode = vertexShaderCode.c_str();
const GLchar* fShaderCode = fragmentShaderCode.c_str();
glShaderSource(vertexShaderID, 1, &vShaderCode, NULL);
glShaderSource(fragmentShaderID, 1, &fShaderCode, NULL);
// compile vertex shader
glCompileShader(vertexShaderID);
// check compile status
status = GL_FALSE;
glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &status);
if(status == GL_FALSE)
{
// output error message
cout << "Failed to compile vertex shader - " << vertexShaderFile << endl;
// output error information
int infoLogLength;
glGetShaderiv(fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
char* errorMessage = new char[infoLogLength + 1];
glGetShaderInfoLog(vertexShaderID, infoLogLength, NULL, errorMessage);
cout << errorMessage << endl;
delete[] errorMessage;
exit(EXIT_FAILURE);
}
// compile fragment shader
glCompileShader(fragmentShaderID);
// check compile status
status = GL_FALSE;
glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &status);
if(status == GL_FALSE)
{
// output error message
cout << "Failed to compile fragment shader - " << fragmentShaderFile << endl;
// output error information
int infoLogLength;
glGetShaderiv(fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
char* errorMessage = new char[infoLogLength + 1];
glGetShaderInfoLog(fragmentShaderID, infoLogLength, NULL, errorMessage);
cout << errorMessage << endl;
delete[] errorMessage;
exit(EXIT_FAILURE);
}
// create program
GLuint programID = glCreateProgram();
// attach shaders to the program object
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, fragmentShaderID);
// flag shaders for deletion (will not be deleted until detached from program)
glDeleteShader(vertexShaderID);
glDeleteShader(fragmentShaderID);
// link program object
glLinkProgram(programID);
// check link status
status = GL_FALSE;
glGetProgramiv(programID, GL_LINK_STATUS, &status);
if(status == GL_FALSE)
{
// output error message
cout << "Failed to link program object." << endl;
// output error information
int infoLogLength;
glGetShaderiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength);
char* errorMessage = new char[infoLogLength + 1];
glGetShaderInfoLog(programID, infoLogLength, NULL, errorMessage);
cout << errorMessage << endl;
delete[] errorMessage;
exit(EXIT_FAILURE);
}
return programID;
}
In case you are wondering what the code does, it creates a cube, then transforms it to make a solar system. I was trying to make 1 cube go dark then bright but I wanted to make sure it worked first by using it on all of them.
I believe:
if (shadeIndex = -1)
should be:
if (shadeIndex == -1)
And then you will need to add a call to glUniform1f in your code, in order to actually set the uniform value, of course.
my OpenGL version is 4.0. I would like to draw a sphere through latitude and longitude. I use this method:
x=ρsinϕcosθ
y=ρsinϕsinθ
z=ρcosϕ
This is a part of my code:
glm::vec3 buffer[1000];
glm::vec3 outer;
buffercount = 1000;
float section = 10.0f;
GLfloat alpha, beta;
int index = 0;
for (alpha = 0.0 ; alpha <= PI; alpha += PI/section)
{
for (beta = 0.0 ; beta <= 2* PI; beta += PI/section)
{
outer.x = radius*cos(beta)*sin(alpha);
outer.y = radius*sin(beta)*sin(alpha);
outer.z = radius*cos(alpha);
buffer[index] = outer;
index = index +1;
}
}
GLuint sphereVBO, sphereVAO;
glGenVertexArrays(1, &sphereVAO);
glGenBuffers(1,&sphereVBO);
glBindVertexArray(sphereVAO);
glBindBuffer(GL_ARRAY_BUFFER,sphereVBO);
glBufferData(GL_ARRAY_BUFFER,sizeof(glm::vec3) *buffercount ,&buffer[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
...
while (!glfwWindowShouldClose(window))
{
...
...
for (GLuint i = 0; i < buffercount; i++)
{
...
...
glm::mat4 model;
model = glm::translate(model, buffer[i]);
GLfloat angle = 10.0f * i;
model = glm::rotate(model, angle, glm::vec3(1.0f, 0.3f, 0.5f));
glUniformMatrix4fv(modelMat, 1, GL_FALSE, glm::value_ptr(model));
}
glDrawArrays(GL_TRIANGLE_FAN, 0, 900);
glfwSwapBuffers(window);
}
if section = 5, the performance is like this:
if section = 20. the performance is like this:
I think that I might have logic problem in my code. I am struggle in this problem...
-----update-----
I edited my code, It doesn't have any error, but I got a blank screen. I guess that something wrong in my vertex shader. I might pass wrong variables to vertex sheder. Please help me.
gluperspective is deprecated in my OpenGL 4.1
I switch to :
float aspect=float(4.0f)/float(3.0f);
glm::mat4 projection_matrix = glm::perspective(60.0f/aspect,aspect,0.1f,100.0f);
It shows that this error: constant expression evaluates to -1 which cannot be narrowed to type 'GLuint'(aka 'unsigned int')
GLuint sphere_vbo[4]={-1,-1,-1,-1};
GLuint sphere_vao[4]={-1,-1,-1,-1};
I'm not sure how to revise it...I switch to:
GLuint sphere_vbo[4]={1,1,1,1};
GLuint sphere_vao[4]={1,1,1,1};
I put Spektre's code in spherer.h file
This is a part of my main.cpp file:
...
...
Shader shader("basic.vert", "basic.frag");
sphere_init();
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
shader.Use();
GLuint MatrixID = glGetUniformLocation(shader.Program, "MVP");
GLfloat radius = 10.0f;
GLfloat camX = sin(glfwGetTime()) * radius;
GLfloat camZ = cos(glfwGetTime()) * radius;
// view matrix
glm::mat4 view;
view = glm::lookAt(glm::vec3(camX, 0.0, camZ), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
glm::mat4 view_matrix = view;
// projection matrix
float aspect=float(4.0f)/float(3.0f);
glm::mat4 projection_matrix = glm::perspective(60.0f/aspect,aspect,0.1f,100.0f);
// model matrix
glm::mat4 model_matrix = glm::mat4(1.0f);// identity
//ModelViewProjection
glm::mat4 model_view_projection = projection_matrix * view_matrix * model_matrix;
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &model_view_projection[0][0]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-10.0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
sphere_draw();
glFlush();
glfwSwapBuffers(window);
}
sphere_exit();
glfwTerminate();
return 0;
}
This is my vertex shader file:
#version 410 core
uniform mat4 MVP;
layout(location = 0) in vec3 vertexPosition_modelspace;
out vec4 vertexColor;
void main()
{
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
vertexColor = vec4(0, 1, 0, 1.0);
}
I added error-check function get_log in my shader.h file.
...
...
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
get_log(vertex);
...
...
void get_log(GLuint shader){
GLint isCompiled = 0;
GLchar infoLog[1024];
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE)
{
printf("----error--- \n");
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "| ERROR::::" << &infoLog << "\n| -- ------------------ --------------------------------- -- |" << std::endl;
glDeleteShader(shader); // Don't leak the shader.
}else{
printf("---no error --- \n");
}
}
I tested both fragment shader and vertex shader, it both showed ---no error---
As I mentioned in the comments you need to add indices to your mesh VAO/VBO. Not sure why GL_QUADS is not implemented on your machine that makes no sense as it is basic primitive so to make this easy to handle I use only GL_TRIANGLES which is far from ideal but what to heck ... Try this:
//---------------------------------------------------------------------------
const int na=36; // vertex grid size
const int nb=18;
const int na3=na*3; // line in grid size
const int nn=nb*na3; // whole grid size
GLfloat sphere_pos[nn]; // vertex
GLfloat sphere_nor[nn]; // normal
//GLfloat sphere_col[nn]; // color
GLuint sphere_ix [na*(nb-1)*6]; // indices
GLuint sphere_vbo[4]={-1,-1,-1,-1};
GLuint sphere_vao[4]={-1,-1,-1,-1};
void sphere_init()
{
// generate the sphere data
GLfloat x,y,z,a,b,da,db,r=3.5;
int ia,ib,ix,iy;
da=2.0*M_PI/GLfloat(na);
db= M_PI/GLfloat(nb-1);
// [Generate sphere point data]
// spherical angles a,b covering whole sphere surface
for (ix=0,b=-0.5*M_PI,ib=0;ib<nb;ib++,b+=db)
for (a=0.0,ia=0;ia<na;ia++,a+=da,ix+=3)
{
// unit sphere
x=cos(b)*cos(a);
y=cos(b)*sin(a);
z=sin(b);
sphere_pos[ix+0]=x*r;
sphere_pos[ix+1]=y*r;
sphere_pos[ix+2]=z*r;
sphere_nor[ix+0]=x;
sphere_nor[ix+1]=y;
sphere_nor[ix+2]=z;
}
// [Generate GL_TRIANGLE indices]
for (ix=0,iy=0,ib=1;ib<nb;ib++)
{
for (ia=1;ia<na;ia++,iy++)
{
// first half of QUAD
sphere_ix[ix]=iy; ix++;
sphere_ix[ix]=iy+1; ix++;
sphere_ix[ix]=iy+na; ix++;
// second half of QUAD
sphere_ix[ix]=iy+na; ix++;
sphere_ix[ix]=iy+1; ix++;
sphere_ix[ix]=iy+na+1; ix++;
}
// first half of QUAD
sphere_ix[ix]=iy; ix++;
sphere_ix[ix]=iy+1-na; ix++;
sphere_ix[ix]=iy+na; ix++;
// second half of QUAD
sphere_ix[ix]=iy+na; ix++;
sphere_ix[ix]=iy-na+1; ix++;
sphere_ix[ix]=iy+1; ix++;
iy++;
}
// [VAO/VBO stuff]
GLuint i;
glGenVertexArrays(4,sphere_vao);
glGenBuffers(4,sphere_vbo);
glBindVertexArray(sphere_vao[0]);
i=0; // vertex
glBindBuffer(GL_ARRAY_BUFFER,sphere_vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sizeof(sphere_pos),sphere_pos,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
i=1; // indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,sphere_vbo[i]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(sphere_ix),sphere_ix,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,4,GL_UNSIGNED_INT,GL_FALSE,0,0);
i=2; // normal
glBindBuffer(GL_ARRAY_BUFFER,sphere_vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sizeof(sphere_nor),sphere_nor,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
/*
i=3; // color
glBindBuffer(GL_ARRAY_BUFFER,sphere_vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sizeof(sphere_col),sphere_col,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
*/
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
}
void sphere_exit()
{
glDeleteVertexArrays(4,sphere_vao);
glDeleteBuffers(4,sphere_vbo);
}
void sphere_draw()
{
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glBindVertexArray(sphere_vao[0]);
// glDrawArrays(GL_POINTS,0,sizeof(sphere_pos)/sizeof(GLfloat)); // POINTS ... no indices for debug
glDrawElements(GL_TRIANGLES,sizeof(sphere_ix)/sizeof(GLuint),GL_UNSIGNED_INT,0); // indices (choose just one line not both !!!)
glBindVertexArray(0);
}
void gl_draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float aspect=float(xs)/float(ys);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0/aspect,aspect,0.1,100.0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-10.0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
sphere_draw();
glFlush();
SwapBuffers(hdc);
}
//---------------------------------------------------------------------------
Usage is simple after OpenGL context is created and extensions loaded call sphere_init() before closing app call sphere_exit() (while OpenGL context is still running) and when you want to render call sphere_draw(). I make an gl_draw() example with some settings and here the preview of it:
The point is to create 2D grid of points covering whole surface of sphere (via spherical long,lat a,b angles) and then just create triangles covering whole grid...
I wrote a minimal code-sample in C++, which is rendering 10000 colored
quads on the screen. I am using "instancing" and so updating only
the model-matrix for each quad each frame. The data of the 6 vertices
are stored in an indivdual VBO und will be reused all the time.
The projection-matrix (orthographic) is injected once at program-start
via uniform. The model-matrix is calculated on the CPU with the library GLM.
I measured the rendering-time and I got only an average FPS of 52.
I think this is MUCH to less, but I cannot find the mistake/bottleneck in my little sample program.
After some analysis it seems, that the 3 calculations done with GLM
are very slow. Am I doing something wrong here? For example, If
I remove the rotating-calculation, I get an FPS-boost of 10 FPS!
Maybe you can help me to find out, what I can do better here and how
can I optimize my sample. It is important for me, that each quad is individual configurable during runtime, so I decided to use instancing.
Moving the matrix-calculations to the GPU seems another option, but I am really confused, why the CPU has so much problems calculating the 10000
model-matrices! Ok, my CPU is very bad (Athlon 2 Core-Duo M300, GPU is ATI Mobility Radeon 4100), but It should do this task in no measurable time, or?
Here is minimal, fully working, compilable example (If u have GLFW and GLM).
Maybe someone have some time and can help me out here :)
#define GLEW_STATIC
#define GLM_FORCE_INLINE
#define GLM_FORCE_SSE2
#include "glew.h"
#include "glfw3.h"
#include "glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include <conio.h>
#include <cstdlib>
#include <iostream>
#include <ctime>
GLuint buildShader()
{
std::string strVSCode =
"#version 330 core\n"
"in vec3 vertexPosition;\n"
"in mat4 modelMatrix;\n"
"uniform mat4 projectionMatrix;\n"
"out vec4 m_color;\n"
"void main() {\n"
" vec4 vecVertex = vec4(vertexPosition, 1);\n"
" gl_Position = projectionMatrix * modelMatrix * vecVertex;\n"
" m_color = gl_Position;\n"
"}\n";
std::string strFSCode = "#version 330 core\n"
"out vec4 frag_colour;\n"
"in vec4 m_color;\n"
"void main() {\n"
" frag_colour = vec4(m_color.x, m_color.y, m_color.z, 0.5f);\n"
"}\n";
GLuint gluiVertexShaderId = glCreateShader(GL_VERTEX_SHADER);
char const * VertexSourcePointer = strVSCode.c_str();
glShaderSource(gluiVertexShaderId, 1, &VertexSourcePointer, NULL);
glCompileShader(gluiVertexShaderId);
GLuint gluiFragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
char const * FragmentSourcePointer = strFSCode.c_str();
glShaderSource(gluiFragmentShaderId, 1, &FragmentSourcePointer, NULL);
glCompileShader(gluiFragmentShaderId);
GLuint gluiProgramId = glCreateProgram();
glAttachShader(gluiProgramId, gluiVertexShaderId);
glAttachShader(gluiProgramId, gluiFragmentShaderId);
glLinkProgram(gluiProgramId);
glDeleteShader(gluiVertexShaderId);
glDeleteShader(gluiFragmentShaderId);
return gluiProgramId;
}
struct Sprite
{
glm::vec3 position, dimension;
float speed, rotation, rx, ry;
};
struct Vertex
{
float x, y, z;
Vertex(){};
Vertex(float x, float y, float z) : x(x), y(y), z(z) {}
};
int main(int arc, char **argv)
{
// GLFW init
int displayResWith = 1366; //modify this here
int displayResHeight = 768; //modify this here
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RED_BITS, 8);
glfwWindowHint(GLFW_GREEN_BITS, 8);
glfwWindowHint(GLFW_BLUE_BITS, 8);
glfwWindowHint(GLFW_ALPHA_BITS, 8);
glfwWindowHint(GLFW_DEPTH_BITS, 32);
glfwWindowHint(GLFW_STENCIL_BITS, 32);
GLFWwindow* window = glfwCreateWindow(displayResWith, displayResHeight,"Instancing", glfwGetPrimaryMonitor(),NULL);
int width, height;
glfwMakeContextCurrent(window);
glfwSwapInterval(0);
glfwGetFramebufferSize(window, &width, &height);
//GLEW init
glewExperimental = GL_TRUE;
glewInit();
const GLubyte* renderer = glGetString(GL_RENDERER);
const GLubyte* version = glGetString(GL_VERSION);
std::cout << "Renderer: " << renderer << std::endl;
std::cout << "OpenGL supported version: " << version << std::endl;
//OpenGL init
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(255.0f, 255.0f, 255.0f, 255.0f);
//Shader
GLuint programID = buildShader();
//VBO vertexBuffer
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
Vertex VertexBufferData[6];
VertexBufferData[0] = Vertex(-0.5f, 0.5f, 0.0f); //Links oben
VertexBufferData[1] = Vertex(-0.5f, -0.5f, 0.0f); //Links unten
VertexBufferData[2] = Vertex(0.5f, -0.5f, 0.0f); //Rechts unten
VertexBufferData[3] = VertexBufferData[2]; //Rechts unten
VertexBufferData[4] = Vertex(0.5f, 0.5f, 0.0f); //Rechts oben
VertexBufferData[5] = VertexBufferData[0]; //Links oben
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*6, VertexBufferData, GL_STATIC_DRAW);
//VBO instanceBuffer
GLuint instanceBuffer;
glGenBuffers(1, &instanceBuffer);
glBindBuffer(GL_ARRAY_BUFFER, instanceBuffer);
int iMaxInstanceCount = 30000;
glm::mat4 *ptrInstanceBufferData = new glm::mat4[iMaxInstanceCount];
glBufferData(GL_ARRAY_BUFFER, iMaxInstanceCount * sizeof(glm::mat4), NULL, GL_STREAM_DRAW);
//VAO - Start
GLuint vertexArrayObject;
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
//For VBO vertexbuffer
glEnableVertexAttribArray(glGetAttribLocation(programID, "vertexPosition"));
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(
glGetAttribLocation(programID, "vertexPosition"),
3,
GL_FLOAT,
GL_FALSE,
sizeof(Vertex),
(void*)0
);
glVertexAttribDivisor(0, 0);
//For VBO instanceBuffer
int pos = glGetAttribLocation(programID, "modelMatrix");
int pos1 = pos + 0;
int pos2 = pos + 1;
int pos3 = pos + 2;
int pos4 = pos + 3;
glEnableVertexAttribArray(pos1);
glEnableVertexAttribArray(pos2);
glEnableVertexAttribArray(pos3);
glEnableVertexAttribArray(pos4);
glBindBuffer(GL_ARRAY_BUFFER, instanceBuffer);
glVertexAttribPointer(pos1, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4 * 4, (void*)(0));
glVertexAttribPointer(pos2, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4 * 4, (void*)(sizeof(float) * 4));
glVertexAttribPointer(pos3, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4 * 4, (void*)(sizeof(float) * 8));
glVertexAttribPointer(pos4, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4 * 4, (void*)(sizeof(float) * 12));
glVertexAttribDivisor(pos1, 1);
glVertexAttribDivisor(pos2, 1);
glVertexAttribDivisor(pos3, 1);
glVertexAttribDivisor(pos4, 1);
glBindVertexArray(0); //VAO - End
//Matrix vars
glm::mat4 Projection, Rotating, Scaling, Translation, Identity;
glm::vec3 ZRotateVec(0.0f, 0.0f, 1.0f);
//Calc projection-matrix and put shader (uniform)
Projection = glm::ortho(0.0f, (float)width, 0.0f, (float)height, 0.0f, 1.0f);
glUseProgram(programID);
glUniformMatrix4fv(glGetUniformLocation(programID, "projectionMatrix"), 1, GL_FALSE, &Projection[0][0]);
//Creating sprites
std::srand(static_cast<unsigned int>(std::time(0)));
int iActInstanceCount = 10000;
Sprite *ptrSprites = new Sprite[iActInstanceCount];
for (int i = 0; i < iActInstanceCount; ++i)
{
ptrSprites[i].dimension = glm::vec3(16, 16, 1.0f);
ptrSprites[i].position = glm::vec3(std::rand()%(width-32),std::rand()%(height-32),-1.0f *((std::rand()%256)/256.0f));
ptrSprites[i].rotation = rand() % 360 + 0.0f;
ptrSprites[i].rx = static_cast<float>(std::rand() % 2);
ptrSprites[i].ry = static_cast<float>(std::rand() % 2);
ptrSprites[i].speed = (std::rand() % 100) + 1.0f;
if (ptrSprites[i].speed < 1.0f) ptrSprites[i].speed = 1.0f;
}
//FPS init
double fFramesRendered = 0.0f;
double fFrameMeasurementStart = 0.0f;
double fFPS = 0.0f;
double fCurrentTime = 0.0f;
glfwSetTime(0);
//Main-loop (also renderloop)
while (!glfwWindowShouldClose(window))
{
//application-logic
if (glfwGetKey(window, GLFW_KEY_ESCAPE)== GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
const double fNewTime = glfwGetTime();
double fDeltaTime = fNewTime - fCurrentTime;
fCurrentTime = fNewTime;
for (int i = 0; i < iActInstanceCount; ++i)
{
float fSpeed = ptrSprites[i].speed * static_cast<float>(fDeltaTime);
ptrSprites[i].rotation += fSpeed;
if (ptrSprites[i].rotation >= 360.0f) ptrSprites[i].rotation = 0.0f;
if (ptrSprites[i].rx == 1) ptrSprites[i].position.x = ptrSprites[i].position.x + fSpeed;
if (ptrSprites[i].rx == 0) ptrSprites[i].position.x = ptrSprites[i].position.x - fSpeed;
if (ptrSprites[i].ry == 1) ptrSprites[i].position.y = ptrSprites[i].position.y + fSpeed;
if (ptrSprites[i].ry == 0) ptrSprites[i].position.y = ptrSprites[i].position.y - fSpeed;
if (ptrSprites[i].position.x <= 0) ptrSprites[i].rx = 1;
if (ptrSprites[i].position.x + ptrSprites[i].dimension.x >= width) ptrSprites[i].rx = 0;
if (ptrSprites[i].position.y <= 0) ptrSprites[i].ry = 1;
if (ptrSprites[i].position.y + ptrSprites[i].dimension.y >= height) ptrSprites[i].ry = 0;
//matrix-calculations (saved in local buffer)
Translation = glm::translate(Identity, ptrSprites[i].position + glm::vec3(ptrSprites[i].dimension.x / 2.0f, ptrSprites[i].dimension.y / 2.0f, 0.0f));
Scaling = glm::scale(Translation, ptrSprites[i].dimension);
ptrInstanceBufferData[i] = glm::rotate(Scaling, ptrSprites[i].rotation, ZRotateVec);
}
//render-call
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programID);
glBindVertexArray(vertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, instanceBuffer);
glBufferData(GL_ARRAY_BUFFER, iMaxInstanceCount * sizeof(glm::mat4), NULL, GL_STREAM_DRAW); // Buffer orphaning
glBufferSubData(GL_ARRAY_BUFFER, 0, iActInstanceCount * sizeof(glm::mat4), ptrInstanceBufferData);
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, iActInstanceCount);
glBindVertexArray(0);
glfwSwapBuffers(window);
glfwPollEvents();
//FPS-stuff
++fFramesRendered;
if ((fCurrentTime*1000.0f) >= (fFrameMeasurementStart*1000.0f) + 1000.0f)
{
fFPS = ((fCurrentTime*1000.0f) - (fFrameMeasurementStart*1000.0f)) / 1000.0f * fFramesRendered;
fFrameMeasurementStart = fCurrentTime;
fFramesRendered = 0;
std::cout << "FPS: " << fFPS << std::endl;
}
}
//Termination and cleanup
glDeleteBuffers(1, &vertexBuffer);
glDeleteBuffers(1, &instanceBuffer);
glDeleteVertexArrays(1, &vertexArrayObject);
glDeleteProgram(programID);
glfwDestroyWindow(window);
glfwTerminate();
return _getch();
}
Well, after testing it on my machine, it is definitely CPU limited, so nothing you do with OGL is going to make much difference. I get about ~300fps with GCC on at least -O1, but only ~80 with -O0. My CPU is very fast (i7 2600k, 4.7ghz), but my GPU is rather slow (GT 520). I'm also on Ubuntu.
Some quick ideas for things that might speed it up a little:
Put the vertex positions in an array in the vertex shader and use gl_VertexID to access them
Use GL_TRIANGLE_STRIP instead of GL_TRIANGLES
Use radians for angles, as otherwise GLM has to convert them
None of these are likely to make much of any impact, really. Just make sure your compiler is set up right, and there probably isn't much more to do.
After many painful hours of attempting to figure out why my lighting is messed up I am still at a loss.
The OpenGL normals are correct (backface culling does not cause any of my triangles to disappear)
I calculate my normals in order to interpolate for lighting, all the triangles on the same faces also have the same normals.
If any one has any thoughts that would be appreciated.
I am definitely new to OpenGL, so that is a bit obvious in my code.
here are my shaders:
vertex shader
#version 330 core
layout(location = 0) in vec3 Position;
layout(location = 1) in vec3 vertexColor;
in vec3 vNormal;
out vec3 fragmentColor; // Output data ; will be interpolated for each fragment.
uniform mat4 MVP;
uniform mat4 transformMatrix;
uniform vec4 LightPosition;
// output values that will be interpretated per-fragment
out vec3 fN;
out vec3 fE;
out vec3 fL;
void main()
{
fN = vNormal;
fE = Position.xyz;
fL = LightPosition.xyz;
if( LightPosition.w != 0.0 ) {
fL = LightPosition.xyz - Position.xyz;
}
// Output position of the vertex, in clip space : MVP * position
vec4 v = vec4(Position,1); // Transform in homoneneous 4D vector
gl_Position = MVP * v;
//gl_Position = MVP * v;
// The color of each vertex will be interpolated
// to produce the color of each fragment
//fragmentColor = vertexColor; // take out at some point
}
and the fragmentShader, using phong shading
#version 330
//out vec3 color;
// per-fragment interpolated values from the vertex shader
in vec3 fN;
in vec3 fL;
in vec3 fE;
out vec4 fColor;
uniform vec4 AmbientProduct, DiffuseProduct, SpecularProduct;
uniform mat4 ModelView;
uniform vec4 LightPosition;
uniform float Shininess;
in vec3 fragmentColor; // Interpolated values from the vertex shaders
void main()
{
// Normalize the input lighting vectors
vec3 N = normalize(fN);
vec3 E = normalize(fE);
vec3 L = normalize(fL);
vec3 H = normalize( L + E );
vec4 ambient = AmbientProduct;
float Kd = max(dot(L, N), 0.0);
vec4 diffuse = Kd*DiffuseProduct;
float Ks = pow(max(dot(N, H), 0.0), Shininess);
vec4 specular = Ks*SpecularProduct;
// discard the specular highlight if the light's behind the vertex
if( dot(L, N) < 0.0 ) {
specular = vec4(0.0, 0.0, 0.0, 1.0);
}
fColor = ambient + diffuse + specular;
fColor.a = 1.0;
//color = vec3(1,0,0);
// Output color = color specified in the vertex shader,
// interpolated between all 3 surrounding vertices
//color = fragmentColor;
}
void setMatrices()
{
GLfloat FoV = 45; // the zoom of the camera
glm::vec3 cameraPosition(4,3,3), // the position of your camera, in world space // change to see what happends
cameraTarget(0,0,0), // where you want to look at, in world space
upVector(0,-1,0);
// Projection matrix : 45° Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
glm::mat4 Projection = glm::perspective(FoV, 3.0f / 3.0f, 0.001f, 100.0f); // ratio needs to change here when the screen size/ratio changes
// Camera matrix
glm::mat4 View = glm::lookAt(
cameraPosition, // Camera is at (4,3,3), in World Space
cameraTarget, // and looks at the origin
upVector // Head is up (set to 0,-1,0 to look upside-down)
);
// Model matrix : an identity matrix (model will be at the origin)
glm::mat4 Model = glm::mat4(1.0f); // Changes for each model !
// Our ModelViewProjection : multiplication of our 3 matrices
glm::mat4 MVP = Projection * View * Model * transformMatrix; //matrix multiplication is the other way around
// Get a handle for our "MVP" uniform.
// Only at initialisation time.
GLuint MatrixID = glGetUniformLocation(programID, "MVP");
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
// For each model you render, since the MVP will be different (at least the M part)
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
RotationID = glGetUniformLocation(programID,"transformMatrix");
//lighting
cubeNormal = glGetAttribLocation( programID, "vNormal" );
}
void setBuffers()
{
// Get a vertex array object
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glUseProgram(programID);
// cube buffer objects
glGenBuffers(1, &CubeVertexbuffer); // Generate 1 buffer, put the resulting identifier in vertexbuffer
glBindBuffer(GL_ARRAY_BUFFER, CubeVertexbuffer); // The following commands will talk about our 'vertexbuffer' buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(CubeBufferData), CubeBufferData, GL_STATIC_DRAW); // Give our vertices to OpenGL.
// cube normal objects
glGenBuffers(1, &CubeNormalbuffer); // Generate 1 buffer, put the resulting identifier in vertexbuffer
glBindBuffer(GL_ARRAY_BUFFER, CubeNormalbuffer); // The following commands will talk about our 'vertexbuffer' buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(CubeNormalBufferData), CubeNormalBufferData, GL_STATIC_DRAW); // Give our vertices to OpenGL.
//octahedron buffer objects
glGenBuffers(1, &OctaVertexbuffer); // Generate 1 buffer, put the resulting identifier in vertexbuffer
glBindBuffer(GL_ARRAY_BUFFER, OctaVertexbuffer); // The following commands will talk about our 'vertexbuffer' buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(octahedronBufData), octahedronBufData, GL_STATIC_DRAW); // Give our vertices to OpenGL.
//tetrahedron buffer objects
glGenBuffers(1, &TetraVertexbuffer); // Generate 1 buffer, put the resulting identifier in vertexbuffer
glBindBuffer(GL_ARRAY_BUFFER, TetraVertexbuffer); // The following commands will talk about our 'vertexbuffer' buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(tetrahedronBufData), tetrahedronBufData, GL_STATIC_DRAW); // Give our vertices to OpenGL.
//dodecahedron buffer objects
glGenBuffers(1, &DodecaVertexbuffer); // Generate 1 buffer, put the resulting identifier in vertexbuffer
glBindBuffer(GL_ARRAY_BUFFER, DodecaVertexbuffer); // The following commands will talk about our 'vertexbuffer' buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(dodecahedronBufData), dodecahedronBufData, GL_STATIC_DRAW); // Give our vertices to OpenGL.
//icosahedron buffer objects
glGenBuffers(1, &icosaVertexbuffer); // Generate 1 buffer, put the resulting identifier in vertexbuffer
glBindBuffer(GL_ARRAY_BUFFER, icosaVertexbuffer); // The following commands will talk about our 'vertexbuffer' buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(icosahedronBufData), icosahedronBufData, GL_STATIC_DRAW); // Give our vertices to OpenGL.
//sphere buffer objects
glGenBuffers(1, &sphereVertexbuffer); // Generate 1 buffer, put the resulting identifier in vertexbuffer
glBindBuffer(GL_ARRAY_BUFFER, sphereVertexbuffer); // The following commands will talk about our 'vertexbuffer' buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(sphereBufData), sphereBufData, GL_STATIC_DRAW); // Give our vertices to OpenGL.
glGenBuffers(1, &colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW);
// lighting stuff
// Initialize shader lighting parameters
point4 light_position= { 0.0, 20.0, -10.0, 0.0 };
color4 light_ambient ={ 0.2, 0.2, 0.2, 1.0 };
color4 light_diffuse ={ 1.0, 1.0, 1.0, 1.0 };
color4 light_specular ={ 1.0, 1.0, 1.0, 1.0 };
color4 material_ambient ={ 1.0, 0.0, 1.0, 1.0 };
color4 material_diffuse ={ 1.0, 0.8, 0.0, 1.0 };
color4 material_specular ={ 1.0, 0.8, 0.0, 1.0 };
float material_shininess = 20.0;
color4 ambient_product;
color4 diffuse_product;
color4 specular_product;
int i;
for (i = 0; i < 3; i++) {
ambient_product[i] = light_ambient[i] * material_ambient[i];
diffuse_product[i] = light_diffuse[i] * material_diffuse[i];
specular_product[i] = light_specular[i] * material_specular[i];
}
//printColor("diffuse", diffuse_product);
//printColor("specular", specular_product);
glUniform4fv( glGetUniformLocation(programID, "AmbientProduct"),
1, ambient_product );
glUniform4fv( glGetUniformLocation(programID, "DiffuseProduct"),
1, diffuse_product );
glUniform4fv( glGetUniformLocation(programID, "SpecularProduct"),
1, specular_product );
glUniform4fv( glGetUniformLocation(programID, "LightPosition"),
1, light_position );
glUniform1f( glGetUniformLocation(programID, "Shininess"),
material_shininess );
}
and some more....
void display()
{
setMatrices(); // initilize Matrices
// Use our shader
//glUseProgram(programID);
glClearColor(0.0f, 0.0f, 0.3f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 2nd attribute buffer : colors
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(
1, // attribute. No particular reason for 1, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glEnableVertexAttribArray(0); // 1rst attribute buffer : vertices
// enum platosShapes{tet, cube, octah, dodec, icos};
switch(shapeInUse)
{
case tet:
{
glBindBuffer(GL_ARRAY_BUFFER, TetraVertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_TRIANGLES, 0, 4*3); // Starting from vertex 0; 3 vertices total -> 1 triangle // need to know amount of vertices here // and change to triangle strips accordingly
}
break;
case cube:
{
//GLuint cubeNormal = glGetAttribLocation( programID, "vNormal" );
glEnableVertexAttribArray( cubeNormal );
glVertexAttribPointer( cubeNormal, 3, GL_FLOAT, GL_FALSE, 0,
(const GLvoid *) (sizeof(CubeNormalBufferData)) );
//glDisableVertexAttribArray( cubeNormal );
glBindBuffer(GL_ARRAY_BUFFER, CubeVertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_TRIANGLES, 0, 12*3); // Starting from vertex 0; 3 vertices total -> 1 triangle // need to know amount of vertices here // and change to triangle strips accordingly
}
break;
case octah:
{
glBindBuffer(GL_ARRAY_BUFFER, OctaVertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_TRIANGLES, 0, 8*3); // Starting from vertex 0; 3 vertices total -> 1 triangle // need to know amount of vertices here // and change to triangle strips accordingly
}
break;
case dodec:
{
glBindBuffer(GL_ARRAY_BUFFER, DodecaVertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_TRIANGLE_FAN, 0, 5 * 6); // Starting from vertex 0; 3 vertices total -> 1 triangle // need to know amount of vertices here // and change to triangle strips accordingly
glDrawArrays(GL_TRIANGLE_FAN, (5 * 6) + 1, 30);
//glutSolidDodecahedron();
//glDrawArrays(GL_TRIANGLE_STRIP,0,5*12);
}
break;
case icos:
{
glBindBuffer(GL_ARRAY_BUFFER, icosaVertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_TRIANGLES, 0, 3*20); // Starting from vertex 0; 3 vertices total -> 1 triangle // need to know amount of vertices here // and change to triangle strips accordingly
}
break;
case sphere:
{
glBindBuffer(GL_ARRAY_BUFFER, sphereVertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
//glDrawElements(GL_TRIANGLES, cnt2, GL_UNSIGNED_INT, 0)
glDrawArrays(GL_TRIANGLE_FAN, 0, 100);
}
}
glDisableVertexAttribArray(0);
glFlush();
}
and some more........
void calculateNormals(GLfloat bufData[], GLfloat normBufData[], int size) // probalby works
{
int count = 0;
GLfloat temp[9];
for(int i = 0; i < size; i++)
{
temp[count] = bufData[i];
count++;
if((i+1) % 9 == 0)
{
count = 0;
//for(int i = 0; i < 9; i++)
//{
// cout << temp[i] << "!,";
// if((i + 1) % 3 == 0)
// cout << "\n";
//}
calculateCross(temp, normBufData);
}
}
printNormals(normBufData, size);
}
void calculateCross(GLfloat bufData[], GLfloat normBufData[]) // probably works
{
static int counter = 0; // need to reset in bettween new buffers
glm::vec3 C1;
glm::vec3 C2;
glm::vec3 normal;
//cout << bufData[0] << "," << bufData[1] << "," << bufData[2] << " buf 1 \n";
//cout << bufData[3] << "," << bufData[4] << "," << bufData[5] << " buf 2 \n";
//cout << bufData[6] << "," << bufData[7] << "," << bufData[8] << " buf 3 \n\n";
//C1.x = bufData[3] - bufData[0];
//C1.y = bufData[4] - bufData[1];
//C1.z = bufData[5] - bufData[2];
//C2.x = bufData[6] - bufData[0];
//C2.y = bufData[7] - bufData[1];
//C2.z = bufData[8] - bufData[2];
C1.x = bufData[0] - bufData[3];
C1.y = bufData[1] - bufData[4];
C1.z = bufData[2] - bufData[5];
C2.x = bufData[0] - bufData[6];
C2.y = bufData[1] - bufData[7];
C2.z = bufData[2] - bufData[8];
//C2.x = bufData[6] - bufData[0];
//C2.y = bufData[7] - bufData[1];
//C2.z = bufData[8] - bufData[2];
//cout << C1.x << " 1x \n";
//cout << C1.y << " 1y \n";
//cout << C1.z << " 1z \n";
//cout << C2.x << " 2x \n";
//cout << C2.y << " 2y \n";
//cout << C2.z << " 2z \n";
normal = glm::cross(C1, C2);
//cout << "\nNORMAL : " << normal.x << "," << normal.y << "," << normal.z << " counter = " << counter << "\n";
for(int j = 0; j < 3; j++)
{
for(int i = 0; i < 3; i++)
{
normBufData[counter] = normal.x;
normBufData[counter + 1] = normal.y;
normBufData[counter + 2] = normal.z;
}
counter+=3;
}
}
and main.....
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(700, 700); // Window Size
glutCreateWindow("Michael - Lab 3");
glutDisplayFunc(display);
glutTimerFunc(10, timeFucn, 10);
glutIdleFunc(Idle);
glutKeyboardFunc(keyboard);
glewExperimental = GL_TRUE;
glewInit();
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST); // Enable depth test
glDepthFunc(GL_LESS); // Accept fragment if it closer to the camera than the former one
GenerateSphere(); // this function generates points for the sphere
programID = LoadShader( "VertexShader.glsl", "FragmentShader.glsl" ); // Create and compile our GLSL program from the shaders
setBuffers(); // initilize buffers
calculateNormals(CubeBufferData,CubeNormalBufferData,108); // calculate norms
//printNormals(CubeNormalBufferData);
glutMainLoop();
}
You forgot to bind the buffer object with normals before calling glVertexAttribPointer( cubeNormal, 3,....);. Therefore, the actual data for normals is taken from the color buffer, which causes weirdest Phong evaluation result.
BTW, nice coding style :)
Phong and Gouraud shadings are not applicable to objects with all planar surfaces, e.g. a cube.