I'm working on a project with OpenGL that uses raymarched graphics and I've run into some trouble controlling the camera.
The scene is generated entirely inside the vertex shader, which is rendered on a 4-vertex plane situated in front of the viewport. My input function gets key-presses and and mouse movement from the user and calculates the translation and rotation of the camera which gets passed into the fragment shader.
The problem is that the rotation and movement of the camera behaves very strangely. Not only does simultaneous pitch and yaw cause the camera to roll (even though I'm using quaternions to calculate rotation), but the camera movement (WASD) seems to only move along the world's X and Z axes rather than the camera's relative axes.
Any help with fixing this would be greatly appreciated.
main.cpp:
#include <iostream>
#include <string>
#include <glad/glad.h>
#include <glfw/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "readshader.h"
#include "input.h"
#define GLM_SWIZZLE_XYZ
#define WIDTH 640
#define HEIGHT 480
using namespace std;
using namespace glm;
int main() {
GLFWwindow* window;
//Vertex array for screen plane
float vertices[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f
};
unsigned int vbo;
unsigned int vao;
unsigned int vs;
unsigned int fs;
unsigned int shader_prog;
//Game logic variables
vec3 camera_pos = vec3(0.0f, 0.0f, 0.0f);
quat camera_rot = quat(0.0f, 0.0f, 0.0f, 0.0f);
vec2 screen_size = vec2(float(WIDTH), float(HEIGHT));
float delta_time = 0.0;
float last_time = 0.0;
unsigned int a_camera_pos;
unsigned int a_camera_rot;
unsigned int a_screen_size;
unsigned int a_delta_time;
//Read shader code from GLSL files
string vs_str = readShader("vert_pass.glsl");
string fs_str = readShader("frag_raymarch_test.glsl");
const char* vs_source = vs_str.c_str();
const char* fs_source = fs_str.c_str();
//Initialize GLFW and create window
glfwInit();
window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL", NULL, NULL);
glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
glViewport(0, 0, WIDTH, HEIGHT);
//Set GLFW input parameters
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
glfwSetCursorPosCallback(window, mouseCallback);
//Create VAO and VBO
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//Compile shaders and create shader program
vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vs_source, NULL);
glCompileShader(vs);
fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fs_source, NULL);
glCompileShader(fs);
shader_prog = glCreateProgram();
glAttachShader(shader_prog, vs);
glAttachShader(shader_prog, fs);
glLinkProgram(shader_prog);
glDetachShader(shader_prog, vs);
glDetachShader(shader_prog, fs);
glDeleteShader(vs);
glDeleteShader(fs);
glUseProgram(shader_prog);
//Setup attribute arrays and uniform variables for vertex shader
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);
a_camera_pos = glGetUniformLocation(shader_prog, "vert_camera_pos");
a_camera_rot = glGetUniformLocation(shader_prog, "vert_camera_rot");
a_screen_size = glGetUniformLocation(shader_prog, "vert_screen_size");
a_delta_time = glGetUniformLocation(shader_prog, "vert_delta_time");
//Main event loop
while (!glfwWindowShouldClose(window)) {
//Calculate delta time
delta_time = glfwGetTime() - last_time;
last_time = glfwGetTime();
//Pass game information to shader program
glProgramUniform3fv(shader_prog, a_camera_pos, 1, value_ptr(camera_pos));
glProgramUniform4fv(shader_prog, a_camera_rot, 1, value_ptr(camera_rot));
glProgramUniform2fv(shader_prog, a_screen_size, 1, value_ptr(screen_size));
glProgramUniform1f(shader_prog, a_delta_time, delta_time);
//Process user input
input(window, &camera_pos, &camera_rot, delta_time);
//Rendering procedure
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glfwSwapBuffers(window);
}
//Cleanup and exit
glDeleteProgram(shader_prog);
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
input.h:
#pragma once
#include <iostream>
#include <glfw/glfw3.h>
#include <glm/glm.hpp>
#define GLM_SWIZZLE_XYZW
#define SPEED 5.0
#define SENS 0.001
using namespace glm;
float camera_pitch = 0.0;
float camera_yaw = 0.0;
bool first = true;
float lastx = 0.0;
float lasty = 0.0;
float offsetx;
float offsety;
void input(GLFWwindow* window, vec3* camera_pos, quat* camera_rot, float delta_time) {
float step = SPEED * delta_time;
vec3 camera_fwd = vec3(0.0f, 0.0f, -1.0f);
vec3 camera_up = vec3(0.0f, 1.0f, 0.0f);
vec3 camera_right = vec3(-1.0f, 0.0f, 0.0f);
quat quatx;
quat quaty;
glfwPollEvents();
//Build rotation quaternion from camera angles
quatx = angleAxis(camera_yaw, camera_up);
quaty = angleAxis(camera_pitch, camera_right);
*camera_rot = quatx * quaty;
//Update camera axis positions
camera_fwd = *camera_rot * camera_fwd * conjugate(*camera_rot);
camera_right = *camera_rot * camera_right * conjugate(*camera_rot);
//Check keyboard presses
if (glfwGetKey(window, GLFW_KEY_W)) {
*camera_pos -= camera_fwd * step;
}
if (glfwGetKey(window, GLFW_KEY_S)) {
*camera_pos += camera_fwd * step;
}
if (glfwGetKey(window, GLFW_KEY_A)) {
*camera_pos -= normalize(cross(camera_fwd, camera_up)) * step;
}
if (glfwGetKey(window, GLFW_KEY_D)) {
*camera_pos += normalize(cross(camera_fwd, camera_up)) * step;
}
if (glfwGetKey(window, GLFW_KEY_SPACE)) {
*camera_pos += camera_up * step;
}
if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL)) {
*camera_pos -= camera_up * step;
}
}
void mouseCallback(GLFWwindow* window, double posx, double posy) {
if (first) {
lastx = -posx;
lasty = -posy;
first = false;
}
offsetx = -posx - lastx;
offsety = lasty + posy;
lastx = -posx;
lasty = -posy;
offsetx *= SENS;
offsety *= SENS;
camera_yaw += offsetx;
camera_pitch += offsety;
if (camera_pitch > 89.0) {
camera_pitch = 89.0;
}
if (camera_pitch < -89.0) {
camera_pitch = -89.0;
}
}
vertex_pass.glsl:
#version 460
//Passes variables from attributes to next shader
layout(location = 0) in vec3 pos;
uniform vec3 vert_camera_pos;
uniform vec4 vert_camera_rot;
uniform vec2 vert_screen_size;
uniform float vert_delta_time;
out vec3 camera_pos;
out vec4 camera_rot;
out vec2 screen_size;
out float delta_time;
void main() {
gl_Position = vec4(pos, 1.0);
camera_pos = vert_camera_pos;
camera_rot = vert_camera_rot;
screen_size = vert_screen_size;
delta_time = vert_delta_time;
}
frag_raymarch_test.glsl:
#version 460
#define MAX_STEPS 100
#define MAX_DIST 10000.0
#define SURF_DIST 0.001
#define NORMAL_SAMPLE_SIZE 0.001
#define TAU 6.283185
#define PI 3.141592
in vec3 camera_pos;
in vec4 camera_rot;
in vec2 screen_size;
in float delta_time;
out vec3 color;
vec3 rotateVector(vec4 quat, vec3 vec) {
return vec + 2.0 * cross(cross(vec, quat.xyz) + quat.w * vec, quat.xyz);
}
//SDF
float getSD(vec3 p) {
vec4 s = vec4(0, 1, 6, 1);
float sphere_dist = length(p - s.xyz) - s.w;
float plane_dist = p.y;
float d = min(sphere_dist, plane_dist);
return d;
}
float getDist(vec3 p) {
float dist = 0;
//SDF
dist = getSD(p);
return dist;
}
float raymarch(vec3 ro, vec3 rd) {
float dist = 0.0;
for(int i = 0; i < MAX_STEPS; i++) {
vec3 p = ro + rd * dist;
dist += getDist(p);
if(dist >= MAX_DIST || dist <= SURF_DIST) {
break;
}
}
return dist;
}
void main() {
vec2 uv = (gl_FragCoord.xy - 0.5 * screen_size) / screen_size.y;
//vec3 ro = vec3(0.0, 1.0, 0.0);
//vec3 ro = camera_pos;
vec3 ro = camera_pos;
vec3 fd = normalize(vec3(uv.x, uv.y, 1.0));
vec3 rd = rotateVector(camera_rot, fd);
color = vec3(raymarch(ro, rd) / 6.0);
}
Figured it out. I went back to using Euler angles instead of quaternions and using them to compute a forward vector for the camera. The problem was that, in the fragment shader, I was using the camera_fwd vector for the look at point when I should have been using camera_pos + camera_fwd.
Related
I am rendering 3d scene with OpenGL. Users are allowed to orbit the scene. Besides the objects in the scene, I want to draw a axis indicator at the top right or bottom left corner to show the current roation status.
Something like the viewport widget at the top right corner in Blender.
Can anyone tell me the direction to do it?
The way I would do it is to:
First- Render your scene;
Second- Render the axis indicator (view cube) on its own to a texture attachment in a frame buffer.
Third- Render the resulting texture to a quad in the top-right of your screen.
Something similar to this: https://learnopengl.com/Advanced-OpenGL/Framebuffers
Very briefly explained, once you have a 3D axis, you start by drawing the 3D axis at camera.Position + camera.Front * smallDist, so it always draws at the center of the screen.
Then, you use glViewport(...) to set the viewport to the corner of the screen, and draw the axis. You can also use eg. glLineWidth(3.0f) to make the lines stand out more.
Here's a rough idea:
#include <iostream>
#include <vector>
#include <math.h>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/ext.hpp>
// camera.h is from basic camera learnopengl tutorial
#include "camera.h"
using glm::mat4;
using glm::vec3;
using glm::radians;
using glm::lookAt;
using std::vector;
void processInput(GLFWwindow *window);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;
// timing
float deltaTime = 0.0f; // time between current frame and last frame
float lastFrame = 0.0f;
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
class Line {
int shaderProgram;
unsigned int VBO, VAO;
vector<float> vertices;
vec3 startPoint;
vec3 endPoint;
mat4 MVP = mat4(1.0);
vec3 lineColor;
public:
Line(vec3 start, vec3 end) {
startPoint = start;
endPoint = end;
lineColor = vec3(1,1,1);
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"uniform mat4 MVP;\n"
"void main()\n"
"{\n"
" gl_Position = MVP * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"uniform vec3 color;\n"
"void main()\n"
"{\n"
" FragColor = vec4(color, 1.0f);\n"
"}\n\0";
// vertex shader
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// check for shader compile errors
// fragment shader
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// check for shader compile errors
// link shaders
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// check for linking errors
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
vertices = {
start.x, start.y, start.z,
end.x, end.y, end.z,
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices)*vertices.size(), vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
int setMVP(mat4 mvp) {
MVP = mvp;
return 1;
}
int setColor(vec3 color) {
lineColor = color;
return 1;
}
int draw() {
glUseProgram(shaderProgram);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "MVP"), 1, GL_FALSE, &MVP[0][0]);
glUniform3fv(glGetUniformLocation(shaderProgram, "color"), 1, &lineColor[0]);
glBindVertexArray(VAO);
glDrawArrays(GL_LINES, 0, 2);
return 1;
}
~Line() {
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);
}
};
int main()
{
// glfw: initialize and configure
// ------------------------------
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
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "drawing lines", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwMakeContextCurrent(window);
glfwSetCursorPosCallback(window, mouse_callback);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
camera.Position = vec3(0,0,3);
camera.MovementSpeed = 0.01f;
// 3d lines example
Line line1(vec3(0,0,0), vec3(0.04,0,0));
line1.setColor(vec3(1,0,0));
Line line2(vec3(0,0,0), vec3(0,0.04,0));
line2.setColor(vec3(0,1,0));
Line line3(vec3(0,0,0), vec3(0,0,0.04));
line3.setColor(vec3(0,0,1));
Line line4(vec3(0,0,0), vec3(10,0,0));
line4.setColor(vec3(1,0,0));
Line line5(vec3(0,0,0), vec3(0,10,0));
line5.setColor(vec3(0,1,0));
Line line6(vec3(0,0,0), vec3(0,0,10));
line6.setColor(vec3(0,0,1));
glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float) SCR_WIDTH / (float)SCR_HEIGHT, 0.01f, 1000.0f);
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
// input
// -----
processInput(window);
// render
// ------
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.01f, 1000.0f);
glm::mat4 view = camera.GetViewMatrix();
float ar = (float)SCR_WIDTH / (float)SCR_HEIGHT;
float fov = 45.0f;
float nearDist = 0.01f;
float Hnear = 2.0f * tan(glm::radians(fov/2)) * nearDist;
float Wnear = Hnear * ar;
glm::vec3 axisPosition = camera.Position + glm::normalize(camera.Front) * 0.2f;
line1.setMVP(projection * view * glm::translate(glm::mat4(1.0f), axisPosition));
line2.setMVP(projection * view * glm::translate(glm::mat4(1.0f), axisPosition));
line3.setMVP(projection * view * glm::translate(glm::mat4(1.0f), axisPosition));
glViewport(SCR_WIDTH-SCR_WIDTH/10.0f,SCR_HEIGHT-SCR_HEIGHT/10.0f,SCR_WIDTH/10.0f,SCR_HEIGHT/10.0f);
glLineWidth(3.0f);
line1.draw();
line2.draw();
line3.draw();
glLineWidth(1.0f);
glViewport(0,0,SCR_WIDTH, SCR_HEIGHT);
line4.setMVP(projection * view);
line5.setMVP(projection * view);
line6.setMVP(projection * view);
line4.draw();
line5.draw();
line6.draw();
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
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);
}
Result:
So I'm drawing some lines by just using a fragment shader. The vertex it's just an empty quad.
The issue I have is that when I zoom out the camera and the lines get smaller they sometimes appear and disappear and I don't understand why.
This is how it looks without zooming
and this is how it looks when the camera is far away from them
The more far away I get from them the more artefacts appear.
This is how my vertex shader looks
#version 330 core
layout(location = 0) in vec2 _position;
out vec2 position;
uniform mat4 uCameraView;
void main() {
gl_Position = uCameraView * vec4(_position.x, _position.y, 0.0f, 1.0f);
position = _position;
}
And this is the fragment
#version 330 core
in vec2 position;
uniform vec4 uGridColor;
uniform float uTileSize;
uniform float uGridBorderSize;
out vec4 fragColor;
void main() {
vec2 uv = mod(position, uTileSize);
vec2 border = mod(uv + (uGridBorderSize / 2.0), uTileSize);
border -= mod(uv - (uGridBorderSize / 2.0), uTileSize);
if (length(border) > uTileSize - uGridBorderSize) {
fragColor = uGridColor;
} else {
fragColor = vec4(0.0);
}
}
Why it's this happening? maybe is something related to antialiasing? My OpenGL setup it's just the default one.
Your current code is making a binary decision "yes line" / "no line". However beyond a certain point (line width < pixel width) you're effectivly dealing with spatial frequencies above the Nyquist limit.
Instead of using a binary "yes"/"no" you need to calculate the pixel coverage, i.e. how much line is inside a pixel. For that you'd normally use a unsigned distance function (UDF). Here's some GLSL code for UDF lines in pixel space (you can also use them in normalized space, but then you'll have to adjust the smoothstep parameters). Try this on https://shadertoy.com
float lsd(vec2 a, vec2 b, vec2 p, float w){
w *= 0.5;
vec2 n = normalize(b-a);
float l = length(b-a);
float t = dot((p-a),n);
float d = length((a-p)+t*n);
float e = min(length(p-a)+w, length(p-b)+w);
return (t > w && t < l-w) ? d : e;
}
float line(vec2 a, vec2 b, float width, vec2 fragcoord){
return max(0., 1.-smoothstep(0., 1., lsd(a, b, fragcoord, width)-0.5*width));
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
float l =
line(vec2(8.,8.), vec2(128.,33.), 1., fragCoord)
+ line(vec2(33.,220.), vec2(260.,20.), 4., fragCoord);
fragColor = vec4(l,l,l,1.0);
}
It is hard to tell based on your shaders alone, so here is an example of how to zoom and pan around a line grid. It uses a projection matrix to zoom which looks slightly different to how you implemented the zoom, but the important bit is that it doesn't have any artefacts of lines thinning when zooming/panning.
Here is a demonstration, hopefully the GIF shows it, but the grid lines are constant thickness as you zoom in and out:
#include <iostream>
#include <vector>
#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>
using std::vector;
using glm::mat4;
using glm::vec3;
using glm::vec4;
void processInput(GLFWwindow *window);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_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;
vec3 rayCast(double xpos, double ypos, mat4 projection, mat4 view) {
// converts a position from the 2d xpos, ypos to a normalized 3d direction
float x = (2.0f * xpos) / SCR_WIDTH - 1.0f;
float y = 1.0f - (2.0f * ypos) / SCR_HEIGHT;
float z = 1.0f;
vec3 ray_nds = vec3(x, y, z);
vec4 ray_clip = vec4(ray_nds.x, ray_nds.y, -1.0f, 1.0f);
// eye space to clip we would multiply by projection so
// clip space to eye space is the inverse projection
vec4 ray_eye = inverse(projection) * ray_clip;
// convert point to forwards
ray_eye = vec4(ray_eye.x, ray_eye.y, -1.0f, 0.0f);
// world space to eye space is usually multiply by view so
// eye space to world space is inverse view
vec4 inv_ray_wor = (inverse(view) * ray_eye);
vec3 ray_wor = vec3(inv_ray_wor.x, inv_ray_wor.y, inv_ray_wor.z);
ray_wor = normalize(ray_wor);
return ray_wor;
}
class Line {
int shaderProgram;
unsigned int VBO, VAO;
vector<float> vertices;
vec3 startPoint;
vec3 endPoint;
mat4 MVP;
vec3 lineColor;
public:
Line(vec3 start, vec3 end) {
startPoint = start;
endPoint = end;
lineColor = vec3(1,1,1);
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"uniform mat4 MVP;\n"
"void main()\n"
"{\n"
" gl_Position = MVP * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"uniform vec3 color;\n"
"void main()\n"
"{\n"
" FragColor = vec4(color, 1.0f);\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);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::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);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::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);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
vertices = {
start.x, start.y, start.z,
end.x, end.y, end.z,
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
int setMVP(mat4 mvp) {
MVP = mvp;
}
int setColor(vec3 color) {
lineColor = color;
}
int draw() {
glUseProgram(shaderProgram);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "MVP"), 1, GL_FALSE, &MVP[0][0]);
glUniform3fv(glGetUniformLocation(shaderProgram, "color"), 1, &lineColor[0]);
glBindVertexArray(VAO);
glDrawArrays(GL_LINES, 0, 2);
return 0;
}
~Line() {
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);
}
};
vec3 cameraPos = glm::vec3(0.0f, 0.0f, 15.0f);
vec3 cameraFront = glm::vec3(0,0,-1);
mat4 model = mat4(1.0);
glm::mat4 view;
glm::mat4 projection;
float scrollSpeed = 2.0f;
float fov = 45.0f;
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, "grid", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
Line x(vec3(0,0,0), vec3(1,0,0));
x.setColor(vec3(1,0,0));
Line y(vec3(0,0,0), vec3(0,1,0));
y.setColor(vec3(0,1,0));
std::vector<Line*> grid = {};
for (int i = -5; i < 6; i++) {
grid.push_back(new Line(vec3(-5, i, 0), vec3(5,i, 0)));
}
for (int j = -5; j < 6; j++) {
grid.push_back(new Line(vec3(j, -5, 0), vec3(j,5, 0)));
};
while (!glfwWindowShouldClose(window))
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
view = glm::lookAt(cameraPos, cameraPos + cameraFront, vec3(0,1,0));
projection = glm::perspective(glm::radians(fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
for (int i = 0; i < grid.size(); i++) {
grid[i]->setMVP(projection * view * model);
grid[i]->draw();
}
glfwSwapBuffers(window);
glfwPollEvents();
}
for (int i = 0; i < grid.size(); i++) {
delete grid.at(i);
}
glfwTerminate();
return 0;
}
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
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;
lastX = xpos;
lastY = ypos;
int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_MIDDLE);
if (state == GLFW_PRESS)
{
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
cameraPos -= scrollSpeed * glm::vec3(xoffset/(float)SCR_WIDTH, yoffset/(float)SCR_WIDTH, 0);
} else {
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
firstMouse = true;
}
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
cameraPos += (float)yoffset * rayCast(lastX, lastY, projection, view);
}
I'm trying to change the position of triangle without using transformation function, By changing only the position of x each time,
this my code in main while loop
float MyPoints[] = { 0.1 , 0.2, 0.3, 0.4, 0.5 , 0.6, 0.7, 0.8, 0.9};
int offset = (-1, 1);
for (int i = 0; i < sizeof(MyPoints); i++) {
offset += MyPoints[i];
ourShader.Use();
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);// unbind
}
and this is in shader
out vec3 ourColor;
out vec2 TexCoord;
uniform vec4 offset;
void main()
{
gl_Position = vec4(position.x + offset, position.y, position.z, 1.0f);
ourColor = color;
TexCoord = texCoord;
}
Edit
this my code in main while loop
float offset = 1.0f;
float step = 0.001f; //move
int i=0;
// Loop until window closed (Game loop)
while (!glfwWindowShouldClose(mainWindow))
{
// Get + Handle user input events
glfwPollEvents();
//Render
// Clear the colorbuffer
glClearColor(0.0f, 0.1f, 0.2f, 1.0f);
//glPointSize(400.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Call Shader Program
//Rendering the first triangle
GLuint program =ourShader.Program ; // program object from "ourShader"
GLint offset_loc = glGetUniformLocation(program, "offset");
float MyPoints[] = { -0.1 , -0.2,-0.3,-0.4,-0.5 ,-0.6,-0.7,-0.8,-0.9 };
int noPoints = sizeof(MyPoints) / sizeof(float);
ourShader.Use();
for (int i = 0; i < noPoints; i++) {
glUniform1f(offset_loc, MyPoints[i] + offset);
}
offset += step;
if (MyPoints[i] + offset >= 1.0f || MyPoints[i] + offset <= -1.0f)
step *= -1.0f;
//update uniform data
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(mainWindow);
glBindVertexArray(0);// unbind
}
and this is in shader
out vec3 ourColor;
out vec2 TexCoord;
uniform float offset;
void main()
{
gl_Position = vec4(position.x + offset, position.y, position.z, 1.0f);
ourColor = color;
TexCoord = texCoord;
}
the Edit code make an movement from (-1.0) till the middle to the end of the window
First of all the number of elements in the array is sizeof(MyPoints) / sizeof(float).
The type of the uniform variable offset has to be float:
uniform float offset;
You've to get the location of the uniform variable offset by glGetUniformLocation and to set the value of the uniform by e.g. glUniform1f:
GLuint program = ; // program object from "ourShader"
GLint offset_loc = glGetUniformLocation(program, "offset");
float MyPoints[] = { 0.1 , 0.2, 0.3, 0.4, 0.5 , 0.6, 0.7, 0.8, 0.9};
int noPoints = sizeof(MyPoints) / sizeof(float);
// bind vertex array
glBindVertexArray(VAO);
// install program
ourShader.Use();
float offset = -1.0f;
for (int i = 0; i < noPoints; i++) {
// set value of the uniform (after program is installed)
offset += MyPoints[i];
glUniform1f(offset_loc, offset);
// draw one triangle
glDrawArrays(GL_TRIANGLES, 0, 3);
}
glBindVertexArray(0);
If you want to make the triangles move, then you've to change the offset of each individual triangle in every frame. e.g.:
float offset = 0.0f;
float step = 0.01f;
while (!glfwWindowShouldClose(mainWindow))
{
// [...]
ourShader.Use();
glUniform1f(offset_loc, offset);
glDrawArrays(GL_TRIANGLES, 0, 3);
// [...]
// change offset
offset += step;
if (offset >= 1.0f || offset <= -1.0f)
step *= -1.0f; // reverse direction
}
i tried to implement a simple raytracing algorithm in an openGl fragment shader which draws a single sphere.
sometimes it draws a distorted sphere, but most of the times it draws nothing.
with the actual sphere origin and radius i get a slightly destored sphere in the right upper corner.
#version 430 core
uniform ivec2 viewportDimensions;
uniform mat4 gl_ProjectionMatrix;
uniform ivec4 viewport;
out vec3 color;
struct Ray {
vec3 origin;
vec3 direction;
};
struct Sphere {
vec3 origin;
float radius;
};
float zNear = -0.1f;
float zFar = -100.0f;
float fieldOfViewX = 3.1415926535897932384626433832795 / 2.0f;
float sampleRay(Ray ray,Sphere s, float distance);
Ray computeEyeRay(float, float, int, int);
bool intersect(Ray r, Sphere s);
bool solveQuadratic(float a, float b, float c);
Ray calcEyeFromWindow(vec3 windowSpace);
void main() {
// Ray r = computeEyeRay(gl_FragCoord.x + 0.5f, gl_FragCoord.y + 0.5f, viewportDimensions.x, viewportDimensions.y);
Ray r = calcEyeFromWindow(vec3(gl_FragCoord.x + 0.5f, gl_FragCoord.y + 0.5f, 1f));
Sphere s;
s.origin = vec3(0.5f,-0.5f,-0.7f);
s.radius = 0.8f;
if (intersect(r,s))
color = vec3(1,1,1);
else
color = vec3(0,0,0);
}
Ray calcEyeFromWindow(vec3 windowSpace)
{
vec4 ndcPos;
ndcPos.xy = ((2.0 * gl_FragCoord.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1;
ndcPos.z = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) /
(gl_DepthRange.far - gl_DepthRange.near);
ndcPos.w = 1.0;
vec4 clipPos = ndcPos / gl_FragCoord.w;
vec4 eyePos = inverse(gl_ProjectionMatrix) * clipPos;
Ray r;
r.origin = eyePos.xyz;
r.direction =normalize(eyePos.xyz);
return r;
}
Ray computeEyeRay(float x, float y, int width, int height) {
const float aspect = float(height) / float(width);
const float s = -2.0f * tan(fieldOfViewX * 0.5f);
const vec3 start = vec3( (float(x) / float(width) - 0.5) * s,
-(float(y) / float(height) - 0.5f) * s * aspect,
1.0f) * zNear;
float startLength = sqrt( (start.x * start.x) + (start.y * start.y) + (start.z * start.z) );
Ray e;
e.origin = start;
e.direction = normalize(start);
return e;
}
bool intersect(Ray r, Sphere s) {
float a = dot(r.direction,r.direction);
float b = dot(r.direction, 2.0 * (r.origin-s.origin));
float c = dot(s.origin, s.origin) + dot(r.origin,r.origin) +-2.0*dot(r.origin,s.origin) - (s.radius*s.radius);
float disc = b*b + (-4.0)*a*c;
if (disc < 0)
return false;
return true;
}
bool solveQuadratic(float a, float b, float c) {
float t, t_1;
float disc = a * b - 4 * a * c;
if (disc < 0)
return false;
else {
if (disc == 0)
t = -0.5 * b / a;
else {
float q = (b > 0) ? -0.5 * (b+sqrt(disc)) : -0.5 * (b-sqrt(disc));
t = q / a;
t_1 = c / q;
}
}
return true;
}
here is the rest of the program if anyone wants to compile and test it.
#include <stdio.h>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <glm\glm.hpp>
// include opengl headers
#include <GL/glew.h>
#include <GL/freeglut.h>
const int VIEWPORT_DIMENSION_X = 1280;
const int VIEWPORT_DIMENSION_Y = 1280;
void glutInitialization(int argc, char **argv);
void glewInitialization();
void display();
void resize(int w, int h);
void idle();
void drawSphere(float x, float y, float z);
GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path);
GLuint VertexArrayID;
GLuint vertexbuffer; // This will identify our vertex buffer
GLuint programID;
static const GLfloat quadvertices[] = {
-1.0f, 1.0f, .0f,
-1.0f, -1.0f, .0f,
1.0f, -1.0f, .0f,
1.0f, -1.0f, .0f,
1.0f, 1.0f, .0f,
-1.0f, 1.0f, .0f
};
static const GLfloat g_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
int main(int argc, char **argv)
{
glutInitialization(argc, argv);
glewInitialization();
// create VAO
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Generate 1 buffer
glGenBuffers(1, &vertexbuffer);
// Give our vertices to OpenGL.
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadvertices), quadvertices, GL_STATIC_DRAW);
glVertexAttribPointer(
0, //
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glEnableVertexAttribArray(0);
glClearColor(0.0,0.0,0.0,0.0);
// Create and compile our GLSL program from the shaders
programID = LoadShaders( "vertex.glsl", "fragment.glsl" );
glViewport(0,0,1280,1280);
// create uniform variables
GLint viewportDimensionsHandle = glGetUniformLocation(programID, "viewportDimensions");
glProgramUniform2i(programID, viewportDimensionsHandle, VIEWPORT_DIMENSION_X, VIEWPORT_DIMENSION_Y);
GLint viewportHandle =glGetUniformLocation(programID, "viewport");
glProgramUniform4i(programID, viewportHandle, 0,0,1280,1280);
// start mainloop
glutMainLoop();
return 0;
}
void glutInitialization(int argc, char **argv) {
// GLUT initializing
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(1280,1280);
glutCreateWindow("raycasting");
// register GLUT callbacks
glutDisplayFunc(display);
glutReshapeFunc(resize);
}
void glewInitialization() {
// GLEW initializing
glewInit();
if (glewIsSupported("GL_VERSION_4_3"))
printf("Ready for OpenGL 4.3\n");
else {
printf("OpenGL 4.3 not supported\n");
exit(1);
}
}
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(programID);
// Bind VAO
glBindVertexArray(VertexArrayID);
// Draw the triangle
glDrawArrays(GL_TRIANGLES, 0, 6); // Starting from vertex 0; 3 vertices total -> 1 triangle
// Unbind VAO
glBindVertexArray(0);
glutSwapBuffers();
}
void resize(int w, int h) {
}
void idle() {
}
void drawSphere(float x, float y, float z) {
glPushMatrix();
}
GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
if(VertexShaderStream.is_open())
{
std::string Line = "";
while(getline(VertexShaderStream, Line))
VertexShaderCode += "\n" + Line;
VertexShaderStream.close();
}
// Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
if(FragmentShaderStream.is_open()){
std::string Line = "";
while(getline(FragmentShaderStream, Line))
FragmentShaderCode += "\n" + Line;
FragmentShaderStream.close();
}
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
printf("Compiling shader : %s\n", vertex_file_path);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> VertexShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
// Compile Fragment Shader
printf("Compiling shader : %s\n", fragment_file_path);
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);
// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);
// Link the program
fprintf(stdout, "Linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> ProgramErrorMessage( std::max(InfoLogLength, int(1)) );
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
return ProgramID;
}
I'm sure it's not a complete solution, but it finally draws a sphere:
#version 430 core
uniform ivec2 viewportDimensions;
uniform mat4 gl_ProjectionMatrix;
uniform ivec4 viewport;
uniform float imageAspectRatio;
uniform float angle;
out vec3 color;
struct Ray {
vec3 origin;
vec3 direction;
};
struct Sphere {
vec3 origin;
float radius;
};
bool intersect(Ray r, Sphere s);
void main() {
focal = 60;
angle = tan(focal * 0.5 * 3.1415926535897932384626433832795 / 180); // convert from degree to radian
float xx = (2 * (gl_FragCoord.x + 0.5) / viewportDimensions.x - 1) * angle * imageAspectRatio;
float yy = (1 - 2 * (gl_FragCoord.y + 0.5) / viewportDimensions.y) * angle;
vec3 rayOrigin = vec3(0,0,0);
vec3 rayDirection = normalize(vec3(xx, yy, -1) - rayOrigin);
Ray r;
r.origin = rayOrigin;
r.direction = rayDirection;
Sphere s;
s.origin = vec3(0.0f,0.0f,-1.1f);
s.radius =0.55f;
if (intersect(r,s))
color = vec3(1,0,1);
else
color = vec3(0,0,0);
}
bool intersect(Ray r, Sphere s) {
float a = dot(r.direction,r.direction);
float b = dot(r.direction, 2.0 * (r.origin-s.origin));
float c = dot(s.origin, s.origin) + dot(r.origin,r.origin) +-2.0*dot(r.origin,s.origin) - (s.radius*s.radius);
float disc = b*b + (-4.0)*a*c;
if (disc < 0)
return false;
return true;
}
e.origin = start;
e.direction = normalize(start);
That looks wrong.
Considering this in an Eye-Ray the origin should be the Eye-Position.
e.origin = vec3(0,0,0);
OpenGL glm calculations don't seem to work in my program. Nothing moves even when i use the glm translate function to translate the z axis with a variable every frame. Am i missing something?
main.cpp
#define GLEW_STATIC
#define NO_SDL_GLEXT
#include "glew.h"
#include <sdl.h>
#undef main
#include "SDL_opengl.h"
#include "timer.h"
#include <time.h>
#include <shader.h>
using namespace std;
#include <glm/gtc/matrix_projection.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;
unsigned int vaoID[1]; // Our Vertex Array Object
unsigned int vboID[1]; // Our Vertex Buffer Object
glm::mat4 projectionMatrix; // Store the projection matrix
glm::mat4 viewMatrix; // Store the view matrix
glm::mat4 modelMatrix; // Store the model matrix
Shader *shader; // Our GLSL shader
float ztransform(0);
bool exited(false);
SDL_Event event;
const int FRAMES_PER_SECOND = 60;
void createSquare(void) {
float* vertices = new float[18]; // Vertices for our square
vertices[0] = -0.5; vertices[1] = -0.5; vertices[2] = 0.0; // Bottom left corner
vertices[3] = -0.5; vertices[4] = 0.5; vertices[5] = 0.0; // Top left corner
vertices[6] = 0.5; vertices[7] = 0.5; vertices[8] = 0.0; // Top Right corner
vertices[9] = 0.5; vertices[10] = -0.5; vertices[11] = 0.0; // Bottom right corner
vertices[12] = -0.5; vertices[13] = -0.5; vertices[14] = 0.0; // Bottom left corner
vertices[15] = 0.5; vertices[16] = 0.5; vertices[17] = 0.0; // Top Right corner
glGenVertexArrays(1, &vaoID[0]); // Create our Vertex Array Object
glBindVertexArray(vaoID[0]); // Bind our Vertex Array Object so we can use it
glGenBuffers(1, vboID); // Generate our Vertex Buffer Object
glBindBuffer(GL_ARRAY_BUFFER, vboID[0]); // Bind our Vertex Buffer Object
glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), vertices, GL_STATIC_DRAW); // Set the size and data of our VBO and set it to STATIC_DRAW
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); // Set up our vertex attributes pointer
glEnableVertexAttribArray(0); // Disable our Vertex Array Object
glBindVertexArray(0); // Disable our Vertex Buffer Object
delete [] vertices; // Delete our vertices from memory
}
void startGL()
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_SetVideoMode(800, 600, 32, SDL_OPENGL);
glewInit();
glClearColor(0.4f, 0.0f, 1.0f, 0.0f);
projectionMatrix = glm::perspective(60.0f, (float)800 / (float)600, 0.1f, 100.f); // Create our perspective projection matrix
shader = new Shader("shader.vert", "shader.frag"); // Create our shader by loading our vertex and fragment shader
createSquare();
}
void drawstuff()
{
glViewport(0, 0, 800, 600); // Set the viewport size to fill the window
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Clear required buffers
viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, ztransform)); // Create our view matrix which will translate us back 5 units
modelMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f)); // Create our model matrix which will halve the size of our model
shader->bind(); // Bind our shader
int projectionMatrixLocation = glGetUniformLocation(shader->id(), "projectionMatrix"); // Get the location of our projection matrix in the shader
int viewMatrixLocation = glGetUniformLocation(shader->id(), "viewMatrix"); // Get the location of our view matrix in the shader
int modelMatrixLocation = glGetUniformLocation(shader->id(), "modelMatrix"); // Get the location of our model matrix in the shader
glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, &projectionMatrix[0][0]); // Send our projection matrix to the shader
glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, &viewMatrix[0][0]); // Send our view matrix to the shader
glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, &modelMatrix[0][0]); // Send our model matrix to the shader
glBindVertexArray(vaoID[0]); // Bind our Vertex Array Object
glDrawArrays(GL_TRIANGLES, 0, 6); // Draw our square
glBindVertexArray(0); // Unbind our Vertex Array Object
shader->unbind(); // Unbind our shader
}
int main (int argc, char* args[])
{
Timer fps;
startGL();
while(exited == false)
{
while( SDL_PollEvent(&event) )
{
if( event.type == SDL_QUIT )
exited = true;
}
drawstuff();
ztransform+=.1
SDL_GL_SwapBuffers();
if( fps.get_ticks() < 1000 / FRAMES_PER_SECOND )
SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.get_ticks() );
}
SDL_Quit();
return 0;
}
shader.frag
#version 150 core
in vec3 pass_Color;
out vec4 out_Color;
void main(void)
{
out_Color = vec4(pass_Color, 1.0);
}
shader.vert
#version 150 core
in vec3 in_Position;
in vec3 in_Color;
out vec3 pass_Color;
void main(void)
{
gl_Position = vec4(in_Position, 1.0);
pass_Color = in_Color;
}
You have to apply your transformation in your vertex shader.
you should define in your vertex shader
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
And then apply these transformations to your input position (note: i may have gotten the order wrong)
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(in_position, 1.0);
Generally though, you would multiply the 3 matrices together in your c++ program and pass in a modelViewProjection matrix.