Initial Commit
This commit is contained in:
commit
54eaed1ca0
284 changed files with 55022 additions and 0 deletions
251
src/hello_camera/camera.cpp
Normal file
251
src/hello_camera/camera.cpp
Normal 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
146
src/hello_camera/camera.h
Normal 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
|
188
src/hello_camera/hellocamera.cpp
Normal file
188
src/hello_camera/hellocamera.cpp
Normal 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;
|
||||
}
|
||||
}
|
64
src/hello_camera/hellocamera.h
Normal file
64
src/hello_camera/hellocamera.h
Normal 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
|
507
src/hello_spheres/hellosphere.cpp
Normal file
507
src/hello_spheres/hellosphere.cpp
Normal 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;
|
||||
}
|
71
src/hello_spheres/hellosphere.h
Normal file
71
src/hello_spheres/hellosphere.h
Normal 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
|
172
src/hello_triangles/hellotriangles.cpp
Normal file
172
src/hello_triangles/hellotriangles.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
42
src/hello_triangles/hellotriangles.h
Normal file
42
src/hello_triangles/hellotriangles.h
Normal 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
11
src/main.cpp
Normal 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
99
src/mainwindow.cpp
Normal 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
42
src/mainwindow.h
Normal 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
116
src/mainwindow.ui
Normal 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>&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>&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
117
src/myopenglwidget.cpp
Normal 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
46
src/myopenglwidget.h
Normal 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
102
src/opengl_stuff.h
Normal 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
57
src/scene.cpp
Normal 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
39
src/scene.h
Normal 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
|
56
src/shader/fs_blinnPhong.glsl
Normal file
56
src/shader/fs_blinnPhong.glsl
Normal 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);
|
||||
}
|
33
src/shader/fs_difference.glsl
Normal file
33
src/shader/fs_difference.glsl
Normal 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);
|
||||
}
|
||||
}
|
7
src/shader/fs_diffuse.glsl
Normal file
7
src/shader/fs_diffuse.glsl
Normal 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);
|
||||
}
|
7
src/shader/fs_normals.glsl
Normal file
7
src/shader/fs_normals.glsl
Normal 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);
|
||||
}
|
15
src/shader/vs_default.glsl
Normal file
15
src/shader/vs_default.glsl
Normal 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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue