Initial Commit

This commit is contained in:
Pierre Cholet 2018-09-12 18:53:34 +02:00
commit 54eaed1ca0
284 changed files with 55022 additions and 0 deletions

251
src/hello_camera/camera.cpp Normal file
View file

@ -0,0 +1,251 @@
#include "camera.h"
#define GLM_ENABLE_EXPERIMENTAL
#include "gtc/quaternion.hpp"
#include "gtx/norm.hpp"
#include "gtc/matrix_transform.hpp"
/*------------------------------------------------------------------------------------------------------------------------*/
Camera::Camera(glm::vec3 position, glm::vec3 up, glm::vec3 look, float zoom) : _position(position), _front(look-position), _up(up), _zoom(zoom) {
}
Camera::~Camera() {
}
glm::mat4 Camera::viewmatrix() const {
return glm::lookAt(_position, _position + _front, _up);
}
void Camera::processkeyboard(Camera_Movement , GLfloat ) {
}
void Camera::processmouseclick(int button, GLfloat xpos, GLfloat ypos) {
_mousebutton = button;
_mousestartx = xpos;
_mousestarty = ypos;
}
void Camera::processmousemovement(int , GLfloat , GLfloat , GLboolean ) {
}
void Camera::processmousescroll(GLfloat ) {
}
float &Camera::zoom() {
return _zoom;
}
glm::vec3 &Camera::position() {
return _position;
}
void Camera::setviewport(glm::vec4 viewport) {
_viewport = viewport;
}
/*------------------------------------------------------------------------------------------------------------------------*/
// A camera class that processes input and calculates the corresponding Eular Angles, Vectors and Matrices for use in OpenGL
// Constructor with vectors
EulerCamera::EulerCamera(glm::vec3 position, glm::vec3 up, GLfloat yaw, GLfloat pitch) : Camera(position, up, glm::vec3(0.0f, 0.0f, -1.0f), ZOOM), _movementspeed(SPEED), _mousesensitivity(SENSITIVTY) {
_worldup = _up;
_yaw = yaw;
_pitch = pitch;
updatecameravectors();
}
EulerCamera::~EulerCamera() {
}
// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
void EulerCamera::processkeyboard(Camera_Movement direction, GLfloat deltaTime) {
GLfloat velocity = _movementspeed * deltaTime;
if (direction == FORWARD)
_position += _front * velocity;
if (direction == BACKWARD)
_position -= _front * velocity;
if (direction == LEFT)
_position -= _right * velocity;
if (direction == RIGHT)
_position += _right * velocity;
}
// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void EulerCamera::processmousemovement(int button, GLfloat xpos, GLfloat ypos, GLboolean constrainPitch) {
(void)button;
float xoffset = xpos - _mousestartx;
float yoffset = _mousestarty - ypos;
_mousestartx = xpos;
_mousestarty = ypos;
xoffset *= _mousesensitivity;
yoffset *= _mousesensitivity;
_yaw += xoffset;
_pitch += yoffset;
// Make sure that when pitch is out of bounds, screen doesn't get flipped
if (constrainPitch)
{
if (_pitch > 89.0f)
_pitch = 89.0f;
if (_pitch < -89.0f)
_pitch = -89.0f;
}
// Update Front, Right and Up Vectors using the updated Eular angles
updatecameravectors();
}
// Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
void EulerCamera::processmousescroll(GLfloat yoffset) {
if (_zoom >= 1.0f && _zoom <= 45.0f)
_zoom -= yoffset;
if (_zoom <= 1.0f)
_zoom = 1.0f;
if (_zoom >= 45.0f)
_zoom = 45.0f;
}
// Calculates the front vector from the Camera's (updated) Eular Angles
void EulerCamera::updatecameravectors() {
// Calculate the new Front vector
glm::vec3 front;
front.x = std::cos(glm::radians(_yaw)) * cos(glm::radians(_pitch));
front.y = sin(glm::radians(_pitch));
front.z = sin(glm::radians(_yaw)) * cos(glm::radians(_pitch));
_front = glm::normalize(front);
// Also re-calculate the Right and Up vector
_right = glm::normalize(glm::cross(_front, _worldup)); // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
_up = glm::normalize(glm::cross(_right, _front));
}
/*------------------------------------------------------------------------------------------------------------------------*/
/* Trackball Camera */
/*------------------------------------------------------------------------------------------------------------------------*/
TrackballCamera::TrackballCamera(glm::vec3 position, glm::vec3 up, glm::vec3 center):
Camera(position, glm::normalize(up), center, ZOOM),
_movementspeed(1.0f), _mousesensitivity(1.0) {
_radius = glm::length(_front);
_front *= 1.f/_radius;
}
TrackballCamera::~TrackballCamera() {
}
void TrackballCamera::processkeyboard(Camera_Movement direction, GLfloat deltaTime) {
(void)direction;
(void)deltaTime;
}
void TrackballCamera::processmouseclick(int button, GLfloat xpos, GLfloat ypos) {
Camera::processmouseclick(button, xpos, ypos);
switch (_mousebutton) {
case 0:
// rotate
_rotstart = getmouseprojectiononball(xpos, ypos);
_rotend = _rotstart;
break;
case 1:
// pan
_panstart = getmouseonscreen(xpos, ypos);
_panend = _panstart;
break;
case 2:
// zoom
break;
default:
break;
}
}
void TrackballCamera::processmousemovement(int button, GLfloat xpos, GLfloat ypos, GLboolean constrainPitch) {
(void)button;
(void)constrainPitch;
switch (_mousebutton) {
case 0:
// rotate
_rotend = getmouseprojectiononball(xpos, ypos);
rotatecamera();
break;
case 1:
// pan
_panend = getmouseonscreen(xpos, ypos);
pancamera();
break;
case 2:
// zoom
break;
default:
break;
}
}
void TrackballCamera::processmousescroll(GLfloat yoffset) {
(void)yoffset;
}
#define SQRT1_2 0.7071067811865476
glm::vec3 TrackballCamera::getmouseprojectiononball(float xpos, float ypos){
glm::vec3 mouseonball = glm::vec3(
(xpos - _viewport.z * 0.5f) / (_viewport.z * 0.5f),
(_viewport.w * 0.5f - ypos) / (_viewport.w * 0.5f),
0.0f
);
float length = glm::length(mouseonball);
length = (length<1.0f) ? length : 1.0f;
mouseonball.z = std::sqrt(1-length*length);
mouseonball = glm::normalize(mouseonball);
return mouseonball;
}
glm::vec2 TrackballCamera::getmouseonscreen(float xpos, float ypos) {
return glm::vec2(
(xpos - _viewport.z * 0.5f) / (_viewport.z * 0.5f),
(ypos - _viewport.w * 0.5f) / (_viewport.w * 0.5f)
);
}
void TrackballCamera::rotatecamera() {
glm::vec3 direction = _rotend - _rotstart;
float velocity = glm::length(direction);
if (velocity > 0.0001) {
glm::vec3 axis = glm::cross(_rotend, _rotstart);
float length = glm::length(axis);
axis = glm::normalize(axis);
float angle = std::atan2(length, glm::dot(_rotstart, _rotend));
glm::quat quaternion = glm::angleAxis(angle, axis);
glm::vec3 center = _position + _front*_radius;
_front = glm::normalize(glm::rotate( quaternion , _front));
_up = glm::normalize(glm::rotate(quaternion , _up));
_position = center-_front*_radius;
_rotstart=_rotend;
}
}
void TrackballCamera::pancamera() {
glm::vec2 mov = _panend - _panstart;
if (glm::length(mov) != 0.0f) {
mov *= _mousesensitivity*_movementspeed;
glm::vec3 pan = glm::cross(_up,_front) * mov.x + _up * mov.y;
_position += pan;
_panstart = _panend;
}
}

146
src/hello_camera/camera.h Normal file
View file

@ -0,0 +1,146 @@
#ifndef CAMERA_H
#define CAMERA_H
#include "opengl_stuff.h"
// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
enum Camera_Movement {
LEFT = 0,
FORWARD,
RIGHT,
BACKWARD
};
/*------------------------------------------------------------------------------------------------------------------------*/
/* Abstract Camera */
/*------------------------------------------------------------------------------------------------------------------------*/
class Camera {
public:
Camera(glm::vec3 position = glm::vec3(0.f, 0.f, 1.f), glm::vec3 up = glm::vec3(0.f, 1.f, 0.f), glm::vec3 look = glm::vec3(0.f, 0.f, 0.f), float zoom=45.f);
virtual ~Camera();
// Returns the view matrix calculated using Eular Angles and the LookAt Matrix
glm::mat4 viewmatrix() const;
float &zoom();
glm::vec3 &position();
void setviewport(glm::vec4 viewport);
// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
virtual void processkeyboard(Camera_Movement direction, GLfloat deltaTime);
// Processes input received from a mouse input system.
virtual void processmouseclick(int button, GLfloat xpos, GLfloat ypos);
// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
virtual void processmousemovement(int button, GLfloat xpos, GLfloat ypos, GLboolean constraint = true);
// Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
virtual void processmousescroll(GLfloat yoffset);
glm::vec3 _position;
glm::vec3 _front;
protected:
glm::vec3 _up;
float _zoom;
glm::vec4 _viewport;
// mouse movement
int _mousebutton;
GLfloat _mousestartx;
GLfloat _mousestarty;
};
/*------------------------------------------------------------------------------------------------------------------------*/
/* Euler Camera : Yaw, Pitch, Roll */
/*------------------------------------------------------------------------------------------------------------------------*/
// from learnopenGL tutorial
// Default camera values
constexpr GLfloat YAW = -90.0f;
constexpr GLfloat PITCH = 0.0f;
constexpr GLfloat SPEED = 3.0f;
constexpr GLfloat SENSITIVTY = 0.25f;
constexpr GLfloat ZOOM = 45.0f;
// An abstract camera class that processes input and calculates the corresponding Eular Angles, Vectors and Matrices for use in OpenGL
class EulerCamera : public Camera {
public:
// Constructor with vectors (default constructor)
EulerCamera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), GLfloat yaw = YAW, GLfloat pitch = PITCH);
~EulerCamera();
// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
void processkeyboard(Camera_Movement direction, GLfloat deltaTime) override;
// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void processmousemovement(int button, GLfloat xpos, GLfloat ypos, GLboolean constrainPitch = true) override;
// Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
void processmousescroll(GLfloat yoffset) override;
private:
// Calculates the front vector from the Camera's (updated) Eular Angles
void updatecameravectors();
// Camera Attributes
glm::vec3 _right;
glm::vec3 _worldup;
// Eular Angles
GLfloat _yaw;
GLfloat _pitch;
// Camera options
GLfloat _movementspeed;
GLfloat _mousesensitivity;
};
/*------------------------------------------------------------------------------------------------------------------------*/
/* Trackball Camera */
/*------------------------------------------------------------------------------------------------------------------------*/
class TrackballCamera : public Camera {
public:
TrackballCamera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3 center = glm::vec3(0.0f, 0.0f, -1.0f));
~TrackballCamera();
// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
void processkeyboard(Camera_Movement direction, GLfloat deltaTime) override;
// Processes input received from a mouse input system.
void processmouseclick(int button, GLfloat xpos, GLfloat ypos) override;
// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void processmousemovement(int button, GLfloat xpos, GLfloat ypos, GLboolean constrainPitch = true) override;
// Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
void processmousescroll(GLfloat yoffset) override;
private:
// Distance to center
float _radius;
// Camera options
GLfloat _movementspeed;
GLfloat _mousesensitivity;
// rotation data
glm::vec3 _rotstart;
glm::vec3 _rotend;
//pan data
glm::vec2 _panstart;
glm::vec2 _panend;
glm::vec3 getmouseprojectiononball(float xpos, float ypos);
glm::vec2 getmouseonscreen(float xpos, float ypos);
void rotatecamera();
void pancamera();
};
#endif // CAMERA_H

View file

@ -0,0 +1,188 @@
#include "hellocamera.h"
#include <iostream>
/*------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------------------------------------------*/
#define deg2rad(x) float(M_PI)*(x)/180.f
static const char* vertexshader_source ="#version 410 core\n\
layout (location = 0) in vec3 position;\n\
layout (location = 1) in vec3 inormal;\n\
uniform mat4 model;\n\
uniform mat4 view;\n\
uniform mat4 projection;\n\
out vec3 normal;\n\
void main()\n\
{\n\
// Note that we read the multiplication from right to left\n\
gl_Position = projection * view * model * vec4(position, 1.0f);\n\
normal = inormal;\n\
}\n";
static const char* fragmentshader_source ="#version 410 core\n\
in vec3 normal;\n\
out vec4 color;\n\
void main()\n\
{\n\
//color = vec4(vec3(clamp(dot(normalize(normal), vec3(0,0,1)), 0, 1)), 1.0);\n\
color = vec4(normalize(normal)*0.5+0.5, 1.0);\n\
}\n";
SimpleCamera::SimpleCamera(int width, int height, MainWindow* w) : Scene(width, height, w), _activecamera(0), _camera(nullptr) {
// Initialise geometric data
_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
};
_normals = {
0.577350269189626f, 0.577350269189626f, 0.577350269189626f,
0.577350269189626f, -0.577350269189626f, 0.577350269189626f,
-0.577350269189626f, -0.577350269189626f, 0.577350269189626f,
-0.577350269189626f, 0.577350269189626f, 0.577350269189626f
};
_indices = {
// Note that we start from 0!
0, 1, 3, // First Triangle
1, 2, 3 // Second Triangle
};
// Initialize the geometry
// 1. Generate geometry buffers
glGenBuffers(1, &_vbo) ;
glGenBuffers(1, &_nbo) ;
glGenBuffers(1, &_ebo) ;
glGenVertexArrays(1, &_vao) ;
// 2. Bind Vertex Array Object
glBindVertexArray(_vao);
// 3. Copy our vertices array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _vertices.size()*sizeof (GLfloat), _vertices.data(), GL_STATIC_DRAW);
// 4. Then set our vertex attributes pointers
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// 5. Copy our normals array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, _nbo);
glBufferData(GL_ARRAY_BUFFER, _normals.size()*sizeof (GLfloat), _normals.data(), GL_STATIC_DRAW);
// 6. Copy our vertices array in a buffer for OpenGL to use
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
// 7. Copy our index array in a element buffer for OpenGL to use
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices.size()*sizeof (GLfloat), _indices.data(), GL_STATIC_DRAW);
//6. Unbind the VAO
glBindVertexArray(0);
// Initialize shaders
GLint success;
GLchar infoLog[512]; // warning fixed size ... request for LOG_LENGTH!!!
GLuint vertexshader, fragmentshader;
// 1. Generate the shader
vertexshader = glCreateShader(GL_VERTEX_SHADER);
// 2. set the source
glShaderSource(vertexshader, 1, &vertexshader_source, NULL);
// 3. Compile
glCompileShader(vertexshader);
// 4. test for compile error
glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &success);
if(!success) {
glGetShaderInfoLog(vertexshader, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentshader, 1, &fragmentshader_source, NULL);
glCompileShader(fragmentshader);
glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &success);
if(!success) {
glGetShaderInfoLog(fragmentshader, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// 1. Generate the program
_program = glCreateProgram();
// 2. Attach the shaders to the program
glAttachShader(_program, vertexshader);
glAttachShader(_program, fragmentshader);
// 3. Link the program
glLinkProgram(_program);
// 4. Test for link errors
glGetProgramiv(_program, GL_LINK_STATUS, &success);
if(!success) {
glGetProgramInfoLog(_program, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::LINK_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexshader);
glDeleteShader(fragmentshader);
_cameraselector.push_back( []()->Camera*{return new EulerCamera(glm::vec3(0.f, 0.f, 1.f));} );
_cameraselector.push_back( []()->Camera*{return new TrackballCamera(glm::vec3(0.f, 0.f, 1.f),glm::vec3(0.f, 1.f, 0.f),glm::vec3(0.f, 0.f, 0.f));} );
_camera.reset(_cameraselector[_activecamera]());
_camera->setviewport(glm::vec4(0.f, 0.f, _width, _height));
_view = _camera->viewmatrix();
_projection = glm::perspective(_camera->zoom(), float(_width) / _height, 0.1f, 100.0f);
}
SimpleCamera::~SimpleCamera() {
}
void SimpleCamera::resize(int width, int height){
Scene::resize(width, height);
_camera->setviewport(glm::vec4(0.f, 0.f, _width, _height));
}
void SimpleCamera::draw() {
Scene::draw();
glUseProgram(_program);
_view = _camera->viewmatrix();
glUniformMatrix4fv( glGetUniformLocation(_program, "model"), 1, GL_FALSE, glm::value_ptr(_model));
glUniformMatrix4fv( glGetUniformLocation(_program, "view"), 1, GL_FALSE, glm::value_ptr(_view));
glUniformMatrix4fv( glGetUniformLocation(_program, "projection"), 1, GL_FALSE, glm::value_ptr(_projection));
glBindVertexArray(_vao);
glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
void SimpleCamera::mouseclick(int button, float xpos, float ypos) {
_button = button;
_mousex = xpos;
_mousey = ypos;
_camera->processmouseclick(_button, xpos, ypos);
}
void SimpleCamera::mousemove(float xpos, float ypos) {
_camera->processmousemovement(_button, xpos, ypos, true);
}
void SimpleCamera::keyboardmove(int key, double time) {
_camera->processkeyboard(Camera_Movement(key), time);
}
bool SimpleCamera::keyboard(unsigned char k) {
switch(k) {
case 'p':
_activecamera = (_activecamera+1)%2;
_camera.reset(_cameraselector[_activecamera]());
_camera->setviewport(glm::vec4(0.f, 0.f, _width, _height));
return true;
default:
return false;
}
}

View file

@ -0,0 +1,64 @@
#ifndef SIMPLECAMERA_H
#define SIMPLECAMERA_H
#include "scene.h"
#include "mainwindow.h"
#include "camera.h"
#include <memory>
#include <functional>
/** Simple drawing demonstration
*/
class SimpleCamera : public Scene {
public:
explicit SimpleCamera(int width, int height, MainWindow* w);
~SimpleCamera();
void resize(int width, int height) override;
void draw() override;
void mouseclick(int button, float xpos, float ypos) override;
void mousemove(float xpos, float ypos) override;
void keyboardmove(int key, double time) override;
bool keyboard(unsigned char k) override;
private:
// A simple geometry
std::vector<GLfloat> _vertices;
std::vector<GLfloat> _normals;
std::vector<GLuint> _indices;
// OpenGL object for geometry
GLuint _vao;
GLuint _vbo;
GLuint _nbo;
GLuint _ebo;
// Shader program for rendering
GLuint _program;
// for mouse management
int _button; // 0 --> left. 1 --> right. 2 --> middle. 3 --> other
float _mousex{0};
float _mousey{0};
// Camera
using CameraSelector=std::function<Camera*()>;
std::vector<CameraSelector> _cameraselector;
int _activecamera;
std::unique_ptr<Camera> _camera;
// matrices
glm::mat4 _model;
glm::mat4 _view;
glm::mat4 _projection;
};
/*------------------------------------------------------------------------------------------------------------------------*/
#endif // SIMPLECAMERA_H

View file

@ -0,0 +1,507 @@
#include "hellosphere.h"
#include <iostream>
#define deg2rad(x) float(M_PI)*(x)/180.f
// CTOR
SimpleSphere::SimpleSphere(int width, int height, MainWindow* w) : Scene(width, height, w), _activecamera(0), _camera(nullptr) {
// Initialize last shaders
_lastVertex = _w->vertexShader;
_lastFragment = _w->fragmentShader;
// Connect programm generation slot ?
// Compute the shape to draw -> Menu ?
//drawCube(0.1f);
drawUVSphere(50, _radius);
//drawIcoSphere(5, _radius);
std::cout << "Vertices count: " << _vertices.size() / 3 << std::endl;
std::cout << "Edges count: " << _indices.size() << std::endl;
std::cout << "Triangles count: " << _indices.size() / 3 << std::endl;
// 1. Generate geometry buffers
glGenBuffers(1, &_vbo) ;
glGenBuffers(1, &_nbo) ;
glGenBuffers(1, &_ebo) ;
glGenVertexArrays(1, &_vao) ;
// 2. Bind Vertex Array Object
glBindVertexArray(_vao);
// 3. Copy our vertices array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _vertices.size()*sizeof (GLfloat), _vertices.data(), GL_STATIC_DRAW);
// 4. Then set our vertex attributes pointers
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// 5. Copy our normals array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, _nbo);
glBufferData(GL_ARRAY_BUFFER, _normals.size()*sizeof (GLfloat), _normals.data(), GL_STATIC_DRAW);
// 6. Copy our vertices array in a buffer for OpenGL to use
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
// 7. Copy our index array in a element buffer for OpenGL to use
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices.size()*sizeof (GLfloat), _indices.data(), GL_STATIC_DRAW);
//6. Unbind the VAO
glBindVertexArray(0);
// Camera Initialization
_cameraselector.push_back( []()->Camera*{return new EulerCamera(glm::vec3(0.f, 0.f, 1.f));} );
_cameraselector.push_back( []()->Camera*{return new TrackballCamera(glm::vec3(0.f, 0.f, 1.f),glm::vec3(0.f, 1.f, 0.f),glm::vec3(0.f, 0.f, 0.f));} );
_camera.reset(_cameraselector[_activecamera]());
_camera->setviewport(glm::vec4(0.f, 0.f, _width, _height));
_view = _camera->viewmatrix();
_projection = glm::perspective(_camera->zoom(), float(_width) / _height, 0.1f, 100.0f);
generateProgram();
glUseProgram(_program);
}
SimpleSphere::~SimpleSphere() {}
void SimpleSphere::resize(int width, int height){
Scene::resize(width, height);
_camera->setviewport(glm::vec4(0.f, 0.f, _width, _height));
}
void SimpleSphere::draw() {
// Set OpenGL Render Mode
Scene::draw();
// Recompute program
if(_lastVertex != _w->vertexShader || _lastFragment != _w->fragmentShader) {
generateProgram();
glUseProgram(_program);
}
// Uniforms
glUniform3f(glGetUniformLocation(_program, "center"), 0.0f, 0.0f, 0.0f);
glUniform1f(glGetUniformLocation(_program, "radius"), _radius);
glUniform1f(glGetUniformLocation(_program, "errorMax"), _errorMax);
glUniform3f(glGetUniformLocation(_program, "cameraView"), _camera->_front.x, _camera->_front.y, _camera->_front.z);
// Camera
_view = _camera->viewmatrix();
glUniformMatrix4fv( glGetUniformLocation(_program, "model"), 1, GL_FALSE, glm::value_ptr(_model));
glUniformMatrix4fv( glGetUniformLocation(_program, "view"), 1, GL_FALSE, glm::value_ptr(_view));
glUniformMatrix4fv( glGetUniformLocation(_program, "projection"), 1, GL_FALSE, glm::value_ptr(_projection));
// Draw the shape
glBindVertexArray(_vao);
glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
void SimpleSphere::mouseclick(int button, float xpos, float ypos) {
_button = button;
_mousex = xpos;
_mousey = ypos;
_camera->processmouseclick(_button, xpos, ypos);
}
void SimpleSphere::mousemove(float xpos, float ypos) {
_camera->processmousemovement(_button, xpos, ypos, true);
}
void SimpleSphere::keyboardmove(int key, double time) {
_camera->processkeyboard(Camera_Movement(key), time);
}
bool SimpleSphere::keyboard(unsigned char k) {
switch(k) {
case 'p':
_activecamera = (_activecamera+1)%2;
_camera.reset(_cameraselector[_activecamera]());
_camera->setviewport(glm::vec4(0.f, 0.f, _width, _height));
return true;
default:
return false;
}
}
void SimpleSphere::generateProgram() {
// Change last shader variables
_lastVertex = _w->vertexShader;
_lastFragment = _w->fragmentShader;
// Initialize shaders
GLint success;
GLchar infoLog[512]; // warning fixed size ... request for LOG_LENGTH!!!
GLuint vertexshader, fragmentshader;
/* VERTEX SHADER */
// 1. Generate the shader
vertexshader = glCreateShader(GL_VERTEX_SHADER);
// 2. set the source
auto pointerVertex = _w->vertexShaders[_w->vertexShader].c_str();
glShaderSource(vertexshader, 1, &pointerVertex, NULL);
// 3. Compile
glCompileShader(vertexshader);
// 4. test for compile error
glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &success);
if(!success) {
glGetShaderInfoLog(vertexshader, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
/* FRAGMENT SHADER */
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
auto pointerFragment = _w->fragmentShaders[_w->fragmentShader].c_str();
glShaderSource(fragmentshader, 1, &pointerFragment, NULL);
glCompileShader(fragmentshader);
glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &success);
if(!success) {
glGetShaderInfoLog(fragmentshader, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
/* Program Object */
// 1. Generate the program
_program = glCreateProgram();
// 2. Attach the shaders to the program
glAttachShader(_program, vertexshader);
glAttachShader(_program, fragmentshader);
// 3. Link the program
glLinkProgram(_program);
// 4. Test for link errors
glGetProgramiv(_program, GL_LINK_STATUS, &success);
if(!success) {
glGetProgramInfoLog(_program, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::LINK_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexshader);
glDeleteShader(fragmentshader);
}
void SimpleSphere::drawCube(float size) {
// Initialise geometric data
_vertices = {
-size, -size, -size,
size, -size, -size,
size, size, -size,
-size, size, -size,
-size, -size, size,
size, -size, size,
size, size, size,
-size, size, size,
};
_normals = {
-size, -size, -size,
size, -size, -size,
size, size, -size,
-size, size, -size,
-size, -size, size,
size, -size, size,
size, size, size,
-size, size, size,
};
_indices = {
// Note that we start from 0!
0, 1, 2, // First Triangle
0, 2, 3, // Second Triangle
1, 5, 6,
1, 6, 2,
4, 0, 3,
4, 3, 7,
5, 4, 7,
5, 7, 6,
0, 1, 5,
0, 5, 4,
3, 2, 6,
3, 6, 7
};
return;
}
void SimpleSphere::drawUVSphere(int resolution, float radius) {
// Rubans et méridiens
for(int u = 0; u < resolution; ++u) {
float theta = float(u) / float(resolution) * 2.f * M_PI;
for (int v = 1; v < resolution; ++v) {
float phi = (float(v) / float(resolution) * M_PI) - M_PI_2;
/* Vertices */
// Compute coordonates
float x = radius * cos(theta) * cos(phi);
float y = radius * sin(phi);
float z = radius * sin(theta) * cos(phi);
// Add to vector
_vertices.push_back(x);
_vertices.push_back(y);
_vertices.push_back(z);
// Normals
glm::vec3 vertex = glm::vec3(x, y, z);
glm::vec3 normal = glm::normalize(vertex);
_normals.push_back(normal.x);
_normals.push_back(normal.y);
_normals.push_back(normal.z);
}
}
// Indices
for(int u = 0; u < resolution; ++u) {
for(int v = 0; v < resolution - 2; ++v) {
int sommetA = u * (resolution - 1) + v;
int sommetB = ((u+1) % resolution) * (resolution - 1) + v;
int sommetC = (u * (resolution - 1) + v + 1);
int sommetD = ((u+1) % resolution) * (resolution - 1) + v + 1;
// Triangle 1
_indices.push_back(sommetA);
_indices.push_back(sommetD);
_indices.push_back(sommetB);
// Triangle 2
_indices.push_back(sommetA);
_indices.push_back(sommetC);
_indices.push_back(sommetD);
}
}
/* Pôles */
for(int i = 0; i < 2; i++) {
// Vertices
float x = 0.f;
float y = round(i - 0.5) * radius;
float z = 0.f;
_vertices.push_back(x);
_vertices.push_back(y);
_vertices.push_back(z);
// Normals
glm::vec3 vertex = glm::vec3(x, y, z);
glm::vec3 normal = glm::normalize(vertex);
_normals.push_back(normal[0]);
_normals.push_back(normal[1]);
_normals.push_back(normal[2]);
// Indices
for(int j = 0; j < resolution; ++j) {
unsigned int sommetA = _vertices.size() / 3 - 1;
unsigned int sommetB = i * (resolution-2) + j * (resolution - 1);
unsigned int sommetC = i * (resolution-2) + ((j + 1) % resolution) * (resolution - 1);
if (i)
_indices.insert(_indices.end(), {sommetA, sommetC, sommetB});
else
_indices.insert(_indices.end(), {sommetA, sommetB, sommetC});
}
}
// Erreur max pour le shader de différence
// L'erreur max se situe au centre d'un quadrilatère sur les bandes de l'équateur
// Ce centre équivaut au centre de l'arête qui consitue la diagonale de ce quadrilatère
uint indexSommetA = (_indices.at(_indices.size() / 2) + 1) * 3;
uint indexSommetB = (_indices.at(_indices.size() / 2) + 2) * 3;
glm::vec3 sommetA = glm::vec3(_vertices.at(indexSommetA), _vertices.at(indexSommetA+1),_vertices.at(indexSommetA+2));
glm::vec3 sommetB = glm::vec3(_vertices.at(indexSommetB), _vertices.at(indexSommetB+1),_vertices.at(indexSommetB+2));
glm::vec3 centre = (sommetA + sommetB) / 2.0f;
_errorMax = abs( glm::length(centre) - _radius) / _radius;
}
void SimpleSphere::drawIcoSphere(int resolution, float radius) {
/* Constantes */
float phi = (1.f + sqrt(5.f)) / 2.f;
// r = a/2 * sqrt(2+phi)
// => a = 2*r / sqrt(2+phi)
// Or constante = a/2 donc a = r / sqrt(2+phi)
float a = radius / sqrt(2.f + phi);
/* Vertices */
// Rectangle 1
for(int i = 0; i < 4; i++) {
float x = round((i/2)%2 - 0.5f) * a * phi;
float y = round((i%2) - 0.5f) * a;
float z = 0.f;
_vertices.push_back(x);
_vertices.push_back(y);
_vertices.push_back(z);
glm::vec3 vertex = glm::vec3(x, y ,z);
glm::vec3 normal = glm::normalize(vertex);
_normals.push_back(normal[0]);
_normals.push_back(normal[1]);
_normals.push_back(normal[2]);
}
// Rectangle 2 (1, 0, a)
for(int i = 0; i < 4; i++) {
float x = round((i%2) - 0.5f) * a;
float y = 0.f;
float z = round((i/2)%2 - 0.5f) * a * phi;
_vertices.push_back(x);
_vertices.push_back(y);
_vertices.push_back(z);
glm::vec3 vertex = glm::vec3(x, y, z);
glm::vec3 normal = glm::normalize(vertex);
_normals.push_back(normal[0]);
_normals.push_back(normal[1]);
_normals.push_back(normal[2]);
}
// Rectangle 3 (0, phi, 1)
for(int i = 0; i < 4; i++) {
float x = 0.f;
float y = round((i/2)%2 - 0.5f) * a * phi;
float z = round((i%2) - 0.5f) * a;
_vertices.push_back(x);
_vertices.push_back(y);
_vertices.push_back(z);
glm::vec3 vertex = glm::vec3(x, y, z);
glm::vec3 normal = glm::normalize(vertex);
_normals.push_back(normal[0]);
_normals.push_back(normal[1]);
_normals.push_back(normal[2]);
}
/* Indices */
_indices.insert(_indices.end(), { 6, 7, 11});
_indices.insert(_indices.end(), { 6, 9, 7});
_indices.insert(_indices.end(), { 7, 3, 11});
_indices.insert(_indices.end(), { 7, 9, 2});
_indices.insert(_indices.end(), { 7, 2, 3});
_indices.insert(_indices.end(), { 5, 3, 2});
_indices.insert(_indices.end(), { 5, 10, 3});
_indices.insert(_indices.end(), { 5, 2, 8});
_indices.insert(_indices.end(), { 5, 4, 10});
_indices.insert(_indices.end(), { 5, 8, 4});
_indices.insert(_indices.end(), { 4, 1, 10});
_indices.insert(_indices.end(), { 4, 8, 0});
_indices.insert(_indices.end(), { 4, 0, 1});
_indices.insert(_indices.end(), { 6, 1, 0});
_indices.insert(_indices.end(), { 1, 6, 11});
_indices.insert(_indices.end(), { 0, 9, 6});
_indices.insert(_indices.end(), { 9, 0, 8});
_indices.insert(_indices.end(), { 9, 8, 2});
_indices.insert(_indices.end(), { 10, 1, 11});
_indices.insert(_indices.end(), { 10, 11, 3});
/* Subdivision */
for (int i = 1; i < resolution; ++i) {
std::vector<GLuint> _newIndices;
// 1. Calculer les points entre chaque arête
// Stockés dans une map dont la clé est la paire d'arêtes, et la valeur l'indice du sommet
std::map<std::pair<int, int>, uint> mapAreteSommet;
// Parcours des triangles
for (unsigned int j = 0; j < _indices.size(); j+=3) {
uint indexSommetA = _indices[j];
uint indexSommetB = _indices[j+1];
uint indexSommetC = _indices[j+2];
uint indexSommetAB, indexSommetBC, indexSommetCA;
// Calcul du point entre le sommet A et le sommet B
// Récupération de l'indice existant pour le point éventuellement déjà calculé
if(mapAreteSommet.count(std::pair<int, int> {indexSommetA, indexSommetB}) != 0)
indexSommetAB = mapAreteSommet.at(std::pair<int, int> {indexSommetA, indexSommetB});
else if(mapAreteSommet.count(std::pair<int, int> {indexSommetB, indexSommetA}) != 0)
indexSommetAB = mapAreteSommet.at(std::pair<int, int> {indexSommetB, indexSommetA});
// Sinon création du point
else {
// Calcul de la coordonnée du point à la moité de l'arête
glm::vec3 sommetA = glm::vec3(_vertices[indexSommetA*3], _vertices[indexSommetA*3+1], _vertices[indexSommetA*3+2]);
glm::vec3 sommetB = glm::vec3(_vertices[indexSommetB*3], _vertices[indexSommetB*3+1], _vertices[indexSommetB*3+2]);
glm::vec3 sommetAB = (sommetA + sommetB) / 2.0f;
// Repositionnement du point sur la sphère hypothétique
float vertexDistance = glm::length(sommetAB);
sommetAB *= radius / vertexDistance;
// Insertion dans les vector _vertices et _indices
_vertices.insert(_vertices.end(), {sommetAB.x, sommetAB.y, sommetAB.z});
_normals.insert(_normals.end(), {sommetAB.x, sommetAB.y, sommetAB.z});
indexSommetAB = _vertices.size() / 3 - 1;
mapAreteSommet[std::pair<int, int> {indexSommetA, indexSommetB}] = indexSommetAB;
}
// Calcul du point entre le sommet B et le sommet C
// Récupération de l'indice existant pour le point éventuellement déjà calculé
if(mapAreteSommet.count(std::pair<int, int> {indexSommetB, indexSommetC}) != 0)
indexSommetBC = mapAreteSommet.at(std::pair<int, int> {indexSommetB, indexSommetC});
else if(mapAreteSommet.count(std::pair<int, int> {indexSommetC, indexSommetB}) != 0)
indexSommetBC = mapAreteSommet.at(std::pair<int, int> {indexSommetC, indexSommetB});
// Sinon création du point
else {
// Calcul de la coordonnée du point à la moité de l'arête
glm::vec3 sommetB = glm::vec3(_vertices[indexSommetB*3], _vertices[indexSommetB*3+1], _vertices[indexSommetB*3+2]);
glm::vec3 sommetC = glm::vec3(_vertices[indexSommetC*3], _vertices[indexSommetC*3+1], _vertices[indexSommetC*3+2]);
glm::vec3 sommetBC = (sommetB + sommetC) / 2.0f;
// Repositionnement du point sur la sphère hypothétique
float vertexDistance = glm::length(sommetBC);
sommetBC *= radius / vertexDistance;
// Insertion dans les vector _vertices et _indices
_vertices.insert(_vertices.end(), {sommetBC.x, sommetBC.y, sommetBC.z});
_normals.insert(_normals.end(), {sommetBC.x, sommetBC.y, sommetBC.z});
indexSommetBC = _vertices.size() / 3 - 1;
mapAreteSommet[std::pair<int, int> {indexSommetB, indexSommetC}] = indexSommetBC;
}
// Calcul du point entre le sommet C et le sommet A
// Récupération de l'indice existant pour le point éventuellement déjà calculé
if(mapAreteSommet.count(std::pair<int, int> {indexSommetC, indexSommetA}) != 0)
indexSommetCA = mapAreteSommet.at(std::pair<int, int> {indexSommetC, indexSommetA});
else if(mapAreteSommet.count(std::pair<int, int> {indexSommetA, indexSommetC}) != 0)
indexSommetCA = mapAreteSommet.at(std::pair<int, int> {indexSommetA, indexSommetC});
// Sinon création du point
else {
glm::vec3 sommetC = glm::vec3(_vertices[indexSommetC*3], _vertices[indexSommetC*3+1], _vertices[indexSommetC*3+2]);
glm::vec3 sommetA = glm::vec3(_vertices[indexSommetA*3], _vertices[indexSommetA*3+1], _vertices[indexSommetA*3+2]);
// Calcul de la coordonnée du point à la moité de l'arête
glm::vec3 sommetCA = (sommetC + sommetA) / 2.0f;
// Repositionnement du point sur la sphère hypothétique
float vertexDistance = glm::length(sommetCA);
sommetCA *= radius / vertexDistance;
// Insertion dans les vector _vertices et _indices
_vertices.insert(_vertices.end(), {sommetCA.x, sommetCA.y, sommetCA.z});
_normals.insert(_normals.end(), {sommetCA.x, sommetCA.y, sommetCA.z});
indexSommetCA = _vertices.size() / 3 - 1;
mapAreteSommet[std::pair<int, int> {indexSommetC, indexSommetA}] = indexSommetCA;
}
// Création des nouveaux triangles
_newIndices.insert(_newIndices.end(), { indexSommetA, indexSommetAB, indexSommetCA});
_newIndices.insert(_newIndices.end(), {indexSommetAB, indexSommetB, indexSommetBC});
_newIndices.insert(_newIndices.end(), {indexSommetBC, indexSommetC, indexSommetCA});
_newIndices.insert(_newIndices.end(), {indexSommetAB, indexSommetBC, indexSommetCA});
}
// Remplacer le tableau d'incides
_indices.swap(_newIndices);
}
// Erreur max pour le shader de différence
// L'erreur max se situe au centre d'un triangle de l'icosaèdre
uint indexSommetA = _indices.at(0) * 3;
uint indexSommetB = _indices.at(1) * 3;
uint indexSommetC = _indices.at(2) * 3;
glm::vec3 sommetA = glm::vec3(_vertices.at(indexSommetA), _vertices.at(indexSommetA+1),_vertices.at(indexSommetA+2));
glm::vec3 sommetB = glm::vec3(_vertices.at(indexSommetB), _vertices.at(indexSommetB+1),_vertices.at(indexSommetB+2));
glm::vec3 sommetC = glm::vec3(_vertices.at(indexSommetC), _vertices.at(indexSommetC+1),_vertices.at(indexSommetC+2));
glm::vec3 centre = (sommetA + sommetB + sommetC) / 3.0f;
_errorMax = abs( glm::length(centre) - _radius) / _radius;
}

View file

@ -0,0 +1,71 @@
#ifndef HELLOSPHERE_H
#define HELLOSPHERE_H
#include "scene.h"
#include "hello_camera/camera.h"
#include "mainwindow.h"
#include <memory>
#include <functional>
/** Simple drawing demonstration
*/
class SimpleSphere : public Scene {
public:
explicit SimpleSphere(int width, int height, MainWindow* w);
~SimpleSphere();
void resize(int width, int height) override;
void draw() override;
void mouseclick(int button, float xpos, float ypos) override;
void mousemove(float xpos, float ypos) override;
void keyboardmove(int key, double time) override;
bool keyboard(unsigned char k) override;
public slots:
void generateProgram();
private:
// A simple geometry
std::vector<GLfloat> _vertices;
std::vector<GLfloat> _normals;
std::vector<GLuint> _indices;
// OpenGL object for geometry
GLuint _vao;
GLuint _vbo;
GLuint _nbo;
GLuint _ebo;
// Shader program for rendering
QString _lastVertex;
QString _lastFragment;
GLuint _program;
// for mouse management
int _button; // 0 --> left. 1 --> right. 2 --> middle. 3 --> other
float _mousex{0};
float _mousey{0};
// Camera
using CameraSelector=std::function<Camera*()>;
std::vector<CameraSelector> _cameraselector;
int _activecamera;
std::unique_ptr<Camera> _camera;
// Matrices
glm::mat4 _model;
glm::mat4 _view;
glm::mat4 _projection;
// Shape Methods
void drawCube(float size = 0.1f);
void drawUVSphere(int resolution = 5, float radius = 0.5f);
void drawIcoSphere(int resolution = 5, float radius = 0.f);
float _radius = 0.5f;
float _errorMax = 0.0f;
};
#endif // HELLOSPHERE_H

View file

@ -0,0 +1,172 @@
#include "hellotriangles.h"
#include <iostream>
static const char* vertexshader_source ="#version 410 core\n\
layout (location = 0) in vec3 position;\n\
layout (location = 1) in vec3 inormal;\n\
out vec3 normal;\n\
void main()\n\
{\n\
normal=inormal;\n\
gl_Position = vec4(position.x, position.y, position.z, 1.0);\n\
}\n";
static const char* fragmentshader_source ="#version 410 core\n\
in vec3 normal;\n\
out vec4 color;\n\
void main()\n\
{\n\
color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n\
}\n";
static const char* fragmentshadernormal_source ="#version 410 core\n\
in vec3 normal;\n\
out vec4 color;\n\
void main()\n\
{\n\
color = vec4(normal*0.5+0.5, 1.0f);\n\
}\n";
SimpleTriangle::SimpleTriangle(int width, int height, MainWindow* w) : Scene(width, height, w) {
// Initialise geometric data
_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
};
_normals = {
0.577350269189626f, 0.577350269189626f, 0.577350269189626f,
0.577350269189626f, -0.577350269189626f, 0.577350269189626f,
-0.577350269189626f, -0.577350269189626f, 0.577350269189626f,
-0.577350269189626f, 0.577350269189626f, 0.577350269189626f
};
_indices = {
// Note that we start from 0!
0, 1, 3, // First Triangle
1, 2, 3 // Second Triangle
};
// Initialize the geometry
// 1. Generate geometry buffers
glGenBuffers(1, &_vbo) ;
glGenBuffers(1, &_nbo) ;
glGenBuffers(1, &_ebo) ;
glGenVertexArrays(1, &_vao) ;
// 2. Bind Vertex Array Object
glBindVertexArray(_vao);
// 3. Copy our vertices array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _vertices.size()*sizeof (GLfloat), _vertices.data(), GL_STATIC_DRAW);
// 4. Then set our vertex attributes pointers
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// 5. Copy our normals array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, _nbo);
glBufferData(GL_ARRAY_BUFFER, _normals.size()*sizeof (GLfloat), _normals.data(), GL_STATIC_DRAW);
// 6. Copy our vertices array in a buffer for OpenGL to use
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
// 7. Copy our index array in a element buffer for OpenGL to use
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices.size()*sizeof (GLfloat), _indices.data(), GL_STATIC_DRAW);
//6. Unbind the VAO
glBindVertexArray(0);
// Initialize shaders
GLint success;
GLchar infoLog[512]; // warning fixed size ... request for LOG_LENGTH!!!
GLuint vertexshader, fragmentshader;
// 1. Generate the shader
vertexshader = glCreateShader(GL_VERTEX_SHADER);
// 2. set the source
glShaderSource(vertexshader, 1, &vertexshader_source, NULL);
// 3. Compile
glCompileShader(vertexshader);
// 4. test for compile error
glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &success);
if(!success) {
glGetShaderInfoLog(vertexshader, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentshader, 1, &fragmentshader_source, NULL);
glCompileShader(fragmentshader);
glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &success);
if(!success) {
glGetShaderInfoLog(fragmentshader, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// 1. Generate the program
_programcolor = _program = glCreateProgram();
// 2. Attach the shaders to the program
glAttachShader(_program, vertexshader);
glAttachShader(_program, fragmentshader);
// 3. Link the program
glLinkProgram(_program);
// 4. Test for link errors
glGetProgramiv(_program, GL_LINK_STATUS, &success);
if(!success) {
glGetProgramInfoLog(_program, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::LINK_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(fragmentshader);
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentshader, 1, &fragmentshadernormal_source, NULL);
glCompileShader(fragmentshader);
glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &success);
if(!success) {
glGetShaderInfoLog(fragmentshader, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// 1. Generate the program
_programnormal = glCreateProgram();
// 2. Attach the shaders to the program
glAttachShader(_programnormal, vertexshader);
glAttachShader(_programnormal, fragmentshader);
// 3. Link the program
glLinkProgram(_programnormal);
// 4. Test for link errors
glGetProgramiv(_programnormal, GL_LINK_STATUS, &success);
if(!success) {
glGetProgramInfoLog(_programnormal, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::LINK_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(fragmentshader);
glDeleteShader(vertexshader);
}
SimpleTriangle::~SimpleTriangle() {
}
void SimpleTriangle::draw() {
Scene::draw();
glUseProgram(_program);
glBindVertexArray(_vao);
glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
bool SimpleTriangle::keyboard(unsigned char k) {
switch(k) {
case 'c' :
_program = _programcolor;
return true;
case 'n' :
_program = _programnormal;
return true;
default:
return false;
}
}

View file

@ -0,0 +1,42 @@
#ifndef SIMPLETRIANGLE_H
#define SIMPLETRIANGLE_H
#include "scene.h"
#include "mainwindow.h"
/** Simple drawing demonstration
*/
class SimpleTriangle : public Scene {
public:
explicit SimpleTriangle(int width, int height, MainWindow* w);
~SimpleTriangle();
void draw() override;
bool keyboard(unsigned char k) override;
private:
// A simple geometry
std::vector<GLfloat> _vertices;
std::vector<GLfloat> _normals;
std::vector<GLuint> _indices;
// OpenGL object for geometry
// Vertex Array Buffer
GLuint _vao;
// Vertex Buffer Object
GLuint _vbo;
// Normal buffer
GLuint _nbo;
// Face buffer
GLuint _ebo;
// Shader program for rendering
GLuint _program;
// Different availableprograms
GLuint _programcolor;
GLuint _programnormal;
};
#endif // SIMPLETRIANGLE_H

11
src/main.cpp Normal file
View file

@ -0,0 +1,11 @@
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

99
src/mainwindow.cpp Normal file
View file

@ -0,0 +1,99 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QDir>
#include <iostream>
#include <sstream>
#include <iomanip>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
QSurfaceFormat format;
format.setVersion(4, 1);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setDepthBufferSize(24);
QSurfaceFormat::setDefaultFormat(format);
ui->setupUi(this);
// Add shaders
addShaders();
ui->openglWidget->setFocus();
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::on_action_Version_OpenGL_triggered() {
std::stringstream message;
message << "Renderer : " << glGetString(GL_RENDERER) << std::endl;
message << "Vendor : " << glGetString(GL_VENDOR) << std::endl;
message << "Version : " << glGetString(GL_VERSION) << std::endl;
message << "GLSL Version : " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
QMessageBox::information(this, "OpenGL Information", message.str().c_str());
}
void MainWindow::on_actionHello_clear_triggered() {
ui->openglWidget->activatedemo(0);
}
void MainWindow::on_actionHello_triangle_triggered() {
ui->openglWidget->activatedemo(1);
}
void MainWindow::on_actionHello_camera_triggered() {
ui->openglWidget->activatedemo(2);
}
void MainWindow::on_actionHello_spheres_triggered() {
ui->openglWidget->activatedemo(3);
}
void MainWindow::on_actionToggle_Back_Face_Culling_triggered(bool checked)
{
culling = checked;
}
void MainWindow::addShaders() {
// Compile shaders Maps
QDir shadersDir = QDir("../src/shader/");
std::cout << "Loading shaders from: " << shadersDir.absolutePath().toStdString() << std::endl;
QStringList shadersPath = shadersDir.entryList(QDir::Files);
for(auto it = shadersPath.cbegin(); it != shadersPath.cend(); ++it) {
QString name(*it);
name.remove(".glsl");
QStringList shader = name.split("_");
//std::cout << shadersDir.absoluteFilePath(*it).toStdString() << std::endl;
QFile shaderFile(shadersDir.absoluteFilePath(*it));
shaderFile.open(QIODevice::ReadOnly | QIODevice::Text);
if(shader.at(0) == "vs")
vertexShaders.insert(shader.at(1), shaderFile.readAll().data());
else
fragmentShaders.insert(shader.at(1), shaderFile.readAll().data());
shaderFile.close();
std::cout << "Added shader: " << shader.at(1).toStdString() << std::endl;
}
if(vertexShaders.empty() || fragmentShaders.empty())
std::cerr << "Not enough shaders found. Please provide vertex AND fragment shaders." << std::endl;
// Add Shaders Maps to menu
ui->menuShaders->addSection("Vertex");
auto it = vertexShaders.constBegin();
while(it != vertexShaders.constEnd()) {
ui->menuShaders->addAction(it++.key(), [=](){ this->vertexShader = it.key(); std::cout << "Changed vertex shader to " << it.key().toStdString() << std::endl; });
}
ui->menuShaders->addSeparator();
ui->menuShaders->addSection("Fragment");
it = fragmentShaders.constBegin();
while(it != fragmentShaders.constEnd()) {
ui->menuShaders->addAction(it++.key(), [=](){ this->fragmentShader = it.key(); std::cout << "Changed fragment shader to " << it.key().toStdString() << std::endl; });
}
// Set default shaders
vertexShader = vertexShaders.constBegin().key();
fragmentShader = fragmentShaders.constBegin().key();
}

42
src/mainwindow.h Normal file
View file

@ -0,0 +1,42 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMap>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QString vertexShader;
QString fragmentShader;
QMap<QString, std::string> vertexShaders;
QMap<QString, std::string> fragmentShaders;
bool culling = true;
private slots:
void on_action_Version_OpenGL_triggered();
void on_actionHello_triangle_triggered();
void on_actionHello_camera_triggered();
void on_actionHello_spheres_triggered();
void on_actionHello_clear_triggered();
void on_actionToggle_Back_Face_Culling_triggered(bool checked);
private:
Ui::MainWindow *ui;
void addShaders();
};
#endif // MAINWINDOW_H

116
src/mainwindow.ui Normal file
View file

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>667</height>
</rect>
</property>
<property name="windowTitle">
<string>Hello OpenGL ...</string>
</property>
<widget class="MyOpenGLWidget" name="openglWidget">
<property name="minimumSize">
<size>
<width>800</width>
<height>600</height>
</size>
</property>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>25</height>
</rect>
</property>
<widget class="QMenu" name="menuInfo">
<property name="title">
<string>Info</string>
</property>
<addaction name="action_Version_OpenGL"/>
</widget>
<widget class="QMenu" name="menu_Demo">
<property name="title">
<string>&amp;Demo</string>
</property>
<addaction name="actionHello_clear"/>
<addaction name="actionHello_triangle"/>
<addaction name="actionHello_camera"/>
<addaction name="actionHello_spheres"/>
</widget>
<widget class="QMenu" name="menuShaders">
<property name="title">
<string>Shaders</string>
</property>
<addaction name="actionToggle_Back_Face_Culling"/>
<addaction name="separator"/>
</widget>
<addaction name="menu_Demo"/>
<addaction name="menuShaders"/>
<addaction name="menuInfo"/>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<action name="action_Version_OpenGL">
<property name="text">
<string>&amp;Version OpenGL</string>
</property>
</action>
<action name="actionHello_triangle">
<property name="text">
<string>Hello triangle ...</string>
</property>
</action>
<action name="actionHello_camera">
<property name="text">
<string>Hello camera ...</string>
</property>
</action>
<action name="actionHello_spheres">
<property name="text">
<string>Hello spheres ...</string>
</property>
</action>
<action name="actionHello_clear">
<property name="text">
<string>Hello clear ...</string>
</property>
</action>
<action name="actionToggle_Back_Face_Culling">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Toggle backface culling</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>MyOpenGLWidget</class>
<extends>QWidget</extends>
<header>myopenglwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

117
src/myopenglwidget.cpp Normal file
View file

@ -0,0 +1,117 @@
#include "myopenglwidget.h"
#include <QMessageBox>
#include <QApplication>
#include <QDateTime>
#include <iostream>
#include <stdexcept>
#include "hello_triangles/hellotriangles.h"
#include "hello_camera/hellocamera.h"
#include "hello_spheres/hellosphere.h"
MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) :QOpenGLWidget(parent), QOpenGLFunctions_4_1_Core(), _scene(nullptr), _lastime(0) {
// add all demo constructors here
_democonstructors.push_back( [](int width, int height, MainWindow* w)->Scene*{std::cout << "Hello clear ..." << std::endl; return new Scene(width, height, w);} );
_democonstructors.push_back( [](int width, int height, MainWindow* w)->Scene*{std::cout << "Hello triangles ..." << std::endl; return new SimpleTriangle(width, height, w);} );
_democonstructors.push_back( [](int width, int height, MainWindow* w)->Scene*{std::cout << "Hello camera ..." << std::endl; return new SimpleCamera(width, height, w);} );
_democonstructors.push_back( [](int width, int height, MainWindow* w)->Scene*{std::cout << "Hello sphere ..." << std::endl; return new SimpleSphere(width, height, w);} );
}
MyOpenGLWidget::~MyOpenGLWidget() {
}
void MyOpenGLWidget::initializeGL() {
if (!initializeOpenGLFunctions()) {
QMessageBox::critical(this, "OpenGL initialization error", "MyOpenGLWidget::initializeGL() : Unable to initialize OpenGL functions");
exit(1);
}
// Initialize OpenGL and all OpenGL dependent stuff below
_scene.reset(_democonstructors[3](width(), height(), (MainWindow*) this->parent()));
}
void MyOpenGLWidget::paintGL() {
std::int64_t starttime = QDateTime::currentMSecsSinceEpoch();
_scene->draw();
glFinish();
std::int64_t endtime = QDateTime::currentMSecsSinceEpoch();
_lastime = endtime-starttime;
}
void MyOpenGLWidget::resizeGL(int width, int height) {
_scene->resize(width, height);
}
void MyOpenGLWidget::mousePressEvent(QMouseEvent *event) {
// buttons are 0(left), 1(right) to 2(middle)
int b;
Qt::MouseButton button=event->button();
if (button & Qt::LeftButton) {
if ((event->modifiers() & Qt::ControlModifier))
b = 2;
else
b = 0;
} else if (button & Qt::RightButton)
b = 1;
else if (button & Qt::MiddleButton)
b = 2;
else
b=3;
_scene->mouseclick(b, event->x(), event->y());
_lastime = QDateTime::currentMSecsSinceEpoch();
}
void MyOpenGLWidget::mouseMoveEvent(QMouseEvent *event) {
_scene->mousemove(event->x(), event->y());
update();
}
void MyOpenGLWidget::keyPressEvent(QKeyEvent *event) {
switch(event->key()) {
// Demo keys
case Qt::Key_0:
case Qt::Key_1:
case Qt::Key_2:
case Qt::Key_3:
case Qt::Key_4:
case Qt::Key_5:
case Qt::Key_6:
case Qt::Key_7:
case Qt::Key_8:
case Qt::Key_9:
activatedemo(event->key()-Qt::Key_0);
break;
// Move keys
case Qt::Key_Left:
case Qt::Key_Up:
case Qt::Key_Right:
case Qt::Key_Down:
_scene->keyboardmove(event->key()-Qt::Key_Left, 1./100/*double(_lastime)/10.*/);
update();
break;
// Wireframe key
case Qt::Key_W:
_scene->toggledrawmode();
update();
break;
// Other keys are transmitted to the scene
default :
if (_scene->keyboard(event->text().toStdString()[0]))
update();
break;
}
}
void MyOpenGLWidget::activatedemo(unsigned int numdemo) {
if (numdemo < _democonstructors.size()) {
std::cout << "Activating demo " << numdemo << " : ";
makeCurrent();
_scene.reset(_democonstructors[numdemo](width(), height(), (MainWindow*) this->parent()));
doneCurrent();
update();
}
}

46
src/myopenglwidget.h Normal file
View file

@ -0,0 +1,46 @@
#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_1_Core>
#include <QKeyEvent>
#include <memory>
#include <functional>
#include "scene.h"
class MyOpenGLWidget : public QOpenGLWidget, public QOpenGLFunctions_4_1_Core {
public:
explicit MyOpenGLWidget(QWidget *parent = 0);
~MyOpenGLWidget();
// OpenGL management
void initializeGL() override;
void paintGL() override;
void resizeGL(int width, int height) override;
// Event maagement
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
// Demo management
void activatedemo(unsigned int numdemo);
private :
std::unique_ptr<Scene> _scene;
using DemoConstructors=std::function<Scene*(int, int, MainWindow*)>;
std::vector<DemoConstructors> _democonstructors;
// for event management
std::int64_t _lastime;
};
#endif // MYOPENGLWIDGET_H

102
src/opengl_stuff.h Normal file
View file

@ -0,0 +1,102 @@
#ifndef OPENGL_STUFF_H
#define OPENGL_STUFF_H
#ifdef __APPLE__
#include <OpenGL/gl3.h>
#include <OpenGL/gl3ext.h>
#else
#define GL_GLEXT_PROTOTYPES 1
#include <GL/gl.h>
#include <GL/glext.h>
#endif
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
/**
@author Mathias Paulin <Mathias.Paulin@irit.fr>
*
* OpenGL error management class.
*
*/
#ifndef NDEBUG
//#error "NDEBUG NOT DEFINED "
// Breakpoints
// This macro will trigger a breakpoint where it is placed. With MSVC a dialog
// will ask you if you want to launch the debugger.
#define BREAKPOINT(ARG) asm volatile ("int $3")
#include <iostream>
#include <cassert>
#define glAssert(code) \
code; \
{\
GLuint err = glGetError(); \
if (err != GL_NO_ERROR) { \
std::cerr<<"erreur OpenGL ("<<__FILE__<<":"<<__LINE__<<", "<<__STRING(code)<<") :"<<\
( (err == GL_INVALID_ENUM) ? " Invalid enum : An unacceptable value is specified for an enumerated argument. The offending command is ignored and has no other side effect than to set the error flag.\n" : \
( (err == GL_INVALID_VALUE) ? " Invalid value : A numeric argument is out of range. The offending command is ignored and has no other side effect than to set the error flag.\n" : \
( (err == GL_INVALID_OPERATION) ? " Invalid operation : The specified operation is not allowed in the current state. The offending command is ignored and has no other side effect than to set the error flag.\n" : \
( (err == GL_INVALID_FRAMEBUFFER_OPERATION) ? " Invalid framebuffer operation : The framebuffer object is not complete. The offending command is ignored and has no other side effect than to set the error flag.\n" : \
( (err == GL_OUT_OF_MEMORY) ? " Out of memory : There is not enough memory left to execute the command. The state of the GL is undefined, except for the state of the error flags, after this error is recorded.\n" : \
/* ( (err == GL_STACK_UNDERFLOW) ? " Stack underflow : An attempt has been made to perform an operation that would cause an internal stack to underflow.\n" : \
( (err == GL_STACK_OVERFLOW) ? " Stack overflow : An attempt has been made to perform an operation that would cause an internal stack to overflow.\n" : */\
nullptr) \
/* )\
)\
*/ )\
)\
)\
)\
<< " ("<<err<<")"<<std::endl; \
BREAKPOINT(0);\
/*assert(false);*/ /*int*b=nullptr; *b=0;*/\
} \
}
#define glCheckError() \
{\
GLuint err = glGetError(); \
if (err != GL_NO_ERROR) { \
std::cerr<<"erreur OpenGL ("<<__FILE__<<":"<<__LINE__<<") :"<<\
( (err == GL_INVALID_ENUM) ? " Invalid enum : An unacceptable value is specified for an enumerated argument. The offending command is ignored and has no other side effect than to set the error flag.\n" : \
( (err == GL_INVALID_VALUE) ? " Invalid value : A numeric argument is out of range. The offending command is ignored and has no other side effect than to set the error flag.\n" : \
( (err == GL_INVALID_OPERATION) ? " Invalid operation : The specified operation is not allowed in the current state. The offending command is ignored and has no other side effect than to set the error flag.\n" : \
( (err == GL_INVALID_FRAMEBUFFER_OPERATION) ? " Invalid framebuffer operation : The framebuffer object is not complete. The offending command is ignored and has no other side effect than to set the error flag.\n" : \
( (err == GL_OUT_OF_MEMORY) ? " Out of memory : There is not enough memory left to execute the command. The state of the GL is undefined, except for the state of the error flags, after this error is recorded.\n" : \
/* ( (err == GL_STACK_UNDERFLOW) ? " Stack underflow : An attempt has been made to perform an operation that would cause an internal stack to underflow.\n" : \
( (err == GL_STACK_OVERFLOW) ? " Stack overflow : An attempt has been made to perform an operation that would cause an internal stack to overflow.\n" : */\
nullptr) \
/* )\
)\
*/ )\
)\
)\
)\
<< " ("<<err<<")"<<std::endl; \
BREAKPOINT(0);\
/*assert(false);*/ /*int*b=nullptr; *b=0; */\
} \
}
#else
//#error "NDEBUG DEFINED "
#define glAssert(code) \
code;
#define glCheckError()
#endif
// #undef NDEBUG
#endif // OPENGL_STUFF_H

57
src/scene.cpp Normal file
View file

@ -0,0 +1,57 @@
#include "scene.h"
#include <iostream>
Scene::Scene(int width, int height, MainWindow* w) : _width(width), _height(height), _w(w), _drawfill(true) {
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, width, height);
}
Scene::~Scene() {
}
void Scene::resize(int width, int height) {
_width = width;
_height = height;
glViewport(0, 0, width, height);
}
void Scene::draw() {
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // Gris foncé
glClear(GL_COLOR_BUFFER_BIT);
// Activer ou non le back face culling
if (_w->culling)
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
// Mode de rendu: sommets, arêtes ou faces
switch(_drawfill) {
case 0: glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
case 1: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
case 2: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
}
}
void Scene::mouseclick(int , float , float ) {
}
void Scene::mousemove(float , float ) {
}
void Scene::keyboardmove(int , double ) {
}
bool Scene::keyboard(unsigned char ) {
return false;
}
void Scene::toggledrawmode() {
_drawfill = (_drawfill + 1) % 3;
}

39
src/scene.h Normal file
View file

@ -0,0 +1,39 @@
#ifndef SCENE_H
#define SCENE_H
#include <vector>
#include "opengl_stuff.h"
#include "mainwindow.h"
/** Simple classe for managing an OpenGL scene
*/
class Scene {
public:
explicit Scene(int width, int height, MainWindow* w);
virtual ~Scene();
virtual void resize(int width, int height);
virtual void draw();
virtual void mouseclick(int button, float xpos, float ypos);
virtual void mousemove(float xpos, float ypos);
virtual void keyboardmove(int key, double time);
virtual bool keyboard(unsigned char k);
void toggledrawmode();
protected:
// Width and heigth of the viewport
int _width;
int _height;
MainWindow* _w;
private:
// Rendering mode
int _drawfill = 1;
};
#endif // SCENE_H

View file

@ -0,0 +1,56 @@
#version 410 core
in vec3 position;
in vec3 normal;
uniform vec3 cameraView;
out vec4 color;
// Couleurs
vec3 materialColor = vec3( 0.4, 1, 0.6);
vec3 specularColor = vec3( 1, 1, 1);
vec3 lightColor = vec3(0.95, 0.98, 1);
// Position de la lumière
vec3 frontLightPos = vec3( 0, 0, 1);
float specCoef = 128;
/* Bibliographie:
* https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model
* http://www.opengl-tutorial.org/fr/beginners-tutorials/tutorial-8-basic-shading/
*/
void main(void)
{
vec3 frontLight = frontLightPos - position;
float distance = pow(length(frontLight), 2);
frontLight = normalize(frontLight);
vec3 normalizedNormal = normalize(normal);
// Paramètres de réflexion initiaux
float lambertian = max(dot(frontLight, normalizedNormal), 0.0);
float specularFactor = 0;
/* Ambient: simule l'éclairage indirect */
vec3 ambient = vec3(0.15, 0.15, 0.15) * materialColor;
/* Diffuse: "couleur" de l'objet dans la zone illuminée */
// Cosinus entre la normale et la direction de la lumière (positif)
// - lumière à la verticale = 1
// - lumière perpendiculaire ou derrière = 0
float cosTheta = clamp( dot( normalizedNormal, frontLight ), 0, 1 );
vec3 diffuse = materialColor * lightColor * cosTheta;
/* Specular: réflexion */
if (lambertian > 0.0) {
vec3 viewDir = normalize(-cameraView);
vec3 halfDir = normalize(frontLight + viewDir);
float specAngle = max(dot(halfDir, normalizedNormal), 0.0);
specularFactor = pow(specAngle, specCoef);
}
vec3 specular = specularColor * lightColor * specularFactor;
/* Couleur = Ambient + Diffuse + Specular */
color = vec4(ambient + diffuse + specular, 1);
}

View file

@ -0,0 +1,33 @@
#version 410 core
in vec3 position;
uniform vec3 center;
uniform float radius;
uniform float errorMax;
out vec4 color;
void main()
{
// Colors
vec4 bleu = vec4(0.094, 0, 1.0, 1.0);
vec4 vert = vec4(0.07, 1.0, 0, 1.0);
vec4 jaune = vec4(0.94, 1.0, 0, 1.0);
vec4 rouge = vec4(1.0, 0, 0, 1.0);
// Compute Value
float value = smoothstep(0.0, errorMax, abs(length(center - position) - radius) / radius);
color = bleu; // Init color
// Heatmap gradient
if (value < 0.85) {
value = smoothstep(0.0, 0.85, value);
color = mix(bleu, vert, value);
}
else if (value < 0.95) {
value = smoothstep(0.85, 0.95, value);
color = mix(vert, jaune, value);
}
else {
value = smoothstep(0.95, 1.0, value);
color = mix(jaune, rouge, value);
}
}

View file

@ -0,0 +1,7 @@
#version 410 core
in vec3 normal;
out vec4 color;
void main()
{
color = vec4(vec3(clamp(dot(normalize(normal), vec3(0, 0,1)), 0, 1)), 1.0);
}

View file

@ -0,0 +1,7 @@
#version 410 core
in vec3 normal;
out vec4 color;
void main()
{
color = vec4(normalize(normal)*0.5+0.5, 1.0);
}

View file

@ -0,0 +1,15 @@
#version 410 core
layout (location = 0) in vec3 iposition;
layout (location = 1) in vec3 inormal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec3 normal;
out vec3 position;
void main()
{
// Note that we read the multiplication from right to left
gl_Position = projection * view * model * vec4(iposition, 1.0f);
normal = inormal;
position = iposition;
}