Add PBR support
Now can configure metalness and roughness for parts, however, the PBR render isn't enabled in the code currently.master
parent
5c25d7d4f8
commit
f7b5fb1c6a
|
@ -556,3 +556,55 @@ https://www.reddit.com/r/gamedev/comments/5iuf3h/i_am_writting_a_3d_monster_mode
|
||||||
http://www.gdcvault.com/play/1020583/Animation-Bootcamp-An-Indie-Approach
|
http://www.gdcvault.com/play/1020583/Animation-Bootcamp-An-Indie-Approach
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<h1>Qt3D</h1>
|
||||||
|
<pre>
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
</pre>
|
|
@ -10,6 +10,8 @@
|
||||||
<file>shaders/default.frag</file>
|
<file>shaders/default.frag</file>
|
||||||
<file>shaders/default.core.vert</file>
|
<file>shaders/default.core.vert</file>
|
||||||
<file>shaders/default.core.frag</file>
|
<file>shaders/default.core.frag</file>
|
||||||
|
<file>shaders/pbr.vert</file>
|
||||||
|
<file>shaders/pbr.frag</file>
|
||||||
<file>ACKNOWLEDGEMENTS.html</file>
|
<file>ACKNOWLEDGEMENTS.html</file>
|
||||||
<file>AUTHORS</file>
|
<file>AUTHORS</file>
|
||||||
<file>CONTRIBUTORS</file>
|
<file>CONTRIBUTORS</file>
|
||||||
|
|
|
@ -3,10 +3,14 @@ in vec4 vertex;
|
||||||
in vec3 normal;
|
in vec3 normal;
|
||||||
in vec3 color;
|
in vec3 color;
|
||||||
in vec2 texCoord;
|
in vec2 texCoord;
|
||||||
|
in float metalness;
|
||||||
|
in float roughness;
|
||||||
out vec3 vert;
|
out vec3 vert;
|
||||||
out vec3 vertNormal;
|
out vec3 vertNormal;
|
||||||
out vec3 vertColor;
|
out vec3 vertColor;
|
||||||
out vec2 vertTexCoord;
|
out vec2 vertTexCoord;
|
||||||
|
out float vertMetalness;
|
||||||
|
out float vertRoughness;
|
||||||
uniform mat4 projMatrix;
|
uniform mat4 projMatrix;
|
||||||
uniform mat4 mvMatrix;
|
uniform mat4 mvMatrix;
|
||||||
uniform mat3 normalMatrix;
|
uniform mat3 normalMatrix;
|
||||||
|
@ -16,5 +20,7 @@ void main()
|
||||||
vertNormal = normalMatrix * normal;
|
vertNormal = normalMatrix * normal;
|
||||||
vertColor = color;
|
vertColor = color;
|
||||||
vertTexCoord = texCoord;
|
vertTexCoord = texCoord;
|
||||||
|
vertMetalness = metalness;
|
||||||
|
vertRoughness = roughness;
|
||||||
gl_Position = projMatrix * mvMatrix * vertex;
|
gl_Position = projMatrix * mvMatrix * vertex;
|
||||||
}
|
}
|
|
@ -2,10 +2,15 @@ attribute vec4 vertex;
|
||||||
attribute vec3 normal;
|
attribute vec3 normal;
|
||||||
attribute vec3 color;
|
attribute vec3 color;
|
||||||
attribute vec2 texCoord;
|
attribute vec2 texCoord;
|
||||||
|
attribute float metalness;
|
||||||
|
attribute float roughness;
|
||||||
varying vec3 vert;
|
varying vec3 vert;
|
||||||
varying vec3 vertNormal;
|
varying vec3 vertNormal;
|
||||||
varying vec3 vertColor;
|
varying vec3 vertColor;
|
||||||
varying vec2 vertTexCoord;
|
varying vec2 vertTexCoord;
|
||||||
|
varying float vertMetalness;
|
||||||
|
varying float vertRoughness;
|
||||||
|
varying vec3 vertView;
|
||||||
uniform mat4 projMatrix;
|
uniform mat4 projMatrix;
|
||||||
uniform mat4 mvMatrix;
|
uniform mat4 mvMatrix;
|
||||||
uniform mat3 normalMatrix;
|
uniform mat3 normalMatrix;
|
||||||
|
|
|
@ -0,0 +1,320 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
// Please note that, this file "pbr.frag" is copied and slightly modified from the Qt3D's pbr shader "metalrough.inc.frag"
|
||||||
|
// https://github.com/qt/qt3d/blob/5.11/src/extras/shaders/gl3/metalrough.inc.frag
|
||||||
|
|
||||||
|
// Exposure correction
|
||||||
|
float exposure;
|
||||||
|
// Gamma correction
|
||||||
|
float gamma;
|
||||||
|
|
||||||
|
varying highp vec3 vert;
|
||||||
|
varying highp vec3 vertNormal;
|
||||||
|
varying highp vec3 vertColor;
|
||||||
|
varying highp vec2 vertTexCoord;
|
||||||
|
varying highp float vertMetalness;
|
||||||
|
varying highp float vertRoughness;
|
||||||
|
varying highp vec3 vertView;
|
||||||
|
uniform highp vec3 lightPos;
|
||||||
|
uniform highp sampler2D textureId;
|
||||||
|
uniform highp int textureEnabled;
|
||||||
|
|
||||||
|
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 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
for (int i = 0; i < lightCount; ++i) {
|
||||||
|
cLinear += pbrModel(i,
|
||||||
|
worldPosition,
|
||||||
|
worldNormal,
|
||||||
|
worldView,
|
||||||
|
baseColor.rgb,
|
||||||
|
metalness,
|
||||||
|
alpha,
|
||||||
|
ambientOcclusion);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
highp vec3 color = vertColor;
|
||||||
|
if (textureEnabled == 1) {
|
||||||
|
color = texture2D(textureId, vertTexCoord).rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: don't hard code here
|
||||||
|
exposure = 0.0;
|
||||||
|
gamma = 2.2;
|
||||||
|
const highp float vertAmbientOcclusion = 1.0;
|
||||||
|
|
||||||
|
// Light settings:
|
||||||
|
// https://doc-snapshots.qt.io/qt5-5.12/qt3d-pbr-materials-lights-qml.html
|
||||||
|
lightCount = 3;
|
||||||
|
|
||||||
|
lights[0].type = TYPE_POINT;
|
||||||
|
lights[0].position = vec3(0.0, 5.0, 0.0);
|
||||||
|
lights[0].color = vec3(1.0, 1.0, 1.0);
|
||||||
|
lights[0].intensity = 5.0;
|
||||||
|
lights[0].constantAttenuation = 1.0;
|
||||||
|
lights[0].linearAttenuation = 0.0;
|
||||||
|
lights[0].quadraticAttenuation = 0.0025;
|
||||||
|
|
||||||
|
lights[1].type = TYPE_POINT;
|
||||||
|
lights[1].position = vec3(5.0, 0.0, 0.0);
|
||||||
|
lights[1].color = vec3(1.0, 1.0, 1.0);
|
||||||
|
lights[1].intensity = 0.8;
|
||||||
|
lights[1].constantAttenuation = 1.0;
|
||||||
|
lights[1].linearAttenuation = 0.0;
|
||||||
|
lights[1].quadraticAttenuation = 0.0025;
|
||||||
|
|
||||||
|
lights[2].type = TYPE_POINT;
|
||||||
|
lights[2].position = vec3(0.0, -5.0, 0.0);
|
||||||
|
lights[2].color = vec3(1.0, 1.0, 1.0);
|
||||||
|
lights[2].intensity = 0.15;
|
||||||
|
lights[2].constantAttenuation = 1.0;
|
||||||
|
lights[2].linearAttenuation = 0.0;
|
||||||
|
lights[2].quadraticAttenuation = 0.0025;
|
||||||
|
|
||||||
|
gl_FragColor = metalRoughFunction(vec4(color, 1.0),
|
||||||
|
vertMetalness,
|
||||||
|
vertRoughness,
|
||||||
|
vertAmbientOcclusion,
|
||||||
|
vert,
|
||||||
|
vertView,
|
||||||
|
vertNormal);
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
attribute vec4 vertex;
|
||||||
|
attribute vec3 normal;
|
||||||
|
attribute vec3 color;
|
||||||
|
attribute vec2 texCoord;
|
||||||
|
attribute float metalness;
|
||||||
|
attribute float roughness;
|
||||||
|
varying vec3 vert;
|
||||||
|
varying vec3 vertNormal;
|
||||||
|
varying vec3 vertColor;
|
||||||
|
varying vec2 vertTexCoord;
|
||||||
|
varying float vertMetalness;
|
||||||
|
varying float vertRoughness;
|
||||||
|
varying vec3 vertView;
|
||||||
|
uniform mat4 projMatrix;
|
||||||
|
uniform mat4 mvMatrix;
|
||||||
|
uniform mat3 normalMatrix;
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vert = vertex.xyz;
|
||||||
|
vertNormal = normalize((projMatrix * mvMatrix * vec4(normal, 1.0)).xyz);
|
||||||
|
vertColor = color;
|
||||||
|
vertTexCoord = texCoord;
|
||||||
|
vertMetalness = metalness;
|
||||||
|
vertRoughness = roughness;
|
||||||
|
vertView = (projMatrix * mvMatrix * vec4(0, 0, 0, 1.0)).xyz;
|
||||||
|
gl_Position = projMatrix * mvMatrix * vertex;
|
||||||
|
}
|
|
@ -157,8 +157,8 @@ GltfFileWriter::GltfFileWriter(MeshResultContext &resultContext,
|
||||||
m_json["meshes"][0]["primitives"][primitiveIndex]["attributes"]["WEIGHTS_0"] = bufferViewIndex + (++attributeIndex);
|
m_json["meshes"][0]["primitives"][primitiveIndex]["attributes"]["WEIGHTS_0"] = bufferViewIndex + (++attributeIndex);
|
||||||
}
|
}
|
||||||
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["baseColorTexture"]["index"] = 0;
|
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["baseColorTexture"]["index"] = 0;
|
||||||
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["metallicFactor"] = 0.0;
|
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["metallicFactor"] = part.second.material.metalness;
|
||||||
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["roughnessFactor"] = 1.0;
|
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["roughnessFactor"] = part.second.material.roughness;
|
||||||
|
|
||||||
primitiveIndex++;
|
primitiveIndex++;
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
#include <QSurfaceFormat>
|
||||||
#include "skeletondocumentwindow.h"
|
#include "skeletondocumentwindow.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
@ -12,6 +13,10 @@ int main(int argc, char ** argv)
|
||||||
{
|
{
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
|
||||||
|
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
|
||||||
|
QSurfaceFormat::setDefaultFormat(format);
|
||||||
|
|
||||||
// QuantumCD/Qt 5 Dark Fusion Palette
|
// QuantumCD/Qt 5 Dark Fusion Palette
|
||||||
// https://gist.github.com/QuantumCD/6245215
|
// https://gist.github.com/QuantumCD/6245215
|
||||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||||
|
|
|
@ -251,6 +251,16 @@ void *MeshGenerator::combinePartMesh(QString partId)
|
||||||
if (MeshGenerator::m_enableDebug)
|
if (MeshGenerator::m_enableDebug)
|
||||||
meshlite_bmesh_enable_debug(m_meshliteContext, bmeshId, 1);
|
meshlite_bmesh_enable_debug(m_meshliteContext, bmeshId, 1);
|
||||||
|
|
||||||
|
float metalness = 0.0;
|
||||||
|
QString metalnessString = valueOfKeyInMapOrEmpty(part, "metalness");
|
||||||
|
if (!metalnessString.isEmpty())
|
||||||
|
metalness = metalnessString.toFloat();
|
||||||
|
|
||||||
|
float roughness = 1.0;
|
||||||
|
QString roughnessString = valueOfKeyInMapOrEmpty(part, "roughness");
|
||||||
|
if (!roughnessString.isEmpty())
|
||||||
|
roughness = roughnessString.toFloat();
|
||||||
|
|
||||||
QString mirroredPartId;
|
QString mirroredPartId;
|
||||||
QUuid mirroredPartIdNotAsString;
|
QUuid mirroredPartIdNotAsString;
|
||||||
if (xMirrored) {
|
if (xMirrored) {
|
||||||
|
@ -291,7 +301,9 @@ void *MeshGenerator::combinePartMesh(QString partId)
|
||||||
bmeshNode.origin = QVector3D(x, y, z);
|
bmeshNode.origin = QVector3D(x, y, z);
|
||||||
bmeshNode.radius = radius;
|
bmeshNode.radius = radius;
|
||||||
bmeshNode.nodeId = QUuid(nodeId);
|
bmeshNode.nodeId = QUuid(nodeId);
|
||||||
bmeshNode.color = partColor;
|
bmeshNode.material.color = partColor;
|
||||||
|
bmeshNode.material.metalness = metalness;
|
||||||
|
bmeshNode.material.roughness = roughness;
|
||||||
bmeshNode.boneMark = boneMark;
|
bmeshNode.boneMark = boneMark;
|
||||||
//if (SkeletonBoneMark::None != boneMark)
|
//if (SkeletonBoneMark::None != boneMark)
|
||||||
// bmeshNode.color = SkeletonBoneMarkToColor(boneMark);
|
// bmeshNode.color = SkeletonBoneMarkToColor(boneMark);
|
||||||
|
@ -362,7 +374,7 @@ void *MeshGenerator::combinePartMesh(QString partId)
|
||||||
|
|
||||||
if (m_requirePreviewPartIds.find(partIdNotAsString) != m_requirePreviewPartIds.end()) {
|
if (m_requirePreviewPartIds.find(partIdNotAsString) != m_requirePreviewPartIds.end()) {
|
||||||
int trimedMeshId = meshlite_trim(m_meshliteContext, meshId, 1);
|
int trimedMeshId = meshlite_trim(m_meshliteContext, meshId, 1);
|
||||||
m_partPreviewMeshMap[partIdNotAsString] = new MeshLoader(m_meshliteContext, trimedMeshId, -1, partColor, nullptr, m_smoothNormal);
|
m_partPreviewMeshMap[partIdNotAsString] = new MeshLoader(m_meshliteContext, trimedMeshId, -1, {partColor, metalness, roughness}, nullptr, m_smoothNormal);
|
||||||
m_generatedPreviewPartIds.insert(partIdNotAsString);
|
m_generatedPreviewPartIds.insert(partIdNotAsString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,7 +709,7 @@ void MeshGenerator::process()
|
||||||
|
|
||||||
if (resultMeshId > 0) {
|
if (resultMeshId > 0) {
|
||||||
loadGeneratedPositionsToMeshResultContext(m_meshliteContext, triangulatedFinalMeshId);
|
loadGeneratedPositionsToMeshResultContext(m_meshliteContext, triangulatedFinalMeshId);
|
||||||
m_mesh = new MeshLoader(m_meshliteContext, resultMeshId, triangulatedFinalMeshId, Theme::white, &m_meshResultContext->triangleColors(), m_smoothNormal);
|
m_mesh = new MeshLoader(m_meshliteContext, resultMeshId, triangulatedFinalMeshId, {Theme::white, 0.0, 1.0}, &m_meshResultContext->triangleMaterials(), m_smoothNormal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needDeleteCacheContext) {
|
if (needDeleteCacheContext) {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#define MAX_VERTICES_PER_FACE 100
|
#define MAX_VERTICES_PER_FACE 100
|
||||||
|
|
||||||
MeshLoader::MeshLoader(void *meshlite, int meshId, int triangulatedMeshId, QColor modelColor, const std::vector<QColor> *triangleColors, bool smoothNormal) :
|
MeshLoader::MeshLoader(void *meshlite, int meshId, int triangulatedMeshId, Material material, const std::vector<Material> *triangleMaterials, bool smoothNormal) :
|
||||||
m_triangleVertices(nullptr),
|
m_triangleVertices(nullptr),
|
||||||
m_triangleVertexCount(0),
|
m_triangleVertexCount(0),
|
||||||
m_edgeVertices(nullptr),
|
m_edgeVertices(nullptr),
|
||||||
|
@ -68,6 +68,8 @@ MeshLoader::MeshLoader(void *meshlite, int meshId, int triangulatedMeshId, QColo
|
||||||
v->colorB = 0.0;
|
v->colorB = 0.0;
|
||||||
v->texU = 0.0;
|
v->texU = 0.0;
|
||||||
v->texV = 0.0;
|
v->texV = 0.0;
|
||||||
|
v->metalness = 0;
|
||||||
|
v->roughness = 1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,9 +97,9 @@ MeshLoader::MeshLoader(void *meshlite, int meshId, int triangulatedMeshId, QColo
|
||||||
GLfloat *triangleNormals = new GLfloat[triangleCount * 3];
|
GLfloat *triangleNormals = new GLfloat[triangleCount * 3];
|
||||||
int loadedTriangleNormalItemCount = meshlite_get_triangle_normal_array(meshlite, triangleMesh, triangleNormals, triangleCount * 3);
|
int loadedTriangleNormalItemCount = meshlite_get_triangle_normal_array(meshlite, triangleMesh, triangleNormals, triangleCount * 3);
|
||||||
|
|
||||||
float modelR = modelColor.redF();
|
float modelR = material.color.redF();
|
||||||
float modelG = modelColor.greenF();
|
float modelG = material.color.greenF();
|
||||||
float modelB = modelColor.blueF();
|
float modelB = material.color.blueF();
|
||||||
m_triangleVertexCount = triangleCount * 3;
|
m_triangleVertexCount = triangleCount * 3;
|
||||||
m_triangleVertices = new Vertex[m_triangleVertexCount * 3];
|
m_triangleVertices = new Vertex[m_triangleVertexCount * 3];
|
||||||
for (int i = 0; i < triangleCount; i++) {
|
for (int i = 0; i < triangleCount; i++) {
|
||||||
|
@ -105,11 +107,15 @@ MeshLoader::MeshLoader(void *meshlite, int meshId, int triangulatedMeshId, QColo
|
||||||
float useColorR = modelR;
|
float useColorR = modelR;
|
||||||
float useColorG = modelG;
|
float useColorG = modelG;
|
||||||
float useColorB = modelB;
|
float useColorB = modelB;
|
||||||
if (triangleColors && i < (int)triangleColors->size()) {
|
float useMetalness = material.metalness;
|
||||||
QColor triangleColor = (*triangleColors)[i];
|
float useRoughness = material.roughness;
|
||||||
useColorR = triangleColor.redF();
|
if (triangleMaterials && i < (int)triangleMaterials->size()) {
|
||||||
useColorG = triangleColor.greenF();
|
auto triangleMaterial = (*triangleMaterials)[i];
|
||||||
useColorB = triangleColor.blueF();
|
useColorR = triangleMaterial.color.redF();
|
||||||
|
useColorG = triangleMaterial.color.greenF();
|
||||||
|
useColorB = triangleMaterial.color.blueF();
|
||||||
|
useMetalness = triangleMaterial.metalness;
|
||||||
|
useRoughness = triangleMaterial.roughness;
|
||||||
}
|
}
|
||||||
TriangulatedFace triangulatedFace;
|
TriangulatedFace triangulatedFace;
|
||||||
triangulatedFace.color.setRedF(useColorR);
|
triangulatedFace.color.setRedF(useColorR);
|
||||||
|
@ -136,6 +142,8 @@ MeshLoader::MeshLoader(void *meshlite, int meshId, int triangulatedMeshId, QColo
|
||||||
v->colorR = useColorR;
|
v->colorR = useColorR;
|
||||||
v->colorG = useColorG;
|
v->colorG = useColorG;
|
||||||
v->colorB = useColorB;
|
v->colorB = useColorB;
|
||||||
|
v->metalness = useMetalness;
|
||||||
|
v->roughness = useRoughness;
|
||||||
}
|
}
|
||||||
m_triangulatedFaces.push_back(triangulatedFace);
|
m_triangulatedFaces.push_back(triangulatedFace);
|
||||||
}
|
}
|
||||||
|
@ -226,6 +234,7 @@ MeshLoader::MeshLoader(MeshResultContext &resultContext) :
|
||||||
const ResultVertex *srcVert = &part.second.vertices[vertexIndex];
|
const ResultVertex *srcVert = &part.second.vertices[vertexIndex];
|
||||||
const QVector3D *srcNormal = &part.second.interpolatedVertexNormals[vertexIndex];
|
const QVector3D *srcNormal = &part.second.interpolatedVertexNormals[vertexIndex];
|
||||||
const ResultVertexUv *srcUv = &part.second.vertexUvs[vertexIndex];
|
const ResultVertexUv *srcUv = &part.second.vertexUvs[vertexIndex];
|
||||||
|
const Material *srcMaterial = &part.second.material;
|
||||||
Vertex *dest = &m_triangleVertices[destIndex];
|
Vertex *dest = &m_triangleVertices[destIndex];
|
||||||
dest->colorR = 0;
|
dest->colorR = 0;
|
||||||
dest->colorG = 0;
|
dest->colorG = 0;
|
||||||
|
@ -238,6 +247,8 @@ MeshLoader::MeshLoader(MeshResultContext &resultContext) :
|
||||||
dest->normX = srcNormal->x();
|
dest->normX = srcNormal->x();
|
||||||
dest->normY = srcNormal->y();
|
dest->normY = srcNormal->y();
|
||||||
dest->normZ = srcNormal->z();
|
dest->normZ = srcNormal->z();
|
||||||
|
dest->metalness = srcMaterial->metalness;
|
||||||
|
dest->roughness = srcMaterial->roughness;
|
||||||
destIndex++;
|
destIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ typedef struct
|
||||||
GLfloat colorB;
|
GLfloat colorB;
|
||||||
GLfloat texU;
|
GLfloat texU;
|
||||||
GLfloat texV;
|
GLfloat texV;
|
||||||
|
GLfloat metalness;
|
||||||
|
GLfloat roughness;
|
||||||
} Vertex;
|
} Vertex;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
@ -38,7 +40,7 @@ struct TriangulatedFace
|
||||||
class MeshLoader
|
class MeshLoader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MeshLoader(void *meshlite, int meshId, int triangulatedMeshId=-1, QColor modelColor=Theme::white, const std::vector<QColor> *triangleColors=nullptr, bool smoothNormal=true);
|
MeshLoader(void *meshlite, int meshId, int triangulatedMeshId=-1, Material material={Theme::white, 0.0, 1.0}, const std::vector<Material> *triangleMaterials=nullptr, bool smoothNormal=true);
|
||||||
MeshLoader(MeshResultContext &resultContext);
|
MeshLoader(MeshResultContext &resultContext);
|
||||||
MeshLoader(Vertex *triangleVertices, int vertexNum);
|
MeshLoader(Vertex *triangleVertices, int vertexNum);
|
||||||
MeshLoader(const MeshLoader &mesh);
|
MeshLoader(const MeshLoader &mesh);
|
||||||
|
|
|
@ -26,7 +26,7 @@ struct CandidateEdge
|
||||||
|
|
||||||
MeshResultContext::MeshResultContext() :
|
MeshResultContext::MeshResultContext() :
|
||||||
m_triangleSourceResolved(false),
|
m_triangleSourceResolved(false),
|
||||||
m_triangleColorResolved(false),
|
m_triangleMaterialResolved(false),
|
||||||
m_triangleEdgeSourceMapResolved(false),
|
m_triangleEdgeSourceMapResolved(false),
|
||||||
m_bmeshNodeMapResolved(false),
|
m_bmeshNodeMapResolved(false),
|
||||||
m_resultPartsResolved(false),
|
m_resultPartsResolved(false),
|
||||||
|
@ -56,13 +56,13 @@ const std::map<int, std::pair<QUuid, QUuid>> &MeshResultContext::vertexSourceMap
|
||||||
return m_vertexSourceMap;
|
return m_vertexSourceMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<QColor> &MeshResultContext::triangleColors()
|
const std::vector<Material> &MeshResultContext::triangleMaterials()
|
||||||
{
|
{
|
||||||
if (!m_triangleColorResolved) {
|
if (!m_triangleMaterialResolved) {
|
||||||
calculateTriangleColors(m_triangleColors);
|
calculateTriangleMaterials(m_triangleMaterials);
|
||||||
m_triangleColorResolved = true;
|
m_triangleMaterialResolved = true;
|
||||||
}
|
}
|
||||||
return m_triangleColors;
|
return m_triangleMaterials;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::pair<int, int>, std::pair<QUuid, QUuid>> &MeshResultContext::triangleEdgeSourceMap()
|
const std::map<std::pair<int, int>, std::pair<QUuid, QUuid>> &MeshResultContext::triangleEdgeSourceMap()
|
||||||
|
@ -257,15 +257,15 @@ void MeshResultContext::calculateRemainingVertexSourceNodesAfterTriangleSourceNo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshResultContext::calculateTriangleColors(std::vector<QColor> &triangleColors)
|
void MeshResultContext::calculateTriangleMaterials(std::vector<Material> &triangleMaterials)
|
||||||
{
|
{
|
||||||
std::map<std::pair<QUuid, QUuid>, QColor> nodeColorMap;
|
std::map<std::pair<QUuid, QUuid>, Material> nodeMaterialMap;
|
||||||
for (const auto &it: bmeshNodes) {
|
for (const auto &it: bmeshNodes) {
|
||||||
nodeColorMap[std::make_pair(it.partId, it.nodeId)] = it.color;
|
nodeMaterialMap[std::make_pair(it.partId, it.nodeId)] = it.material;
|
||||||
}
|
}
|
||||||
const auto sourceNodes = triangleSourceNodes();
|
const auto sourceNodes = triangleSourceNodes();
|
||||||
for (const auto &it: sourceNodes) {
|
for (const auto &it: sourceNodes) {
|
||||||
triangleColors.push_back(nodeColorMap[it]);
|
triangleMaterials.push_back(nodeMaterialMap[it]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@ void MeshResultContext::calculateResultParts(std::map<QUuid, ResultPart> &parts)
|
||||||
auto it = parts.find(sourceNode.first);
|
auto it = parts.find(sourceNode.first);
|
||||||
if (it == parts.end()) {
|
if (it == parts.end()) {
|
||||||
ResultPart newPart;
|
ResultPart newPart;
|
||||||
newPart.color = triangleColors()[x];
|
newPart.material = triangleMaterials()[x];
|
||||||
parts.insert(std::make_pair(sourceNode.first, newPart));
|
parts.insert(std::make_pair(sourceNode.first, newPart));
|
||||||
}
|
}
|
||||||
auto &resultPart = parts[sourceNode.first];
|
auto &resultPart = parts[sourceNode.first];
|
||||||
|
|
|
@ -10,13 +10,20 @@
|
||||||
|
|
||||||
#define MAX_WEIGHT_NUM 4
|
#define MAX_WEIGHT_NUM 4
|
||||||
|
|
||||||
|
struct Material
|
||||||
|
{
|
||||||
|
QColor color;
|
||||||
|
float metalness;
|
||||||
|
float roughness;
|
||||||
|
};
|
||||||
|
|
||||||
struct BmeshNode
|
struct BmeshNode
|
||||||
{
|
{
|
||||||
QUuid partId;
|
QUuid partId;
|
||||||
QUuid nodeId;
|
QUuid nodeId;
|
||||||
QVector3D origin;
|
QVector3D origin;
|
||||||
float radius = 0;
|
float radius = 0;
|
||||||
QColor color;
|
Material material;
|
||||||
SkeletonBoneMark boneMark;
|
SkeletonBoneMark boneMark;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,7 +58,7 @@ struct ResultVertexUv
|
||||||
|
|
||||||
struct ResultPart
|
struct ResultPart
|
||||||
{
|
{
|
||||||
QColor color;
|
Material material;
|
||||||
std::vector<ResultVertex> vertices;
|
std::vector<ResultVertex> vertices;
|
||||||
std::vector<int> verticesOldIndicies;
|
std::vector<int> verticesOldIndicies;
|
||||||
std::vector<QVector3D> interpolatedVertexNormals;
|
std::vector<QVector3D> interpolatedVertexNormals;
|
||||||
|
@ -83,7 +90,7 @@ public:
|
||||||
MeshResultContext();
|
MeshResultContext();
|
||||||
public:
|
public:
|
||||||
const std::vector<std::pair<QUuid, QUuid>> &triangleSourceNodes();
|
const std::vector<std::pair<QUuid, QUuid>> &triangleSourceNodes();
|
||||||
const std::vector<QColor> &triangleColors();
|
const std::vector<Material> &triangleMaterials();
|
||||||
const std::map<std::pair<int, int>, std::pair<QUuid, QUuid>> &triangleEdgeSourceMap();
|
const std::map<std::pair<int, int>, std::pair<QUuid, QUuid>> &triangleEdgeSourceMap();
|
||||||
const std::map<std::pair<QUuid, QUuid>, BmeshNode *> &bmeshNodeMap();
|
const std::map<std::pair<QUuid, QUuid>, BmeshNode *> &bmeshNodeMap();
|
||||||
const std::map<QUuid, ResultPart> &parts();
|
const std::map<QUuid, ResultPart> &parts();
|
||||||
|
@ -94,7 +101,7 @@ public:
|
||||||
const std::vector<QVector3D> &interpolatedVertexNormals();
|
const std::vector<QVector3D> &interpolatedVertexNormals();
|
||||||
private:
|
private:
|
||||||
bool m_triangleSourceResolved;
|
bool m_triangleSourceResolved;
|
||||||
bool m_triangleColorResolved;
|
bool m_triangleMaterialResolved;
|
||||||
bool m_triangleEdgeSourceMapResolved;
|
bool m_triangleEdgeSourceMapResolved;
|
||||||
bool m_bmeshNodeMapResolved;
|
bool m_bmeshNodeMapResolved;
|
||||||
bool m_resultPartsResolved;
|
bool m_resultPartsResolved;
|
||||||
|
@ -103,7 +110,7 @@ private:
|
||||||
bool m_vertexNormalsInterpolated;
|
bool m_vertexNormalsInterpolated;
|
||||||
private:
|
private:
|
||||||
std::vector<std::pair<QUuid, QUuid>> m_triangleSourceNodes;
|
std::vector<std::pair<QUuid, QUuid>> m_triangleSourceNodes;
|
||||||
std::vector<QColor> m_triangleColors;
|
std::vector<Material> m_triangleMaterials;
|
||||||
std::map<std::pair<int, int>, std::pair<QUuid, QUuid>> m_triangleEdgeSourceMap;
|
std::map<std::pair<int, int>, std::pair<QUuid, QUuid>> m_triangleEdgeSourceMap;
|
||||||
std::map<std::pair<QUuid, QUuid>, BmeshNode *> m_bmeshNodeMap;
|
std::map<std::pair<QUuid, QUuid>, BmeshNode *> m_bmeshNodeMap;
|
||||||
std::map<QUuid, ResultPart> m_resultParts;
|
std::map<QUuid, ResultPart> m_resultParts;
|
||||||
|
@ -117,7 +124,7 @@ private:
|
||||||
private:
|
private:
|
||||||
void calculateTriangleSourceNodes(std::vector<std::pair<QUuid, QUuid>> &triangleSourceNodes, std::map<int, std::pair<QUuid, QUuid>> &vertexSourceMap);
|
void calculateTriangleSourceNodes(std::vector<std::pair<QUuid, QUuid>> &triangleSourceNodes, std::map<int, std::pair<QUuid, QUuid>> &vertexSourceMap);
|
||||||
void calculateRemainingVertexSourceNodesAfterTriangleSourceNodesSolved(std::map<int, std::pair<QUuid, QUuid>> &vertexSourceMap);
|
void calculateRemainingVertexSourceNodesAfterTriangleSourceNodesSolved(std::map<int, std::pair<QUuid, QUuid>> &vertexSourceMap);
|
||||||
void calculateTriangleColors(std::vector<QColor> &triangleColors);
|
void calculateTriangleMaterials(std::vector<Material> &triangleMaterials);
|
||||||
void calculateTriangleEdgeSourceMap(std::map<std::pair<int, int>, std::pair<QUuid, QUuid>> &triangleEdgeSourceMap);
|
void calculateTriangleEdgeSourceMap(std::map<std::pair<int, int>, std::pair<QUuid, QUuid>> &triangleEdgeSourceMap);
|
||||||
void calculateBmeshNodeMap(std::map<std::pair<QUuid, QUuid>, BmeshNode *> &bmeshNodeMap);
|
void calculateBmeshNodeMap(std::map<std::pair<QUuid, QUuid>, BmeshNode *> &bmeshNodeMap);
|
||||||
void calculateResultParts(std::map<QUuid, ResultPart> &parts);
|
void calculateResultParts(std::map<QUuid, ResultPart> &parts);
|
||||||
|
|
|
@ -152,10 +152,14 @@ void ModelMeshBinder::paint(ModelShaderProgram *program)
|
||||||
f->glEnableVertexAttribArray(1);
|
f->glEnableVertexAttribArray(1);
|
||||||
f->glEnableVertexAttribArray(2);
|
f->glEnableVertexAttribArray(2);
|
||||||
f->glEnableVertexAttribArray(3);
|
f->glEnableVertexAttribArray(3);
|
||||||
f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(GLfloat), 0);
|
f->glEnableVertexAttribArray(4);
|
||||||
f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
|
f->glEnableVertexAttribArray(5);
|
||||||
f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(GLfloat), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
|
f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
|
||||||
f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(GLfloat), reinterpret_cast<void *>(9 * sizeof(GLfloat)));
|
f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(9 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(11 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(12 * sizeof(GLfloat)));
|
||||||
m_vboTriangle.release();
|
m_vboTriangle.release();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
@ -171,10 +175,14 @@ void ModelMeshBinder::paint(ModelShaderProgram *program)
|
||||||
f->glEnableVertexAttribArray(1);
|
f->glEnableVertexAttribArray(1);
|
||||||
f->glEnableVertexAttribArray(2);
|
f->glEnableVertexAttribArray(2);
|
||||||
f->glEnableVertexAttribArray(3);
|
f->glEnableVertexAttribArray(3);
|
||||||
f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(GLfloat), 0);
|
f->glEnableVertexAttribArray(4);
|
||||||
f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
|
f->glEnableVertexAttribArray(5);
|
||||||
f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(GLfloat), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
|
f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
|
||||||
f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(GLfloat), reinterpret_cast<void *>(9 * sizeof(GLfloat)));
|
f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(9 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(11 * sizeof(GLfloat)));
|
||||||
|
f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(12 * sizeof(GLfloat)));
|
||||||
m_vboEdge.release();
|
m_vboEdge.release();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,19 +17,26 @@ const QString &ModelShaderProgram::loadShaderSource(const QString &name)
|
||||||
return insertResult.first->second;
|
return insertResult.first->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelShaderProgram::ModelShaderProgram()
|
ModelShaderProgram::ModelShaderProgram(bool usePBR)
|
||||||
{
|
{
|
||||||
if (QSurfaceFormat::defaultFormat().profile() == QSurfaceFormat::CoreProfile) {
|
if (QSurfaceFormat::defaultFormat().profile() == QSurfaceFormat::CoreProfile) {
|
||||||
this->addShaderFromSourceCode(QOpenGLShader::Vertex, loadShaderSource(":/shaders/default.core.vert"));
|
this->addShaderFromSourceCode(QOpenGLShader::Vertex, loadShaderSource(":/shaders/default.core.vert"));
|
||||||
this->addShaderFromSourceCode(QOpenGLShader::Fragment, loadShaderSource(":/shaders/default.core.frag"));
|
this->addShaderFromSourceCode(QOpenGLShader::Fragment, loadShaderSource(":/shaders/default.core.frag"));
|
||||||
|
} else {
|
||||||
|
if (usePBR) {
|
||||||
|
this->addShaderFromSourceCode(QOpenGLShader::Vertex, loadShaderSource(":/shaders/pbr.vert"));
|
||||||
|
this->addShaderFromSourceCode(QOpenGLShader::Fragment, loadShaderSource(":/shaders/pbr.frag"));
|
||||||
} else {
|
} else {
|
||||||
this->addShaderFromSourceCode(QOpenGLShader::Vertex, loadShaderSource(":/shaders/default.vert"));
|
this->addShaderFromSourceCode(QOpenGLShader::Vertex, loadShaderSource(":/shaders/default.vert"));
|
||||||
this->addShaderFromSourceCode(QOpenGLShader::Fragment, loadShaderSource(":/shaders/default.frag"));
|
this->addShaderFromSourceCode(QOpenGLShader::Fragment, loadShaderSource(":/shaders/default.frag"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this->bindAttributeLocation("vertex", 0);
|
this->bindAttributeLocation("vertex", 0);
|
||||||
this->bindAttributeLocation("normal", 1);
|
this->bindAttributeLocation("normal", 1);
|
||||||
this->bindAttributeLocation("color", 2);
|
this->bindAttributeLocation("color", 2);
|
||||||
this->bindAttributeLocation("texCoord", 3);
|
this->bindAttributeLocation("texCoord", 3);
|
||||||
|
this->bindAttributeLocation("metalness", 4);
|
||||||
|
this->bindAttributeLocation("roughness", 5);
|
||||||
this->link();
|
this->link();
|
||||||
|
|
||||||
this->bind();
|
this->bind();
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
class ModelShaderProgram : public QOpenGLShaderProgram
|
class ModelShaderProgram : public QOpenGLShaderProgram
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ModelShaderProgram();
|
ModelShaderProgram(bool usePBR=false);
|
||||||
int projMatrixLoc();
|
int projMatrixLoc();
|
||||||
int mvMatrixLoc();
|
int mvMatrixLoc();
|
||||||
int normalMatrixLoc();
|
int normalMatrixLoc();
|
||||||
|
|
|
@ -874,6 +874,10 @@ void SkeletonDocument::toSnapshot(SkeletonSnapshot *snapshot, const std::set<QUu
|
||||||
part["deformWidth"] = QString::number(partIt.second.deformWidth);
|
part["deformWidth"] = QString::number(partIt.second.deformWidth);
|
||||||
if (!partIt.second.name.isEmpty())
|
if (!partIt.second.name.isEmpty())
|
||||||
part["name"] = partIt.second.name;
|
part["name"] = partIt.second.name;
|
||||||
|
if (partIt.second.metalnessAdjusted())
|
||||||
|
part["metalness"] = QString::number(partIt.second.metalness);
|
||||||
|
if (partIt.second.roughnessAdjusted())
|
||||||
|
part["roughness"] = QString::number(partIt.second.roughness);
|
||||||
snapshot->parts[part["id"]] = part;
|
snapshot->parts[part["id"]] = part;
|
||||||
}
|
}
|
||||||
for (const auto &nodeIt: nodeMap) {
|
for (const auto &nodeIt: nodeMap) {
|
||||||
|
@ -1071,6 +1075,12 @@ void SkeletonDocument::addFromSnapshot(const SkeletonSnapshot &snapshot, bool fr
|
||||||
const auto &deformWidthIt = partKv.second.find("deformWidth");
|
const auto &deformWidthIt = partKv.second.find("deformWidth");
|
||||||
if (deformWidthIt != partKv.second.end())
|
if (deformWidthIt != partKv.second.end())
|
||||||
part.setDeformWidth(deformWidthIt->second.toFloat());
|
part.setDeformWidth(deformWidthIt->second.toFloat());
|
||||||
|
const auto &metalnessIt = partKv.second.find("metalness");
|
||||||
|
if (metalnessIt != partKv.second.end())
|
||||||
|
part.metalness = metalnessIt->second.toFloat();
|
||||||
|
const auto &roughnessIt = partKv.second.find("roughness");
|
||||||
|
if (roughnessIt != partKv.second.end())
|
||||||
|
part.roughness = roughnessIt->second.toFloat();
|
||||||
newAddedPartIds.insert(part.id);
|
newAddedPartIds.insert(part.id);
|
||||||
}
|
}
|
||||||
for (const auto &nodeKv: snapshot.nodes) {
|
for (const auto &nodeKv: snapshot.nodes) {
|
||||||
|
@ -2145,6 +2155,32 @@ void SkeletonDocument::setPartDeformWidth(QUuid partId, float width)
|
||||||
emit skeletonChanged();
|
emit skeletonChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkeletonDocument::setPartMetalness(QUuid partId, float metalness)
|
||||||
|
{
|
||||||
|
auto part = partMap.find(partId);
|
||||||
|
if (part == partMap.end()) {
|
||||||
|
qDebug() << "Part not found:" << partId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
part->second.metalness = metalness;
|
||||||
|
part->second.dirty = true;
|
||||||
|
emit partMetalnessChanged(partId);
|
||||||
|
emit skeletonChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkeletonDocument::setPartRoughness(QUuid partId, float roughness)
|
||||||
|
{
|
||||||
|
auto part = partMap.find(partId);
|
||||||
|
if (part == partMap.end()) {
|
||||||
|
qDebug() << "Part not found:" << partId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
part->second.roughness = roughness;
|
||||||
|
part->second.dirty = true;
|
||||||
|
emit partRoughnessChanged(partId);
|
||||||
|
emit skeletonChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void SkeletonDocument::setPartRoundState(QUuid partId, bool rounded)
|
void SkeletonDocument::setPartRoundState(QUuid partId, bool rounded)
|
||||||
{
|
{
|
||||||
auto part = partMap.find(partId);
|
auto part = partMap.find(partId);
|
||||||
|
|
|
@ -97,6 +97,8 @@ public:
|
||||||
std::vector<QUuid> nodeIds;
|
std::vector<QUuid> nodeIds;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
bool wrapped;
|
bool wrapped;
|
||||||
|
float metalness;
|
||||||
|
float roughness;
|
||||||
SkeletonPart(const QUuid &withId=QUuid()) :
|
SkeletonPart(const QUuid &withId=QUuid()) :
|
||||||
visible(true),
|
visible(true),
|
||||||
locked(false),
|
locked(false),
|
||||||
|
@ -110,7 +112,9 @@ public:
|
||||||
color(Theme::white),
|
color(Theme::white),
|
||||||
hasColor(false),
|
hasColor(false),
|
||||||
dirty(true),
|
dirty(true),
|
||||||
wrapped(false)
|
wrapped(false),
|
||||||
|
metalness(0.0),
|
||||||
|
roughness(1.0)
|
||||||
{
|
{
|
||||||
id = withId.isNull() ? QUuid::createUuid() : withId;
|
id = withId.isNull() ? QUuid::createUuid() : withId;
|
||||||
}
|
}
|
||||||
|
@ -142,6 +146,18 @@ public:
|
||||||
{
|
{
|
||||||
return deformThicknessAdjusted() || deformWidthAdjusted();
|
return deformThicknessAdjusted() || deformWidthAdjusted();
|
||||||
}
|
}
|
||||||
|
bool metalnessAdjusted() const
|
||||||
|
{
|
||||||
|
return fabs(metalness - 0.0) >= 0.01;
|
||||||
|
}
|
||||||
|
bool roughnessAdjusted() const
|
||||||
|
{
|
||||||
|
return fabs(roughness - 1.0) >= 0.01;
|
||||||
|
}
|
||||||
|
bool materialAdjusted() const
|
||||||
|
{
|
||||||
|
return metalnessAdjusted() || roughnessAdjusted();
|
||||||
|
}
|
||||||
bool isEditVisible() const
|
bool isEditVisible() const
|
||||||
{
|
{
|
||||||
return visible && !disabled;
|
return visible && !disabled;
|
||||||
|
@ -162,6 +178,8 @@ public:
|
||||||
wrapped = other.wrapped;
|
wrapped = other.wrapped;
|
||||||
componentId = other.componentId;
|
componentId = other.componentId;
|
||||||
dirty = other.dirty;
|
dirty = other.dirty;
|
||||||
|
metalness = other.metalness;
|
||||||
|
roughness = other.roughness;
|
||||||
}
|
}
|
||||||
void updatePreviewMesh(MeshLoader *previewMesh)
|
void updatePreviewMesh(MeshLoader *previewMesh)
|
||||||
{
|
{
|
||||||
|
@ -444,6 +462,8 @@ signals:
|
||||||
void partRoundStateChanged(QUuid partId);
|
void partRoundStateChanged(QUuid partId);
|
||||||
void partColorStateChanged(QUuid partId);
|
void partColorStateChanged(QUuid partId);
|
||||||
void partWrapStateChanged(QUuid partId);
|
void partWrapStateChanged(QUuid partId);
|
||||||
|
void partMetalnessChanged(QUuid partId);
|
||||||
|
void partRoughnessChanged(QUuid partId);
|
||||||
void componentInverseStateChanged(QUuid partId);
|
void componentInverseStateChanged(QUuid partId);
|
||||||
void cleanup();
|
void cleanup();
|
||||||
void originChanged();
|
void originChanged();
|
||||||
|
@ -583,6 +603,8 @@ public slots:
|
||||||
void setPartRoundState(QUuid partId, bool rounded);
|
void setPartRoundState(QUuid partId, bool rounded);
|
||||||
void setPartColorState(QUuid partId, bool hasColor, QColor color);
|
void setPartColorState(QUuid partId, bool hasColor, QColor color);
|
||||||
void setPartWrapState(QUuid partId, bool wrapped);
|
void setPartWrapState(QUuid partId, bool wrapped);
|
||||||
|
void setPartMetalness(QUuid partId, float metalness);
|
||||||
|
void setPartRoughness(QUuid partId, float roughness);
|
||||||
void setComponentInverseState(QUuid componentId, bool inverse);
|
void setComponentInverseState(QUuid componentId, bool inverse);
|
||||||
void moveComponentUp(QUuid componentId);
|
void moveComponentUp(QUuid componentId);
|
||||||
void moveComponentDown(QUuid componentId);
|
void moveComponentDown(QUuid componentId);
|
||||||
|
|
|
@ -760,6 +760,8 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
||||||
connect(m_document, &SkeletonDocument::partRoundStateChanged, partTreeWidget, &SkeletonPartTreeWidget::partRoundStateChanged);
|
connect(m_document, &SkeletonDocument::partRoundStateChanged, partTreeWidget, &SkeletonPartTreeWidget::partRoundStateChanged);
|
||||||
connect(m_document, &SkeletonDocument::partWrapStateChanged, partTreeWidget, &SkeletonPartTreeWidget::partWrapStateChanged);
|
connect(m_document, &SkeletonDocument::partWrapStateChanged, partTreeWidget, &SkeletonPartTreeWidget::partWrapStateChanged);
|
||||||
connect(m_document, &SkeletonDocument::partColorStateChanged, partTreeWidget, &SkeletonPartTreeWidget::partColorStateChanged);
|
connect(m_document, &SkeletonDocument::partColorStateChanged, partTreeWidget, &SkeletonPartTreeWidget::partColorStateChanged);
|
||||||
|
connect(m_document, &SkeletonDocument::partMetalnessChanged, partTreeWidget, &SkeletonPartTreeWidget::partMetalnessChanged);
|
||||||
|
connect(m_document, &SkeletonDocument::partRoughnessChanged, partTreeWidget, &SkeletonPartTreeWidget::partRoughnessChanged);
|
||||||
connect(m_document, &SkeletonDocument::partRemoved, partTreeWidget, &SkeletonPartTreeWidget::partRemoved);
|
connect(m_document, &SkeletonDocument::partRemoved, partTreeWidget, &SkeletonPartTreeWidget::partRemoved);
|
||||||
connect(m_document, &SkeletonDocument::cleanup, partTreeWidget, &SkeletonPartTreeWidget::removeAllContent);
|
connect(m_document, &SkeletonDocument::cleanup, partTreeWidget, &SkeletonPartTreeWidget::removeAllContent);
|
||||||
connect(m_document, &SkeletonDocument::partChecked, partTreeWidget, &SkeletonPartTreeWidget::partChecked);
|
connect(m_document, &SkeletonDocument::partChecked, partTreeWidget, &SkeletonPartTreeWidget::partChecked);
|
||||||
|
|
|
@ -932,6 +932,28 @@ void SkeletonPartTreeWidget::partColorStateChanged(QUuid partId)
|
||||||
widget->updateColorButton();
|
widget->updateColorButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkeletonPartTreeWidget::partMetalnessChanged(QUuid partId)
|
||||||
|
{
|
||||||
|
auto item = m_partItemMap.find(partId);
|
||||||
|
if (item == m_partItemMap.end()) {
|
||||||
|
qDebug() << "Part item not found:" << partId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SkeletonPartWidget *widget = (SkeletonPartWidget *)itemWidget(item->second, 0);
|
||||||
|
widget->updateColorButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkeletonPartTreeWidget::partRoughnessChanged(QUuid partId)
|
||||||
|
{
|
||||||
|
auto item = m_partItemMap.find(partId);
|
||||||
|
if (item == m_partItemMap.end()) {
|
||||||
|
qDebug() << "Part item not found:" << partId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SkeletonPartWidget *widget = (SkeletonPartWidget *)itemWidget(item->second, 0);
|
||||||
|
widget->updateColorButton();
|
||||||
|
}
|
||||||
|
|
||||||
void SkeletonPartTreeWidget::partChecked(QUuid partId)
|
void SkeletonPartTreeWidget::partChecked(QUuid partId)
|
||||||
{
|
{
|
||||||
auto item = m_partItemMap.find(partId);
|
auto item = m_partItemMap.find(partId);
|
||||||
|
|
|
@ -62,6 +62,8 @@ public slots:
|
||||||
void partRoundStateChanged(QUuid partId);
|
void partRoundStateChanged(QUuid partId);
|
||||||
void partWrapStateChanged(QUuid partId);
|
void partWrapStateChanged(QUuid partId);
|
||||||
void partColorStateChanged(QUuid partId);
|
void partColorStateChanged(QUuid partId);
|
||||||
|
void partMetalnessChanged(QUuid partId);
|
||||||
|
void partRoughnessChanged(QUuid partId);
|
||||||
void partChecked(QUuid partId);
|
void partChecked(QUuid partId);
|
||||||
void partUnchecked(QUuid partId);
|
void partUnchecked(QUuid partId);
|
||||||
void groupChanged(QTreeWidgetItem *item, int column);
|
void groupChanged(QTreeWidgetItem *item, int column);
|
||||||
|
|
|
@ -131,6 +131,8 @@ SkeletonPartWidget::SkeletonPartWidget(const SkeletonDocument *document, QUuid p
|
||||||
connect(this, &SkeletonPartWidget::setPartRoundState, m_document, &SkeletonDocument::setPartRoundState);
|
connect(this, &SkeletonPartWidget::setPartRoundState, m_document, &SkeletonDocument::setPartRoundState);
|
||||||
connect(this, &SkeletonPartWidget::setPartWrapState, m_document, &SkeletonDocument::setPartWrapState);
|
connect(this, &SkeletonPartWidget::setPartWrapState, m_document, &SkeletonDocument::setPartWrapState);
|
||||||
connect(this, &SkeletonPartWidget::setPartColorState, m_document, &SkeletonDocument::setPartColorState);
|
connect(this, &SkeletonPartWidget::setPartColorState, m_document, &SkeletonDocument::setPartColorState);
|
||||||
|
connect(this, &SkeletonPartWidget::setPartMetalness, m_document, &SkeletonDocument::setPartMetalness);
|
||||||
|
connect(this, &SkeletonPartWidget::setPartRoughness, m_document, &SkeletonDocument::setPartRoughness);
|
||||||
connect(this, &SkeletonPartWidget::checkPart, m_document, &SkeletonDocument::checkPart);
|
connect(this, &SkeletonPartWidget::checkPart, m_document, &SkeletonDocument::checkPart);
|
||||||
connect(this, &SkeletonPartWidget::enableBackgroundBlur, m_document, &SkeletonDocument::enableBackgroundBlur);
|
connect(this, &SkeletonPartWidget::enableBackgroundBlur, m_document, &SkeletonDocument::enableBackgroundBlur);
|
||||||
connect(this, &SkeletonPartWidget::disableBackgroundBlur, m_document, &SkeletonDocument::disableBackgroundBlur);
|
connect(this, &SkeletonPartWidget::disableBackgroundBlur, m_document, &SkeletonDocument::disableBackgroundBlur);
|
||||||
|
@ -301,9 +303,10 @@ void SkeletonPartWidget::showColorSettingPopup(const QPoint &pos)
|
||||||
palette.setColor(QPalette::Button, choosenColor);
|
palette.setColor(QPalette::Button, choosenColor);
|
||||||
pickButton->setPalette(palette);
|
pickButton->setPalette(palette);
|
||||||
|
|
||||||
QHBoxLayout *layout = new QHBoxLayout;
|
QHBoxLayout *colorLayout = new QHBoxLayout;
|
||||||
layout->addWidget(colorEraser);
|
colorLayout->addWidget(colorEraser);
|
||||||
layout->addWidget(pickButton);
|
colorLayout->addWidget(pickButton);
|
||||||
|
colorLayout->addStretch();
|
||||||
|
|
||||||
connect(colorEraser, &QPushButton::clicked, [=]() {
|
connect(colorEraser, &QPushButton::clicked, [=]() {
|
||||||
emit setPartColorState(m_partId, false, Theme::white);
|
emit setPartColorState(m_partId, false, Theme::white);
|
||||||
|
@ -320,7 +323,55 @@ void SkeletonPartWidget::showColorSettingPopup(const QPoint &pos)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
popup->setLayout(layout);
|
FloatNumberWidget *metalnessWidget = new FloatNumberWidget;
|
||||||
|
metalnessWidget->setItemName(tr("Metalness"));
|
||||||
|
metalnessWidget->setRange(0, 1);
|
||||||
|
metalnessWidget->setValue(part->metalness);
|
||||||
|
|
||||||
|
connect(metalnessWidget, &FloatNumberWidget::valueChanged, [=](float value) {
|
||||||
|
emit setPartMetalness(m_partId, value);
|
||||||
|
emit groupOperationAdded();
|
||||||
|
});
|
||||||
|
|
||||||
|
FloatNumberWidget *roughnessWidget = new FloatNumberWidget;
|
||||||
|
roughnessWidget->setItemName(tr("Roughness"));
|
||||||
|
roughnessWidget->setRange(0, 1);
|
||||||
|
roughnessWidget->setValue(part->roughness);
|
||||||
|
|
||||||
|
connect(roughnessWidget, &FloatNumberWidget::valueChanged, [=](float value) {
|
||||||
|
emit setPartRoughness(m_partId, value);
|
||||||
|
emit groupOperationAdded();
|
||||||
|
});
|
||||||
|
|
||||||
|
QPushButton *metalnessEraser = new QPushButton(QChar(fa::eraser));
|
||||||
|
initToolButton(metalnessEraser);
|
||||||
|
|
||||||
|
connect(metalnessEraser, &QPushButton::clicked, [=]() {
|
||||||
|
metalnessWidget->setValue(0.0);
|
||||||
|
emit groupOperationAdded();
|
||||||
|
});
|
||||||
|
|
||||||
|
QPushButton *roughnessEraser = new QPushButton(QChar(fa::eraser));
|
||||||
|
initToolButton(roughnessEraser);
|
||||||
|
|
||||||
|
connect(roughnessEraser, &QPushButton::clicked, [=]() {
|
||||||
|
roughnessWidget->setValue(1.0);
|
||||||
|
emit groupOperationAdded();
|
||||||
|
});
|
||||||
|
|
||||||
|
QHBoxLayout *metalnessLayout = new QHBoxLayout;
|
||||||
|
QHBoxLayout *roughnessLayout = new QHBoxLayout;
|
||||||
|
metalnessLayout->addWidget(metalnessEraser);
|
||||||
|
metalnessLayout->addWidget(metalnessWidget);
|
||||||
|
roughnessLayout->addWidget(roughnessEraser);
|
||||||
|
roughnessLayout->addWidget(roughnessWidget);
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
mainLayout->addLayout(colorLayout);
|
||||||
|
mainLayout->addLayout(metalnessLayout);
|
||||||
|
mainLayout->addLayout(roughnessLayout);
|
||||||
|
|
||||||
|
popup->setLayout(mainLayout);
|
||||||
|
|
||||||
QWidgetAction *action = new QWidgetAction(this);
|
QWidgetAction *action = new QWidgetAction(this);
|
||||||
action->setDefaultWidget(popup);
|
action->setDefaultWidget(popup);
|
||||||
|
@ -518,7 +569,7 @@ void SkeletonPartWidget::updateColorButton()
|
||||||
qDebug() << "Part not found:" << m_partId;
|
qDebug() << "Part not found:" << m_partId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (part->hasColor)
|
if (part->hasColor || part->materialAdjusted())
|
||||||
updateButton(m_colorButton, QChar(fa::eyedropper), true);
|
updateButton(m_colorButton, QChar(fa::eyedropper), true);
|
||||||
else
|
else
|
||||||
updateButton(m_colorButton, QChar(fa::eyedropper), false);
|
updateButton(m_colorButton, QChar(fa::eyedropper), false);
|
||||||
|
|
|
@ -21,6 +21,8 @@ signals:
|
||||||
void setPartRoundState(QUuid partId, bool rounded);
|
void setPartRoundState(QUuid partId, bool rounded);
|
||||||
void setPartColorState(QUuid partId, bool hasColor, QColor color);
|
void setPartColorState(QUuid partId, bool hasColor, QColor color);
|
||||||
void setPartWrapState(QUuid partId, bool wrapped);
|
void setPartWrapState(QUuid partId, bool wrapped);
|
||||||
|
void setPartMetalness(QUuid partId, float metalness);
|
||||||
|
void setPartRoughness(QUuid partId, float roughness);
|
||||||
void movePartUp(QUuid partId);
|
void movePartUp(QUuid partId);
|
||||||
void movePartDown(QUuid partId);
|
void movePartDown(QUuid partId);
|
||||||
void movePartToTop(QUuid partId);
|
void movePartToTop(QUuid partId);
|
||||||
|
|
|
@ -45,11 +45,11 @@ MeshLoader *SkinnedMeshCreator::createMeshFromTransform(const std::vector<QMatri
|
||||||
int triangleVerticesNum = 0;
|
int triangleVerticesNum = 0;
|
||||||
for (size_t triangleIndex = 0; triangleIndex < m_meshResultContext.triangles.size(); triangleIndex++) {
|
for (size_t triangleIndex = 0; triangleIndex < m_meshResultContext.triangles.size(); triangleIndex++) {
|
||||||
const auto &sourceTriangle = m_meshResultContext.triangles[triangleIndex];
|
const auto &sourceTriangle = m_meshResultContext.triangles[triangleIndex];
|
||||||
QColor triangleColor = m_meshResultContext.triangleColors()[triangleIndex];
|
Material triangleMaterial = m_meshResultContext.triangleMaterials()[triangleIndex];
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
Vertex ¤tVertex = triangleVertices[triangleVerticesNum++];
|
Vertex ¤tVertex = triangleVertices[triangleVerticesNum++];
|
||||||
const auto &sourcePosition = transformedPositions[sourceTriangle.indicies[i]];
|
const auto &sourcePosition = transformedPositions[sourceTriangle.indicies[i]];
|
||||||
const auto &sourceColor = triangleColor;
|
const auto &sourceColor = triangleMaterial.color;
|
||||||
const auto &sourceNormal = transformedPoseNormals[sourceTriangle.indicies[i]];
|
const auto &sourceNormal = transformedPoseNormals[sourceTriangle.indicies[i]];
|
||||||
currentVertex.posX = sourcePosition.x();
|
currentVertex.posX = sourcePosition.x();
|
||||||
currentVertex.posY = sourcePosition.y();
|
currentVertex.posY = sourcePosition.y();
|
||||||
|
@ -62,6 +62,8 @@ MeshLoader *SkinnedMeshCreator::createMeshFromTransform(const std::vector<QMatri
|
||||||
currentVertex.normX = sourceNormal.x();
|
currentVertex.normX = sourceNormal.x();
|
||||||
currentVertex.normY = sourceNormal.y();
|
currentVertex.normY = sourceNormal.y();
|
||||||
currentVertex.normZ = sourceNormal.z();
|
currentVertex.normZ = sourceNormal.z();
|
||||||
|
currentVertex.metalness = triangleMaterial.metalness;
|
||||||
|
currentVertex.roughness = triangleMaterial.roughness;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ MeshLoader *TextureGenerator::takeResultMesh()
|
||||||
|
|
||||||
void TextureGenerator::process()
|
void TextureGenerator::process()
|
||||||
{
|
{
|
||||||
const std::vector<QColor> &triangleColors = m_resultContext->triangleColors();
|
const std::vector<Material> &triangleMaterials = m_resultContext->triangleMaterials();
|
||||||
const std::vector<ResultTriangleUv> &triangleUvs = m_resultContext->triangleUvs();
|
const std::vector<ResultTriangleUv> &triangleUvs = m_resultContext->triangleUvs();
|
||||||
|
|
||||||
m_resultTextureColorImage = new QImage(TextureGenerator::m_textureWidth, TextureGenerator::m_textureHeight, QImage::Format_ARGB32);
|
m_resultTextureColorImage = new QImage(TextureGenerator::m_textureWidth, TextureGenerator::m_textureHeight, QImage::Format_ARGB32);
|
||||||
|
@ -105,10 +105,10 @@ void TextureGenerator::process()
|
||||||
path.lineTo(uv->uv[j][0] * TextureGenerator::m_textureWidth, uv->uv[j][1] * TextureGenerator::m_textureHeight);
|
path.lineTo(uv->uv[j][0] * TextureGenerator::m_textureWidth, uv->uv[j][1] * TextureGenerator::m_textureHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QPen textureBorderPen(triangleColors[i]);
|
QPen textureBorderPen(triangleMaterials[i].color);
|
||||||
textureBorderPen.setWidth(32);
|
textureBorderPen.setWidth(32);
|
||||||
texturePainter.setPen(textureBorderPen);
|
texturePainter.setPen(textureBorderPen);
|
||||||
texturePainter.setBrush(QBrush(triangleColors[i]));
|
texturePainter.setBrush(QBrush(triangleMaterials[i].color));
|
||||||
texturePainter.drawPath(path);
|
texturePainter.drawPath(path);
|
||||||
}
|
}
|
||||||
// round 2, real paint
|
// round 2, real paint
|
||||||
|
@ -123,7 +123,7 @@ void TextureGenerator::process()
|
||||||
path.lineTo(uv->uv[j][0] * TextureGenerator::m_textureWidth, uv->uv[j][1] * TextureGenerator::m_textureHeight);
|
path.lineTo(uv->uv[j][0] * TextureGenerator::m_textureWidth, uv->uv[j][1] * TextureGenerator::m_textureHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
texturePainter.fillPath(path, QBrush(triangleColors[i]));
|
texturePainter.fillPath(path, QBrush(triangleMaterials[i].color));
|
||||||
}
|
}
|
||||||
|
|
||||||
pen.setWidth(0);
|
pen.setWidth(0);
|
||||||
|
|
Loading…
Reference in New Issue