Prepare for new render implementation
parent
eaf29d2c65
commit
58290a9b21
|
@ -157,12 +157,12 @@ HEADERS += sources/mesh_result_post_processor.h
|
||||||
SOURCES += sources/mesh_result_post_processor.cc
|
SOURCES += sources/mesh_result_post_processor.cc
|
||||||
HEADERS += sources/model.h
|
HEADERS += sources/model.h
|
||||||
SOURCES += sources/model.cc
|
SOURCES += sources/model.cc
|
||||||
HEADERS += sources/model_mesh_binder.h
|
|
||||||
SOURCES += sources/model_mesh_binder.cc
|
|
||||||
HEADERS += sources/model_offscreen_render.h
|
HEADERS += sources/model_offscreen_render.h
|
||||||
SOURCES += sources/model_offscreen_render.cc
|
SOURCES += sources/model_offscreen_render.cc
|
||||||
HEADERS += sources/model_shader_program.h
|
HEADERS += sources/model_opengl_program.h
|
||||||
SOURCES += sources/model_shader_program.cc
|
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_shader_vertex.h
|
||||||
HEADERS += sources/model_widget.h
|
HEADERS += sources/model_widget.h
|
||||||
SOURCES += sources/model_widget.cc
|
SOURCES += sources/model_widget.cc
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,448 +0,0 @@
|
||||||
#include <QMutexLocker>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QTextStream>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <map>
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QSurfaceFormat>
|
|
||||||
#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<void *>(3 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(9 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(11 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(12 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(13 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(7, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(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<void *>(3 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(9 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(11 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(12 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(13 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(7, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(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<void *>(3 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(9 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(11 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(12 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(13 * sizeof(GLfloat)));
|
|
||||||
f->glVertexAttribPointer(7, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(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;
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
#ifndef DUST3D_APPLICATION_MODEL_MESH_BINDER_H_
|
|
||||||
#define DUST3D_APPLICATION_MODEL_MESH_BINDER_H_
|
|
||||||
|
|
||||||
#include <QOpenGLVertexArrayObject>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QOpenGLBuffer>
|
|
||||||
#include <QString>
|
|
||||||
#include <QOpenGLTexture>
|
|
||||||
#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
|
|
|
@ -1,216 +1,51 @@
|
||||||
#include <QOpenGLFramebufferObjectFormat>
|
#include "model_offscreen_render.h"
|
||||||
#include <QThread>
|
|
||||||
#include <QDebug>
|
ModelOffscreenRender::ModelOffscreenRender(const QSurfaceFormat &format, QScreen *targetScreen):
|
||||||
#include "model_offscreen_render.h"
|
QOffscreenSurface(targetScreen)
|
||||||
|
{
|
||||||
ModelOffscreenRender::ModelOffscreenRender(const QSurfaceFormat &format, QScreen *targetScreen) :
|
}
|
||||||
QOffscreenSurface(targetScreen),
|
|
||||||
m_context(nullptr),
|
ModelOffscreenRender::~ModelOffscreenRender()
|
||||||
m_mesh(nullptr)
|
{
|
||||||
{
|
// TODO
|
||||||
setFormat(format);
|
}
|
||||||
create();
|
|
||||||
if (!isValid())
|
void ModelOffscreenRender::setXRotation(int angle)
|
||||||
qDebug() << "ModelOffscreenRender is invalid";
|
{
|
||||||
}
|
// TODO
|
||||||
|
}
|
||||||
ModelOffscreenRender::~ModelOffscreenRender()
|
|
||||||
{
|
void ModelOffscreenRender::setYRotation(int angle)
|
||||||
// FIXME: If delete m_renderFbo inside toImage,
|
{
|
||||||
// sometimes, the application will freeze, maybe there are dead locks inside the destruction call
|
// TODO
|
||||||
// move it here can make sure it will be deleted on the main GUI thread to avoid dead locks
|
}
|
||||||
delete m_renderFbo;
|
|
||||||
|
void ModelOffscreenRender::setZRotation(int angle)
|
||||||
destroy();
|
{
|
||||||
delete m_mesh;
|
// TODO
|
||||||
delete m_normalMap;
|
}
|
||||||
delete m_depthMap;
|
|
||||||
}
|
void ModelOffscreenRender::setEyePosition(const QVector3D &eyePosition)
|
||||||
|
{
|
||||||
void ModelOffscreenRender::updateMesh(Model *mesh)
|
// TODO
|
||||||
{
|
}
|
||||||
delete m_mesh;
|
|
||||||
m_mesh = mesh;
|
void ModelOffscreenRender::setMoveToPosition(const QVector3D &moveToPosition)
|
||||||
}
|
{
|
||||||
|
// TODO
|
||||||
void ModelOffscreenRender::setRenderThread(QThread *thread)
|
}
|
||||||
{
|
|
||||||
this->moveToThread(thread);
|
void ModelOffscreenRender::setRenderThread(QThread *thread)
|
||||||
}
|
{
|
||||||
|
// TODO
|
||||||
void ModelOffscreenRender::setXRotation(int angle)
|
}
|
||||||
{
|
|
||||||
m_xRot = angle;
|
void ModelOffscreenRender::updateMesh(Model *mesh)
|
||||||
}
|
{
|
||||||
|
// TODO
|
||||||
void ModelOffscreenRender::setYRotation(int angle)
|
}
|
||||||
{
|
|
||||||
m_yRot = angle;
|
QImage ModelOffscreenRender::toImage(const QSize &size)
|
||||||
}
|
{
|
||||||
|
// TODO
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,50 +1,24 @@
|
||||||
#ifndef DUST3D_APPLICATION_MODEL_OFFSCREEN_RENDER_H_
|
#ifndef DUST3D_APPLICATION_MODEL_OFFSCREEN_RENDER_H_
|
||||||
#define DUST3D_APPLICATION_MODEL_OFFSCREEN_RENDER_H_
|
#define DUST3D_APPLICATION_MODEL_OFFSCREEN_RENDER_H_
|
||||||
|
|
||||||
#include <QOffscreenSurface>
|
#include <QOffscreenSurface>
|
||||||
#include <QScreen>
|
#include <QSurfaceFormat>
|
||||||
#include <QOpenGLFunctions>
|
#include <QVector3D>
|
||||||
#include <QOpenGLContext>
|
#include "model.h"
|
||||||
#include <QImage>
|
|
||||||
#include <QThread>
|
class ModelOffscreenRender: public QOffscreenSurface
|
||||||
#include <QOpenGLFramebufferObject>
|
{
|
||||||
#include "model_shader_program.h"
|
public:
|
||||||
#include "model_mesh_binder.h"
|
ModelOffscreenRender(const QSurfaceFormat &format, QScreen *targetScreen=Q_NULLPTR);
|
||||||
#include "model.h"
|
~ModelOffscreenRender();
|
||||||
|
void setXRotation(int angle);
|
||||||
class ModelOffscreenRender : QOffscreenSurface
|
void setYRotation(int angle);
|
||||||
{
|
void setZRotation(int angle);
|
||||||
public:
|
void setEyePosition(const QVector3D &eyePosition);
|
||||||
ModelOffscreenRender(const QSurfaceFormat &format, QScreen *targetScreen=Q_NULLPTR);
|
void setMoveToPosition(const QVector3D &moveToPosition);
|
||||||
~ModelOffscreenRender();
|
void setRenderThread(QThread *thread);
|
||||||
void setXRotation(int angle);
|
void updateMesh(Model *mesh);
|
||||||
void setYRotation(int angle);
|
QImage toImage(const QSize &size);
|
||||||
void setZRotation(int angle);
|
};
|
||||||
void setEyePosition(const QVector3D &eyePosition);
|
|
||||||
void setMoveToPosition(const QVector3D &moveToPosition);
|
#endif
|
||||||
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
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
#include <QOpenGLFunctions>
|
||||||
|
#include <QOpenGLContext>
|
||||||
|
#include "model_opengl_object.h"
|
||||||
|
|
||||||
|
void ModelOpenGLObject::update(std::unique_ptr<Model> 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<Model> 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<void *>(3 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(9 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(11 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(12 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(13 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(7, 1, GL_FLOAT, GL_FALSE, sizeof(ModelShaderVertex), reinterpret_cast<void *>(16 * sizeof(GLfloat)));
|
||||||
|
m_buffer.release();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef DUST3D_APPLICATION_MODEL_OPENGL_OBJECT_H_
|
||||||
|
#define DUST3D_APPLICATION_MODEL_OPENGL_OBJECT_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QOpenGLVertexArrayObject>
|
||||||
|
#include <QOpenGLBuffer>
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
|
class ModelOpenGLObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void update(std::unique_ptr<Model> mesh);
|
||||||
|
void draw();
|
||||||
|
private:
|
||||||
|
void copyMeshToOpenGL();
|
||||||
|
QOpenGLVertexArrayObject m_vertexArrayObject;
|
||||||
|
QOpenGLBuffer m_buffer;
|
||||||
|
std::unique_ptr<Model> m_mesh;
|
||||||
|
bool m_meshIsDirty = false;
|
||||||
|
QMutex m_meshMutex;
|
||||||
|
int m_meshTriangleVertexCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,44 @@
|
||||||
|
#include <QOpenGLFunctions>
|
||||||
|
#include <QFile>
|
||||||
|
#include "model_opengl_program.h"
|
||||||
|
|
||||||
|
static const QString &loadShaderSource(const QString &name)
|
||||||
|
{
|
||||||
|
static std::map<QString, QString> 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;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef DUST3D_APPLICATION_MODEL_OPENGL_PROGRAM_H_
|
||||||
|
#define DUST3D_APPLICATION_MODEL_OPENGL_PROGRAM_H_
|
||||||
|
|
||||||
|
#include <QOpenGLShaderProgram>
|
||||||
|
|
||||||
|
class ModelOpenGLProgram: public QOpenGLShaderProgram
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void load(bool isCoreProfile=false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isLoaded = false;
|
||||||
|
bool m_isCoreProfile = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,209 +0,0 @@
|
||||||
#include <QFile>
|
|
||||||
#include <map>
|
|
||||||
#include "model_shader_program.h"
|
|
||||||
|
|
||||||
const QString &ModelShaderProgram::loadShaderSource(const QString &name)
|
|
||||||
{
|
|
||||||
static std::map<QString, QString> 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;
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
#ifndef DUST3D_APPLICATION_MODEL_SHADER_PROGRAM_H_
|
|
||||||
#define DUST3D_APPLICATION_MODEL_SHADER_PROGRAM_H_
|
|
||||||
|
|
||||||
#include <QOpenGLShaderProgram>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
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
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QOpenGLShaderProgram>
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
@ -7,7 +6,6 @@
|
||||||
#include <QSurfaceFormat>
|
#include <QSurfaceFormat>
|
||||||
#include "model_widget.h"
|
#include "model_widget.h"
|
||||||
|
|
||||||
bool ModelWidget::m_transparent = true;
|
|
||||||
float ModelWidget::m_minZoomRatio = 5.0;
|
float ModelWidget::m_minZoomRatio = 5.0;
|
||||||
float ModelWidget::m_maxZoomRatio = 80.0;
|
float ModelWidget::m_maxZoomRatio = 80.0;
|
||||||
|
|
||||||
|
@ -19,18 +17,14 @@ QVector3D ModelWidget::m_defaultEyePosition = QVector3D(0, 0, -2.5);
|
||||||
ModelWidget::ModelWidget(QWidget *parent) :
|
ModelWidget::ModelWidget(QWidget *parent) :
|
||||||
QOpenGLWidget(parent)
|
QOpenGLWidget(parent)
|
||||||
{
|
{
|
||||||
if (m_transparent) {
|
setAttribute(Qt::WA_AlwaysStackOnTop);
|
||||||
setAttribute(Qt::WA_AlwaysStackOnTop);
|
setAttribute(Qt::WA_TranslucentBackground);
|
||||||
setAttribute(Qt::WA_TranslucentBackground);
|
|
||||||
QSurfaceFormat fmt = format();
|
QSurfaceFormat fmt = format();
|
||||||
fmt.setAlphaBufferSize(8);
|
fmt.setAlphaBufferSize(8);
|
||||||
fmt.setSamples(4);
|
fmt.setSamples(4);
|
||||||
setFormat(fmt);
|
setFormat(fmt);
|
||||||
} else {
|
|
||||||
QSurfaceFormat fmt = format();
|
|
||||||
fmt.setSamples(4);
|
|
||||||
setFormat(fmt);
|
|
||||||
}
|
|
||||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
|
||||||
m_widthInPixels = width() * window()->devicePixelRatio();
|
m_widthInPixels = width() * window()->devicePixelRatio();
|
||||||
|
@ -115,46 +109,19 @@ void ModelWidget::setZRotation(int angle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Model *ModelWidget::fetchCurrentMesh()
|
|
||||||
{
|
|
||||||
return m_meshBinder.fetchCurrentMesh();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelWidget::cleanup()
|
void ModelWidget::cleanup()
|
||||||
{
|
{
|
||||||
if (m_program == nullptr)
|
if (!m_openglProgram)
|
||||||
return;
|
return;
|
||||||
makeCurrent();
|
makeCurrent();
|
||||||
m_meshBinder.cleanup();
|
m_openglObject.reset();
|
||||||
delete m_program;
|
m_openglProgram.reset();
|
||||||
m_program = nullptr;
|
|
||||||
doneCurrent();
|
doneCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelWidget::initializeGL()
|
void ModelWidget::initializeGL()
|
||||||
{
|
{
|
||||||
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ModelWidget::cleanup);
|
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()
|
void ModelWidget::disableCullFace()
|
||||||
|
@ -169,16 +136,18 @@ void ModelWidget::setMoveToPosition(const QVector3D &moveToPosition)
|
||||||
|
|
||||||
void ModelWidget::paintGL()
|
void ModelWidget::paintGL()
|
||||||
{
|
{
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
glEnable(GL_DEPTH_TEST);
|
f->glEnable(GL_BLEND);
|
||||||
|
f->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
f->glEnable(GL_DEPTH_TEST);
|
||||||
if (m_enableCullFace)
|
if (m_enableCullFace)
|
||||||
glEnable(GL_CULL_FACE);
|
f->glEnable(GL_CULL_FACE);
|
||||||
#ifdef GL_LINE_SMOOTH
|
#ifdef GL_LINE_SMOOTH
|
||||||
glEnable(GL_LINE_SMOOTH);
|
f->glEnable(GL_LINE_SMOOTH);
|
||||||
#endif
|
#endif
|
||||||
glViewport(0, 0, m_widthInPixels, m_heightInPixels);
|
f->glViewport(0, 0, m_widthInPixels, m_heightInPixels);
|
||||||
|
|
||||||
m_world.setToIdentity();
|
m_world.setToIdentity();
|
||||||
m_world.rotate(m_xRot / 16.0f, 1, 0, 0);
|
m_world.rotate(m_xRot / 16.0f, 1, 0, 0);
|
||||||
|
@ -188,37 +157,18 @@ void ModelWidget::paintGL()
|
||||||
m_camera.setToIdentity();
|
m_camera.setToIdentity();
|
||||||
m_camera.translate(m_eyePosition.x(), m_eyePosition.y(), m_eyePosition.z());
|
m_camera.translate(m_eyePosition.x(), m_eyePosition.y(), m_eyePosition.z());
|
||||||
|
|
||||||
m_program->bind();
|
if (!m_openglProgram) {
|
||||||
m_program->setUniformValue(m_program->eyePosLoc(), m_eyePosition);
|
m_openglProgram = std::make_unique<ModelOpenGLProgram>();
|
||||||
m_program->setUniformValue(m_program->toonShadingEnabledLoc(), 0);
|
const char *openglVersion = (const char *)f->glGetString(GL_VERSION);
|
||||||
m_program->setUniformValue(m_program->projectionMatrixLoc(), m_projection);
|
m_openglProgram->load(nullptr != openglVersion &&
|
||||||
m_program->setUniformValue(m_program->modelMatrixLoc(), m_world);
|
'\0' != openglVersion[0] &&
|
||||||
QMatrix3x3 normalMatrix = m_world.normalMatrix();
|
format().profile() == QSurfaceFormat::CoreProfile);
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
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()
|
void ModelWidget::updateProjectionMatrix()
|
||||||
|
@ -251,27 +201,24 @@ std::pair<QVector3D, QVector3D> ModelWidget::screenPositionToMouseRay(const QPoi
|
||||||
|
|
||||||
void ModelWidget::toggleWireframe()
|
void ModelWidget::toggleWireframe()
|
||||||
{
|
{
|
||||||
if (m_meshBinder.isWireframeVisible())
|
// TODO
|
||||||
m_meshBinder.hideWireframe();
|
|
||||||
else
|
|
||||||
m_meshBinder.showWireframe();
|
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelWidget::isWireframeVisible()
|
bool ModelWidget::isWireframeVisible()
|
||||||
{
|
{
|
||||||
return m_meshBinder.isWireframeVisible();
|
// TODO
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelWidget::enableEnvironmentLight()
|
void ModelWidget::enableEnvironmentLight()
|
||||||
{
|
{
|
||||||
m_meshBinder.enableEnvironmentLight();
|
// TODO
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelWidget::isEnvironmentLightEnabled()
|
bool ModelWidget::isEnvironmentLightEnabled()
|
||||||
{
|
{
|
||||||
return m_meshBinder.isEnvironmentLightEnabled();
|
// TODO
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelWidget::toggleRotation()
|
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 ModelWidget::inputMousePressEventFromOtherWidget(QMouseEvent *event, bool notGraphics)
|
||||||
{
|
{
|
||||||
bool shouldStartMove = false;
|
bool shouldStartMove = false;
|
||||||
|
@ -471,26 +408,16 @@ void ModelWidget::setMousePickRadius(float radius)
|
||||||
|
|
||||||
void ModelWidget::updateMesh(Model *mesh)
|
void ModelWidget::updateMesh(Model *mesh)
|
||||||
{
|
{
|
||||||
m_meshBinder.updateMesh(mesh);
|
if (!m_openglObject)
|
||||||
|
m_openglObject = std::make_unique<ModelOpenGLObject>();
|
||||||
|
m_openglObject->update(std::unique_ptr<Model>(mesh));
|
||||||
emit renderParametersChanged();
|
emit renderParametersChanged();
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelWidget::updateColorTexture(QImage *colorTextureImage)
|
void ModelWidget::updateColorTexture(QImage *colorTextureImage)
|
||||||
{
|
{
|
||||||
m_meshBinder.updateColorTexture(colorTextureImage);
|
// TODO
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ModelWidget::widthInPixels()
|
int ModelWidget::widthInPixels()
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
#ifndef DUST3D_APPLICATION_MODEL_WIDGET_H_
|
#ifndef DUST3D_APPLICATION_MODEL_WIDGET_H_
|
||||||
#define DUST3D_APPLICATION_MODEL_WIDGET_H_
|
#define DUST3D_APPLICATION_MODEL_WIDGET_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
#include <QOpenGLFunctions>
|
|
||||||
#include <QOpenGLVertexArrayObject>
|
|
||||||
#include <QOpenGLBuffer>
|
#include <QOpenGLBuffer>
|
||||||
#include <QMatrix4x4>
|
#include <QMatrix4x4>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QRubberBand>
|
|
||||||
#include <QVector2D>
|
#include <QVector2D>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "model_shader_program.h"
|
#include "model_opengl_program.h"
|
||||||
#include "model_mesh_binder.h"
|
#include "model_opengl_object.h"
|
||||||
|
|
||||||
class ModelWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
class ModelWidget : public QOpenGLWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
signals:
|
signals:
|
||||||
|
@ -31,21 +29,11 @@ signals:
|
||||||
public:
|
public:
|
||||||
ModelWidget(QWidget *parent = 0);
|
ModelWidget(QWidget *parent = 0);
|
||||||
~ModelWidget();
|
~ModelWidget();
|
||||||
static bool isTransparent()
|
|
||||||
{
|
|
||||||
return m_transparent;
|
|
||||||
}
|
|
||||||
static void setTransparent(bool t)
|
|
||||||
{
|
|
||||||
m_transparent = t;
|
|
||||||
}
|
|
||||||
Model *fetchCurrentMesh();
|
|
||||||
void updateMesh(Model *mesh);
|
void updateMesh(Model *mesh);
|
||||||
void updateColorTexture(QImage *colorTextureImage);
|
void updateColorTexture(QImage *colorTextureImage);
|
||||||
void toggleWireframe();
|
void toggleWireframe();
|
||||||
bool isWireframeVisible();
|
bool isWireframeVisible();
|
||||||
void toggleRotation();
|
void toggleRotation();
|
||||||
void toggleUvCheck();
|
|
||||||
void enableEnvironmentLight();
|
void enableEnvironmentLight();
|
||||||
bool isEnvironmentLightEnabled();
|
bool isEnvironmentLightEnabled();
|
||||||
void enableMove(bool enabled);
|
void enableMove(bool enabled);
|
||||||
|
@ -59,8 +47,6 @@ public:
|
||||||
bool inputWheelEventFromOtherWidget(QWheelEvent *event);
|
bool inputWheelEventFromOtherWidget(QWheelEvent *event);
|
||||||
bool inputMouseReleaseEventFromOtherWidget(QMouseEvent *event);
|
bool inputMouseReleaseEventFromOtherWidget(QMouseEvent *event);
|
||||||
QPoint convertInputPosFromOtherWidget(QMouseEvent *event);
|
QPoint convertInputPosFromOtherWidget(QMouseEvent *event);
|
||||||
void fetchCurrentToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap);
|
|
||||||
void updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap);
|
|
||||||
int widthInPixels();
|
int widthInPixels();
|
||||||
int heightInPixels();
|
int heightInPixels();
|
||||||
void setNotGraphics(bool notGraphics);
|
void setNotGraphics(bool notGraphics);
|
||||||
|
@ -93,20 +79,19 @@ private:
|
||||||
int m_yRot = m_defaultYRotation;
|
int m_yRot = m_defaultYRotation;
|
||||||
int m_zRot = m_defaultZRotation;
|
int m_zRot = m_defaultZRotation;
|
||||||
int m_directionOnMoveStart = 0;
|
int m_directionOnMoveStart = 0;
|
||||||
ModelShaderProgram *m_program = nullptr;
|
std::unique_ptr<ModelOpenGLProgram> m_openglProgram;
|
||||||
|
std::unique_ptr<ModelOpenGLObject> m_openglObject;
|
||||||
bool m_moveStarted = false;
|
bool m_moveStarted = false;
|
||||||
bool m_moveEnabled = true;
|
bool m_moveEnabled = true;
|
||||||
bool m_zoomEnabled = true;
|
bool m_zoomEnabled = true;
|
||||||
bool m_mousePickingEnabled = false;
|
bool m_mousePickingEnabled = false;
|
||||||
QVector3D m_mousePickTargetPositionInModelSpace;
|
QVector3D m_mousePickTargetPositionInModelSpace;
|
||||||
QPoint m_lastPos;
|
QPoint m_lastPos;
|
||||||
ModelMeshBinder m_meshBinder;
|
|
||||||
QMatrix4x4 m_projection;
|
QMatrix4x4 m_projection;
|
||||||
QMatrix4x4 m_camera;
|
QMatrix4x4 m_camera;
|
||||||
QMatrix4x4 m_world;
|
QMatrix4x4 m_world;
|
||||||
float m_mousePickRadius = 0.0;
|
float m_mousePickRadius = 0.0;
|
||||||
QVector3D m_eyePosition = m_defaultEyePosition;
|
QVector3D m_eyePosition = m_defaultEyePosition;
|
||||||
static bool m_transparent;
|
|
||||||
static float m_minZoomRatio;
|
static float m_minZoomRatio;
|
||||||
static float m_maxZoomRatio;
|
static float m_maxZoomRatio;
|
||||||
QPoint m_moveStartPos;
|
QPoint m_moveStartPos;
|
||||||
|
|
|
@ -28,8 +28,6 @@ void PartPreviewImagesGenerator::generate()
|
||||||
|
|
||||||
m_offscreenRender->setZRotation(0);
|
m_offscreenRender->setZRotation(0);
|
||||||
m_offscreenRender->setEyePosition(QVector3D(0, 0, -4.0));
|
m_offscreenRender->setEyePosition(QVector3D(0, 0, -4.0));
|
||||||
m_offscreenRender->enableEnvironmentLight();
|
|
||||||
m_offscreenRender->setRenderPurpose(0);
|
|
||||||
for (auto &it: m_partPreviews) {
|
for (auto &it: m_partPreviews) {
|
||||||
if (it.second.isCutFace) {
|
if (it.second.isCutFace) {
|
||||||
m_offscreenRender->setXRotation(0);
|
m_offscreenRender->setXRotation(0);
|
||||||
|
|
Loading…
Reference in New Issue