I am currently developing a test project for OpenGL to discover its possibilities.
I am experiencing a weird bug with GLFW 4.0 apparently called "mouse drift" (from different github issues). It means that even though my mouse is not moving, the glfw input callback will still be called with small x and y values (generally 1 or -1).
I provided my code here : https://github.com/Lygaen/testgl (not ads or promoting, just giving the link to the full project to help reproduce). I am using a basic GLFW, GLAD and GLM framework.
My goal is to calculate the delta position of the mouse, to have correct camera movement.
Thank you for any help that you could provide !
Here is the code that calculates input :
window.h
#ifndef __WINDOW_H__
#define __WINDOW_H__
#include <string>
#include <glad/gl.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <vector>
class Window
{
private:
GLFWwindow *window;
bool correctlyLoaded;
static void resizeCallback(GLFWwindow *, int, int);
public:
Window(const std::string &, int, int);
~Window();
const bool hasCorrectlyLoaded();
const bool shouldClose();
const void pollEvents();
const void exitNextFrame();
};
class Input
{
private:
static char *keyStates;
static bool *mouseStates;
static glm::dvec2 pos;
static glm::dvec2 delta;
static std::vector<int> pressed;
static void keyCallback(GLFWwindow *, int, int, int, int);
static void mouseCallback(GLFWwindow *, double, double);
static void mouseButtonCallback(GLFWwindow *, int, int, int);
public:
static const bool isPressed(int);
static const bool isDown(int);
static const bool isReleased(int);
static const glm::dvec2 getMousePosition();
static const glm::dvec2 getMouseDelta();
static const bool isMouseButtonDown(int);
static const void setCallbacks(GLFWwindow *);
static const void loopClear();
static const void terminate();
};
#endif // __WINDOW_H__
window.cpp
#include "window.h"
#include <spdlog/spdlog.h>
#include <algorithm>
Window::Window(const std::string &title, int width, int height)
{
correctlyLoaded = false;
if (!glfwInit())
{
spdlog::default_logger()->critical("Could not load GLFW");
return;
}
spdlog::default_logger()->info("Loaded GLFW {}", glfwGetVersionString());
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
if (!window)
{
spdlog::default_logger()->critical("Failed to create GLFW window !");
return;
}
glfwMakeContextCurrent(window);
if (!gladLoadGL(glfwGetProcAddress))
{
spdlog::default_logger()->critical("Failed to load OpenGL !");
return;
}
spdlog::default_logger()->info("Loaded OpenGL {}", glfwGetVersionString());
glViewport(0, 0, width, height);
glEnable(GL_MULTISAMPLE);
glfwSetFramebufferSizeCallback(window, Window::resizeCallback);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
Input::setCallbacks(window);
correctlyLoaded = true;
}
Window::~Window()
{
glfwTerminate();
}
void Window::resizeCallback(GLFWwindow *, int width, int height)
{
glViewport(0, 0, width, height);
}
const bool Window::hasCorrectlyLoaded()
{
return correctlyLoaded;
}
const bool Window::shouldClose()
{
return glfwWindowShouldClose(window);
}
const void Window::pollEvents()
{
Input::loopClear();
glfwSwapBuffers(window);
glfwPollEvents();
}
const void Window::exitNextFrame()
{
glfwSetWindowShouldClose(window, true);
}
char *Input::keyStates;
bool *Input::mouseStates;
glm::tvec2<double> Input::pos;
glm::tvec2<double> Input::delta;
std::vector<int> Input::pressed;
void Input::keyCallback(GLFWwindow *, int key, int /*scancode*/, int action, int /*mods*/)
{
if (key < 0 || key > GLFW_KEY_LAST)
return;
keyStates[key] = action;
if (action == GLFW_PRESS)
{
pressed.push_back(key);
}
}
void Input::mouseCallback(GLFWwindow *window, double nXPos, double nYPos)
{
glm::dvec2 newPos = {nXPos, nYPos};
delta = newPos - pos;
pos = newPos;
glfwSetCursorPos(window, 0, 0);
}
void Input::mouseButtonCallback(GLFWwindow *window, int button, int action, int /*mods*/)
{
if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
return;
mouseStates[button] = action;
}
const bool Input::isPressed(int key)
{
return std::count(pressed.begin(), pressed.end(), key);
}
const bool Input::isDown(int key)
{
return keyStates[key] != GLFW_RELEASE;
}
const bool Input::isReleased(int key)
{
return keyStates[key] == GLFW_RELEASE;
}
const glm::dvec2 Input::getMousePosition()
{
return pos;
}
const glm::dvec2 Input::getMouseDelta()
{
return delta;
}
const bool Input::isMouseButtonDown(int mouseButton)
{
return mouseStates[mouseButton] == GLFW_PRESS;
}
const void Input::setCallbacks(GLFWwindow *window)
{
keyStates = new char[GLFW_KEY_LAST];
mouseStates = new bool[GLFW_MOUSE_BUTTON_LAST];
glfwSetKeyCallback(window, Input::keyCallback);
glfwSetCursorPosCallback(window, Input::mouseCallback);
glfwSetMouseButtonCallback(window, Input::mouseButtonCallback);
}
const void Input::loopClear()
{
pressed.clear();
}
const void Input::terminate()
{
delete[] keyStates;
delete[] mouseStates;
}
main.cpp
#include <iostream>
#include "gui/window.h"
#include "gui/gl/shader.h"
#include <spdlog/spdlog.h>
#include <spdlog/fmt/bin_to_hex.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/scalar_multiplication.hpp>
glm::mat4 fpsView(glm::vec3 cam, float pitch, float yaw)
{
float cosPitch = cos(pitch);
float sinPitch = sin(pitch);
float cosYaw = cos(yaw);
float sinYaw = sin(yaw);
glm::vec3 xaxis = {cosYaw, 0, -sinYaw};
glm::vec3 yaxis = {sinYaw * sinPitch, cosPitch, cosYaw * sinPitch};
glm::vec3 zaxis = {sinYaw * cosPitch, -sinPitch, cosPitch * cosYaw};
// Create a 4x4 view matrix from the right, up, forward and eye position vectors
glm::mat4 viewMatrix = {
glm::vec4(xaxis.x, yaxis.x, zaxis.x, 0),
glm::vec4(xaxis.y, yaxis.y, zaxis.y, 0),
glm::vec4(xaxis.z, yaxis.z, zaxis.z, 0),
glm::vec4(-glm::dot(xaxis, cam), -glm::dot(yaxis, cam), -glm::dot(zaxis, cam), 1)};
return viewMatrix;
}
int main(int, char **)
{
#ifndef NDEBUG
spdlog::set_level(spdlog::level::trace);
#endif
Window window("Test GL", 800, 600);
if (!window.hasCorrectlyLoaded())
{
return 1;
}
float vertices[] = {
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
unsigned int indices[] = {
// note that we start from 0!
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
Shader shader;
unsigned int VAO;
GL(glGenVertexArrays(1, &VAO));
GL(glBindVertexArray(VAO));
unsigned int VBO;
GL(glGenBuffers(1, &VBO));
GL(glBindBuffer(GL_ARRAY_BUFFER, VBO));
GL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
unsigned int EBO;
GL(glGenBuffers(1, &EBO));
GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO));
GL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW));
GL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void *)0));
GL(glEnableVertexAttribArray(0));
glm::mat4 Projection = glm::perspective(glm::radians(90.0f), (float)800 / (float)600, 0.1f, 100.0f);
glm::vec3 cam{4, 3, 3};
glm::vec2 dir{0, 0};
glm::mat4 Model = glm::mat4(1.0f);
while (!window.shouldClose())
{
GL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));
GL(glClear(GL_COLOR_BUFFER_BIT));
glm::mat4 View = fpsView(cam, dir.y, dir.x);
glm::mat4 mvp = Projection * View * Model;
shader.setUniform("MVP", &mvp);
shader.bind();
GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO));
GL(glBindVertexArray(VAO));
GL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0));
GL(glBindVertexArray(0));
window.pollEvents();
if (Input::isPressed(GLFW_KEY_ESCAPE))
{
window.exitNextFrame();
}
if (Input::isPressed(GLFW_KEY_F6))
{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
else if (Input::isReleased(GLFW_KEY_F6))
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
glm::dvec2 d = Input::getMouseDelta();
dir += d * 0.001;
}
spdlog::default_logger()->info("Quitting !");
}
Related
I expect to see hello in the console:
DebugDrawer.cpp
#include "DebugDrawer.h"
#include <iostream>
DebugDrawer::DebugDrawer()
{
}
void DebugDrawer::DrawSegment(const b2Vec2 &p1, const b2Vec2 &p2, const b2Color &color)
{
std::cout << "hello" << std::endl;
}
void DebugDrawer::DrawSolidPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) { }
void DebugDrawer::DrawPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) { }
void DebugDrawer::DrawPoint(const b2Vec2 &p, float size, const b2Color &color) { }
void DebugDrawer::DrawCircle(const b2Vec2 ¢er, float radius, const b2Color &color) { }
void DebugDrawer::DrawSolidCircle(const b2Vec2 ¢er, float radius, const b2Vec2 &axis, const b2Color &color) { }
void DebugDrawer::DrawTransform(const b2Transform &xf) { }
I inherited from the b2Draw and overloaded the methods:
DebugDrawer.h
#ifndef DEBUGDRAWER_H
#define DEBUGDRAWER_H
#include "box2d/b2_draw.h"
class DebugDrawer : public b2Draw
{
public:
DebugDrawer();
private:
void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
void DrawPoint (const b2Vec2 &p, float size, const b2Color &color);
void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
void DrawCircle(const b2Vec2& center, float radius, const b2Color& color);
void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color);
void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color);
void DrawTransform(const b2Transform& xf);
};
#endif // DEBUGDRAWER_H
I created an object with the box shape:
b2PolygonShape shape;
shape.SetAsBox(50.f / WORLD_SCALE, 50.f / WORLD_SCALE);
b2BodyDef bdef;
bdef.type = b2_staticBody;
pBody = pWorld->CreateBody(&bdef);
pBody->CreateFixture(&shape, 2.f);
I set the debug draw in the main.cpp file:
pDebugDrawer = new DebugDrawer();
pWorld->SetDebugDraw(pDebugDrawer);
I set flags:
uint32 flags = 0;
flags += b2Draw::e_shapeBit;
flags += b2Draw::e_jointBit;
flags += b2Draw::e_centerOfMassBit;
flags += b2Draw::e_aabbBit;
flags += b2Draw::e_pairBit;
pDebugDrawer->SetFlags(flags);
I call pWorld.Step() and pWorld->DebugDraw():
pWorld->Step(0.016f, 8, 3);
pWorld->DebugDraw();
main.cpp
#ifdef _WIN32
#include <windows.h>
extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001;
#endif
#define SDL_MAIN_HANDLED
#include <glad/glad.h>
#include <SDL.h>
#include <box2d/box2d.h>
#include <iostream>
#include "DebugDrawer.h"
const float WORLD_SCALE = 30.f;
b2World* pWorld;
DebugDrawer* pDebugDrawer;
b2Body* pBody;
int main()
{
// Initialize the SDL2 library
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
SDL_Log("Failed to initialize the SDL2 library: %s", SDL_GetError());
return 1;
}
// Create a SDL window
const int WIN_WIDTH = 500;
const int WIN_HEIGHT = 500;
SDL_Window* window = SDL_CreateWindow(
"Empty Window",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
WIN_WIDTH, WIN_HEIGHT,
SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
// Create a SDL renderer
SDL_Renderer* renderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_ACCELERATED);
if (!renderer)
{
SDL_Log("Failed to create a SDL renderer %s", SDL_GetError());
return 1;
}
SDL_GLContext context = SDL_GL_CreateContext(window);
// Initialize the GLAD library
if (!gladLoadGL())
{
SDL_Log("Failed to initialize the GLAD library");
return 1;
}
glViewport(0, 0, WIN_WIDTH, WIN_HEIGHT);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
b2Vec2 gravity(0.f, 9.8f);
pWorld = new b2World(gravity);
pDebugDrawer = new DebugDrawer();
pWorld->SetDebugDraw(pDebugDrawer);
uint32 flags = 0;
flags += b2Draw::e_shapeBit;
flags += b2Draw::e_jointBit;
flags += b2Draw::e_centerOfMassBit;
flags += b2Draw::e_aabbBit;
flags += b2Draw::e_pairBit;
pDebugDrawer->SetFlags(flags);
b2PolygonShape shape;
shape.SetAsBox(50.f / WORLD_SCALE, 50.f / WORLD_SCALE);
b2BodyDef bdef;
bdef.type = b2_staticBody;
pBody = pWorld->CreateBody(&bdef);
pBody->CreateFixture(&shape, 2.f);
SDL_Event event;
bool running = true;
SDL_PollEvent(&event);
while (running)
{
switch (event.type)
{
case SDL_QUIT:
running = false;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
running = false;
break;
}
break;
}
glClear(GL_COLOR_BUFFER_BIT);
pWorld->Step(0.016f, 8, 3);
pWorld->DebugDraw();
SDL_GL_SwapWindow(window);
SDL_PollEvent(&event);
}
delete pWorld;
delete pDebugDrawer;
SDL_GL_DeleteContext(context);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
I should use DrawPolygon to draw segments of colliders when I use boxes to draw borders around game objects. DrawSegment() will be called when an instance of b2EdgeShape is created:
b2EdgeShape edgeShape;
edgeShape.SetOneSided(b2Vec2(0.f, 0.f), b2Vec2(1.f, 0.f),
b2Vec2(2.f, 0.f), b2Vec2(3.f, 0.f));
m_pEdgeBody = m_pWorld->CreateBody(&bdef);
m_pEdgeBody->CreateFixture(&edgeShape, 2.f);
I have tried to abtract my OpenGl code into classes, which has worked fine so far. It would always render until I recently build a Game class which is a derived class of the Window2 class (which I have also only recently created).
I am pretty sure that the bug is not to be found in the Mesh, Shader, PointLight or the Material class (as they have worked properly in the past).
The window does appear and has the correct background color. The render function is also called in the game loop so I am not sure what the problem is. Here is the code...
Game.h
#ifndef GAME_H
#define GAME_H
#include <iostream>
#include <stdio.h>
#include <vector>
#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include "GameBlock.h"
#include "blocks/NormalGameBlock.h"
#include <PointLight.h>
#include <Window2.h>
#include <memory>
#include <Renderer.h>
#include <Mesh.h>
#include <Shader.h>
#include <Material.h>
#include <Utils.h>
class Game : private Window2 {
private:
Mesh* mesh;
Shader* shader;
Material* material;
PointLight* pointLight;
glm::mat4 projection;
glm::vec3 viewPosition;
glm::mat4 view;
public:
Game();
~Game();
void initialize();
void start();
void stop();
// override the functions provided by base class Window2
void input(Keys k) override;
void update() override;
void render() override;
};
#endif
Game.cpp
#include "Game.h"
Game::Game()
:
Window2((int)(1080 * 0.7f), (int)(1920 * 0.7f), "Game", false)
{
PRINT_FUNC;
pointLight = new PointLight
(
glm::vec3(0.0, 0.0, 1.0),
glm::vec3(1.0, 1.0, 1.0) * 0.0f,
glm::vec3(1.0, 1.0, 1.0) * 0.3f,
glm::vec3(1.0, 1.0, 1.0) * 1.0f,
1.0f,
0.01f,
0.01f
);
material = new Material
(
glm::vec3(0.0f, 0.0f, 1.0f) * 1.0f,
glm::vec3(0.0f, 0.0f, 1.0f) * 1.0f,
glm::vec3(0.0f, 0.0f, 1.0f) * 1.0f,
1.0f,
256.0f,
1.0f
);
}
Game::~Game() {
PRINT_FUNC;
delete mesh;
delete shader;
delete material;
delete pointLight;
}
void Game::initialize() {
PRINT_FUNC;
Window2::intitialize2();
mesh = new Mesh(Mesh::loadVertices("assets/box2.obj", false));
shader = new Shader("shaders/vertex_shader copy.glsl", "shaders/fragment_shader copy.glsl");
projection = glm::perspective(glm::radians(35.0f), 9.0f / 16.0f, 0.1f, 1000.0f);
viewPosition = glm::vec3(0, 1, 0);
view = glm::lookAt(
viewPosition, // Camera is at (4,3,3), in World Space
glm::vec3(0, 0, 0), // and looks at the origin
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
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);
}
void Game::start() {
run();
}
void Game::stop() {
close();
}
void Game::input(Keys k) {
}
void Game::update() {
}
void Game::render() {
shader->activate();
shader->setMat4("P", projection);
shader->setMat4("V", view);
shader->setVec3("viewPos", viewPosition);
Renderer::render(mesh, shader, material, pointLight);
}
Window2.h
#ifndef WINDOW_2_H
#define WINDOW_2_H
#define GLEW_STATIC
#include <GL/glew.h> // include GLEW and new version of GL on Windows
#include <glfw3.h> // GLFW helper library
#include <iostream>
struct Keys {
bool W, A, S, D;
bool Left, Right, Up, Down;
bool N0, N1, N2, N3, N4, N5, N6, N7, N8, N9;
bool Space, Esc;
bool Shift;
};
class Window2 {
private:
GLFWmonitor* m_monitor;
unsigned int m_width;
unsigned int m_height;
int m_posX;
int m_posY;
const char* m_title;
const bool m_fullscreen;
float aspectRatio;
public:
GLFWwindow* m_window;
Window2(unsigned int width, unsigned int height, const char* title, const bool fullscreen);
~Window2();
void intitialize2();
void run();
void close();
// override functions
virtual void input(Keys k);
virtual void update();
virtual void render();
void setResizeCallback(void(*ptr)(GLFWwindow*, int, int));
void setSize(int width, int height);
float getAspectRatio();
void makeCurrent() const;
// clear window
void clear(float r, float g, float b);
// swap
void swap();
// poll events
void poll();
// get time in milliseconds
static unsigned int getTimeMS();
};
#endif
Window2.cpp
#include "Window2.h"
#include <iostream>
#include <chrono>
#include <Utils.h>
Window2::Window2
(
unsigned int width,
unsigned int height,
const char* title,
const bool fullscreen
)
:
m_width(width),
m_height(height),
m_title(title),
m_fullscreen(fullscreen)
{
PRINT_FUNC;
}
Window2::~Window2() {
PRINT_FUNC;
glfwDestroyWindow(m_window);
}
void Window2::intitialize2() {
PRINT_FUNC;
if (!glfwInit())
{
fprintf(stderr, "ERROR: could not start GLFW3\n");
return;
}
const GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
m_width = m_fullscreen ? mode->width : m_width;
m_height = m_fullscreen ? mode->height : m_height;
aspectRatio = (float)m_width / (float)m_height;
m_window = glfwCreateWindow(m_width, m_height, m_title, m_fullscreen ? glfwGetPrimaryMonitor() : NULL, NULL);
if (!m_window) {
fprintf(stderr, "ERROR: could not open Window2 with GLFW3\n");
glfwTerminate();
return;
}
glfwMakeContextCurrent(m_window);
// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit();
//setSize(m_width, m_height);
// get version info
const GLubyte* renderer = glGetString(GL_RENDERER);
const GLubyte* version = glGetString(GL_VERSION);
printf("Renderer: %s\n", renderer);
printf("OpenGL version supported %s\n\n", version);
}
void Window2::run() {
PRINT_FUNC;
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);
unsigned int previous = getTimeMS();
unsigned int lag = 0;
const unsigned int msPerUpdate = 1000 / 60;
while (!glfwWindowShouldClose(m_window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.8, 0.8, 0.8, 1);
unsigned int current = getTimeMS();
unsigned int elapsed = current - previous;
previous = current;
lag += elapsed;
const Keys k{
glfwGetKey(m_window, GLFW_KEY_W) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_A) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_S) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_D) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_LEFT) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_RIGHT) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_UP) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_DOWN) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_0) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_1) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_2) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_3) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_4) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_5) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_6) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_7) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_8) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_9) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_SPACE) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_ESCAPE) == GLFW_PRESS,
glfwGetKey(m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS
};
//input
input(k);
while (lag >= msPerUpdate)
{
// update
update();
lag -= msPerUpdate;
}
// render
render();
glfwSwapBuffers(m_window);
glfwPollEvents();
}
}
void Window2::input(Keys k) {
}
void Window2::update() {
}
void Window2::render() {
}
void Window2::close() {
glfwSetWindowShouldClose(m_window, GLFW_TRUE);
}
void Window2::setSize(int width, int height) {
m_width = width;
m_height = height;
aspectRatio = (float)m_width / (float)m_height;
glViewport(0, 0, width, height);
}
void Window2::setResizeCallback(void(*ptr)(GLFWwindow*, int, int)) {
glfwSetWindowSizeCallback(m_window, ptr);
}
void Window2::makeCurrent() const {
glfwMakeContextCurrent(m_window);
}
float Window2::getAspectRatio() {
return aspectRatio;
}
unsigned int Window2::getTimeMS() {
std::chrono::milliseconds mt = std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now().time_since_epoch());
return mt.count();
}
This is how the class is created in Main.cpp:
int main(int argc, char* argv[])
{
Game game;
game.initialize();
game.start();
glfwTerminate();
return 0;
}
Just a guess, I would expect you to set the version of OpenGL, after glfwInit(). For instance set it to version 3.3, I use 4.6:
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
The general rendering routine looks like this. Check where and if glUseProgram called somewhere, and if it is called:
glUseProgram(progId);
glBindVertexArray(vao); //vertex array object here, (not vertex buffer object)
glDrawXXX(GL_XXX, args); //for instance glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3);
I suppose shaders are compiled and program is linked successfully. So far is hard to guess from provided code. Other guesses might be missing some transformation, or missing any bind before drawing. The MVP transformation might send the object outside the window just by a small mistake. Transforming GL routines to OOP should be done in small steps. The way it is implemented really shows the level of understanding it.
I'm currently working on a project involving two cubes. The first cube meant to be static, while the second is going to rotate, or orbit, around the first. I'm very new to OpenGL programming, so I'm having quite a bit of difficulty getting this to work. Can anyone point me in the right direction? So far, I just have two cubes, but I am unable to get them to move as if they were animated. Here is my code if you would like to offer suggestions. Thank you so much!
Main:
#include "vgl.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <vector>
#include "Box.h"
#include "Camera.h"
#include "VertexBufferData.h"
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
using namespace std;
using namespace glm;
#define SPACEBAR_KEY 32
#define ESCAPE_KEY 033
Camera* camera;
vector<Box * > gameObjects;
bool keyDown[255];
void CheckKeyboard(){
if (keyDown['a'])
camera->RotateLeft();
if (keyDown['d'])
camera->RotateRight();
if (keyDown['w'])
camera->MoveForward();
if (keyDown['s'])
camera->MoveBackWard();
if (keyDown['e'])
camera->StrafeRight();
if (keyDown['q'])
camera->StrafeLeft();
}
void closeApp()
{
delete camera;
for (auto it = gameObjects.begin(); it != gameObjects.end(); ++it) {
delete (*it);
}
}
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case ESCAPE_KEY: // ASCII Escape Key Code
closeApp();
exit(EXIT_SUCCESS);
break;
default:
keyDown[key] = true;
}
glutPostRedisplay();
}
void keyboardUp(unsigned char key, int x, int y)
{
keyDown[key] = false;
}
void mouseWheel(int button, int direction, int x, int y)
{
if (button == 16)
camera->ResetFOV();
else if (direction > 0)
camera->ZoomIn();
else
camera->ZoomOut();
}
void mouseMovement(int x, int y)
{
static bool warp = true;
if (warp)
{
if (x>glutGet(GLUT_WINDOW_WIDTH) / 2)
camera->RotateRight();
else if (x<glutGet(GLUT_WINDOW_WIDTH) / 2)
camera->RotateLeft();
if (y>glutGet(GLUT_WINDOW_HEIGHT) / 2)
camera->RotateUp();
else if (y<glutGet(GLUT_WINDOW_HEIGHT) / 2)
camera->RotateDown();
glutWarpPointer(glutGet(GLUT_WINDOW_WIDTH) / 2, glutGet(GLUT_WINDOW_HEIGHT) / 2);
warp = false;
}
else
warp = true;
}
void timer(int value)
{
glutPostRedisplay();
glutTimerFunc(25, timer, 0);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
CheckKeyboard();
camera->Update();
for (auto it = gameObjects.begin(); it != gameObjects.end(); ++it) {
(*it)->shaderProgram->bindShader();
glm::mat4 MVP = camera->ProjectionMatrix * camera->ViewMatrix * (*it)->getModelMatrix();
(*it)->shaderProgram->sendUniform4x4("MVP", glm::value_ptr(MVP));
(*it)->Draw();
}
glutSwapBuffers();
}
void init()
{
int i = 0, forever = 0;
camera = new Camera();
memset(keyDown, false, sizeof(keyDown));
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
glutWarpPointer(glutGet(GLUT_WINDOW_WIDTH) / 2, glutGet(GLUT_WINDOW_HEIGHT) / 2);
glutSetCursor(GLUT_CURSOR_FULL_CROSSHAIR);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_CULL_FACE);
VertexBufferData vertexBufferData = VertexBufferData("Data\\Models\\Objects.xml");
gameObjects.push_back(new Box(vertexBufferData, glm::vec3(-2.0f, 0.0f, 0.0f), "Data\\Shaders\\Vertex.shader", "Data\\Shaders\\Fragment.shader"));
gameObjects.push_back(new Box(vertexBufferData, glm::vec3(2.0f, 0.0f, 0.0f), "Data\\Shaders\\Vertex.shader", "Data\\Shaders\\Fragment.shader"));
gameObjects[1]->setRotation(45.0f, vec3(0.0f, 0.0f, 1.0f));
gameObjects[0]->setScaleMatrix(vec3(2, 2, 2));
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(1024, 768);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutCreateWindow("Satterwhite_Project_3");
if (glewInit())
{
cerr << "Unable to init glew" << endl;
exit(EXIT_FAILURE);
}
init();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutKeyboardUpFunc(keyboardUp);
glutPassiveMotionFunc(mouseMovement);
glutMouseWheelFunc(mouseWheel);
glutTimerFunc(25, timer, 0);
glutMainLoop();
return 0;
}
Box.cpp
#include "Box.h"
Box::Box(VertexBufferData &vbd, vec3 initialPosition,const string vertexShader, const string fragmentShader):GameObject(vertexShader, fragmentShader)
{
Position=initialPosition;
vertexBufferData =vbd;
RotationMatrix=mat4(1.0f);
OrbitMatrix = mat4(1.0f);
ScaleMatrix=mat4(1.0f);
TranslationMatrix =translate(glm::mat4(1.0f), Position);
if (!shaderProgram->initialize())
{
std::cerr << "Could not initialize the shaders" << std::endl;
}
shaderProgram->bindShader();
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vertexBufferData.verticiesSize, &vertexBufferData.verticies[0], GL_STATIC_DRAW);
glGenBuffers(1, &fragmentBuffer);
glBindBuffer(GL_ARRAY_BUFFER, fragmentBuffer);
glBufferData(GL_ARRAY_BUFFER, vertexBufferData.colorSize, &vertexBufferData.colors[0], GL_STATIC_DRAW);
shaderProgram->linkProgram();
}
void Box::setRotation(float degrees, vec3 axis)
{
RotationMatrix=rotate(glm::mat4(1.0f), degrees, axis);
RotationMatrix=rotate(RotationMatrix, degrees, vec3(1.0f,0.0f,0.0f));
}
void Box::setScaleMatrix(vec3 scale)
{
ScaleMatrix = glm::scale(mat4(1.0f), scale);
}
/*void Box::setOrbitMatrix(vec3 Position, vec3 axis)
{
OrbitMatrix =
}*/
void Box::Draw()
{
shaderProgram->bindShader();
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT,GL_FALSE, 0, BUFFER_OFFSET(0));
glBindBuffer(GL_ARRAY_BUFFER, fragmentBuffer);
glVertexAttribPointer(1, 3, GL_FLOAT,GL_FALSE, 0, BUFFER_OFFSET(0));
glDrawArrays(GL_TRIANGLES, 0, vertexBufferData.verticies.size());
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
Box.h
#pragma once
#include "GameObject.h"
class Box : public GameObject
{
private:
mat4 ModelMatrix;
mat4 RotationMatrix;
mat4 OrbitMatrix;
mat4 TranslationMatrix;
mat4 ScaleMatrix;
public:
void Draw();
virtual ObjectType getType() const { return BOX; }
mat4 getModelMatrix() {return TranslationMatrix*RotationMatrix*ScaleMatrix;}
mat4 getMRotationMatrix() {return RotationMatrix;}
mat4 getTranslationMatrix() {return TranslationMatrix;}
mat4 getOrbitMatrix(){ return OrbitMatrix; }
mat4 getScaleMatrix() {return ScaleMatrix;}
void setRotation(float degrees, vec3 axis);
void setScaleMatrix(vec3 scale);
void setOrbitMatrix(vec3 Position, vec3 axis);
Box(VertexBufferData &vertexBufferData, vec3 initialPosition, const string vertexShader, const string fragmentShader);
vec3 Position;
mat4 rot;
mat4 scale;
};
I have a very peculiar problem that I can not figure out. For my scene I have created a spline class which I use to generate points for which my camera traverses. This works fine and dandy when I create an instance of the spline class in my scene and use it. I have some functionality in my spline class for showing the points on the spline that use uniform data to draw their position and give them a color. This all works fine when I create an instance directly in my scene.
HOWEVER, I want to create multiple splines to have my camera traverse so I created a fairly simple management class to handle multiple splines. This works however for some reason I can not puzzle out why when I create an instance of a spline with the manager the uniform variables aren't working. Everything else works fine. When I say they don't work what I mean is that the getLocation functions work (they get the locationIDs as expected), the data to be sent is the same, there are no errors or warnings concerning the functions that are supposed to actually send the data down to their locations. The spline draws properly however they are always black and haven't been translated.
Here is my scene class. The constructors for both my manager and the spline class its self are exactly the same so in my ClothScene.hpp I can switch the type of the mSplineManager object from the manager class to the spline class and the uniform variables work fine.
#include "ClothScene.hpp"
#include <atlas/core/GLFW.hpp>
#include <atlas/core/Log.hpp>
#include <atlas/core/Macros.hpp>
#include <atlas/core/Float.hpp>
#include <iostream>
ClothScene::ClothScene() :
mIsPlaying(false),
mLastTime(0.0f),
mFPS(60.0f),
mTick(1.0f / mFPS),
mAnimTime(0.0f),
mAnimLength(10.0f),
mSplineManager(int(mAnimLength * mFPS)),
ballPosition{ -10.0f, 0.0f, 14.0f }
{
glEnable(GL_DEPTH_TEST);
auto mat = glm::translate(atlas::math::Matrix4(1.0f), ballPosition);
mBall.transformGeometry(mat);
}
ClothScene::~ClothScene() {
}
void ClothScene::mousePressEvent(int button, int action, int modifiers, double xPos, double yPos) {
USING_ATLAS_MATH_NS;
if (button == GLFW_MOUSE_BUTTON_LEFT && modifiers == GLFW_MOD_ALT)
{
if (action == GLFW_PRESS)
{
mIsDragging = true;
//Camera tilt up and down or turn left, right
mCamera.mouseDown(Point2(xPos, yPos), ClothCamera::CameraMovements::TUMBLE);
}
else
{
mIsDragging = false;
mCamera.mouseUp();
}
}
else if (button == GLFW_MOUSE_BUTTON_MIDDLE && modifiers == GLFW_MOD_ALT)
{
if (action == GLFW_PRESS)
{
mIsDragging = true;
//Camera move left, right, up, down
mCamera.mouseDown(Point2(xPos, yPos), ClothCamera::CameraMovements::TRACK);
}
else
{
mIsDragging = false;
mCamera.mouseUp();
}
}
else if (button == GLFW_MOUSE_BUTTON_RIGHT && modifiers == GLFW_MOD_ALT)
{
if (action == GLFW_PRESS)
{
// first click.
mIsDragging = true;
//Camera move back and forth
mCamera.mouseDown(Point2(xPos, yPos), ClothCamera::CameraMovements::DOLLY);
}
else
{
mIsDragging = false;
mCamera.mouseUp();
}
}
else if (action != GLFW_PRESS)
{
mIsDragging = false;
mCamera.mouseUp();
}
}
void ClothScene::mouseMoveEvent(double xPos, double yPos) {
mCamera.mouseUpdate(glm::vec2(xPos, yPos));
}
void ClothScene::keyPressEvent(int key, int scancode, int action, int mods) {
UNUSED(scancode);
UNUSED(mods);
if (action == GLFW_PRESS)
{
switch (key)
{
case GLFW_KEY_T:
mCamera.resetCamera();
break;
case GLFW_KEY_W:
mCamera.strafeCamera(0);
break;
case GLFW_KEY_S:
mCamera.strafeCamera(1);
break;
case GLFW_KEY_A:
mCamera.strafeCamera(2);
break;
case GLFW_KEY_D:
mCamera.strafeCamera(3);
break;
case GLFW_KEY_R:
mCamera.strafeCamera(4);
break;
case GLFW_KEY_F:
mCamera.strafeCamera(5);
break;
case GLFW_KEY_Q:
mCamera.strafeCamera(6);
break;
case GLFW_KEY_E:
mCamera.strafeCamera(7);
break;
case GLFW_KEY_C:
mCamera.newPosition(glm::vec3(0.0f, 3.0f, 0.0f));
break;
case GLFW_KEY_U:
mSplineManager.showSpline();
break;
case GLFW_KEY_I:
mSplineManager.showControlPoints();
break;
case GLFW_KEY_O:
mSplineManager.showCage();
break;
case GLFW_KEY_P:
mSplineManager.showSplinePoints();
break;
case GLFW_KEY_SPACE:
mIsPlaying = !mIsPlaying;
default:
break;
}
}
}
void ClothScene::screenResizeEvent(int width, int height) {
glViewport(0, 0, width, height);
mProjection = glm::perspective(glm::radians(45.0),(double)width / height, 1.0, 1000.0);
}
void ClothScene::renderScene() {
float grey = 161.0f / 255.0f;
glClearColor(grey, grey, grey, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
mView = mCamera.getCameraMatrix();
mGrid.renderGeometry(mProjection, mView);
mSplineManager.renderGeometry(mProjection, mView);
mBall.renderGeometry(mProjection, mView);
}
void ClothScene::updateScene(double time)
{
mTime.currentTime = (float)time;
mTime.totalTime += (float)time;
if (atlas::core::geq(mTime.currentTime - mLastTime, mTick))
{
mLastTime += mTick;
mTime.deltaTime = mTick;
if (mIsPlaying)
{
mAnimTime += mTick;
mSplineManager.updateGeometry(mTime);
if (mSplineManager.doneInterpolation())
{
mIsPlaying = false;
return;
}
auto point = mSplineManager.getSplinePosition();
mCamera.newPosition(point);
mCamera.lookAt(ballPosition);
auto mat = glm::translate(atlas::math::Matrix4(1.0f), ballPosition);
mBall.transformGeometry(mat);
}
}
}
Here is my SplineManger class. It super simple, it just creates a vector of splines and then applies the exact same functionality iterated through all of the splines in the vector. For some reason this prevents the shader from receiving the uniform data.
#include "SplineManager.hpp"
SplineManager::SplineManager(int totalFrames) :
finishedAllSplines(false),
currentSpline(0)
{
mTotalFrames = totalFrames;
addSplines();
}
SplineManager::~SplineManager() {
}
void SplineManager::addSplines() {
mControlPoints = std::vector<Point>
{
{ -20, -5, 0 },
{ -19, 5, -15 },
{ 12.7f, -5, -1.4f },
{ 20, 8.2f, 4.4f }
};
mSplines.push_back(Spline(mTotalFrames, mControlPoints));
}
void SplineManager::renderGeometry(atlas::math::Matrix4 projection, atlas::math::Matrix4 view) {
for (int i = 0; i < mSplines.size(); ++i) {
mSplines[i].renderGeometry(projection, view);
}
}
void SplineManager::updateGeometry(atlas::utils::Time const& t) {
mSplines[currentSpline].updateGeometry(t);
if (mSplines[currentSpline].doneInterpolation()) {
++currentSpline;
if (currentSpline == mSplines.size()) {
finishedAllSplines = true;
}
}
}
atlas::math::Point SplineManager::getSplinePosition() {
return mSplines[currentSpline].getSplinePosition();
}
void SplineManager::showSpline() {
for (int i = 0; i < mSplines.size(); ++i) {
mSplines[i].showSpline();
}
}
void SplineManager::showControlPoints() {
for (int i = 0; i < mSplines.size(); ++i) {
mSplines[i].showControlPoints();
}
}
void SplineManager::showCage() {
for (int i = 0; i < mSplines.size(); ++i) {
mSplines[i].showCage();
}
}
void SplineManager::showSplinePoints() {
for (int i = 0; i < mSplines.size(); ++i) {
mSplines[i].showSplinePoints();
}
}
bool SplineManager::doneInterpolation() {
return finishedAllSplines;
}
Here is my spline class. Again, this all works totally fine when I directly create an instance of it in the scene class. When instances are created in the SplineManager the uniform variables don't work.
#include "Spline.h"
#include "ShaderPaths.hpp"
#include <atlas/core/Macros.hpp>
Spline::Spline(int totalFrames) :
mResolution(500),
mTotalFrames(totalFrames),
mCurrentFrame(0),
mShowControlPoints(false),
mShowCage(false),
mShowSplinePoints(false),
mShowSpline(false),
mIsInterpolationDone(false)
{
USING_ATLAS_MATH_NS;
USING_ATLAS_GL_NS;
//Bezier
mBasisMatrix = Matrix4(
1.0f, 0.0f, 0.0f, 0.0f,
-3.0f, 3.0f, 0.0f, 0.0f,
3.0f, -6.0f, 3.0f, 0.0f,
-1.0f, 3.0f, -3.0f, 1.0f);
mControlPoints = std::vector<Point>
{
{ -20, -5, 0 },
{ -19, 5, -15 },
{ 12.7f, -5, -1.4f },
{ 20, 8.2f, 4.4f }
};
std::vector<Point> splinePoints;
float scale = 1.0f / mResolution;
for (int res = 0; res < mResolution + 1; ++res)
{
splinePoints.push_back(evaluateSpline(scale * res));
}
generateArcLengthTable();
glGenVertexArrays(1, &mVao);
glBindVertexArray(mVao);
glGenBuffers(1, &mControlBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mControlBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Point) * mControlPoints.size(),
mControlPoints.data(), GL_STATIC_DRAW);
glGenBuffers(1, &mSplineBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mSplineBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Point) * splinePoints.size(), splinePoints.data(), GL_STATIC_DRAW);
std::string shaderDir = generated::ShaderPaths::getShaderDirectory();
std::vector<ShaderInfo> shaders
{
{ GL_VERTEX_SHADER, shaderDir + "spline.vs.glsl" },
{ GL_FRAGMENT_SHADER, shaderDir + "spline.fs.glsl" }
};
mShaders.push_back(ShaderPointer(new Shader));
mShaders[0]->compileShaders(shaders);
mShaders[0]->linkShaders();
GLuint var;
var = mShaders[0]->getUniformVariable("uMVP");
mUniforms.insert(UniformKey("uMVP", var));
var = mShaders[0]->getUniformVariable("fColour");
mUniforms.insert(UniformKey("fColour", var));
mShaders[0]->disableShaders();
glBindVertexArray(0);
}
Spline::~Spline()
{
glDeleteVertexArrays(1, &mVao);
glDeleteVertexArrays(1, &mControlBuffer);
glDeleteVertexArrays(1, &mSplineBuffer);
}
void Spline::renderGeometry(atlas::math::Matrix4 projection,
atlas::math::Matrix4 view)
{
USING_ATLAS_MATH_NS;
mShaders[0]->enableShaders();
glBindVertexArray(mVao);
Matrix4 mvp = projection * view * mModel;
glUniformMatrix4fv(mUniforms["uMVP"], 1, GL_FALSE, &mvp[0][0]);
// Draw the control points first.
glUniform3f(mUniforms["fColour"], 1, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, mControlBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
if (mShowControlPoints)
{
glPointSize(5.0f);
glDrawArrays(GL_POINTS, 0, GLsizei(mControlPoints.size()));
glPointSize(1.0f);
}
if (mShowCage)
{
glDrawArrays(GL_LINE_STRIP, 0, GLsizei(mControlPoints.size()));
}
// Now draw the spline.
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, mSplineBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glUniform3f(mUniforms["fColour"], 0, 1, 0);
if (mShowSpline)
{
glLineWidth(5.0f);
glDrawArrays(GL_LINE_STRIP, 0, mResolution + 1);
glLineWidth(1.0f);
}
if (mShowSplinePoints)
{
glPointSize(8.0f);
glDrawArrays(GL_POINTS, 1, mResolution);
glPointSize(1.0f);
}
glDisableVertexAttribArray(0);
mShaders[0]->disableShaders();
}
void Spline::updateGeometry(atlas::utils::Time const& t)
{
UNUSED(t);
mSplinePosition = interpolateOnSpline();
mCurrentFrame++;
if (mCurrentFrame == mTotalFrames)
{
mIsInterpolationDone = true;
return;
}
}
void Spline::showControlPoints()
{
mShowControlPoints = !mShowControlPoints;
}
void Spline::showCage()
{
mShowCage = !mShowCage;
}
void Spline::showSplinePoints()
{
mShowSplinePoints = !mShowSplinePoints;
}
void Spline::showSpline()
{
mShowSpline = !mShowSpline;
}
bool Spline::doneInterpolation()
{
return mIsInterpolationDone;
}
atlas::math::Point Spline::getSplinePosition()
{
return mSplinePosition;
}
atlas::math::Point Spline::interpolateOnSpline()
{
int n = int(mTable.size());
float totalDistance = mTable[n - 1];
float step = totalDistance / mTotalFrames;
float currDistance = step * mCurrentFrame;
int index = tableLookUp(currDistance);
float t = (1.0f / mResolution) * (index % mResolution);
return evaluateSpline(t);
}
atlas::math::Point Spline::evaluateSpline(float t)
{
USING_ATLAS_MATH_NS;
Vector4 xControls =
{
mControlPoints[0].x, mControlPoints[1].x,
mControlPoints[2].x, mControlPoints[3].x
};
Vector4 yControls =
{
mControlPoints[0].y, mControlPoints[1].y,
mControlPoints[2].y, mControlPoints[3].y
};
Vector4 zControls =
{
mControlPoints[0].z, mControlPoints[1].z,
mControlPoints[2].z, mControlPoints[3].z
};
Vector4 xCoeff = xControls * mBasisMatrix;
Vector4 yCoeff = yControls * mBasisMatrix;
Vector4 zCoeff = zControls * mBasisMatrix;
float xcr, ycr, zcr;
xcr = xCoeff[0] + t * xCoeff[1] + t * t * xCoeff[2] + t * t * t * xCoeff[3];
ycr = yCoeff[0] + t * yCoeff[1] + t * t * yCoeff[2] + t * t * t * yCoeff[3];
zcr = zCoeff[0] + t * zCoeff[1] + t * t * zCoeff[2] + t * t * t * zCoeff[3];
return Point(xcr, ycr, zcr);
}
void Spline::generateArcLengthTable()
{
USING_ATLAS_MATH_NS;
if (!mTable.empty())
{
mTable.clear();
}
float scale = 1.0f / mResolution;
mTable.push_back(0.0f);
for (int i = 1; i < mResolution + 1; ++i)
{
Point p0 = evaluateSpline((i - 1) * scale);
Point p1 = evaluateSpline(i * scale);
Point dist = p0 - p1;
mTable.push_back(mTable[i - 1] + glm::length(dist));
}
}
int Spline::tableLookUp(float distance)
{
// Find the entry in our table that corresponds to the given distance.
float epsilon = chooseEpsilon();
for (int i = 0; i < int(mTable.size()); ++i)
{
if (glm::abs(mTable[i] - distance) < epsilon)
{
return i;
}
}
return -1;
}
float Spline::chooseEpsilon()
{
// Find the largest difference and use that to look up distances
// in our table.
float epsilon = 0.0f;
float diff;
for (int i = 0; i < mTable.size() - 1; ++i)
{
diff = glm::abs(mTable[i] - mTable[i + 1]);
if (diff > epsilon)
{
epsilon = diff;
}
}
return epsilon;
}
void Spline::setSplineCoordinates(std::vector<atlas::math::Point> mControlPoints_) {
mControlPoints = mControlPoints_;
}
The header files for anyone interested.
SplineManager.hpp
#ifndef SPLINEMANAGER_HPP
#define SPLINEMANAGER_HPP
#pragma once
#include <atlas/utils/Geometry.hpp>
#include "Spline.h"
USING_ATLAS_MATH_NS;
USING_ATLAS_GL_NS;
class SplineManager : public atlas::utils::Geometry {
public:
SplineManager(int totalFrames);
~SplineManager();
atlas::math::Point getSplinePosition();
void addSplines();
void showSpline();
void showControlPoints();
void showCage();
void showSplinePoints();
bool doneInterpolation();
void updateGeometry(atlas::utils::Time const& t) override;
void renderGeometry(atlas::math::Matrix4 projection, atlas::math::Matrix4 view) override;
private:
std::vector<Spline> mSplines;
std::vector<atlas::math::Point> mControlPoints;
int mTotalFrames;
int currentSpline;
bool finishedAllSplines;
};
#endif
Spline.h
#ifndef LAB04_INCLUDE_SPLINE_HPP
#define LAB04_INCLUDE_SPLINE_HPP
#pragma once
#include <atlas/utils/Geometry.hpp>
#include <fstream>
class Spline : public atlas::utils::Geometry
{
public:
Spline(int totalFrames, std::vector<atlas::math::Point> mControlPoints_);
Spline(int totalFrames);
~Spline();
void renderGeometry(atlas::math::Matrix4 projection,
atlas::math::Matrix4 view) override;
void updateGeometry(atlas::utils::Time const& t) override;
void showControlPoints();
void showCage();
void showSplinePoints();
void showSpline();
bool doneInterpolation();
atlas::math::Point getSplinePosition();
void setSplineCoordinates(std::vector<atlas::math::Point> mControlPoints_);
private:
atlas::math::Point interpolateOnSpline();
atlas::math::Point evaluateSpline(float t);
void generateArcLengthTable();
int tableLookUp(float distance);
float chooseEpsilon();
atlas::math::Matrix4 mBasisMatrix;
std::vector<atlas::math::Point> mControlPoints;
std::vector<float> mTable;
atlas::math::Point mSplinePosition;
GLuint mVao;
GLuint mControlBuffer;
GLuint mSplineBuffer;
int mResolution;
int mTotalFrames;
int mCurrentFrame;
bool mShowControlPoints;
bool mShowCage;
bool mShowSplinePoints;
bool mShowSpline;
bool mIsInterpolationDone;
};
#endif
ClothScene.hpp
#ifndef SCENE_HPP
#define SCENE_HPP
#pragma once
#include <atlas\utils\Scene.hpp>
#include "ClothCamera.hpp"
#include "SplineManager.hpp"
#include "Grid.hpp"
#include "Spline.h"
#include "Ball.hpp"
//#include "Cloth.hpp"
class ClothScene : public atlas::utils::Scene {
public:
ClothScene();
~ClothScene();
void mousePressEvent(int button, int action, int modifiers, double xPos, double yPos) override;
void mouseMoveEvent(double xPos, double yPos) override;
void keyPressEvent(int key, int scancode, int action, int mods) override;
void screenResizeEvent(int width, int height) override;
void renderScene() override;
void updateScene(double time) override;
private:
bool mIsDragging;
bool mIsPlaying;
float mLastTime;
float mFPS;
float mTick;
float mAnimTime;
float mAnimLength;
glm::vec3 ballPosition;
ClothCamera mCamera;
Grid mGrid;
SplineManager mSplineManager;//, mSpline2;
Ball mBall;
std::vector<atlas::math::Point> mControlPoints;
};
#endif
This program builds with no problem, and the executable starts up, but no triangle shows up. I am following a GLSL tutorial where a Shader class is made to handle GLSL files.
Shader.h
#ifndef SHADER_H_
#define SHADER_H_
#include <GL/glew.h>
#include <GL/glfw.h>
#include <string>
class Shader {
public:
Shader();
Shader(const char *vsFile, const char *fsFile);
~Shader();
void init(const char *vsFile, const char *fsFile);
void bind();
void unbind();
unsigned int id();
private:
unsigned int shader_id;
unsigned int shader_vp;
unsigned int shader_fp;
};
#endif // SHADER_H_
Shader.cpp
#include "Shader.h"
#include <cstring>
#include <iostream>
#include <ftream>
#include <cstdlib>
using namespace std;
static char* textFileRead(const char *fileName) {
char* text;
if (fileName != NULL) {
FILE *file = fopen(fileName, "rt");
if (file != NULL) {
fseek(file, 0, SEEK_END);
int count = ftell(file);
rewind(file);
if (count > 0) {
text = (char*)malloc(sizeof(char) * (count + 1));
count = fread(text, sizeof(char), count, file);
text[count] = '\0';
}
fclose(file);
}
}
return text;
}
Shader::Shader() {}
Shader::Shader(const char *vsFile, const char *fsFile)
{
init(vsFile, fsFile);
}
void Shader::init(const char *vsFile, const char *fsFile)
{
shader_vp = glCreateShader(GL_VERTEX_SHADER);
shader_fp = glCreateShader(GL_FRAGMENT_SHADER);
const char *vsText = textFileRead(vsFile);
const char *fsText = textFileRead(fsFile);
if (vsText == NULL || fsText == NULL)
{
cerr << "Either vertex shader or fragment shader file is not found" << endl;
return;
}
glShaderSource(shader_vp, 1, &vsText, 0);
glShaderSource(shader_fp, 1, &fsText, 0);
glCompileShader(shader_vp);
glCompileShader(shader_fp);
shader_id = glCreateProgram();
glAttachShader(shader_id, shader_fp);
glAttachShader(shader_id, shader_vp);
glLinkProgram(shader_id);
}
Shader::~Shader()
{
glDetachShader(shader_id, shader_fp);
glDetachShader(shader_id, shader_vp);
glDeleteShader(shader_fp);
glDeleteShader(shader_vp);
glDeleteShader(shader_id);
}
unsigned int Shader::id()
{
return shader_id;
}
void Shader::bind()
{
glUseProgram(shader_id);
}
void Shader::unbind()
{
glUseProgram(0);
}
Main.cpp
#include "Shader.h"
#include <cstdlib>
#include <iostream>
using namespace std;
Shader shader;
void init()
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
shader.init("shader.vert", "shader.frag");
}
void resize(int w, int h)
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
}
int main()
{
int running = GL_TRUE;
// init GLFW
if (!glfwInit())
exit(EXIT_FAILURE);
if (!glfwOpenWindow(300, 300, 0, 0, 0, 0, 0, 0, GLFW_WINDOW))
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSetWindowTitle("ohhai.");
glfwSetWindowSizeCallback(resize);
/* CHECK GLEW */
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
cout << "Error: " << glewGetErrorString(err) << endl;
}
cout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << endl;
if (!GLEW_ARB_vertex_buffer_object)
{
cerr << "VBO not supported\n";
exit(1);
}
init();
while (running)
{
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glShadeModel(GL_SMOOTH);
shader.bind();
glBegin(GL_TRIANGLES);
//glColor3f(0.2f, 0.5f, 0.54f);
glVertex2f(0.0f, 0.5f);
//glColor3f(0.75f, 0.8f, 0.1f);
glVertex2f(-.5f, -.5f);
//glColor3f(0.0f, 0.9f, 0.2f);
glVertex2f(0.5f, -0.5f);
glEnd();
shader.unbind();
glfwSwapBuffers();
running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED);
}
glfwTerminate();
exit(EXIT_SUCCESS);
}
shader.vert
void main()
{
// set the posistion of the current matrix
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
shader.frag
void main(void)
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
Again, when this compiles under g++, it goes through fine, but no triangle was shown.
I haven't found the part where you setup the camera (modelview matrix) with gluLookAt or glTranslate/glRotate/glScale. So you use the default, corresponding to a camera at the origin and looking into -z, thus your triangle (which lies in the z=0 plane) is behind the near plane.