diff --git a/mdl/black.jpg b/img/black.jpg similarity index 100% rename from mdl/black.jpg rename to img/black.jpg diff --git a/img/clouds1_down (copie).jpg b/img/clouds1_down (copie).jpg new file mode 100644 index 0000000..de818e6 Binary files /dev/null and b/img/clouds1_down (copie).jpg differ diff --git a/img/clouds1_down.jpg b/img/clouds1_down.jpg new file mode 100644 index 0000000..e34c8af Binary files /dev/null and b/img/clouds1_down.jpg differ diff --git a/img/clouds1_east.jpg b/img/clouds1_east.jpg new file mode 100644 index 0000000..fdf2cb5 Binary files /dev/null and b/img/clouds1_east.jpg differ diff --git a/img/clouds1_north.jpg b/img/clouds1_north.jpg new file mode 100644 index 0000000..9a27454 Binary files /dev/null and b/img/clouds1_north.jpg differ diff --git a/img/clouds1_south.jpg b/img/clouds1_south.jpg new file mode 100644 index 0000000..84d0fca Binary files /dev/null and b/img/clouds1_south.jpg differ diff --git a/img/clouds1_up (copie).jpg b/img/clouds1_up (copie).jpg new file mode 100644 index 0000000..ac8ead2 Binary files /dev/null and b/img/clouds1_up (copie).jpg differ diff --git a/img/clouds1_up.jpg b/img/clouds1_up.jpg new file mode 100644 index 0000000..f45663a Binary files /dev/null and b/img/clouds1_up.jpg differ diff --git a/img/clouds1_west.jpg b/img/clouds1_west.jpg new file mode 100644 index 0000000..8c8306b Binary files /dev/null and b/img/clouds1_west.jpg differ diff --git a/mdl/dji600.jpg b/img/dji600.jpg similarity index 100% rename from mdl/dji600.jpg rename to img/dji600.jpg diff --git a/mdl/ground.jpg b/img/ground.jpg similarity index 100% rename from mdl/ground.jpg rename to img/ground.jpg diff --git a/mdl/mdl.jpg b/img/mdl.jpg similarity index 100% rename from mdl/mdl.jpg rename to img/mdl.jpg diff --git a/mdl/cube.obj b/mdl/cube.obj new file mode 100644 index 0000000..de4003f --- /dev/null +++ b/mdl/cube.obj @@ -0,0 +1,30 @@ +# Blender v2.90.1 OBJ File: '' +# www.blender.org +o Cube +v -1.000000 -1.000000 1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 0.0000 +s off +f 2//1 3//1 1//1 +f 4//2 7//2 3//2 +f 8//3 5//3 7//3 +f 6//4 1//4 5//4 +f 7//5 1//5 3//5 +f 4//6 6//6 8//6 +f 2//1 4//1 3//1 +f 4//2 8//2 7//2 +f 8//3 6//3 5//3 +f 6//4 2//4 1//4 +f 7//5 5//5 1//5 +f 4//6 2//6 6//6 diff --git a/projet.pro b/projet.pro index 78954f1..f7e12ef 100644 --- a/projet.pro +++ b/projet.pro @@ -11,8 +11,10 @@ SOURCES += src/main_window.cc SOURCES += src/opengl_mesh.cc SOURCES += src/opengl_widget.cc SOURCES += src/drone_controller.cc +SOURCES += src/load_obj.cc HEADERS += src/main_window.hh HEADERS += src/opengl_mesh.hh HEADERS += src/opengl_widget.hh HEADERS += src/drone_controller.hh +HEADERS += src/load_obj.hh diff --git a/resources.qrc b/resources.qrc index 8facd60..2ff2adf 100644 --- a/resources.qrc +++ b/resources.qrc @@ -3,10 +3,20 @@ mdl/dji600.obj mdl/dji600.mtl - mdl/dji600.jpg - mdl/test.obj - mdl/test.mtl - mdl/black.jpg - mdl/ground.jpg + mdl/cube.obj + + img/dji600.jpg + img/ground.jpg + img/clouds1_up.jpg + img/clouds1_down.jpg + img/clouds1_north.jpg + img/clouds1_east.jpg + img/clouds1_south.jpg + img/clouds1_west.jpg + + shaders/main.vert + shaders/main.frag + shaders/skybox.vert + shaders/skybox.frag diff --git a/shaders/main.frag b/shaders/main.frag new file mode 100644 index 0000000..8eb47ec --- /dev/null +++ b/shaders/main.frag @@ -0,0 +1,20 @@ +#version 330 core + +in vec3 norm; +in vec2 uv; +in vec3 frag_pos; + +out vec4 final_col; + +uniform sampler2D tex; + +void main() { + vec3 light_col = vec3(1, .964, .783); + vec3 ambient = light_col * .2; + + vec3 light_dir = normalize(vec3(5, 10, -8)); + float diff = max(dot(normalize(norm), light_dir), 0.0); + vec3 diffuse = diff * light_col; + + final_col = texture(tex, uv) * vec4(ambient + diffuse, 1); +} diff --git a/shaders/main.vert b/shaders/main.vert new file mode 100644 index 0000000..33e6849 --- /dev/null +++ b/shaders/main.vert @@ -0,0 +1,20 @@ +#version 330 core + +layout(location = 0) in vec3 in_pos; +layout(location = 1) in vec3 in_norm; +layout(location = 2) in vec2 in_uv; + +out vec3 norm; +out vec2 uv; +out vec3 frag_pos; + +uniform mat4 proj; +uniform mat4 view; +uniform mat4 model; + +void main() { + gl_Position = proj * view * model * vec4(in_pos, 1.0); + norm = in_norm; + uv = in_uv; + frag_pos = vec3(model * vec4(in_pos, 1.0)); +} diff --git a/shaders/skybox.frag b/shaders/skybox.frag new file mode 100644 index 0000000..f5f8edb --- /dev/null +++ b/shaders/skybox.frag @@ -0,0 +1,23 @@ +#version 330 core + +// in vec3 tex_coord; + +// out vec4 final_col; + +// uniform samplerCube skybox; + +// void main() { +// // final_col = texture(skybox, tex_coord); +// final_col = vec4(0, 0, 0, 1); +// } + +in vec3 tex_coords; + +out vec4 final_col; + +uniform samplerCube tex; + +void main() { + final_col = texture(tex, tex_coords); + // final_col = vec4(1, 0, 1, 1); +} diff --git a/shaders/skybox.vert b/shaders/skybox.vert new file mode 100644 index 0000000..ac4ac5e --- /dev/null +++ b/shaders/skybox.vert @@ -0,0 +1,28 @@ +#version 330 core + +// layout(location = 0) in vec3 in_pos; + +// out vec3 tex_coords; + +// uniform mat4 proj; +// uniform mat4 view; + +// void main() { +// // vec4 pos = proj * view * vec4(in_pos, 1.0); +// // gl_Position = pos.xyww; +// gl_Position = proj * vec4(in_pos, 1.0); +// tex_coords = in_pos; +// } + +layout(location = 0) in vec3 in_pos; + +out vec3 tex_coords; + +uniform mat4 proj; +uniform mat4 view; + +void main() { + tex_coords = in_pos; + vec4 pos = proj * mat4(mat3(view)) * vec4(in_pos, 1.0); + gl_Position = pos.xyww; +} diff --git a/src/drone_controller.cc b/src/drone_controller.cc index c41721e..9a6c5db 100644 --- a/src/drone_controller.cc +++ b/src/drone_controller.cc @@ -1,8 +1,6 @@ #include "drone_controller.hh" #include "opengl_widget.hh" - -#define TINYOBJLOADER_IMPLEMENTATION -#include "tiny_obj_loader.h" +#include "load_obj.hh" #include #include @@ -26,62 +24,8 @@ OpenGLMesh *Drone::mesh = nullptr; Drone::Drone() { if (!mesh_initialized) { - QFile obj_file(":/mdl/dji600.obj"); - QFile mtl_file(":/mdl/dji600.mtl"); - obj_file.open(QIODevice::ReadOnly | QIODevice::Text); - mtl_file.open(QIODevice::ReadOnly | QIODevice::Text); - std::string obj = obj_file.readAll().toStdString(); - std::string mtl = mtl_file.readAll().toStdString(); - tinyobj::ObjReaderConfig cfg; - cfg.triangulate = true; - cfg.vertex_color = false; - tinyobj::ObjReader reader; - if (!reader.ParseFromString(obj, mtl, cfg)) { - if (!reader.Error().empty()) { - qWarning() << "Erreur lors de la lecture de du modèle"; - } - exit(1); - } - // if (!reader.Warning().empty()) { - // qWarning() << "TinyObjReader: " << reader.Warning(); - // } - auto& attrib = reader.GetAttrib(); - auto& shapes = reader.GetShapes(); - - QVector verts; - - for (size_t s = 0; s < shapes.size(); s++) { - // Loop over faces(polygon) - size_t index_offset = 0; - for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) { - size_t fv = shapes[s].mesh.num_face_vertices[f]; - - // Loop over vertices in the face. - for (size_t v = 0; v < fv; v++) { - tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v]; - tinyobj::real_t vx = attrib.vertices[3*idx.vertex_index+0]; - tinyobj::real_t vy = attrib.vertices[3*idx.vertex_index+1]; - tinyobj::real_t vz = attrib.vertices[3*idx.vertex_index+2]; - tinyobj::real_t nx = attrib.normals[3*idx.normal_index+0]; - tinyobj::real_t ny = attrib.normals[3*idx.normal_index+1]; - tinyobj::real_t nz = attrib.normals[3*idx.normal_index+2]; - tinyobj::real_t ts = attrib.texcoords[2*idx.texcoord_index+0]; - tinyobj::real_t tt = attrib.texcoords[2*idx.texcoord_index+1]; - verts.append(vx); - verts.append(vy); - verts.append(vz); - verts.append(nx); - verts.append(ny); - verts.append(nz); - verts.append(ts); - verts.append(tt); - // qDebug() << "vert" << vx << vy << vz << "tex" << ts << tt; - } - index_offset += fv; - } - } - - QOpenGLTexture *texture = new QOpenGLTexture(QImage(":/mdl/dji600.jpg").mirrored()); + QVector verts = load_obj(":/mdl/dji600.obj", LOAD_OBJ_NORMALS | LOAD_OBJ_UVS); + QOpenGLTexture *texture = new QOpenGLTexture(QImage(":/img/dji600.jpg").mirrored()); // texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); // texture->setMagnificationFilter(QOpenGLTexture::Linear); mesh = new OpenGLMesh(verts, texture); @@ -147,7 +91,7 @@ DroneController::DroneController(const QJsonObject &json) } OpenGLWidget::instance->makeCurrent(); - QOpenGLTexture *ground_tex = new QOpenGLTexture(QImage(":/mdl/ground.jpg").mirrored()); + QOpenGLTexture *ground_tex = new QOpenGLTexture(QImage(":/img/ground.jpg").mirrored()); OpenGLMesh *ground = new OpenGLMesh({ -100, 0, -100, 0, 1, 0, 0, 0, 100, 0, -100, 0, 1, 0, 1, 0, @@ -158,6 +102,7 @@ DroneController::DroneController(const QJsonObject &json) }, ground_tex); OpenGLWidget::instance->meshes.append(*ground); OpenGLWidget::instance->doneCurrent(); + connect(&timer, &QTimer::timeout, this, &DroneController::step); } diff --git a/src/load_obj.cc b/src/load_obj.cc new file mode 100644 index 0000000..2e079f0 --- /dev/null +++ b/src/load_obj.cc @@ -0,0 +1,68 @@ +#include "load_obj.hh" + +#define TINYOBJLOADER_IMPLEMENTATION +#include "tiny_obj_loader.h" +#include +#include + + +QVector load_obj(const char *path, int flags) { + QFile obj_file(path); + obj_file.open(QIODevice::ReadOnly | QIODevice::Text); + std::string obj = obj_file.readAll().toStdString(); + tinyobj::ObjReaderConfig cfg; + cfg.triangulate = true; + cfg.vertex_color = false; + tinyobj::ObjReader reader; + if (!reader.ParseFromString(obj, "", cfg)) { + if (!reader.Error().empty()) { + qWarning() << "Erreur lors de la lecture de du modèle"; + } + exit(1); + } + // if (!reader.Warning().empty()) { + // qWarning() << "TinyObjReader: " << reader.Warning(); + // } + auto& attrib = reader.GetAttrib(); + auto& shapes = reader.GetShapes(); + + QVector verts; + + for (size_t s = 0; s < shapes.size(); s++) { + // Loop over faces(polygon) + size_t index_offset = 0; + for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) { + size_t fv = shapes[s].mesh.num_face_vertices[f]; + + // Loop over vertices in the face. + for (size_t v = 0; v < fv; v++) { + tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v]; + tinyobj::real_t vx = attrib.vertices[3*idx.vertex_index+0]; + tinyobj::real_t vy = attrib.vertices[3*idx.vertex_index+1]; + tinyobj::real_t vz = attrib.vertices[3*idx.vertex_index+2]; + verts.append(vx); + verts.append(vy); + verts.append(vz); + + if (flags & LOAD_OBJ_NORMALS) { + tinyobj::real_t nx = attrib.normals[3*idx.normal_index+0]; + tinyobj::real_t ny = attrib.normals[3*idx.normal_index+1]; + tinyobj::real_t nz = attrib.normals[3*idx.normal_index+2]; + verts.append(nx); + verts.append(ny); + verts.append(nz); + } + + if (flags & LOAD_OBJ_UVS) { + tinyobj::real_t ts = attrib.texcoords[2*idx.texcoord_index+0]; + tinyobj::real_t tt = attrib.texcoords[2*idx.texcoord_index+1]; + verts.append(ts); + verts.append(tt); + } + // qDebug() << "vert" << vx << vy << vz << "tex" << ts << tt; + } + index_offset += fv; + } + } + return verts; +} diff --git a/src/load_obj.hh b/src/load_obj.hh new file mode 100644 index 0000000..089d4b5 --- /dev/null +++ b/src/load_obj.hh @@ -0,0 +1,13 @@ +#ifndef LOAD_OBJ_HH +#define LOAD_OBJ_HH + +#include +#include + +#define LOAD_OBJ_NORMALS 1 << 0 +#define LOAD_OBJ_UVS 1 << 1 + +QVector load_obj(const char *path, int flags); + + +#endif diff --git a/src/opengl_mesh.cc b/src/opengl_mesh.cc index 6e1ff72..f2f0981 100644 --- a/src/opengl_mesh.cc +++ b/src/opengl_mesh.cc @@ -10,8 +10,8 @@ OpenGLMesh::OpenGLMesh(QVector verts, QOpenGLTexture *tex) QOpenGLFunctions_4_4_Core *glf = OpenGLWidget::instance; nverts = verts.size() / 8; glf->glGenVertexArrays(1, &vao); - glf->glGenBuffers(1, &vbo); glf->glBindVertexArray(vao); + glf->glGenBuffers(1, &vbo); glf->glBindBuffer(GL_ARRAY_BUFFER, vbo); glf->glBufferData(GL_ARRAY_BUFFER, nverts * 8 * sizeof (float), verts.data(), GL_STATIC_DRAW); glf->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof (float), 0); diff --git a/src/opengl_widget.cc b/src/opengl_widget.cc index 42bc612..8d7cab5 100644 --- a/src/opengl_widget.cc +++ b/src/opengl_widget.cc @@ -1,53 +1,9 @@ #include "opengl_widget.hh" +#include "load_obj.hh" + #include - - -static const GLchar *vertex_shader_source = R"glsl( -#version 330 core - -layout(location = 0) in vec3 in_pos; -layout(location = 1) in vec3 in_norm; -layout(location = 2) in vec2 in_uv; - -out vec3 norm; -out vec2 uv; -out vec3 frag_pos; - -uniform mat4 proj; -uniform mat4 view; -uniform mat4 model; - -void main() { - gl_Position = proj * view * model * vec4(in_pos, 1.0); - norm = in_norm; - uv = in_uv; - frag_pos = vec3(model * vec4(in_pos, 1.0)); -} -)glsl"; - -static const GLchar *fragment_shader_source = R"glsl( -#version 330 core - -in vec3 norm; -in vec2 uv; -in vec3 frag_pos; - -out vec4 final_col; - -uniform sampler2D tex; - -void main() { - vec3 light_col = vec3(1, .964, .783); - vec3 ambient = light_col * .2; - - vec3 light_dir = normalize(vec3(5, 10, -8)); - float diff = max(dot(normalize(norm), light_dir), 0.0); - vec3 diffuse = diff * light_col; - - final_col = texture(tex, uv) * vec4(ambient + diffuse, 1); -} -)glsl"; +#include static void GLAPIENTRY opengl_debug_cb(GLenum source, GLenum type, GLuint id, @@ -56,7 +12,10 @@ static void GLAPIENTRY opengl_debug_cb(GLenum source, GLenum type, GLuint id, const void* userParam) { (void) source; (void) type; (void) id; (void) severity; (void) length; (void) userParam; - qDebug() << "OpenGL debug output:" << message; + // Those are a bit too verbose + if (!QString((const char *) message).startsWith("Shader Stats:")) { + qDebug() << "OpenGL debug output:" << message; + } } @@ -74,6 +33,93 @@ OpenGLWidget::~OpenGLWidget() { } +void OpenGLWidget::loadSkybox() { + if (!skybox_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/skybox.vert")) { + qFatal("Error compiling skybox.vert: %s", skybox_program.log().toLocal8Bit().constData()); + } + if (!skybox_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/skybox.frag")) { + qFatal("Error compiling skybox.frag: %s", skybox_program.log().toLocal8Bit().constData()); + } + if (!skybox_program.link()) { + qFatal("Error linking the skybox shader program: %s", skybox_program.log().toLocal8Bit().constData()); + } + skybox_program.bind(); + skybox_program.setUniformValue("skybox", 0); + + // GLfloat skybox_verts[] = { + // -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, + // -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, + // 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, + // -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, + // -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, + // -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0 + // }; + QVector skybox_verts = load_obj(":/mdl/cube.obj", 0); + + // OpenGL native VAO version + glGenVertexArrays(1, &skybox_vao); + glBindVertexArray(skybox_vao); + glGenBuffers(1, &skybox_vbo); + glBindBuffer(GL_ARRAY_BUFFER, skybox_vbo); + glBufferData(GL_ARRAY_BUFFER, skybox_verts.size() * sizeof (GLfloat), skybox_verts.data(), GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(0); + glBindVertexArray(0); + + // // QOpenGLVertexArrayObject version + // skybox_vao.create(); + // skybox_vao.bind(); + // QOpenGLBuffer skybox_vbo(QOpenGLBuffer::VertexBuffer); + // skybox_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw); + // skybox_vbo.allocate((void *) skybox_verts.data(), skybox_verts.size() * sizeof (GLfloat)); + // skybox_program.setAttributeBuffer(0, GL_FLOAT, 0, 3, 0); + // skybox_program.enableAttributeArray(0); + + // Skybox texture images + QVector skybox_img { + QImage(":/img/clouds1_west.jpg").convertToFormat(QImage::Format_RGB888), + QImage(":/img/clouds1_east.jpg").convertToFormat(QImage::Format_RGB888), + QImage(":/img/clouds1_up.jpg").convertToFormat(QImage::Format_RGB888), + QImage(":/img/clouds1_down.jpg").convertToFormat(QImage::Format_RGB888), + QImage(":/img/clouds1_south.jpg").convertToFormat(QImage::Format_RGB888), + QImage(":/img/clouds1_north.jpg").convertToFormat(QImage::Format_RGB888) + }; + size_t width = skybox_img[0].width(); + size_t height = skybox_img[0].height(); + + // OpenGL native texture version + glGenTextures(1, &skybox_tex); + glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_tex); + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, + (const GLvoid *) skybox_img[i].constBits()); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + + // // QOpenGLTexture skybox texture version + // skybox_tex = new QOpenGLTexture(QOpenGLTexture::TargetCubeMap); + // skybox_tex->create(); + // skybox_tex->setSize(width, skybox_img[0].height(), height); + // skybox_tex->setFormat(QOpenGLTexture::RGBA8_UNorm); + // skybox_tex->allocateStorage(); + // for (int i = 0; i < 6; i++) { + // skybox_tex->setData(0, 0, (QOpenGLTexture::CubeMapFace) (QOpenGLTexture::CubeMapPositiveX + i), + // QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, + // (const void*) skybox_img[i].constBits(), 0); + // } + // skybox_tex->setWrapMode(QOpenGLTexture::ClampToEdge); + // skybox_tex->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); + // skybox_tex->setMagnificationFilter(QOpenGLTexture::LinearMipMapLinear); + + skybox_program.release(); +} + + void OpenGLWidget::initializeGL() { initializeOpenGLFunctions(); GLint major, minor; @@ -84,67 +130,22 @@ void OpenGLWidget::initializeGL() { glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(opengl_debug_cb, 0); - /* Compile the vertex shader. */ - GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL); - glCompileShader(vertex_shader); - GLint status; - glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &status); - if (status != GL_TRUE) { - char log[1024]; - glGetShaderInfoLog(vertex_shader, sizeof log, NULL, log); - fprintf(stderr, "Failed to compile the vertex shader: %s\n", log); - exit(1); + if (!main_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/main.vert")) { + qFatal("Error compiling main.vert: %s", main_program.log().toLocal8Bit().constData()); } - - /* Compile the fragment shader. */ - GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL); - glCompileShader(fragment_shader); - glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &status); - if (status != GL_TRUE) { - char log[1024]; - glGetShaderInfoLog(fragment_shader, sizeof log, NULL, log); - fprintf(stderr, "Failed to compile the fragment shader: %s\n", log); - exit(1); + if (!main_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/main.frag")) { + qFatal("Error compiling main.frag: %s", main_program.log().toLocal8Bit().constData()); } - - /* Link the shader program. */ - GLuint shader_program = glCreateProgram(); - glAttachShader(shader_program, vertex_shader); - glAttachShader(shader_program, fragment_shader); - glBindFragDataLocation(shader_program, 0, "final_col"); - glLinkProgram(shader_program); - glGetProgramiv(shader_program, GL_LINK_STATUS, &status); - if (status != GL_TRUE) { - char log[1024]; - glGetProgramInfoLog(shader_program, sizeof log, NULL, log); - fprintf(stderr, "Failed to link the shader program: %s\n", log); - exit(1); + if (!main_program.link()) { + qFatal("Error linking the main shader program: %s", main_program.log().toLocal8Bit().constData()); } + main_program.bind(); + main_program.setUniformValue("tex", 0); + main_program.release(); - /* Use it. */ - glUseProgram(shader_program); - - /* Get the position attribute. */ - pos_attr = glGetAttribLocation(shader_program, "pos"); - - proj_attr = glGetUniformLocation(shader_program, "proj"); - view_attr = glGetUniformLocation(shader_program, "view"); - model_attr = glGetUniformLocation(shader_program, "model"); - - QMatrix4x4 view; - view.translate(0, 0, 5); - glUniformMatrix4fv(view_attr, 1, GL_FALSE, view.data()); - - QMatrix4x4 trans; - trans.translate(0, 0, -5); - glUniformMatrix4fv(view_attr, 1, GL_FALSE, trans.data()); - - glUniform1i(glGetUniformLocation(shader_program, "tex"), 0); + loadSkybox(); glClearColor(1, 1, 1, 0); - glEnable(GL_DEPTH_TEST); glEnable(GL_MULTISAMPLE); @@ -153,9 +154,8 @@ void OpenGLWidget::initializeGL() { void OpenGLWidget::resizeGL(int w, int h) { - QMatrix4x4 projection; - projection.perspective(FOV, (float) w/h, .01, 1000); - glUniformMatrix4fv(proj_attr, 1, GL_FALSE, projection.data()); + proj.setToIdentity(); + proj.perspective(FOV, (float) w/h, .01, 1000); } @@ -164,14 +164,55 @@ void OpenGLWidget::paintGL() { QMatrix4x4 trans; trans.translate(0, 0, -cam_dist); QMatrix4x4 view = trans * rot; - glUniformMatrix4fv(view_attr, 1, GL_FALSE, view.data()); + + // skybox_vao.bind(); + // glActiveTexture(GL_TEXTURE0); + // glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_tex); + // // skybox_tex->bind(); + // glDrawArrays(GL_TRIANGLES, 0, 36); + // // skybox_tex->release(); + // skybox_vao.release(); + + glDepthMask(GL_FALSE); + glDepthFunc(GL_LEQUAL); + skybox_program.bind(); + skybox_program.setUniformValue("proj", proj); + skybox_program.setUniformValue("view", view); + // skybox_program.setUniformValue("model", QMatrix4x4()); + glBindVertexArray(skybox_vao); glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_tex); + // skybox_tex->bind(); + // skybox_vao.bind(); + glDrawArrays(GL_TRIANGLES, 0, 36); + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + // skybox_tex->release(); + skybox_program.release(); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LESS); + + main_program.bind(); + main_program.setUniformValue("proj", proj); + main_program.setUniformValue("view", view); + glActiveTexture(GL_TEXTURE0); + + // main_program.setUniformValue("model", QMatrix4x4()); + // skybox_vao.bind(); + // glDrawArrays(GL_TRIANGLES, 0, 36); + + // skybox_program.bind(); + // skybox_program.setUniformValue("proj", proj); + // skybox_program.setUniformValue("view", view); + for (const OpenGLMesh &mesh : meshes) { - glUniformMatrix4fv(model_attr, 1, GL_FALSE, mesh.mat.data()); + main_program.setUniformValue("model", mesh.mat); glBindVertexArray(mesh.vao); mesh.tex->bind(); glDrawArrays(GL_TRIANGLES, 0, mesh.nverts); + mesh.tex->release(); } + main_program.release(); + } diff --git a/src/opengl_widget.hh b/src/opengl_widget.hh index 9259784..5bd4a07 100644 --- a/src/opengl_widget.hh +++ b/src/opengl_widget.hh @@ -7,6 +7,8 @@ #include #include #include +#include +#include #define FOV 70 @@ -14,12 +16,21 @@ class OpenGLWidget : public QOpenGLWidget, public QOpenGLFunctions_4_4_Core { Q_OBJECT - GLuint pos_attr, proj_attr, view_attr, model_attr; - - QMatrix4x4 rot, rot_start; + QMatrix4x4 rot, rot_start, proj; GLfloat cam_dist = 1; QPoint mouse_pos; + QOpenGLShaderProgram main_program; + QOpenGLShaderProgram skybox_program; + // QOpenGLTexture *skybox_tex; + GLuint skybox_tex; + // QOpenGLVertexArrayObject skybox_vao; + // QOpenGLBuffer skybox_vbo; + GLuint skybox_vao; + GLuint skybox_vbo; + + void loadSkybox(); + protected: virtual void mousePressEvent(QMouseEvent *e); virtual void mouseReleaseEvent(QMouseEvent *e);