diff --git a/application/application.pro b/application/application.pro index be8926f1..d44db070 100644 --- a/application/application.pro +++ b/application/application.pro @@ -157,12 +157,12 @@ HEADERS += sources/mesh_result_post_processor.h SOURCES += sources/mesh_result_post_processor.cc HEADERS += sources/model.h SOURCES += sources/model.cc -HEADERS += sources/model_mesh_binder.h -SOURCES += sources/model_mesh_binder.cc HEADERS += sources/model_offscreen_render.h SOURCES += sources/model_offscreen_render.cc -HEADERS += sources/model_shader_program.h -SOURCES += sources/model_shader_program.cc +HEADERS += sources/model_opengl_program.h +SOURCES += sources/model_opengl_program.cc +HEADERS += sources/model_opengl_object.h +SOURCES += sources/model_opengl_object.cc HEADERS += sources/model_shader_vertex.h HEADERS += sources/model_widget.h SOURCES += sources/model_widget.cc diff --git a/application/shaders/model.frag b/application/shaders/model.frag index 3d871453..e69de29b 100644 --- a/application/shaders/model.frag +++ b/application/shaders/model.frag @@ -1,538 +0,0 @@ -#version 110 -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -float exposure; -float gamma; - -varying vec3 vert; -varying vec3 vertRaw; -varying vec3 vertNormal; -varying vec3 vertColor; -varying vec2 vertTexCoord; -varying float vertMetalness; -varying float vertRoughness; -varying vec3 cameraPos; -varying vec3 firstLightPos; -varying vec3 secondLightPos; -varying vec3 thirdLightPos; -varying float vertAlpha; -uniform sampler2D textureId; -uniform int textureEnabled; -uniform sampler2D normalMapId; -uniform int normalMapEnabled; -uniform sampler2D metalnessRoughnessAmbientOcclusionMapId; -uniform int metalnessMapEnabled; -uniform int roughnessMapEnabled; -uniform int ambientOcclusionMapEnabled; -uniform int mousePickEnabled; -uniform vec3 mousePickTargetPosition; -uniform float mousePickRadius; -uniform int toonShadingEnabled; -uniform int renderPurpose; -uniform int toonEdgeEnabled; -uniform float screenWidth; -uniform float screenHeight; -uniform sampler2D toonNormalMapId; -uniform sampler2D toonDepthMapId; - -const int MAX_LIGHTS = 8; -const int TYPE_POINT = 0; -const int TYPE_DIRECTIONAL = 1; -const int TYPE_SPOT = 2; -struct Light { - int type; - vec3 position; - vec3 color; - float intensity; - vec3 direction; - float constantAttenuation; - float linearAttenuation; - float quadraticAttenuation; - float cutOffAngle; -}; -int lightCount; -Light lights[MAX_LIGHTS]; - -float sobel_v[9]; -float sobel_h[9]; - -float normalEdgeSobel() -{ - sobel_v[0] = -1.0; - sobel_v[1] = 0.0; - sobel_v[2] = 1.0; - sobel_v[3] = -2.0; - sobel_v[4] = 0.0; - sobel_v[5] = 2.0; - sobel_v[6] = -1.0; - sobel_v[7] = 0.0; - sobel_v[8] = 1.0; - - sobel_h[0] = -1.0; - sobel_h[1] = -2.0; - sobel_h[2] = -1.0; - sobel_h[3] = 0.0; - sobel_h[4] = 0.0; - sobel_h[5] = 0.0; - sobel_h[6] = 1.0; - sobel_h[7] = 2.0; - sobel_h[8] = 1.0; - - // vec2 coord = gl_TexCoord[0].st; - vec2 coord = vec2(gl_FragCoord.x / screenWidth - 1.0, 1.0 - gl_FragCoord.y / screenHeight); - //float len = length(coord); - - float sx = 1.0 / screenWidth; - float sy = 1.0 / screenHeight; - float n[9]; - vec3 ref = vec3(1.0, 1.0, 1.0); - - n[0] = dot(texture2D(toonNormalMapId, vec2(coord.x - sx, coord.y - sy)).rgb, ref); - n[1] = dot(texture2D(toonNormalMapId, vec2(coord.x, coord.y - sy)).rgb, ref); - n[2] = dot(texture2D(toonNormalMapId, vec2(coord.x + sx, coord.y - sy)).rgb, ref); - n[3] = dot(texture2D(toonNormalMapId, vec2(coord.x - sx, coord.y)).rgb, ref); - n[4] = dot(texture2D(toonNormalMapId, vec2(coord.x, coord.y)).rgb, ref); - n[5] = dot(texture2D(toonNormalMapId, vec2(coord.x + sx, coord.y)).rgb, ref); - n[6] = dot(texture2D(toonNormalMapId, vec2(coord.x - sx, coord.y + sy)).rgb, ref); - n[7] = dot(texture2D(toonNormalMapId, vec2(coord.x, coord.y + sy)).rgb, ref); - n[8] = dot(texture2D(toonNormalMapId, vec2(coord.x + sx, coord.y + sy)).rgb, ref); - - float v, h; - - v = 0.0; - h = 0.0; - - for (int i = 0; i < 9; ++i) { - v += sobel_v[i] * n[i]; - h += sobel_h[i] * n[i]; - } - - float enhanceFactor = 1.0; - - float r = sqrt(v * v * enhanceFactor + h * h * enhanceFactor); - return smoothstep(0.0, 1.0, r); -} - -float depthEdgeSobel() -{ - sobel_v[0] = -1.0; - sobel_v[1] = 0.0; - sobel_v[2] = 1.0; - sobel_v[3] = -2.0; - sobel_v[4] = 0.0; - sobel_v[5] = 2.0; - sobel_v[6] = -1.0; - sobel_v[7] = 0.0; - sobel_v[8] = 1.0; - - sobel_h[0] = -1.0; - sobel_h[1] = -2.0; - sobel_h[2] = -1.0; - sobel_h[3] = 0.0; - sobel_h[4] = 0.0; - sobel_h[5] = 0.0; - sobel_h[6] = 1.0; - sobel_h[7] = 2.0; - sobel_h[8] = 1.0; - - // vec2 coord = gl_TexCoord[0].st; - vec2 coord = vec2(gl_FragCoord.x / screenWidth - 1.0, 1.0 - gl_FragCoord.y / screenHeight); - //float len = length(coord); - - float sx = 1.0 / screenWidth; - float sy = 1.0 / screenHeight; - float n[9]; - - n[0] = texture2D(toonDepthMapId, vec2(coord.x - sx, coord.y - sy)).r; - n[1] = texture2D(toonDepthMapId, vec2(coord.x, coord.y - sy)).r; - n[2] = texture2D(toonDepthMapId, vec2(coord.x + sx, coord.y - sy)).r; - n[3] = texture2D(toonDepthMapId, vec2(coord.x - sx, coord.y)).r; - n[4] = texture2D(toonDepthMapId, vec2(coord.x, coord.y)).r; - n[5] = texture2D(toonDepthMapId, vec2(coord.x + sx, coord.y)).r; - n[6] = texture2D(toonDepthMapId, vec2(coord.x - sx, coord.y + sy)).r; - n[7] = texture2D(toonDepthMapId, vec2(coord.x, coord.y + sy)).r; - n[8] = texture2D(toonDepthMapId, vec2(coord.x + sx, coord.y + sy)).r; - - float v, h; - - v = 0.0; - h = 0.0; - - for (int i = 0; i < 9; ++i) { - v += sobel_v[i] * n[i]; - h += sobel_h[i] * n[i]; - } - - float enhanceFactor = 10.0; - - float r = sqrt(v * v * enhanceFactor + h * h * enhanceFactor); - return smoothstep(0.0, 1.0, r); -} - -float remapRoughness(const in float roughness) -{ - // As per page 14 of - // http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - // we remap the roughness to give a more perceptually linear response - // of "bluriness" as a function of the roughness specified by the user. - // r = roughness^2 - float maxSpecPower; - float minRoughness; - maxSpecPower = 999999.0; - minRoughness = sqrt(2.0 / (maxSpecPower + 2.0)); - return max(roughness * roughness, minRoughness); -} - -float normalDistribution(const in vec3 n, const in vec3 h, const in float alpha) -{ - // Blinn-Phong approximation - see - // http://graphicrants.blogspot.co.uk/2013/08/specular-brdf-reference.html - float specPower = 2.0 / (alpha * alpha) - 2.0; - return (specPower + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), specPower); -} - -vec3 fresnelFactor(const in vec3 color, const in float cosineFactor) -{ - // Calculate the Fresnel effect value - vec3 f = color; - vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0); - return clamp(F, f, vec3(1.0)); -} - -float geometricModel(const in float lDotN, - const in float vDotN, - const in vec3 h) -{ - // Implicit geometric model (equal to denominator in specular model). - // This currently assumes that there is no attenuation by geometric shadowing or - // masking according to the microfacet theory. - return lDotN * vDotN; -} - -vec3 specularModel(const in vec3 F0, - const in float sDotH, - const in float sDotN, - const in float vDotN, - const in vec3 n, - const in vec3 h) -{ - // Clamp sDotN and vDotN to small positive value to prevent the - // denominator in the reflection equation going to infinity. Balance this - // by using the clamped values in the geometric factor function to - // avoid ugly seams in the specular lighting. - float sDotNPrime = max(sDotN, 0.001); - float vDotNPrime = max(vDotN, 0.001); - - vec3 F = fresnelFactor(F0, sDotH); - float G = geometricModel(sDotNPrime, vDotNPrime, h); - - vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); - return clamp(cSpec, vec3(0.0), vec3(1.0)); -} - -vec3 pbrModel(const in int lightIndex, - const in vec3 wPosition, - const in vec3 wNormal, - const in vec3 wView, - const in vec3 baseColor, - const in float metalness, - const in float alpha, - const in float ambientOcclusion) -{ - // Calculate some useful quantities - vec3 n = wNormal; - vec3 s = vec3(0.0); - vec3 v = wView; - vec3 h = vec3(0.0); - - float vDotN = dot(v, n); - float sDotN = 0.0; - float sDotH = 0.0; - float att = 1.0; - - if (lights[lightIndex].type != TYPE_DIRECTIONAL) { - // Point and Spot lights - vec3 sUnnormalized = vec3(lights[lightIndex].position) - wPosition; - s = normalize(sUnnormalized); - - // Calculate the attenuation factor - sDotN = dot(s, n); - if (sDotN > 0.0) { - if (lights[lightIndex].constantAttenuation != 0.0 - || lights[lightIndex].linearAttenuation != 0.0 - || lights[lightIndex].quadraticAttenuation != 0.0) { - float dist = length(sUnnormalized); - att = 1.0 / (lights[lightIndex].constantAttenuation + - lights[lightIndex].linearAttenuation * dist + - lights[lightIndex].quadraticAttenuation * dist * dist); - } - - // The light direction is in world space already - if (lights[lightIndex].type == TYPE_SPOT) { - // Check if fragment is inside or outside of the spot light cone - if (degrees(acos(dot(-s, lights[lightIndex].direction))) > lights[lightIndex].cutOffAngle) - sDotN = 0.0; - } - } - } else { - // Directional lights - // The light direction is in world space already - s = normalize(-lights[lightIndex].direction); - sDotN = dot(s, n); - } - - h = normalize(s + v); - sDotH = dot(s, h); - - // Calculate diffuse component - vec3 diffuseColor = (1.0 - metalness) * baseColor * lights[lightIndex].color; - vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159; - - // Calculate specular component - vec3 dielectricColor = vec3(0.04); - vec3 F0 = mix(dielectricColor, baseColor, metalness); - vec3 specularFactor = vec3(0.0); - if (sDotN > 0.0) { - specularFactor = specularModel(F0, sDotH, sDotN, vDotN, n, h); - specularFactor *= normalDistribution(n, h, alpha); - } - vec3 specularColor = lights[lightIndex].color; - vec3 specular = specularColor * specularFactor; - - // Blend between diffuse and specular to conserver energy - vec3 color = att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular)); - - // Reduce by ambient occlusion amount - color *= ambientOcclusion; - - return color; -} - -vec3 toneMap(const in vec3 c) -{ - return c / (c + vec3(1.0)); -} - -vec3 gammaCorrect(const in vec3 color) -{ - return pow(color, vec3(1.0 / gamma)); -} - -// http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl -vec3 rgb2hsv(vec3 c) -{ - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) -{ - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} - -vec4 metalRoughFunction(const in vec4 baseColor, - const in float metalness, - const in float roughness, - const in float ambientOcclusion, - const in vec3 worldPosition, - const in vec3 worldView, - const in vec3 worldNormal) -{ - vec3 cLinear = vec3(0.0); - - // Remap roughness for a perceptually more linear correspondence - float alpha = remapRoughness(roughness); - - if (toonShadingEnabled != 1) { - for (int i = 0; i < lightCount; ++i) { - cLinear += pbrModel(i, - worldPosition, - worldNormal, - worldView, - baseColor.rgb, - metalness, - alpha, - ambientOcclusion); - } - } else { - float intensity; - intensity = dot(vec3(1.0, 1.0, 1.0), worldNormal); - - vec3 hsv = rgb2hsv(baseColor.rgb); - if (intensity > 0.966) - cLinear = hsv2rgb(vec3(hsv.r, hsv.g, hsv.b * 2.0)); - else - cLinear = hsv2rgb(vec3(hsv.r, hsv.g, hsv.b * 0.1)); - - if (toonEdgeEnabled > 0) { - float depthEdge = depthEdgeSobel(); - float normalEdge = normalEdgeSobel(); - if (depthEdge >= 0.009 || normalEdge >= 0.7) { - cLinear = hsv2rgb(vec3(hsv.r, hsv.g, hsv.b * 0.02)); - } else if (toonEdgeEnabled == 2) { - return vec4(0.0, 0.0, 0.0, 0.0); - } - } - } - - // Apply exposure correction - cLinear *= pow(2.0, exposure); - - // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1] - vec3 cToneMapped = toneMap(cLinear); - - // Apply gamma correction prior to display - vec3 cGamma = gammaCorrect(cToneMapped); - - return vec4(cGamma, baseColor.a); -} - -void main() -{ - // FIXME: don't hard code here - exposure = 1.0; - gamma = 2.2; - - // Light settings: - // https://doc-snapshots.qt.io/qt5-5.12/qt3d-pbr-materials-lights-qml.html - lightCount = 3; - - // Key light - lights[0].type = TYPE_POINT; - lights[0].position = firstLightPos; - lights[0].color = vec3(1.0, 1.0, 1.0); - lights[0].intensity = 3.0; - lights[0].constantAttenuation = 0.0; - lights[0].linearAttenuation = 0.0; - lights[0].quadraticAttenuation = 0.0; - - // Fill light - lights[1].type = TYPE_POINT; - lights[1].position = secondLightPos; - lights[1].color = vec3(1.0, 1.0, 1.0); - lights[1].intensity = 1.0; - lights[1].constantAttenuation = 0.0; - lights[1].linearAttenuation = 0.0; - lights[1].quadraticAttenuation = 0.0; - - // Rim light - lights[2].type = TYPE_POINT; - lights[2].position = thirdLightPos; - lights[2].color = vec3(1.0, 1.0, 1.0); - lights[2].intensity = 0.5; - lights[2].constantAttenuation = 0.0; - lights[2].linearAttenuation = 0.0; - lights[2].quadraticAttenuation = 0.0; - - vec3 color = vertColor; - float alpha = vertAlpha; - if (textureEnabled == 1) { - vec4 textColor = texture2D(textureId, vertTexCoord); - color = textColor.rgb; - alpha = textColor.a; - } - if (mousePickEnabled == 1) { - float dist = distance(mousePickTargetPosition, vertRaw); - if (dist <= mousePickRadius && dist >= mousePickRadius * 0.9) { - color = color + vec3(0.99, 0.4, 0.13); - } - } - color = pow(color, vec3(gamma)); - - vec3 normal = vertNormal; - if (normalMapEnabled == 1) { - normal = texture2D(normalMapId, vertTexCoord).rgb; - normal = normalize(normal * 2.0 - 1.0); - } - - // Red: Ambient Occlusion - // Green: Roughness - // Blue: Metallic - - float metalness = vertMetalness; - if (metalnessMapEnabled == 1) { - metalness = texture2D(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).b; - } - - float roughness = vertRoughness; - if (roughnessMapEnabled == 1) { - roughness = texture2D(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).g; - } - - float ambientOcclusion = 1.0; - if (ambientOcclusionMapEnabled == 1) { - ambientOcclusion = texture2D(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).r; - } - - roughness = min(0.99, roughness); - metalness = min(0.99, metalness); - - if (renderPurpose == 0) { - gl_FragColor = metalRoughFunction(vec4(color, alpha), - metalness, - roughness, - ambientOcclusion, - vert, - normalize(cameraPos - vert), - normal); - } else if (renderPurpose == 1) { - gl_FragColor = vec4(normal, 1.0); - } else if (renderPurpose == 2) { - gl_FragColor = vec4(vec3(gl_FragCoord.w), 1.0); - } -} diff --git a/application/shaders/model.vert b/application/shaders/model.vert index 76296dbe..e69de29b 100644 --- a/application/shaders/model.vert +++ b/application/shaders/model.vert @@ -1,68 +0,0 @@ -#version 110 -attribute vec4 vertex; -attribute vec3 normal; -attribute vec3 color; -attribute vec2 texCoord; -attribute float metalness; -attribute float roughness; -attribute vec3 tangent; -attribute float alpha; -varying vec3 vert; -varying vec3 vertRaw; -varying vec3 vertNormal; -varying vec3 vertColor; -varying vec2 vertTexCoord; -varying float vertMetalness; -varying float vertRoughness; -varying vec3 cameraPos; -varying vec3 firstLightPos; -varying vec3 secondLightPos; -varying vec3 thirdLightPos; -varying float vertAlpha; -uniform mat4 projectionMatrix; -uniform mat4 modelMatrix; -uniform mat3 normalMatrix; -uniform mat4 viewMatrix; -uniform int normalMapEnabled; -uniform vec3 eyePos; - -mat3 transpose(mat3 m) -{ - return mat3(m[0][0], m[1][0], m[2][0], - m[0][1], m[1][1], m[2][1], - m[0][2], m[1][2], m[2][2]); -} - -void main() -{ - vert = (modelMatrix * vertex).xyz; - vertRaw = vert; - vertNormal = normalize((modelMatrix * vec4(normal, 1.0)).xyz); - vertColor = color; - vertAlpha = alpha; - cameraPos = eyePos; - - firstLightPos = vec3(5.0, 5.0, 5.0); - secondLightPos = vec3(-5.0, 5.0, 5.0); - thirdLightPos = vec3(0.0, -5.0, -5.0); - - gl_Position = projectionMatrix * viewMatrix * vec4(vert, 1.0); - - if (normalMapEnabled == 1) { - vec3 T = normalize(normalMatrix * tangent); - vec3 N = normalize(normalMatrix * normal); - T = normalize(T - dot(T, N) * N); - vec3 B = cross(N, T); - - mat3 TBN = transpose(mat3(T, B, N)); - firstLightPos = TBN * firstLightPos; - secondLightPos = TBN * secondLightPos; - thirdLightPos = TBN * thirdLightPos; - cameraPos = TBN * cameraPos; - vert = TBN * vert; - } - - vertTexCoord = texCoord; - vertMetalness = metalness; - vertRoughness = roughness; -} \ No newline at end of file diff --git a/application/shaders/model_core.frag b/application/shaders/model_core.frag index c079e7d2..e69de29b 100644 --- a/application/shaders/model_core.frag +++ b/application/shaders/model_core.frag @@ -1,652 +0,0 @@ -#version 330 -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -float exposure; -float gamma; - -in vec3 vert; -in vec3 vertRaw; -in vec3 vertNormal; -in vec3 vertColor; -in vec2 vertTexCoord; -in float vertMetalness; -in float vertRoughness; -in vec3 cameraPos; -in vec3 firstLightPos; -in vec3 secondLightPos; -in vec3 thirdLightPos; -in float vertAlpha; -out vec4 fragColor; -uniform sampler2D textureId; -uniform int textureEnabled; -uniform sampler2D normalMapId; -uniform int normalMapEnabled; -uniform sampler2D metalnessRoughnessAmbientOcclusionMapId; -uniform int metalnessMapEnabled; -uniform int roughnessMapEnabled; -uniform int ambientOcclusionMapEnabled; -uniform int mousePickEnabled; -uniform vec3 mousePickTargetPosition; -uniform float mousePickRadius; -uniform samplerCube environmentIrradianceMapId; -uniform int environmentIrradianceMapEnabled; -uniform samplerCube environmentSpecularMapId; -uniform int environmentSpecularMapEnabled; -uniform int toonShadingEnabled; -uniform int renderPurpose; -uniform int toonEdgeEnabled; -uniform float screenWidth; -uniform float screenHeight; -uniform sampler2D toonNormalMapId; -uniform sampler2D toonDepthMapId; - -const int MAX_LIGHTS = 8; -const int TYPE_POINT = 0; -const int TYPE_DIRECTIONAL = 1; -const int TYPE_SPOT = 2; -struct Light { - int type; - vec3 position; - vec3 color; - float intensity; - vec3 direction; - float constantAttenuation; - float linearAttenuation; - float quadraticAttenuation; - float cutOffAngle; -}; -int lightCount; -Light lights[MAX_LIGHTS]; - -float sobel_v[9]; -float sobel_h[9]; - -float normalEdgeSobel() -{ - sobel_v[0] = -1.0; - sobel_v[1] = 0.0; - sobel_v[2] = 1.0; - sobel_v[3] = -2.0; - sobel_v[4] = 0.0; - sobel_v[5] = 2.0; - sobel_v[6] = -1.0; - sobel_v[7] = 0.0; - sobel_v[8] = 1.0; - - sobel_h[0] = -1.0; - sobel_h[1] = -2.0; - sobel_h[2] = -1.0; - sobel_h[3] = 0.0; - sobel_h[4] = 0.0; - sobel_h[5] = 0.0; - sobel_h[6] = 1.0; - sobel_h[7] = 2.0; - sobel_h[8] = 1.0; - - // vec2 coord = gl_TexCoord[0].st; - vec2 coord = vec2(gl_FragCoord.x / screenWidth, 1.0 - gl_FragCoord.y / screenHeight); - //float len = length(coord); - - float sx = 1.0 / screenWidth; - float sy = 1.0 / screenHeight; - float n[9]; - vec3 ref = vec3(1.0, 1.0, 1.0); - - n[0] = dot(texture(toonNormalMapId, vec2(coord.x - sx, coord.y - sy)).rgb, ref); - n[1] = dot(texture(toonNormalMapId, vec2(coord.x, coord.y - sy)).rgb, ref); - n[2] = dot(texture(toonNormalMapId, vec2(coord.x + sx, coord.y - sy)).rgb, ref); - n[3] = dot(texture(toonNormalMapId, vec2(coord.x - sx, coord.y)).rgb, ref); - n[4] = dot(texture(toonNormalMapId, vec2(coord.x, coord.y)).rgb, ref); - n[5] = dot(texture(toonNormalMapId, vec2(coord.x + sx, coord.y)).rgb, ref); - n[6] = dot(texture(toonNormalMapId, vec2(coord.x - sx, coord.y + sy)).rgb, ref); - n[7] = dot(texture(toonNormalMapId, vec2(coord.x, coord.y + sy)).rgb, ref); - n[8] = dot(texture(toonNormalMapId, vec2(coord.x + sx, coord.y + sy)).rgb, ref); - - float v, h; - - v = 0.0; - h = 0.0; - - for (int i = 0; i < 9; ++i) { - v += sobel_v[i] * n[i]; - h += sobel_h[i] * n[i]; - } - - float enhanceFactor = 1.0; - - float r = sqrt(v * v * enhanceFactor + h * h * enhanceFactor); - return smoothstep(0.0, 1.0, r); -} - -float depthEdgeSobel() -{ - sobel_v[0] = -1; - sobel_v[1] = 0; - sobel_v[2] = 1; - sobel_v[3] = -2; - sobel_v[4] = 0; - sobel_v[5] = 2; - sobel_v[6] = -1; - sobel_v[7] = 0; - sobel_v[8] = 1; - - sobel_h[0] = -1; - sobel_h[1] = -2; - sobel_h[2] = -1; - sobel_h[3] = 0; - sobel_h[4] = 0; - sobel_h[5] = 0; - sobel_h[6] = 1; - sobel_h[7] = 2; - sobel_h[8] = 1; - - // vec2 coord = gl_TexCoord[0].st; - vec2 coord = vec2(gl_FragCoord.x / screenWidth, 1.0 - gl_FragCoord.y / screenHeight); - //float len = length(coord); - - float sx = 1.0 / screenWidth; - float sy = 1.0 / screenHeight; - float n[9]; - - n[0] = texture(toonDepthMapId, vec2(coord.x - sx, coord.y - sy)).r; - n[1] = texture(toonDepthMapId, vec2(coord.x, coord.y - sy)).r; - n[2] = texture(toonDepthMapId, vec2(coord.x + sx, coord.y - sy)).r; - n[3] = texture(toonDepthMapId, vec2(coord.x - sx, coord.y)).r; - n[4] = texture(toonDepthMapId, vec2(coord.x, coord.y)).r; - n[5] = texture(toonDepthMapId, vec2(coord.x + sx, coord.y)).r; - n[6] = texture(toonDepthMapId, vec2(coord.x - sx, coord.y + sy)).r; - n[7] = texture(toonDepthMapId, vec2(coord.x, coord.y + sy)).r; - n[8] = texture(toonDepthMapId, vec2(coord.x + sx, coord.y + sy)).r; - - float v, h; - - v = 0.0; - h = 0.0; - - for (int i = 0; i < 9; ++i) { - v += sobel_v[i] * n[i]; - h += sobel_h[i] * n[i]; - } - - float enhanceFactor = 10.0; - - float r = sqrt(v * v * enhanceFactor + h * h * enhanceFactor); - return smoothstep(0.0, 1.0, r); -} - -int mipLevelCount(const in samplerCube cube) -{ - int baseSize = textureSize(cube, 0).x; - int nMips = int(log2(float(baseSize > 0 ? baseSize : 1))) + 1; - return nMips; -} - -float remapRoughness(const in float roughness) -{ - // As per page 14 of - // http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - // we remap the roughness to give a more perceptually linear response - // of "bluriness" as a function of the roughness specified by the user. - // r = roughness^2 - float maxSpecPower; - float minRoughness; - maxSpecPower = 999999.0; - minRoughness = sqrt(2.0 / (maxSpecPower + 2.0)); - return max(roughness * roughness, minRoughness); -} - -float alphaToMipLevel(float alpha) -{ - float specPower = 2.0 / (alpha * alpha) - 2.0; - - // We use the mip level calculation from Lys' default power drop, which in - // turn is a slight modification of that used in Marmoset Toolbag. See - // https://docs.knaldtech.com/doku.php?id=specular_lys for details. - // For now we assume a max specular power of 999999 which gives - // maxGlossiness = 1. - const float k0 = 0.00098; - const float k1 = 0.9921; - float glossiness = (pow(2.0, -10.0 / sqrt(specPower)) - k0) / k1; - - // TODO: Optimize by doing this on CPU and set as - // uniform int environmentSpecularMapIdMipLevels say (if present in shader). - // Lookup the number of mips in the specular envmap - int mipLevels = mipLevelCount(environmentSpecularMapId); - - // Offset of smallest miplevel we should use (corresponds to specular - // power of 1). I.e. in the 32x32 sized mip. - const float mipOffset = 5.0; - - // The final factor is really 1 - g / g_max but as mentioned above g_max - // is 1 by definition here so we can avoid the division. If we make the - // max specular power for the spec map configurable, this will need to - // be handled properly. - float mipLevel = (mipLevels - 1.0 - mipOffset) * (1.0 - glossiness); - return mipLevel; -} - -float normalDistribution(const in vec3 n, const in vec3 h, const in float alpha) -{ - // Blinn-Phong approximation - see - // http://graphicrants.blogspot.co.uk/2013/08/specular-brdf-reference.html - float specPower = 2.0 / (alpha * alpha) - 2.0; - return (specPower + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), specPower); -} - -vec3 fresnelFactor(const in vec3 color, const in float cosineFactor) -{ - // Calculate the Fresnel effect value - vec3 f = color; - vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0); - return clamp(F, f, vec3(1.0)); -} - -float geometricModel(const in float lDotN, - const in float vDotN, - const in vec3 h) -{ - // Implicit geometric model (equal to denominator in specular model). - // This currently assumes that there is no attenuation by geometric shadowing or - // masking according to the microfacet theory. - return lDotN * vDotN; -} - -vec3 specularModel(const in vec3 F0, - const in float sDotH, - const in float sDotN, - const in float vDotN, - const in vec3 n, - const in vec3 h) -{ - // Clamp sDotN and vDotN to small positive value to prevent the - // denominator in the reflection equation going to infinity. Balance this - // by using the clamped values in the geometric factor function to - // avoid ugly seams in the specular lighting. - float sDotNPrime = max(sDotN, 0.001); - float vDotNPrime = max(vDotN, 0.001); - - vec3 F = fresnelFactor(F0, sDotH); - float G = geometricModel(sDotNPrime, vDotNPrime, h); - - vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); - return clamp(cSpec, vec3(0.0), vec3(1.0)); -} - -vec3 pbrModel(const in int lightIndex, - const in vec3 wPosition, - const in vec3 wNormal, - const in vec3 wView, - const in vec3 baseColor, - const in float metalness, - const in float alpha, - const in float ambientOcclusion) -{ - // Calculate some useful quantities - vec3 n = wNormal; - vec3 s = vec3(0.0); - vec3 v = wView; - vec3 h = vec3(0.0); - - float vDotN = dot(v, n); - float sDotN = 0.0; - float sDotH = 0.0; - float att = 1.0; - - if (lights[lightIndex].type != TYPE_DIRECTIONAL) { - // Point and Spot lights - vec3 sUnnormalized = vec3(lights[lightIndex].position) - wPosition; - s = normalize(sUnnormalized); - - // Calculate the attenuation factor - sDotN = dot(s, n); - if (sDotN > 0.0) { - if (lights[lightIndex].constantAttenuation != 0.0 - || lights[lightIndex].linearAttenuation != 0.0 - || lights[lightIndex].quadraticAttenuation != 0.0) { - float dist = length(sUnnormalized); - att = 1.0 / (lights[lightIndex].constantAttenuation + - lights[lightIndex].linearAttenuation * dist + - lights[lightIndex].quadraticAttenuation * dist * dist); - } - - // The light direction is in world space already - if (lights[lightIndex].type == TYPE_SPOT) { - // Check if fragment is inside or outside of the spot light cone - if (degrees(acos(dot(-s, lights[lightIndex].direction))) > lights[lightIndex].cutOffAngle) - sDotN = 0.0; - } - } - } else { - // Directional lights - // The light direction is in world space already - s = normalize(-lights[lightIndex].direction); - sDotN = dot(s, n); - } - - h = normalize(s + v); - sDotH = dot(s, h); - - // Calculate diffuse component - vec3 diffuseColor = (1.0 - metalness) * baseColor * lights[lightIndex].color; - vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159; - - // Calculate specular component - vec3 dielectricColor = vec3(0.04); - vec3 F0 = mix(dielectricColor, baseColor, metalness); - vec3 specularFactor = vec3(0.0); - if (sDotN > 0.0) { - specularFactor = specularModel(F0, sDotH, sDotN, vDotN, n, h); - specularFactor *= normalDistribution(n, h, alpha); - } - vec3 specularColor = lights[lightIndex].color; - vec3 specular = specularColor * specularFactor; - - // Blend between diffuse and specular to conserver energy - vec3 color = att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular)); - - // Reduce by ambient occlusion amount - color *= ambientOcclusion; - - return color; -} - -vec3 pbrIblModel(const in vec3 wNormal, - const in vec3 wView, - const in vec3 baseColor, - const in float metalness, - const in float alpha, - const in float ambientOcclusion) -{ - // Calculate reflection direction of view vector about surface normal - // vector in world space. This is used in the fragment shader to sample - // from the environment textures for a light source. This is equivalent - // to the l vector for punctual light sources. Armed with this, calculate - // the usual factors needed - vec3 n = wNormal; - vec3 l = reflect(-wView, n); - vec3 v = wView; - vec3 h = normalize(l + v); - float vDotN = dot(v, n); - float lDotN = dot(l, n); - float lDotH = dot(l, h); - - // Calculate diffuse component - vec3 diffuseColor = (1.0 - metalness) * baseColor; - vec3 diffuse = diffuseColor * texture(environmentIrradianceMapId, l).rgb; - - // Calculate specular component - vec3 dielectricColor = vec3(0.04); - vec3 F0 = mix(dielectricColor, baseColor, metalness); - vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h); - - float lod = alphaToMipLevel(alpha); -//#define DEBUG_SPECULAR_LODS -#ifdef DEBUG_SPECULAR_LODS - if (lod > 7.0) - return vec3(1.0, 0.0, 0.0); - else if (lod > 6.0) - return vec3(1.0, 0.333, 0.0); - else if (lod > 5.0) - return vec3(1.0, 1.0, 0.0); - else if (lod > 4.0) - return vec3(0.666, 1.0, 0.0); - else if (lod > 3.0) - return vec3(0.0, 1.0, 0.666); - else if (lod > 2.0) - return vec3(0.0, 0.666, 1.0); - else if (lod > 1.0) - return vec3(0.0, 0.0, 1.0); - else if (lod > 0.0) - return vec3(1.0, 0.0, 1.0); -#endif - vec3 specularSkyColor = textureLod(environmentSpecularMapId, l, lod).rgb; - vec3 specular = specularSkyColor * specularFactor; - - // Blend between diffuse and specular to conserve energy - vec3 color = specular + diffuse * (vec3(1.0) - specularFactor); - - // Reduce by ambient occlusion amount - color *= ambientOcclusion; - - return color; -} - -vec3 toneMap(const in vec3 c) -{ - return c / (c + vec3(1.0)); -} - -vec3 gammaCorrect(const in vec3 color) -{ - return pow(color, vec3(1.0 / gamma)); -} - -// http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl -vec3 rgb2hsv(vec3 c) -{ - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) -{ - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} - -vec4 metalRoughFunction(const in vec4 baseColor, - const in float metalness, - const in float roughness, - const in float ambientOcclusion, - const in vec3 worldPosition, - const in vec3 worldView, - const in vec3 worldNormal) -{ - vec3 cLinear = vec3(0.0); - - // Remap roughness for a perceptually more linear correspondence - float alpha = remapRoughness(roughness); - - if (toonShadingEnabled != 1) { - if (environmentIrradianceMapEnabled == 1) { - cLinear += pbrIblModel(worldNormal, - worldView, - baseColor.rgb, - metalness, - alpha, - ambientOcclusion); - } - - for (int i = 0; i < lightCount; ++i) { - cLinear += pbrModel(i, - worldPosition, - worldNormal, - worldView, - baseColor.rgb, - metalness, - alpha, - ambientOcclusion); - } - } else { - float intensity; - intensity = dot(vec3(1.0, 1.0, 1.0), worldNormal); - - vec3 hsv = rgb2hsv(baseColor.rgb); - if (intensity > 0.966) - cLinear = hsv2rgb(vec3(hsv.r, hsv.g, hsv.b * 2.0)); - else - cLinear = hsv2rgb(vec3(hsv.r, hsv.g, hsv.b * 0.1)); - - if (toonEdgeEnabled > 0) { - float depthEdge = depthEdgeSobel(); - float normalEdge = normalEdgeSobel(); - if (depthEdge >= 0.009 || normalEdge >= 0.7) { - cLinear = hsv2rgb(vec3(hsv.r, hsv.g, hsv.b * 0.02)); - } else if (toonEdgeEnabled == 2) { - return vec4(0.0, 0.0, 0.0, 0.0); - } - } - } - - // Apply exposure correction - cLinear *= pow(2.0, exposure); - - // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1] - vec3 cToneMapped = toneMap(cLinear); - - // Apply gamma correction prior to display - vec3 cGamma = gammaCorrect(cToneMapped); - - return vec4(cGamma, baseColor.a); -} - -void main() -{ - // FIXME: don't hard code here - exposure = 1.0; - gamma = 2.2; - - // Light settings: - // https://doc-snapshots.qt.io/qt5-5.12/qt3d-pbr-materials-lights-qml.html - lightCount = 3; - - // Key light - lights[0].type = TYPE_POINT; - lights[0].position = firstLightPos; - lights[0].color = vec3(1.0, 1.0, 1.0); - lights[0].intensity = 3.0; - lights[0].constantAttenuation = 1.0; - lights[0].linearAttenuation = 0.0; - lights[0].quadraticAttenuation = 0.0025; - - // Fill light - lights[1].type = TYPE_POINT; - lights[1].position = secondLightPos; - lights[1].color = vec3(1.0, 1.0, 1.0); - lights[1].intensity = 0.1; - lights[1].constantAttenuation = 0.0; - lights[1].linearAttenuation = 0.0; - lights[1].quadraticAttenuation = 0.0; - - // Rim light - lights[2].type = TYPE_POINT; - lights[2].position = thirdLightPos; - lights[2].color = vec3(1.0, 1.0, 1.0); - lights[2].intensity = 0.05; - lights[2].constantAttenuation = 0.0; - lights[2].linearAttenuation = 0.0; - lights[2].quadraticAttenuation = 0.0; - - vec3 color = vertColor; - float alpha = vertAlpha; - if (textureEnabled == 1) { - vec4 textColor = texture(textureId, vertTexCoord); - color = textColor.rgb; - alpha = textColor.a; - } - if (mousePickEnabled == 1) { - float dist = distance(mousePickTargetPosition, vertRaw); - if (dist <= mousePickRadius && dist >= mousePickRadius * 0.9) { - color = color + vec3(0.99, 0.4, 0.13); - } - } - color = pow(color, vec3(gamma)); - - vec3 normal = vertNormal; - if (normalMapEnabled == 1) { - normal = texture(normalMapId, vertTexCoord).rgb; - normal = normalize(normal * 2.0 - 1.0); - } - - // Red: Ambient Occlusion - // Green: Roughness - // Blue: Metallic - - float metalness = vertMetalness; - if (metalnessMapEnabled == 1) { - metalness = texture(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).b; - } - - float roughness = vertRoughness; - if (roughnessMapEnabled == 1) { - roughness = texture(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).g; - } - - float ambientOcclusion = 1.0; - if (ambientOcclusionMapEnabled == 1) { - ambientOcclusion = texture(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).r; - } - - roughness = min(0.99, roughness); - if (environmentIrradianceMapEnabled != 1) { - metalness = min(0.99, metalness); - } - - if (renderPurpose == 0) { - fragColor = metalRoughFunction(vec4(color, alpha), - metalness, - roughness, - ambientOcclusion, - vert, - normalize(cameraPos - vert), - normal); - } else if (renderPurpose == 1) { - fragColor = vec4(normal, 1.0); - } else if (renderPurpose == 2) { - fragColor = vec4(vec3(gl_FragCoord.w), 1.0); - } -} diff --git a/application/shaders/model_core.vert b/application/shaders/model_core.vert index 06bd3c5c..e69de29b 100644 --- a/application/shaders/model_core.vert +++ b/application/shaders/model_core.vert @@ -1,68 +0,0 @@ -#version 330 -layout(location = 0) in vec4 vertex; -layout(location = 1) in vec3 normal; -layout(location = 2) in vec3 color; -layout(location = 3) in vec2 texCoord; -layout(location = 4) in float metalness; -layout(location = 5) in float roughness; -layout(location = 6) in vec3 tangent; -layout(location = 7) in float alpha; -out vec3 vert; -out vec3 vertRaw; -out vec3 vertNormal; -out vec3 vertColor; -out vec2 vertTexCoord; -out float vertMetalness; -out float vertRoughness; -out vec3 cameraPos; -out vec3 firstLightPos; -out vec3 secondLightPos; -out vec3 thirdLightPos; -out float vertAlpha; -uniform mat4 projectionMatrix; -uniform mat4 modelMatrix; -uniform mat3 normalMatrix; -uniform mat4 viewMatrix; -uniform int normalMapEnabled; -uniform vec3 eyePos; - -mat3 transpose(mat3 m) -{ - return mat3(m[0][0], m[1][0], m[2][0], - m[0][1], m[1][1], m[2][1], - m[0][2], m[1][2], m[2][2]); -} - -void main() -{ - vert = (modelMatrix * vertex).xyz; - vertRaw = vert; - vertNormal = normalize((modelMatrix * vec4(normal, 1.0)).xyz); - vertColor = color; - vertAlpha = alpha; - cameraPos = eyePos; - - firstLightPos = vec3(5.0, 5.0, 5.0); - secondLightPos = vec3(-5.0, 5.0, 5.0); - thirdLightPos = vec3(0.0, -5.0, -5.0); - - gl_Position = projectionMatrix * viewMatrix * vec4(vert, 1.0); - - if (normalMapEnabled == 1) { - vec3 T = normalize(normalMatrix * tangent); - vec3 N = normalize(normalMatrix * normal); - T = normalize(T - dot(T, N) * N); - vec3 B = cross(N, T); - - mat3 TBN = transpose(mat3(T, B, N)); - firstLightPos = TBN * firstLightPos; - secondLightPos = TBN * secondLightPos; - thirdLightPos = TBN * thirdLightPos; - cameraPos = TBN * cameraPos; - vert = TBN * vert; - } - - vertTexCoord = texCoord; - vertMetalness = metalness; - vertRoughness = roughness; -} \ No newline at end of file diff --git a/application/sources/model_mesh_binder.cc b/application/sources/model_mesh_binder.cc deleted file mode 100644 index 3ac3723b..00000000 --- a/application/sources/model_mesh_binder.cc +++ /dev/null @@ -1,448 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "model_mesh_binder.h" -#include "dds_file.h" - -ModelMeshBinder::ModelMeshBinder(bool toolEnabled) : - m_toolEnabled(toolEnabled) -{ -} - -ModelMeshBinder::~ModelMeshBinder() -{ - delete m_mesh; - delete m_newMesh; - delete m_texture; - delete m_normalMap; - delete m_metalnessRoughnessAmbientOcclusionMap; - delete m_environmentIrradianceMap; - delete m_environmentSpecularMap; - delete m_toonNormalMap; - delete m_toonDepthMap; - delete m_newToonNormalMap; - delete m_newToonDepthMap; - delete m_currentToonNormalMap; - delete m_currentToonDepthMap; - delete m_colorTextureImage; -} - -void ModelMeshBinder::updateMesh(Model *mesh) -{ - QMutexLocker lock(&m_newMeshMutex); - if (mesh != m_mesh) { - delete m_newMesh; - m_newMesh = mesh; - m_newMeshComing = true; - } -} - -void ModelMeshBinder::updateColorTexture(QImage *colorTextureImage) -{ - QMutexLocker lock(&m_colorTextureMutex); - delete m_colorTextureImage; - m_colorTextureImage = colorTextureImage; -} - -void ModelMeshBinder::reloadMesh() -{ - Model *mesh = nullptr; - { - QMutexLocker lock(&m_newMeshMutex); - if (nullptr == m_mesh) - return; - mesh = new Model(*m_mesh); - } - if (nullptr != mesh) - updateMesh(mesh); -} - -void ModelMeshBinder::initialize() -{ - m_vaoTriangle.create(); - m_vaoEdge.create(); - if (m_toolEnabled) - m_vaoTool.create(); -} - -void ModelMeshBinder::enableEnvironmentLight() -{ - m_environmentLightEnabled = true; -} - -bool ModelMeshBinder::isEnvironmentLightEnabled() -{ - return m_environmentLightEnabled; -} - -Model *ModelMeshBinder::fetchCurrentMesh() -{ - QMutexLocker lock(&m_meshMutex); - if (nullptr == m_mesh) - return nullptr; - return new Model(*m_mesh); -} - -void ModelMeshBinder::paint(ModelShaderProgram *program) -{ - Model *newMesh = nullptr; - bool hasNewMesh = false; - if (m_newMeshComing) { - QMutexLocker lock(&m_newMeshMutex); - if (m_newMeshComing) { - newMesh = m_newMesh; - m_newMesh = nullptr; - m_newMeshComing = false; - hasNewMesh = true; - } - } - if (m_newToonMapsComing) { - QMutexLocker lock(&m_toonNormalAndDepthMapMutex); - if (m_newToonMapsComing) { - - delete m_toonNormalMap; - m_toonNormalMap = nullptr; - delete m_currentToonNormalMap; - m_currentToonNormalMap = nullptr; - if (nullptr != m_newToonNormalMap) { - m_toonNormalMap = new QOpenGLTexture(*m_newToonNormalMap); - m_currentToonNormalMap = m_newToonNormalMap; - m_newToonNormalMap = nullptr; - } - - delete m_toonDepthMap; - m_toonDepthMap = nullptr; - delete m_currentToonDepthMap; - m_currentToonDepthMap = nullptr; - if (nullptr != m_newToonDepthMap) { - m_toonDepthMap = new QOpenGLTexture(*m_newToonDepthMap); - m_currentToonDepthMap = m_newToonDepthMap; - m_newToonDepthMap = nullptr; - } - - m_newToonMapsComing = false; - } - } - { - QMutexLocker lock(&m_meshMutex); - if (hasNewMesh) { - delete m_mesh; - m_mesh = newMesh; - if (m_mesh) { - m_hasTexture = nullptr != m_mesh->textureImage(); - delete m_texture; - m_texture = nullptr; - if (m_hasTexture) { - if (m_checkUvEnabled) { - static QImage *s_checkUv = nullptr; - if (nullptr == s_checkUv) - s_checkUv = new QImage(":/resources/checkuv.png"); - m_texture = new QOpenGLTexture(*s_checkUv); - } else { - m_texture = new QOpenGLTexture(*m_mesh->textureImage()); - } - } - - m_hasNormalMap = nullptr != m_mesh->normalMapImage(); - delete m_normalMap; - m_normalMap = nullptr; - if (m_hasNormalMap) - m_normalMap = new QOpenGLTexture(*m_mesh->normalMapImage()); - - m_hasMetalnessMap = m_mesh->hasMetalnessInImage(); - m_hasRoughnessMap = m_mesh->hasRoughnessInImage(); - m_hasAmbientOcclusionMap = m_mesh->hasAmbientOcclusionInImage(); - delete m_metalnessRoughnessAmbientOcclusionMap; - m_metalnessRoughnessAmbientOcclusionMap = nullptr; - if (nullptr != m_mesh->metalnessRoughnessAmbientOcclusionImage() && - (m_hasMetalnessMap || m_hasRoughnessMap || m_hasAmbientOcclusionMap)) - m_metalnessRoughnessAmbientOcclusionMap = new QOpenGLTexture(*m_mesh->metalnessRoughnessAmbientOcclusionImage()); - - //delete m_environmentIrradianceMap; - //m_environmentIrradianceMap = nullptr; - //delete m_environmentSpecularMap; - //m_environmentSpecularMap = nullptr; - if (program->isCoreProfile() && - m_environmentLightEnabled/* && - (m_hasMetalnessMap || m_hasRoughnessMap)*/) { - if (nullptr == m_environmentIrradianceMap) { - DdsFileReader irradianceFile(":/resources/cedar_bridge_irradiance.dds"); - m_environmentIrradianceMap = irradianceFile.createOpenGLTexture(); - } - - if (nullptr == m_environmentSpecularMap) { - DdsFileReader specularFile(":/resources/cedar_bridge_specular.dds"); - m_environmentSpecularMap = specularFile.createOpenGLTexture(); - } - } - - { - QOpenGLVertexArrayObject::Binder vaoBinder(&m_vaoTriangle); - if (m_vboTriangle.isCreated()) - m_vboTriangle.destroy(); - m_vboTriangle.create(); - m_vboTriangle.bind(); - m_vboTriangle.allocate(m_mesh->triangleVertices(), m_mesh->triangleVertexCount() * sizeof(ModelShaderVertex)); - m_renderTriangleVertexCount = m_mesh->triangleVertexCount(); - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - f->glEnableVertexAttribArray(0); - f->glEnableVertexAttribArray(1); - f->glEnableVertexAttribArray(2); - f->glEnableVertexAttribArray(3); - f->glEnableVertexAttribArray(4); - f->glEnableVertexAttribArray(5); - f->glEnableVertexAttribArray(6); - f->glEnableVertexAttribArray(7); - f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), 0); - f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(3 * sizeof(GLfloat))); - f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(6 * sizeof(GLfloat))); - f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(9 * sizeof(GLfloat))); - f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(11 * sizeof(GLfloat))); - f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(12 * sizeof(GLfloat))); - f->glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(13 * sizeof(GLfloat))); - f->glVertexAttribPointer(7, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(16 * sizeof(GLfloat))); - m_vboTriangle.release(); - } - { - QOpenGLVertexArrayObject::Binder vaoBinder(&m_vaoEdge); - if (m_vboEdge.isCreated()) - m_vboEdge.destroy(); - m_vboEdge.create(); - m_vboEdge.bind(); - m_vboEdge.allocate(m_mesh->edgeVertices(), m_mesh->edgeVertexCount() * sizeof(ModelShaderVertex)); - m_renderEdgeVertexCount = m_mesh->edgeVertexCount(); - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - f->glEnableVertexAttribArray(0); - f->glEnableVertexAttribArray(1); - f->glEnableVertexAttribArray(2); - f->glEnableVertexAttribArray(3); - f->glEnableVertexAttribArray(4); - f->glEnableVertexAttribArray(5); - f->glEnableVertexAttribArray(6); - f->glEnableVertexAttribArray(7); - f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), 0); - f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(3 * sizeof(GLfloat))); - f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(6 * sizeof(GLfloat))); - f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(9 * sizeof(GLfloat))); - f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(11 * sizeof(GLfloat))); - f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(12 * sizeof(GLfloat))); - f->glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(13 * sizeof(GLfloat))); - f->glVertexAttribPointer(7, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(16 * sizeof(GLfloat))); - m_vboEdge.release(); - } - if (m_toolEnabled) { - QOpenGLVertexArrayObject::Binder vaoBinder(&m_vaoTool); - if (m_vboTool.isCreated()) - m_vboTool.destroy(); - m_vboTool.create(); - m_vboTool.bind(); - m_vboTool.allocate(m_mesh->toolVertices(), m_mesh->toolVertexCount() * sizeof(ModelShaderVertex)); - m_renderToolVertexCount = m_mesh->toolVertexCount(); - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - f->glEnableVertexAttribArray(0); - f->glEnableVertexAttribArray(1); - f->glEnableVertexAttribArray(2); - f->glEnableVertexAttribArray(3); - f->glEnableVertexAttribArray(4); - f->glEnableVertexAttribArray(5); - f->glEnableVertexAttribArray(6); - f->glEnableVertexAttribArray(7); - f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), 0); - f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(3 * sizeof(GLfloat))); - f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(6 * sizeof(GLfloat))); - f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(9 * sizeof(GLfloat))); - f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(11 * sizeof(GLfloat))); - f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(12 * sizeof(GLfloat))); - f->glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(13 * sizeof(GLfloat))); - f->glVertexAttribPointer(7, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(16 * sizeof(GLfloat))); - m_vboTool.release(); - } else { - m_renderToolVertexCount = 0; - } - } else { - m_renderTriangleVertexCount = 0; - m_renderEdgeVertexCount = 0; - m_renderToolVertexCount = 0; - } - } - } - program->setUniformValue(program->textureIdLoc(), 0); - program->setUniformValue(program->normalMapIdLoc(), 1); - program->setUniformValue(program->metalnessRoughnessAmbientOcclusionMapIdLoc(), 2); - program->setUniformValue(program->environmentIrradianceMapIdLoc(), 3); - program->setUniformValue(program->environmentSpecularMapIdLoc(), 4); - program->setUniformValue(program->toonNormalMapIdLoc(), 5); - program->setUniformValue(program->toonDepthMapIdLoc(), 6); - if (m_showWireframe) { - if (m_renderEdgeVertexCount > 0) { - QOpenGLVertexArrayObject::Binder vaoBinder(&m_vaoEdge); - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - // glDrawArrays GL_LINES crashes on Mesa GL - if (program->isCoreProfile()) { - program->setUniformValue(program->textureEnabledLoc(), 0); - program->setUniformValue(program->normalMapEnabledLoc(), 0); - program->setUniformValue(program->metalnessMapEnabledLoc(), 0); - program->setUniformValue(program->roughnessMapEnabledLoc(), 0); - program->setUniformValue(program->ambientOcclusionMapEnabledLoc(), 0); - if (program->isCoreProfile()) { - program->setUniformValue(program->environmentIrradianceMapEnabledLoc(), 0); - program->setUniformValue(program->environmentSpecularMapEnabledLoc(), 0); - } - f->glDrawArrays(GL_LINES, 0, m_renderEdgeVertexCount); - } - } - } - if (m_renderTriangleVertexCount > 0) { - QOpenGLVertexArrayObject::Binder vaoBinder(&m_vaoTriangle); - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - if (m_hasTexture) { - { - QMutexLocker lock(&m_colorTextureMutex); - if (m_colorTextureImage) { - delete m_texture; - m_texture = new QOpenGLTexture(*m_colorTextureImage); - delete m_colorTextureImage; - m_colorTextureImage = nullptr; - } - } - if (m_texture) - m_texture->bind(0); - program->setUniformValue(program->textureEnabledLoc(), 1); - } else { - program->setUniformValue(program->textureEnabledLoc(), 0); - } - if (m_hasNormalMap) { - if (m_normalMap) - m_normalMap->bind(1); - program->setUniformValue(program->normalMapEnabledLoc(), 1); - } else { - program->setUniformValue(program->normalMapEnabledLoc(), 0); - } - if (m_hasMetalnessMap || m_hasRoughnessMap || m_hasAmbientOcclusionMap) { - if (m_metalnessRoughnessAmbientOcclusionMap) - m_metalnessRoughnessAmbientOcclusionMap->bind(2); - } - program->setUniformValue(program->metalnessMapEnabledLoc(), m_hasMetalnessMap ? 1 : 0); - program->setUniformValue(program->roughnessMapEnabledLoc(), m_hasRoughnessMap ? 1 : 0); - program->setUniformValue(program->ambientOcclusionMapEnabledLoc(), m_hasAmbientOcclusionMap ? 1 : 0); - if (program->isCoreProfile()) { - if (nullptr != m_environmentIrradianceMap && nullptr != m_metalnessRoughnessAmbientOcclusionMap) { - m_environmentIrradianceMap->bind(3); - program->setUniformValue(program->environmentIrradianceMapEnabledLoc(), 1); - } else { - program->setUniformValue(program->environmentIrradianceMapEnabledLoc(), 0); - } - if (nullptr != m_environmentSpecularMap && nullptr != m_metalnessRoughnessAmbientOcclusionMap) { - m_environmentSpecularMap->bind(4); - program->setUniformValue(program->environmentSpecularMapEnabledLoc(), 1); - } else { - program->setUniformValue(program->environmentSpecularMapEnabledLoc(), 0); - } - } - if (nullptr != m_toonNormalMap && nullptr != m_toonDepthMap) { - m_toonNormalMap->bind(5); - m_toonDepthMap->bind(6); - program->setUniformValue(program->toonEdgeEnabledLoc(), (int)0); - } - f->glDrawArrays(GL_TRIANGLES, 0, m_renderTriangleVertexCount); - } - if (m_toolEnabled) { - if (m_renderToolVertexCount > 0) { - QOpenGLVertexArrayObject::Binder vaoBinder(&m_vaoTool); - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - program->setUniformValue(program->textureEnabledLoc(), 0); - program->setUniformValue(program->normalMapEnabledLoc(), 0); - program->setUniformValue(program->metalnessMapEnabledLoc(), 0); - program->setUniformValue(program->roughnessMapEnabledLoc(), 0); - program->setUniformValue(program->ambientOcclusionMapEnabledLoc(), 0); - if (program->isCoreProfile()) { - program->setUniformValue(program->environmentIrradianceMapEnabledLoc(), 0); - program->setUniformValue(program->environmentSpecularMapEnabledLoc(), 0); - } - f->glDrawArrays(GL_TRIANGLES, 0, m_renderToolVertexCount); - } - } -} - -void ModelMeshBinder::fetchCurrentToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap) -{ - QMutexLocker lock(&m_toonNormalAndDepthMapMutex); - if (nullptr != normalMap && nullptr != m_currentToonNormalMap) - *normalMap = *m_currentToonNormalMap; - if (nullptr != depthMap && nullptr != m_currentToonDepthMap) - *depthMap = *m_currentToonDepthMap; -} - -void ModelMeshBinder::updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap) -{ - QMutexLocker lock(&m_toonNormalAndDepthMapMutex); - - delete m_newToonNormalMap; - m_newToonNormalMap = normalMap; - - delete m_newToonDepthMap; - m_newToonDepthMap = depthMap; - - m_newToonMapsComing = true; -} - -void ModelMeshBinder::cleanup() -{ - if (m_vboTriangle.isCreated()) - m_vboTriangle.destroy(); - if (m_vboEdge.isCreated()) - m_vboEdge.destroy(); - if (m_toolEnabled) { - if (m_vboTool.isCreated()) - m_vboTool.destroy(); - } - delete m_texture; - m_texture = nullptr; - delete m_normalMap; - m_normalMap = nullptr; - delete m_metalnessRoughnessAmbientOcclusionMap; - m_metalnessRoughnessAmbientOcclusionMap = nullptr; - delete m_environmentIrradianceMap; - m_environmentIrradianceMap = nullptr; - delete m_environmentSpecularMap; - m_environmentSpecularMap = nullptr; - delete m_toonNormalMap; - m_toonNormalMap = nullptr; - delete m_toonDepthMap; - m_toonDepthMap = nullptr; -} - -void ModelMeshBinder::showWireframe() -{ - m_showWireframe = true; -} - -void ModelMeshBinder::hideWireframe() -{ - m_showWireframe = false; -} - -bool ModelMeshBinder::isWireframeVisible() -{ - return m_showWireframe; -} - -void ModelMeshBinder::enableCheckUv() -{ - m_checkUvEnabled = true; -} - -void ModelMeshBinder::disableCheckUv() -{ - m_checkUvEnabled = false; -} - -bool ModelMeshBinder::isCheckUvEnabled() -{ - return m_checkUvEnabled; -} diff --git a/application/sources/model_mesh_binder.h b/application/sources/model_mesh_binder.h deleted file mode 100644 index 4fbb41e4..00000000 --- a/application/sources/model_mesh_binder.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef DUST3D_APPLICATION_MODEL_MESH_BINDER_H_ -#define DUST3D_APPLICATION_MODEL_MESH_BINDER_H_ - -#include -#include -#include -#include -#include -#include "model.h" -#include "model_shader_program.h" - -class ModelMeshBinder -{ -public: - ModelMeshBinder(bool toolEnabled=false); - ~ModelMeshBinder(); - Model *fetchCurrentMesh(); - void updateMesh(Model *mesh); - void updateColorTexture(QImage *colorTextureImage); - void initialize(); - void paint(ModelShaderProgram *program); - void cleanup(); - void showWireframe(); - void hideWireframe(); - bool isWireframeVisible(); - void enableCheckUv(); - void disableCheckUv(); - void enableEnvironmentLight(); - bool isEnvironmentLightEnabled(); - bool isCheckUvEnabled(); - void reloadMesh(); - void fetchCurrentToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap); - void updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap); -private: - Model *m_mesh = nullptr; - Model *m_newMesh = nullptr; - int m_renderTriangleVertexCount = 0; - int m_renderEdgeVertexCount = 0; - int m_renderToolVertexCount = 0; - bool m_newMeshComing = false; - bool m_showWireframe = false; - bool m_hasTexture = false; - QOpenGLTexture *m_texture = nullptr; - bool m_hasNormalMap = false; - QOpenGLTexture *m_normalMap = nullptr; - bool m_hasMetalnessMap = false; - bool m_hasRoughnessMap = false; - bool m_hasAmbientOcclusionMap = false; - QOpenGLTexture *m_metalnessRoughnessAmbientOcclusionMap = nullptr; - bool m_toolEnabled = false; - bool m_checkUvEnabled = false; - bool m_environmentLightEnabled = false; - QOpenGLTexture *m_environmentIrradianceMap = nullptr; - QOpenGLTexture *m_environmentSpecularMap = nullptr; - QOpenGLTexture *m_toonNormalMap = nullptr; - QOpenGLTexture *m_toonDepthMap = nullptr; - QImage *m_newToonNormalMap = nullptr; - QImage *m_newToonDepthMap = nullptr; - QImage *m_currentToonNormalMap = nullptr; - QImage *m_currentToonDepthMap = nullptr; - QImage *m_colorTextureImage = nullptr; - bool m_newToonMapsComing = false; - QOpenGLVertexArrayObject m_vaoTriangle; - QOpenGLBuffer m_vboTriangle; - QOpenGLVertexArrayObject m_vaoEdge; - QOpenGLBuffer m_vboEdge; - QOpenGLVertexArrayObject m_vaoTool; - QOpenGLBuffer m_vboTool; - QMutex m_meshMutex; - QMutex m_newMeshMutex; - QMutex m_toonNormalAndDepthMapMutex; - QMutex m_colorTextureMutex; -}; - -#endif diff --git a/application/sources/model_offscreen_render.cc b/application/sources/model_offscreen_render.cc index 1fe98781..aae31935 100644 --- a/application/sources/model_offscreen_render.cc +++ b/application/sources/model_offscreen_render.cc @@ -1,216 +1,51 @@ -#include -#include -#include -#include "model_offscreen_render.h" - -ModelOffscreenRender::ModelOffscreenRender(const QSurfaceFormat &format, QScreen *targetScreen) : - QOffscreenSurface(targetScreen), - m_context(nullptr), - m_mesh(nullptr) -{ - setFormat(format); - create(); - if (!isValid()) - qDebug() << "ModelOffscreenRender is invalid"; -} - -ModelOffscreenRender::~ModelOffscreenRender() -{ - // FIXME: If delete m_renderFbo inside toImage, - // sometimes, the application will freeze, maybe there are dead locks inside the destruction call - // move it here can make sure it will be deleted on the main GUI thread to avoid dead locks - delete m_renderFbo; - - destroy(); - delete m_mesh; - delete m_normalMap; - delete m_depthMap; -} - -void ModelOffscreenRender::updateMesh(Model *mesh) -{ - delete m_mesh; - m_mesh = mesh; -} - -void ModelOffscreenRender::setRenderThread(QThread *thread) -{ - this->moveToThread(thread); -} - -void ModelOffscreenRender::setXRotation(int angle) -{ - m_xRot = angle; -} - -void ModelOffscreenRender::setYRotation(int angle) -{ - m_yRot = angle; -} - -void ModelOffscreenRender::setZRotation(int angle) -{ - m_zRot = angle; -} - -void ModelOffscreenRender::setEyePosition(const QVector3D &eyePosition) -{ - m_eyePosition = eyePosition; -} - -void ModelOffscreenRender::setMoveToPosition(const QVector3D &moveToPosition) -{ - m_moveToPosition = moveToPosition; -} - -void ModelOffscreenRender::enableWireframe() -{ - m_isWireframeVisible = true; -} - -void ModelOffscreenRender::setRenderPurpose(int purpose) -{ - m_renderPurpose = purpose; -} - -void ModelOffscreenRender::setToonShading(bool toonShading) -{ - m_toonShading = toonShading; -} - -void ModelOffscreenRender::enableEnvironmentLight() -{ - m_isEnvironmentLightEnabled = true; -} - -void ModelOffscreenRender::updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap) -{ - delete m_normalMap; - m_normalMap = normalMap; - - delete m_depthMap; - m_depthMap = depthMap; -} - -QImage ModelOffscreenRender::toImage(const QSize &size) -{ - QImage image; - - m_context = new QOpenGLContext(); - m_context->setFormat(format()); - if (!m_context->create()) { - delete m_context; - m_context = nullptr; - - qDebug() << "QOpenGLContext create failed"; - return image; - } - - if (!m_context->makeCurrent(this)) { - delete m_context; - m_context = nullptr; - - qDebug() << "QOpenGLContext makeCurrent failed"; - return image; - } - - QOpenGLFramebufferObjectFormat format; - format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); - format.setSamples(4); - format.setTextureTarget(GL_TEXTURE_2D); - format.setInternalTextureFormat(GL_RGBA32F_ARB); - m_renderFbo = new QOpenGLFramebufferObject(size, format); - m_renderFbo->bind(); - m_context->functions()->glViewport(0, 0, size.width(), size.height()); - - if (nullptr != m_mesh) { - QMatrix4x4 projection; - QMatrix4x4 world; - QMatrix4x4 camera; - - bool isCoreProfile = false; - const char *versionString = (const char *)m_context->functions()->glGetString(GL_VERSION); - if (nullptr != versionString && - '\0' != versionString[0] && - 0 == strstr(versionString, "Mesa")) { - isCoreProfile = m_context->format().profile() == QSurfaceFormat::CoreProfile; - } - - ModelShaderProgram *program = new ModelShaderProgram(isCoreProfile); - ModelMeshBinder meshBinder; - meshBinder.initialize(); - if (m_isWireframeVisible) - meshBinder.showWireframe(); - else - meshBinder.hideWireframe(); - if (m_isEnvironmentLightEnabled) - meshBinder.enableEnvironmentLight(); - if (nullptr != m_normalMap && nullptr != m_depthMap) { - meshBinder.updateToonNormalAndDepthMaps(m_normalMap, m_depthMap); - m_normalMap = nullptr; - m_depthMap = nullptr; - } - - m_context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - m_context->functions()->glEnable(GL_BLEND); - m_context->functions()->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - m_context->functions()->glEnable(GL_DEPTH_TEST); - //m_context->functions()->glEnable(GL_CULL_FACE); -#ifdef GL_LINE_SMOOTH - m_context->functions()->glEnable(GL_LINE_SMOOTH); -#endif - - world.setToIdentity(); - world.rotate(m_xRot / 16.0f, 1, 0, 0); - world.rotate(m_yRot / 16.0f, 0, 1, 0); - world.rotate(m_zRot / 16.0f, 0, 0, 1); - - projection.setToIdentity(); - projection.translate(m_moveToPosition.x(), m_moveToPosition.y(), m_moveToPosition.z()); - projection.perspective(45.0f, GLfloat(size.width()) / size.height(), 0.01f, 100.0f); - - camera.setToIdentity(); - camera.translate(m_eyePosition); - - program->bind(); - program->setUniformValue(program->eyePosLoc(), m_eyePosition); - program->setUniformValue(program->toonShadingEnabledLoc(), m_toonShading ? 1 : 0); - program->setUniformValue(program->projectionMatrixLoc(), projection); - program->setUniformValue(program->modelMatrixLoc(), world); - QMatrix3x3 normalMatrix = world.normalMatrix(); - program->setUniformValue(program->normalMatrixLoc(), normalMatrix); - program->setUniformValue(program->viewMatrixLoc(), camera); - program->setUniformValue(program->textureEnabledLoc(), 0); - program->setUniformValue(program->normalMapEnabledLoc(), 0); - program->setUniformValue(program->mousePickEnabledLoc(), 0); - program->setUniformValue(program->renderPurposeLoc(), m_renderPurpose); - - program->setUniformValue(program->toonEdgeEnabledLoc(), 0); - program->setUniformValue(program->screenWidthLoc(), (GLfloat)size.width()); - program->setUniformValue(program->screenHeightLoc(), (GLfloat)size.height()); - program->setUniformValue(program->toonNormalMapIdLoc(), 0); - program->setUniformValue(program->toonDepthMapIdLoc(), 0); - - meshBinder.updateMesh(m_mesh); - meshBinder.paint(program); - - meshBinder.cleanup(); - - program->release(); - delete program; - - m_mesh = nullptr; - } - - m_context->functions()->glFlush(); - - image = m_renderFbo->toImage(); - - m_renderFbo->release(); - - m_context->doneCurrent(); - delete m_context; - m_context = nullptr; - - return image; -} +#include "model_offscreen_render.h" + +ModelOffscreenRender::ModelOffscreenRender(const QSurfaceFormat &format, QScreen *targetScreen): + QOffscreenSurface(targetScreen) +{ +} + +ModelOffscreenRender::~ModelOffscreenRender() +{ + // TODO +} + +void ModelOffscreenRender::setXRotation(int angle) +{ + // TODO +} + +void ModelOffscreenRender::setYRotation(int angle) +{ + // TODO +} + +void ModelOffscreenRender::setZRotation(int angle) +{ + // TODO +} + +void ModelOffscreenRender::setEyePosition(const QVector3D &eyePosition) +{ + // TODO +} + +void ModelOffscreenRender::setMoveToPosition(const QVector3D &moveToPosition) +{ + // TODO +} + +void ModelOffscreenRender::setRenderThread(QThread *thread) +{ + // TODO +} + +void ModelOffscreenRender::updateMesh(Model *mesh) +{ + // TODO +} + +QImage ModelOffscreenRender::toImage(const QSize &size) +{ + // TODO +} diff --git a/application/sources/model_offscreen_render.h b/application/sources/model_offscreen_render.h index a79299ea..17c6502d 100644 --- a/application/sources/model_offscreen_render.h +++ b/application/sources/model_offscreen_render.h @@ -1,50 +1,24 @@ -#ifndef DUST3D_APPLICATION_MODEL_OFFSCREEN_RENDER_H_ -#define DUST3D_APPLICATION_MODEL_OFFSCREEN_RENDER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include "model_shader_program.h" -#include "model_mesh_binder.h" -#include "model.h" - -class ModelOffscreenRender : QOffscreenSurface -{ -public: - ModelOffscreenRender(const QSurfaceFormat &format, QScreen *targetScreen=Q_NULLPTR); - ~ModelOffscreenRender(); - void setXRotation(int angle); - void setYRotation(int angle); - void setZRotation(int angle); - void setEyePosition(const QVector3D &eyePosition); - void setMoveToPosition(const QVector3D &moveToPosition); - void setRenderPurpose(int purpose); - void setRenderThread(QThread *thread); - void enableWireframe(); - void enableEnvironmentLight(); - void updateMesh(Model *mesh); - void updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap); - void setToonShading(bool toonShading); - QImage toImage(const QSize &size); -private: - int m_xRot = 0; - int m_yRot = 0; - int m_zRot = 0; - QVector3D m_eyePosition; - QVector3D m_moveToPosition; - int m_renderPurpose = 0; - QOpenGLContext *m_context = nullptr; - QOpenGLFramebufferObject *m_renderFbo = nullptr; - Model *m_mesh = nullptr; - QImage *m_normalMap = nullptr; - QImage *m_depthMap = nullptr; - bool m_toonShading = false; - bool m_isWireframeVisible = false; - bool m_isEnvironmentLightEnabled = false; -}; - -#endif +#ifndef DUST3D_APPLICATION_MODEL_OFFSCREEN_RENDER_H_ +#define DUST3D_APPLICATION_MODEL_OFFSCREEN_RENDER_H_ + +#include +#include +#include +#include "model.h" + +class ModelOffscreenRender: public QOffscreenSurface +{ +public: + ModelOffscreenRender(const QSurfaceFormat &format, QScreen *targetScreen=Q_NULLPTR); + ~ModelOffscreenRender(); + void setXRotation(int angle); + void setYRotation(int angle); + void setZRotation(int angle); + void setEyePosition(const QVector3D &eyePosition); + void setMoveToPosition(const QVector3D &moveToPosition); + void setRenderThread(QThread *thread); + void updateMesh(Model *mesh); + QImage toImage(const QSize &size); +}; + +#endif diff --git a/application/sources/model_opengl_object.cc b/application/sources/model_opengl_object.cc new file mode 100644 index 00000000..a32692e5 --- /dev/null +++ b/application/sources/model_opengl_object.cc @@ -0,0 +1,63 @@ +#include +#include +#include "model_opengl_object.h" + +void ModelOpenGLObject::update(std::unique_ptr mesh) +{ + QMutexLocker lock(&m_meshMutex); + m_mesh = std::move(mesh); + m_meshIsDirty = true; +} + +void ModelOpenGLObject::draw() +{ + copyMeshToOpenGL(); + if (0 == m_meshTriangleVertexCount) + return; + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glDrawArrays(GL_TRIANGLES, 0, m_meshTriangleVertexCount); +} + +void ModelOpenGLObject::copyMeshToOpenGL() +{ + std::unique_ptr mesh; + bool meshChanged = false; + if (m_meshIsDirty) { + QMutexLocker lock(&m_meshMutex); + if (m_meshIsDirty) { + m_meshIsDirty = false; + meshChanged = true; + mesh = std::move(m_mesh); + } + } + if (!meshChanged) + return; + m_meshTriangleVertexCount = 0; + if (mesh) { + QOpenGLVertexArrayObject::Binder binder(&m_vertexArrayObject); + if (m_buffer.isCreated()) + m_buffer.destroy(); + m_buffer.create(); + m_buffer.bind(); + m_buffer.allocate(mesh->triangleVertices(), mesh->triangleVertexCount() * sizeof(ModelShaderVertex)); + m_meshTriangleVertexCount = mesh->triangleVertexCount(); + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glEnableVertexAttribArray(0); + f->glEnableVertexAttribArray(1); + f->glEnableVertexAttribArray(2); + f->glEnableVertexAttribArray(3); + f->glEnableVertexAttribArray(4); + f->glEnableVertexAttribArray(5); + f->glEnableVertexAttribArray(6); + f->glEnableVertexAttribArray(7); + f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), 0); + f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(3 * sizeof(GLfloat))); + f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(6 * sizeof(GLfloat))); + f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(9 * sizeof(GLfloat))); + f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(11 * sizeof(GLfloat))); + f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(12 * sizeof(GLfloat))); + f->glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(13 * sizeof(GLfloat))); + f->glVertexAttribPointer(7, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast(16 * sizeof(GLfloat))); + m_buffer.release(); + } +} \ No newline at end of file diff --git a/application/sources/model_opengl_object.h b/application/sources/model_opengl_object.h new file mode 100644 index 00000000..4ac8279b --- /dev/null +++ b/application/sources/model_opengl_object.h @@ -0,0 +1,25 @@ +#ifndef DUST3D_APPLICATION_MODEL_OPENGL_OBJECT_H_ +#define DUST3D_APPLICATION_MODEL_OPENGL_OBJECT_H_ + +#include +#include +#include +#include +#include "model.h" + +class ModelOpenGLObject +{ +public: + void update(std::unique_ptr mesh); + void draw(); +private: + void copyMeshToOpenGL(); + QOpenGLVertexArrayObject m_vertexArrayObject; + QOpenGLBuffer m_buffer; + std::unique_ptr m_mesh; + bool m_meshIsDirty = false; + QMutex m_meshMutex; + int m_meshTriangleVertexCount = 0; +}; + +#endif diff --git a/application/sources/model_opengl_program.cc b/application/sources/model_opengl_program.cc new file mode 100644 index 00000000..10d2fae1 --- /dev/null +++ b/application/sources/model_opengl_program.cc @@ -0,0 +1,44 @@ +#include +#include +#include "model_opengl_program.h" + +static const QString &loadShaderSource(const QString &name) +{ + static std::map s_shaderSources; + auto findShader = s_shaderSources.find(name); + if (findShader != s_shaderSources.end()) { + return findShader->second; + } + QFile file(name); + file.open(QFile::ReadOnly | QFile::Text); + QTextStream stream(&file); + auto insertResult = s_shaderSources.insert({name, stream.readAll()}); + return insertResult.first->second; +} + +void ModelOpenGLProgram::load(bool isCoreProfile) +{ + if (m_isLoaded) + return; + + m_isCoreProfile = isCoreProfile; + if (m_isCoreProfile) { + addShaderFromSourceCode(QOpenGLShader::Vertex, loadShaderSource(":/shaders/model_core.vert")); + addShaderFromSourceCode(QOpenGLShader::Fragment, loadShaderSource(":/shaders/model_core.frag")); + } else { + addShaderFromSourceCode(QOpenGLShader::Vertex, loadShaderSource(":/shaders/model.vert")); + addShaderFromSourceCode(QOpenGLShader::Fragment, loadShaderSource(":/shaders/model.frag")); + } + bindAttributeLocation("vertex", 0); + bindAttributeLocation("normal", 1); + bindAttributeLocation("color", 2); + bindAttributeLocation("texCoord", 3); + bindAttributeLocation("metalness", 4); + bindAttributeLocation("roughness", 5); + bindAttributeLocation("tangent", 6); + bindAttributeLocation("alpha", 7); + link(); + bind(); + + m_isLoaded = true; +} diff --git a/application/sources/model_opengl_program.h b/application/sources/model_opengl_program.h new file mode 100644 index 00000000..2edd1be6 --- /dev/null +++ b/application/sources/model_opengl_program.h @@ -0,0 +1,16 @@ +#ifndef DUST3D_APPLICATION_MODEL_OPENGL_PROGRAM_H_ +#define DUST3D_APPLICATION_MODEL_OPENGL_PROGRAM_H_ + +#include + +class ModelOpenGLProgram: public QOpenGLShaderProgram +{ +public: + void load(bool isCoreProfile=false); + +private: + bool m_isLoaded = false; + bool m_isCoreProfile = false; +}; + +#endif diff --git a/application/sources/model_shader_program.cc b/application/sources/model_shader_program.cc deleted file mode 100644 index f166c9fa..00000000 --- a/application/sources/model_shader_program.cc +++ /dev/null @@ -1,209 +0,0 @@ -#include -#include -#include "model_shader_program.h" - -const QString &ModelShaderProgram::loadShaderSource(const QString &name) -{ - static std::map s_shaderSources; - auto findShader = s_shaderSources.find(name); - if (findShader != s_shaderSources.end()) { - return findShader->second; - } - QFile file(name); - file.open(QFile::ReadOnly | QFile::Text); - QTextStream stream(&file); - auto insertResult = s_shaderSources.insert({name, stream.readAll()}); - return insertResult.first->second; -} - -bool ModelShaderProgram::isCoreProfile() -{ - return m_isCoreProfile; -} - -ModelShaderProgram::ModelShaderProgram(bool isCoreProfile) -{ - if (isCoreProfile) { - this->addShaderFromSourceCode(QOpenGLShader::Vertex, loadShaderSource(":/shaders/model_core.vert")); - this->addShaderFromSourceCode(QOpenGLShader::Fragment, loadShaderSource(":/shaders/model_core.frag")); - m_isCoreProfile = true; - } else { - this->addShaderFromSourceCode(QOpenGLShader::Vertex, loadShaderSource(":/shaders/model.vert")); - this->addShaderFromSourceCode(QOpenGLShader::Fragment, loadShaderSource(":/shaders/model.frag")); - } - this->bindAttributeLocation("vertex", 0); - this->bindAttributeLocation("normal", 1); - this->bindAttributeLocation("color", 2); - this->bindAttributeLocation("texCoord", 3); - this->bindAttributeLocation("metalness", 4); - this->bindAttributeLocation("roughness", 5); - this->bindAttributeLocation("tangent", 6); - this->bindAttributeLocation("alpha", 7); - this->link(); - - this->bind(); - m_projectionMatrixLoc = this->uniformLocation("projectionMatrix"); - m_modelMatrixLoc = this->uniformLocation("modelMatrix"); - m_normalMatrixLoc = this->uniformLocation("normalMatrix"); - m_viewMatrixLoc = this->uniformLocation("viewMatrix"); - m_eyePosLoc = this->uniformLocation("eyePos"); - m_textureIdLoc = this->uniformLocation("textureId"); - m_textureEnabledLoc = this->uniformLocation("textureEnabled"); - m_normalMapIdLoc = this->uniformLocation("normalMapId"); - m_normalMapEnabledLoc = this->uniformLocation("normalMapEnabled"); - m_metalnessMapEnabledLoc = this->uniformLocation("metalnessMapEnabled"); - m_roughnessMapEnabledLoc = this->uniformLocation("roughnessMapEnabled"); - m_ambientOcclusionMapEnabledLoc = this->uniformLocation("ambientOcclusionMapEnabled"); - m_metalnessRoughnessAmbientOcclusionMapIdLoc = this->uniformLocation("metalnessRoughnessAmbientOcclusionMapId"); - m_mousePickEnabledLoc = this->uniformLocation("mousePickEnabled"); - m_mousePickTargetPositionLoc = this->uniformLocation("mousePickTargetPosition"); - m_mousePickRadiusLoc = this->uniformLocation("mousePickRadius"); - m_toonShadingEnabledLoc = this->uniformLocation("toonShadingEnabled"); - m_renderPurposeLoc = this->uniformLocation("renderPurpose"); - m_toonEdgeEnabledLoc = this->uniformLocation("toonEdgeEnabled"); - m_screenWidthLoc = this->uniformLocation("screenWidth"); - m_screenHeightLoc = this->uniformLocation("screenHeight"); - m_toonNormalMapIdLoc = this->uniformLocation("toonNormalMapId"); - m_toonDepthMapIdLoc = this->uniformLocation("toonDepthMapId"); - if (m_isCoreProfile) { - m_environmentIrradianceMapIdLoc = this->uniformLocation("environmentIrradianceMapId"); - m_environmentIrradianceMapEnabledLoc = this->uniformLocation("environmentIrradianceMapEnabled"); - m_environmentSpecularMapIdLoc = this->uniformLocation("environmentSpecularMapId"); - m_environmentSpecularMapEnabledLoc = this->uniformLocation("environmentSpecularMapEnabled"); - } -} - -int ModelShaderProgram::projectionMatrixLoc() -{ - return m_projectionMatrixLoc; -} - -int ModelShaderProgram::modelMatrixLoc() -{ - return m_modelMatrixLoc; -} - -int ModelShaderProgram::normalMatrixLoc() -{ - return m_normalMatrixLoc; -} - -int ModelShaderProgram::viewMatrixLoc() -{ - return m_viewMatrixLoc; -} - -int ModelShaderProgram::eyePosLoc() -{ - return m_eyePosLoc; -} - -int ModelShaderProgram::textureEnabledLoc() -{ - return m_textureEnabledLoc; -} - -int ModelShaderProgram::textureIdLoc() -{ - return m_textureIdLoc; -} - -int ModelShaderProgram::normalMapEnabledLoc() -{ - return m_normalMapEnabledLoc; -} - -int ModelShaderProgram::normalMapIdLoc() -{ - return m_normalMapIdLoc; -} - -int ModelShaderProgram::metalnessMapEnabledLoc() -{ - return m_metalnessMapEnabledLoc; -} - -int ModelShaderProgram::roughnessMapEnabledLoc() -{ - return m_roughnessMapEnabledLoc; -} - -int ModelShaderProgram::ambientOcclusionMapEnabledLoc() -{ - return m_ambientOcclusionMapEnabledLoc; -} - -int ModelShaderProgram::metalnessRoughnessAmbientOcclusionMapIdLoc() -{ - return m_metalnessRoughnessAmbientOcclusionMapIdLoc; -} - -int ModelShaderProgram::mousePickEnabledLoc() -{ - return m_mousePickEnabledLoc; -} - -int ModelShaderProgram::mousePickTargetPositionLoc() -{ - return m_mousePickTargetPositionLoc; -} - -int ModelShaderProgram::mousePickRadiusLoc() -{ - return m_mousePickRadiusLoc; -} - -int ModelShaderProgram::environmentIrradianceMapIdLoc() -{ - return m_environmentIrradianceMapIdLoc; -} - -int ModelShaderProgram::environmentIrradianceMapEnabledLoc() -{ - return m_environmentIrradianceMapEnabledLoc; -} - -int ModelShaderProgram::environmentSpecularMapIdLoc() -{ - return m_environmentSpecularMapIdLoc; -} - -int ModelShaderProgram::environmentSpecularMapEnabledLoc() -{ - return m_environmentSpecularMapEnabledLoc; -} - -int ModelShaderProgram::toonShadingEnabledLoc() -{ - return m_toonShadingEnabledLoc; -} - -int ModelShaderProgram::renderPurposeLoc() -{ - return m_renderPurposeLoc; -} - -int ModelShaderProgram::toonEdgeEnabledLoc() -{ - return m_toonEdgeEnabledLoc; -} - -int ModelShaderProgram::screenWidthLoc() -{ - return m_screenWidthLoc; -} - -int ModelShaderProgram::screenHeightLoc() -{ - return m_screenHeightLoc; -} - -int ModelShaderProgram::toonNormalMapIdLoc() -{ - return m_toonNormalMapIdLoc; -} - -int ModelShaderProgram::toonDepthMapIdLoc() -{ - return m_toonDepthMapIdLoc; -} diff --git a/application/sources/model_shader_program.h b/application/sources/model_shader_program.h deleted file mode 100644 index 98788631..00000000 --- a/application/sources/model_shader_program.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef DUST3D_APPLICATION_MODEL_SHADER_PROGRAM_H_ -#define DUST3D_APPLICATION_MODEL_SHADER_PROGRAM_H_ - -#include -#include - -class ModelShaderProgram : public QOpenGLShaderProgram -{ -public: - ModelShaderProgram(bool isCoreProfile); - int projectionMatrixLoc(); - int modelMatrixLoc(); - int normalMatrixLoc(); - int viewMatrixLoc(); - int eyePosLoc(); - int textureIdLoc(); - int textureEnabledLoc(); - int normalMapEnabledLoc(); - int normalMapIdLoc(); - int metalnessMapEnabledLoc(); - int roughnessMapEnabledLoc(); - int ambientOcclusionMapEnabledLoc(); - int metalnessRoughnessAmbientOcclusionMapIdLoc(); - int mousePickEnabledLoc(); - int mousePickTargetPositionLoc(); - int mousePickRadiusLoc(); - int environmentIrradianceMapIdLoc(); - int environmentIrradianceMapEnabledLoc(); - int environmentSpecularMapIdLoc(); - int environmentSpecularMapEnabledLoc(); - int toonShadingEnabledLoc(); - int renderPurposeLoc(); - int toonEdgeEnabledLoc(); - int screenWidthLoc(); - int screenHeightLoc(); - int toonNormalMapIdLoc(); - int toonDepthMapIdLoc(); - bool isCoreProfile(); - static const QString &loadShaderSource(const QString &name); -private: - bool m_isCoreProfile = false; - int m_projectionMatrixLoc = 0; - int m_modelMatrixLoc = 0; - int m_normalMatrixLoc = 0; - int m_viewMatrixLoc = 0; - int m_eyePosLoc = 0; - int m_textureIdLoc = 0; - int m_textureEnabledLoc = 0; - int m_normalMapEnabledLoc = 0; - int m_normalMapIdLoc = 0; - int m_metalnessMapEnabledLoc = 0; - int m_roughnessMapEnabledLoc = 0; - int m_ambientOcclusionMapEnabledLoc = 0; - int m_metalnessRoughnessAmbientOcclusionMapIdLoc = 0; - int m_mousePickEnabledLoc = 0; - int m_mousePickTargetPositionLoc = 0; - int m_mousePickRadiusLoc = 0; - int m_environmentIrradianceMapIdLoc = 0; - int m_environmentIrradianceMapEnabledLoc = 0; - int m_environmentSpecularMapIdLoc = 0; - int m_environmentSpecularMapEnabledLoc = 0; - int m_toonShadingEnabledLoc = 0; - int m_renderPurposeLoc = 0; - int m_toonEdgeEnabledLoc = 0; - int m_screenWidthLoc = 0; - int m_screenHeightLoc = 0; - int m_toonNormalMapIdLoc = 0; - int m_toonDepthMapIdLoc = 0; -}; - -#endif diff --git a/application/sources/model_widget.cc b/application/sources/model_widget.cc index 6f2c9cff..7c18d148 100644 --- a/application/sources/model_widget.cc +++ b/application/sources/model_widget.cc @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -7,7 +6,6 @@ #include #include "model_widget.h" -bool ModelWidget::m_transparent = true; float ModelWidget::m_minZoomRatio = 5.0; float ModelWidget::m_maxZoomRatio = 80.0; @@ -19,18 +17,14 @@ QVector3D ModelWidget::m_defaultEyePosition = QVector3D(0, 0, -2.5); ModelWidget::ModelWidget(QWidget *parent) : QOpenGLWidget(parent) { - if (m_transparent) { - setAttribute(Qt::WA_AlwaysStackOnTop); - setAttribute(Qt::WA_TranslucentBackground); - QSurfaceFormat fmt = format(); - fmt.setAlphaBufferSize(8); - fmt.setSamples(4); - setFormat(fmt); - } else { - QSurfaceFormat fmt = format(); - fmt.setSamples(4); - setFormat(fmt); - } + setAttribute(Qt::WA_AlwaysStackOnTop); + setAttribute(Qt::WA_TranslucentBackground); + + QSurfaceFormat fmt = format(); + fmt.setAlphaBufferSize(8); + fmt.setSamples(4); + setFormat(fmt); + setContextMenuPolicy(Qt::CustomContextMenu); m_widthInPixels = width() * window()->devicePixelRatio(); @@ -115,46 +109,19 @@ void ModelWidget::setZRotation(int angle) } } -Model *ModelWidget::fetchCurrentMesh() -{ - return m_meshBinder.fetchCurrentMesh(); -} - void ModelWidget::cleanup() { - if (m_program == nullptr) + if (!m_openglProgram) return; makeCurrent(); - m_meshBinder.cleanup(); - delete m_program; - m_program = nullptr; + m_openglObject.reset(); + m_openglProgram.reset(); doneCurrent(); } void ModelWidget::initializeGL() { connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ModelWidget::cleanup); - - initializeOpenGLFunctions(); - if (m_transparent) { - glClearColor(0, 0, 0, 0); - } else { - QColor bgcolor = QWidget::palette().color(QWidget::backgroundRole()); - glClearColor(bgcolor.redF(), bgcolor.greenF(), bgcolor.blueF(), 1); - } - - bool isCoreProfile = false; - const char *versionString = (const char *)glGetString(GL_VERSION); - if (nullptr != versionString && - '\0' != versionString[0]) { - isCoreProfile = format().profile() == QSurfaceFormat::CoreProfile; - } - - m_program = new ModelShaderProgram(isCoreProfile); - - m_meshBinder.initialize(); - - m_program->release(); } void ModelWidget::disableCullFace() @@ -169,16 +136,18 @@ void ModelWidget::setMoveToPosition(const QVector3D &moveToPosition) void ModelWidget::paintGL() { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_DEPTH_TEST); + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + + f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + f->glEnable(GL_BLEND); + f->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + f->glEnable(GL_DEPTH_TEST); if (m_enableCullFace) - glEnable(GL_CULL_FACE); + f->glEnable(GL_CULL_FACE); #ifdef GL_LINE_SMOOTH - glEnable(GL_LINE_SMOOTH); + f->glEnable(GL_LINE_SMOOTH); #endif - glViewport(0, 0, m_widthInPixels, m_heightInPixels); + f->glViewport(0, 0, m_widthInPixels, m_heightInPixels); m_world.setToIdentity(); m_world.rotate(m_xRot / 16.0f, 1, 0, 0); @@ -188,37 +157,18 @@ void ModelWidget::paintGL() m_camera.setToIdentity(); m_camera.translate(m_eyePosition.x(), m_eyePosition.y(), m_eyePosition.z()); - m_program->bind(); - m_program->setUniformValue(m_program->eyePosLoc(), m_eyePosition); - m_program->setUniformValue(m_program->toonShadingEnabledLoc(), 0); - m_program->setUniformValue(m_program->projectionMatrixLoc(), m_projection); - m_program->setUniformValue(m_program->modelMatrixLoc(), m_world); - QMatrix3x3 normalMatrix = m_world.normalMatrix(); - m_program->setUniformValue(m_program->normalMatrixLoc(), normalMatrix); - m_program->setUniformValue(m_program->viewMatrixLoc(), m_camera); - m_program->setUniformValue(m_program->textureEnabledLoc(), 0); - m_program->setUniformValue(m_program->normalMapEnabledLoc(), 0); - m_program->setUniformValue(m_program->renderPurposeLoc(), 0); - - m_program->setUniformValue(m_program->toonEdgeEnabledLoc(), 0); - m_program->setUniformValue(m_program->screenWidthLoc(), (GLfloat)m_widthInPixels); - m_program->setUniformValue(m_program->screenHeightLoc(), (GLfloat)m_heightInPixels); - m_program->setUniformValue(m_program->toonNormalMapIdLoc(), 0); - m_program->setUniformValue(m_program->toonDepthMapIdLoc(), 0); - - if (m_mousePickingEnabled && !m_mousePickTargetPositionInModelSpace.isNull()) { - m_program->setUniformValue(m_program->mousePickEnabledLoc(), 1); - m_program->setUniformValue(m_program->mousePickTargetPositionLoc(), - m_world * m_mousePickTargetPositionInModelSpace); - } else { - m_program->setUniformValue(m_program->mousePickEnabledLoc(), 0); - m_program->setUniformValue(m_program->mousePickTargetPositionLoc(), QVector3D()); + if (!m_openglProgram) { + m_openglProgram = std::make_unique(); + const char *openglVersion = (const char *)f->glGetString(GL_VERSION); + m_openglProgram->load(nullptr != openglVersion && + '\0' != openglVersion[0] && + format().profile() == QSurfaceFormat::CoreProfile); } - m_program->setUniformValue(m_program->mousePickRadiusLoc(), m_mousePickRadius); - - m_meshBinder.paint(m_program); - m_program->release(); + m_openglProgram->bind(); + if (m_openglObject) + m_openglObject->draw(); + m_openglProgram->release(); } void ModelWidget::updateProjectionMatrix() @@ -251,27 +201,24 @@ std::pair ModelWidget::screenPositionToMouseRay(const QPoi void ModelWidget::toggleWireframe() { - if (m_meshBinder.isWireframeVisible()) - m_meshBinder.hideWireframe(); - else - m_meshBinder.showWireframe(); - update(); + // TODO } bool ModelWidget::isWireframeVisible() { - return m_meshBinder.isWireframeVisible(); + // TODO + return false; } void ModelWidget::enableEnvironmentLight() { - m_meshBinder.enableEnvironmentLight(); - update(); + // TODO } bool ModelWidget::isEnvironmentLightEnabled() { - return m_meshBinder.isEnvironmentLightEnabled(); + // TODO + return false; } void ModelWidget::toggleRotation() @@ -290,16 +237,6 @@ void ModelWidget::toggleRotation() } } -void ModelWidget::toggleUvCheck() -{ - if (m_meshBinder.isCheckUvEnabled()) - m_meshBinder.disableCheckUv(); - else - m_meshBinder.enableCheckUv(); - m_meshBinder.reloadMesh(); - update(); -} - bool ModelWidget::inputMousePressEventFromOtherWidget(QMouseEvent *event, bool notGraphics) { bool shouldStartMove = false; @@ -471,26 +408,16 @@ void ModelWidget::setMousePickRadius(float radius) void ModelWidget::updateMesh(Model *mesh) { - m_meshBinder.updateMesh(mesh); + if (!m_openglObject) + m_openglObject = std::make_unique(); + m_openglObject->update(std::unique_ptr(mesh)); emit renderParametersChanged(); update(); } void ModelWidget::updateColorTexture(QImage *colorTextureImage) { - m_meshBinder.updateColorTexture(colorTextureImage); - update(); -} - -void ModelWidget::fetchCurrentToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap) -{ - m_meshBinder.fetchCurrentToonNormalAndDepthMaps(normalMap, depthMap); -} - -void ModelWidget::updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap) -{ - m_meshBinder.updateToonNormalAndDepthMaps(normalMap, depthMap); - update(); + // TODO } int ModelWidget::widthInPixels() diff --git a/application/sources/model_widget.h b/application/sources/model_widget.h index f6c0c624..6c082362 100644 --- a/application/sources/model_widget.h +++ b/application/sources/model_widget.h @@ -1,20 +1,18 @@ #ifndef DUST3D_APPLICATION_MODEL_WIDGET_H_ #define DUST3D_APPLICATION_MODEL_WIDGET_H_ +#include #include -#include -#include #include #include #include -#include #include #include #include "model.h" -#include "model_shader_program.h" -#include "model_mesh_binder.h" +#include "model_opengl_program.h" +#include "model_opengl_object.h" -class ModelWidget : public QOpenGLWidget, protected QOpenGLFunctions +class ModelWidget : public QOpenGLWidget { Q_OBJECT signals: @@ -31,21 +29,11 @@ signals: public: ModelWidget(QWidget *parent = 0); ~ModelWidget(); - static bool isTransparent() - { - return m_transparent; - } - static void setTransparent(bool t) - { - m_transparent = t; - } - Model *fetchCurrentMesh(); void updateMesh(Model *mesh); void updateColorTexture(QImage *colorTextureImage); void toggleWireframe(); bool isWireframeVisible(); void toggleRotation(); - void toggleUvCheck(); void enableEnvironmentLight(); bool isEnvironmentLightEnabled(); void enableMove(bool enabled); @@ -59,8 +47,6 @@ public: bool inputWheelEventFromOtherWidget(QWheelEvent *event); bool inputMouseReleaseEventFromOtherWidget(QMouseEvent *event); QPoint convertInputPosFromOtherWidget(QMouseEvent *event); - void fetchCurrentToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap); - void updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap); int widthInPixels(); int heightInPixels(); void setNotGraphics(bool notGraphics); @@ -93,20 +79,19 @@ private: int m_yRot = m_defaultYRotation; int m_zRot = m_defaultZRotation; int m_directionOnMoveStart = 0; - ModelShaderProgram *m_program = nullptr; + std::unique_ptr m_openglProgram; + std::unique_ptr m_openglObject; bool m_moveStarted = false; bool m_moveEnabled = true; bool m_zoomEnabled = true; bool m_mousePickingEnabled = false; QVector3D m_mousePickTargetPositionInModelSpace; QPoint m_lastPos; - ModelMeshBinder m_meshBinder; QMatrix4x4 m_projection; QMatrix4x4 m_camera; QMatrix4x4 m_world; float m_mousePickRadius = 0.0; QVector3D m_eyePosition = m_defaultEyePosition; - static bool m_transparent; static float m_minZoomRatio; static float m_maxZoomRatio; QPoint m_moveStartPos; diff --git a/application/sources/part_preview_images_generator.cc b/application/sources/part_preview_images_generator.cc index a5fc3752..7de9a921 100644 --- a/application/sources/part_preview_images_generator.cc +++ b/application/sources/part_preview_images_generator.cc @@ -28,8 +28,6 @@ void PartPreviewImagesGenerator::generate() m_offscreenRender->setZRotation(0); m_offscreenRender->setEyePosition(QVector3D(0, 0, -4.0)); - m_offscreenRender->enableEnvironmentLight(); - m_offscreenRender->setRenderPurpose(0); for (auto &it: m_partPreviews) { if (it.second.isCutFace) { m_offscreenRender->setXRotation(0);