diff options
author | ccolin | 2020-12-28 17:36:45 +0100 |
---|---|---|
committer | ccolin | 2020-12-28 17:36:45 +0100 |
commit | f3a34665978729ef65010ac2a4a9408e27d5bf3e (patch) | |
tree | e8f4d6f2402c9b7113e33684f64b82a98d990313 /src/opengl_widget.cc | |
parent | ef37119f4e94c83a6357ebc0b94a39e4e53b20d7 (diff) |
skybox
Diffstat (limited to 'src/opengl_widget.cc')
-rw-r--r-- | src/opengl_widget.cc | 257 |
1 files changed, 149 insertions, 108 deletions
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 <QMouseEvent> - - -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; +#include "load_obj.hh" -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 <QMouseEvent> +#include <QOpenGLBuffer> 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<GLfloat> 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<QImage> 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(); + } |