diff --git a/ACKNOWLEDGEMENTS.html b/ACKNOWLEDGEMENTS.html index 8beecfcb..39a2c273 100644 --- a/ACKNOWLEDGEMENTS.html +++ b/ACKNOWLEDGEMENTS.html @@ -1296,4 +1296,9 @@ https://www.reddit.com/r/gamedev/comments/5iuf3h/i_am_writting_a_3d_monster_mode LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +

Greg Zaal

+
+    https://hdrihaven.com/hdri/?h=cedar_bridge
 
\ No newline at end of file diff --git a/dust3d.pro b/dust3d.pro index 48c8db83..5fff1c41 100644 --- a/dust3d.pro +++ b/dust3d.pro @@ -505,6 +505,9 @@ HEADERS += src/projectfacestonodes.h SOURCES += src/simulateclothmeshes.cpp HEADERS += src/simulateclothmeshes.h +SOURCES += src/ddsfile.cpp +HEADERS += src/ddsfile.h + SOURCES += src/main.cpp HEADERS += src/version.h diff --git a/resources.qrc b/resources.qrc index 3b0ebb54..3fab310b 100644 --- a/resources.qrc +++ b/resources.qrc @@ -23,6 +23,8 @@ resources/heptagon.png resources/userdefined.png resources/checkuv.png + resources/cedar_bridge_irradiance.dds + resources/cedar_bridge_specular.dds shaders/default.vert shaders/default.frag shaders/default.core.vert diff --git a/resources/cedar_bridge_irradiance.dds b/resources/cedar_bridge_irradiance.dds new file mode 100644 index 00000000..c08c4630 Binary files /dev/null and b/resources/cedar_bridge_irradiance.dds differ diff --git a/resources/cedar_bridge_specular.dds b/resources/cedar_bridge_specular.dds new file mode 100644 index 00000000..ac9d49cc Binary files /dev/null and b/resources/cedar_bridge_specular.dds differ diff --git a/shaders/default.core.frag b/shaders/default.core.frag index 3bf72812..41c6a8f6 100644 --- a/shaders/default.core.frag +++ b/shaders/default.core.frag @@ -53,35 +53,39 @@ // https://github.com/qt/qt3d/blob/5.11/src/extras/shaders/gl3/metalrough.inc.frag // Exposure correction -highp float exposure; +float exposure; // Gamma correction -highp float gamma; +float gamma; -in highp vec3 vert; -in highp vec3 vertRaw; -in highp vec3 vertNormal; -in highp vec3 vertColor; -in highp vec2 vertTexCoord; -in highp float vertMetalness; -in highp float vertRoughness; -in highp vec3 cameraPos; -in highp vec3 firstLightPos; -in highp vec3 secondLightPos; -in highp vec3 thirdLightPos; -in highp float vertAlpha; -out highp vec4 fragColor; -uniform highp vec3 lightPos; -uniform highp sampler2D textureId; -uniform highp int textureEnabled; -uniform highp sampler2D normalMapId; -uniform highp int normalMapEnabled; -uniform highp sampler2D metalnessRoughnessAmbientOcclusionMapId; -uniform highp int metalnessMapEnabled; -uniform highp int roughnessMapEnabled; -uniform highp int ambientOcclusionMapEnabled; -uniform highp int mousePickEnabled; -uniform highp vec3 mousePickTargetPosition; -uniform highp float mousePickRadius; +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 vec3 lightPos; +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; const int MAX_LIGHTS = 8; const int TYPE_POINT = 0; @@ -89,51 +93,88 @@ const int TYPE_DIRECTIONAL = 1; const int TYPE_SPOT = 2; struct Light { int type; - highp vec3 position; - highp vec3 color; - highp float intensity; - highp vec3 direction; - highp float constantAttenuation; - highp float linearAttenuation; - highp float quadraticAttenuation; - highp float cutOffAngle; + vec3 position; + vec3 color; + float intensity; + vec3 direction; + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; + float cutOffAngle; }; int lightCount; Light lights[MAX_LIGHTS]; -highp float remapRoughness(const in highp float roughness) +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 - highp float maxSpecPower; - highp float minRoughness; + float maxSpecPower; + float minRoughness; maxSpecPower = 999999.0; minRoughness = sqrt(2.0 / (maxSpecPower + 2.0)); return max(roughness * roughness, minRoughness); } -highp float normalDistribution(const in highp vec3 n, const in highp vec3 h, const in highp float alpha) +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 - highp float specPower = 2.0 / (alpha * alpha) - 2.0; + float specPower = 2.0 / (alpha * alpha) - 2.0; return (specPower + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), specPower); } -highp vec3 fresnelFactor(const in highp vec3 color, const in highp float cosineFactor) +vec3 fresnelFactor(const in vec3 color, const in float cosineFactor) { // Calculate the Fresnel effect value - highp vec3 f = color; - highp vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0); + vec3 f = color; + vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0); return clamp(F, f, vec3(1.0)); } -highp float geometricModel(const in highp float lDotN, - const in highp float vDotN, - const in highp vec3 h) +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 @@ -141,50 +182,50 @@ highp float geometricModel(const in highp float lDotN, return lDotN * vDotN; } -highp vec3 specularModel(const in highp vec3 F0, - const in highp float sDotH, - const in highp float sDotN, - const in highp float vDotN, - const in highp vec3 n, - const in highp vec3 h) +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. - highp float sDotNPrime = max(sDotN, 0.001); - highp float vDotNPrime = max(vDotN, 0.001); + float sDotNPrime = max(sDotN, 0.001); + float vDotNPrime = max(vDotN, 0.001); - highp vec3 F = fresnelFactor(F0, sDotH); - highp float G = geometricModel(sDotNPrime, vDotNPrime, h); + vec3 F = fresnelFactor(F0, sDotH); + float G = geometricModel(sDotNPrime, vDotNPrime, h); - highp vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); + vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); return clamp(cSpec, vec3(0.0), vec3(1.0)); } -highp vec3 pbrModel(const in int lightIndex, - const in highp vec3 wPosition, - const in highp vec3 wNormal, - const in highp vec3 wView, - const in highp vec3 baseColor, - const in highp float metalness, - const in highp float alpha, - const in highp float ambientOcclusion) +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 - highp vec3 n = wNormal; - highp vec3 s = vec3(0.0); - highp vec3 v = wView; - highp vec3 h = vec3(0.0); + vec3 n = wNormal; + vec3 s = vec3(0.0); + vec3 v = wView; + vec3 h = vec3(0.0); - highp float vDotN = dot(v, n); - highp float sDotN = 0.0; - highp float sDotH = 0.0; - highp float att = 1.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 - highp vec3 sUnnormalized = vec3(lights[lightIndex].position) - wPosition; + vec3 sUnnormalized = vec3(lights[lightIndex].position) - wPosition; s = normalize(sUnnormalized); // Calculate the attenuation factor @@ -193,7 +234,7 @@ highp vec3 pbrModel(const in int lightIndex, if (lights[lightIndex].constantAttenuation != 0.0 || lights[lightIndex].linearAttenuation != 0.0 || lights[lightIndex].quadraticAttenuation != 0.0) { - highp float dist = length(sUnnormalized); + float dist = length(sUnnormalized); att = 1.0 / (lights[lightIndex].constantAttenuation + lights[lightIndex].linearAttenuation * dist + lights[lightIndex].quadraticAttenuation * dist * dist); @@ -217,22 +258,22 @@ highp vec3 pbrModel(const in int lightIndex, sDotH = dot(s, h); // Calculate diffuse component - highp vec3 diffuseColor = (1.0 - metalness) * baseColor * lights[lightIndex].color; - highp vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159; + vec3 diffuseColor = (1.0 - metalness) * baseColor * lights[lightIndex].color; + vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159; // Calculate specular component - highp vec3 dielectricColor = vec3(0.04); - highp vec3 F0 = mix(dielectricColor, baseColor, metalness); - highp vec3 specularFactor = vec3(0.0); + 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); } - highp vec3 specularColor = lights[lightIndex].color; - highp vec3 specular = specularColor * specularFactor; + vec3 specularColor = lights[lightIndex].color; + vec3 specular = specularColor * specularFactor; // Blend between diffuse and specular to conserver energy - highp vec3 color = att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular)); + vec3 color = att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular)); // Reduce by ambient occlusion amount color *= ambientOcclusion; @@ -240,29 +281,99 @@ highp vec3 pbrModel(const in int lightIndex, return color; } -highp vec3 toneMap(const in highp vec3 c) +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)); } -highp vec3 gammaCorrect(const in highp vec3 color) +vec3 gammaCorrect(const in vec3 color) { return pow(color, vec3(1.0 / gamma)); } -highp vec4 metalRoughFunction(const in highp vec4 baseColor, - const in highp float metalness, - const in highp float roughness, - const in highp float ambientOcclusion, - const in highp vec3 worldPosition, - const in highp vec3 worldView, - const in highp vec3 worldNormal) +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) { - highp vec3 cLinear = vec3(0.0); + vec3 cLinear = vec3(0.0); // Remap roughness for a perceptually more linear correspondence - highp float alpha = remapRoughness(roughness); - + float alpha = remapRoughness(roughness); + + if (environmentIrradianceMapEnabled == 1) { + cLinear += pbrIblModel(worldNormal, + worldView, + baseColor.rgb, + metalness, + alpha, + ambientOcclusion); + } + for (int i = 0; i < lightCount; ++i) { cLinear += pbrModel(i, worldPosition, @@ -278,10 +389,10 @@ highp vec4 metalRoughFunction(const in highp vec4 baseColor, cLinear *= pow(2.0, exposure); // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1] - highp vec3 cToneMapped = toneMap(cLinear); + vec3 cToneMapped = toneMap(cLinear); // Apply gamma correction prior to display - highp vec3 cGamma = gammaCorrect(cToneMapped); + vec3 cGamma = gammaCorrect(cToneMapped); return vec4(cGamma, baseColor.a); } @@ -323,10 +434,10 @@ void main() lights[2].linearAttenuation = 0.0; lights[2].quadraticAttenuation = 0.0; - highp vec3 color = vertColor; - highp float alpha = vertAlpha; + vec3 color = vertColor; + float alpha = vertAlpha; if (textureEnabled == 1) { - highp vec4 textColor = texture(textureId, vertTexCoord); + vec4 textColor = texture(textureId, vertTexCoord); color = textColor.rgb; alpha = textColor.a; } @@ -337,7 +448,7 @@ void main() } color = pow(color, vec3(gamma)); - highp vec3 normal = vertNormal; + vec3 normal = vertNormal; if (normalMapEnabled == 1) { normal = texture(normalMapId, vertTexCoord).rgb; normal = normalize(normal * 2.0 - 1.0); @@ -347,23 +458,25 @@ void main() // Green: Roughness // Blue: Metallic - highp float metalness = vertMetalness; + float metalness = vertMetalness; if (metalnessMapEnabled == 1) { metalness = texture(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).b; } - highp float roughness = vertRoughness; + float roughness = vertRoughness; if (roughnessMapEnabled == 1) { roughness = texture(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).g; } - highp float ambientOcclusion = 1.0; + float ambientOcclusion = 1.0; if (ambientOcclusionMapEnabled == 1) { ambientOcclusion = texture(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).r; } - roughness = min(0.99, roughness); - metalness = min(0.99, metalness); + if (environmentIrradianceMapEnabled != 1) { + roughness = min(0.99, roughness); + metalness = min(0.99, metalness); + } fragColor = metalRoughFunction(vec4(color, alpha), metalness, diff --git a/shaders/default.core.vert b/shaders/default.core.vert index 2955b5c1..210e1e83 100644 --- a/shaders/default.core.vert +++ b/shaders/default.core.vert @@ -1,29 +1,29 @@ #version 330 -layout(location = 0) in highp vec4 vertex; -layout(location = 1) in highp vec3 normal; -layout(location = 2) in highp vec3 color; -layout(location = 3) in highp vec2 texCoord; -layout(location = 4) in highp float metalness; -layout(location = 5) in highp float roughness; -layout(location = 6) in highp vec3 tangent; -layout(location = 7) in highp float alpha; -out highp vec3 vert; -out highp vec3 vertRaw; -out highp vec3 vertNormal; -out highp vec3 vertColor; -out highp vec2 vertTexCoord; -out highp float vertMetalness; -out highp float vertRoughness; -out highp vec3 cameraPos; -out highp vec3 firstLightPos; -out highp vec3 secondLightPos; -out highp vec3 thirdLightPos; -out highp float vertAlpha; -uniform highp mat4 projectionMatrix; -uniform highp mat4 modelMatrix; -uniform highp mat3 normalMatrix; -uniform highp mat4 viewMatrix; -uniform highp int normalMapEnabled; +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; mat3 transpose(mat3 m) { diff --git a/shaders/default.frag b/shaders/default.frag index 401f7b56..6a1c225e 100644 --- a/shaders/default.frag +++ b/shaders/default.frag @@ -52,34 +52,34 @@ // https://github.com/qt/qt3d/blob/5.11/src/extras/shaders/gl3/metalrough.inc.frag // Exposure correction -highp float exposure; +float exposure; // Gamma correction -highp float gamma; +float gamma; -varying highp vec3 vert; -varying highp vec3 vertRaw; -varying highp vec3 vertNormal; -varying highp vec3 vertColor; -varying highp vec2 vertTexCoord; -varying highp float vertMetalness; -varying highp float vertRoughness; -varying highp vec3 cameraPos; -varying highp vec3 firstLightPos; -varying highp vec3 secondLightPos; -varying highp vec3 thirdLightPos; -varying highp float vertAlpha; -uniform highp vec3 lightPos; -uniform highp sampler2D textureId; -uniform highp int textureEnabled; -uniform highp sampler2D normalMapId; -uniform highp int normalMapEnabled; -uniform highp sampler2D metalnessRoughnessAmbientOcclusionMapId; -uniform highp int metalnessMapEnabled; -uniform highp int roughnessMapEnabled; -uniform highp int ambientOcclusionMapEnabled; -uniform highp int mousePickEnabled; -uniform highp vec3 mousePickTargetPosition; -uniform highp float mousePickRadius; +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 vec3 lightPos; +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; const int MAX_LIGHTS = 8; const int TYPE_POINT = 0; @@ -87,51 +87,51 @@ const int TYPE_DIRECTIONAL = 1; const int TYPE_SPOT = 2; struct Light { int type; - highp vec3 position; - highp vec3 color; - highp float intensity; - highp vec3 direction; - highp float constantAttenuation; - highp float linearAttenuation; - highp float quadraticAttenuation; - highp float cutOffAngle; + vec3 position; + vec3 color; + float intensity; + vec3 direction; + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; + float cutOffAngle; }; int lightCount; Light lights[MAX_LIGHTS]; -highp float remapRoughness(const in highp float roughness) +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 - highp float maxSpecPower; - highp float minRoughness; + float maxSpecPower; + float minRoughness; maxSpecPower = 999999.0; minRoughness = sqrt(2.0 / (maxSpecPower + 2.0)); return max(roughness * roughness, minRoughness); } -highp float normalDistribution(const in highp vec3 n, const in highp vec3 h, const in highp float alpha) +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 - highp float specPower = 2.0 / (alpha * alpha) - 2.0; + float specPower = 2.0 / (alpha * alpha) - 2.0; return (specPower + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), specPower); } -highp vec3 fresnelFactor(const in highp vec3 color, const in highp float cosineFactor) +vec3 fresnelFactor(const in vec3 color, const in float cosineFactor) { // Calculate the Fresnel effect value - highp vec3 f = color; - highp vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0); + vec3 f = color; + vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0); return clamp(F, f, vec3(1.0)); } -highp float geometricModel(const in highp float lDotN, - const in highp float vDotN, - const in highp vec3 h) +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 @@ -139,50 +139,50 @@ highp float geometricModel(const in highp float lDotN, return lDotN * vDotN; } -highp vec3 specularModel(const in highp vec3 F0, - const in highp float sDotH, - const in highp float sDotN, - const in highp float vDotN, - const in highp vec3 n, - const in highp vec3 h) +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. - highp float sDotNPrime = max(sDotN, 0.001); - highp float vDotNPrime = max(vDotN, 0.001); + float sDotNPrime = max(sDotN, 0.001); + float vDotNPrime = max(vDotN, 0.001); - highp vec3 F = fresnelFactor(F0, sDotH); - highp float G = geometricModel(sDotNPrime, vDotNPrime, h); + vec3 F = fresnelFactor(F0, sDotH); + float G = geometricModel(sDotNPrime, vDotNPrime, h); - highp vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); + vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); return clamp(cSpec, vec3(0.0), vec3(1.0)); } -highp vec3 pbrModel(const in int lightIndex, - const in highp vec3 wPosition, - const in highp vec3 wNormal, - const in highp vec3 wView, - const in highp vec3 baseColor, - const in highp float metalness, - const in highp float alpha, - const in highp float ambientOcclusion) +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 - highp vec3 n = wNormal; - highp vec3 s = vec3(0.0); - highp vec3 v = wView; - highp vec3 h = vec3(0.0); + vec3 n = wNormal; + vec3 s = vec3(0.0); + vec3 v = wView; + vec3 h = vec3(0.0); - highp float vDotN = dot(v, n); - highp float sDotN = 0.0; - highp float sDotH = 0.0; - highp float att = 1.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 - highp vec3 sUnnormalized = vec3(lights[lightIndex].position) - wPosition; + vec3 sUnnormalized = vec3(lights[lightIndex].position) - wPosition; s = normalize(sUnnormalized); // Calculate the attenuation factor @@ -191,7 +191,7 @@ highp vec3 pbrModel(const in int lightIndex, if (lights[lightIndex].constantAttenuation != 0.0 || lights[lightIndex].linearAttenuation != 0.0 || lights[lightIndex].quadraticAttenuation != 0.0) { - highp float dist = length(sUnnormalized); + float dist = length(sUnnormalized); att = 1.0 / (lights[lightIndex].constantAttenuation + lights[lightIndex].linearAttenuation * dist + lights[lightIndex].quadraticAttenuation * dist * dist); @@ -215,22 +215,22 @@ highp vec3 pbrModel(const in int lightIndex, sDotH = dot(s, h); // Calculate diffuse component - highp vec3 diffuseColor = (1.0 - metalness) * baseColor * lights[lightIndex].color; - highp vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159; + vec3 diffuseColor = (1.0 - metalness) * baseColor * lights[lightIndex].color; + vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159; // Calculate specular component - highp vec3 dielectricColor = vec3(0.04); - highp vec3 F0 = mix(dielectricColor, baseColor, metalness); - highp vec3 specularFactor = vec3(0.0); + 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); } - highp vec3 specularColor = lights[lightIndex].color; - highp vec3 specular = specularColor * specularFactor; + vec3 specularColor = lights[lightIndex].color; + vec3 specular = specularColor * specularFactor; // Blend between diffuse and specular to conserver energy - highp vec3 color = att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular)); + vec3 color = att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular)); // Reduce by ambient occlusion amount color *= ambientOcclusion; @@ -238,28 +238,28 @@ highp vec3 pbrModel(const in int lightIndex, return color; } -highp vec3 toneMap(const in highp vec3 c) +vec3 toneMap(const in vec3 c) { return c / (c + vec3(1.0)); } -highp vec3 gammaCorrect(const in highp vec3 color) +vec3 gammaCorrect(const in vec3 color) { return pow(color, vec3(1.0 / gamma)); } -highp vec4 metalRoughFunction(const in highp vec4 baseColor, - const in highp float metalness, - const in highp float roughness, - const in highp float ambientOcclusion, - const in highp vec3 worldPosition, - const in highp vec3 worldView, - const in highp vec3 worldNormal) +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) { - highp vec3 cLinear = vec3(0.0); + vec3 cLinear = vec3(0.0); // Remap roughness for a perceptually more linear correspondence - highp float alpha = remapRoughness(roughness); + float alpha = remapRoughness(roughness); for (int i = 0; i < lightCount; ++i) { cLinear += pbrModel(i, @@ -276,10 +276,10 @@ highp vec4 metalRoughFunction(const in highp vec4 baseColor, cLinear *= pow(2.0, exposure); // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1] - highp vec3 cToneMapped = toneMap(cLinear); + vec3 cToneMapped = toneMap(cLinear); // Apply gamma correction prior to display - highp vec3 cGamma = gammaCorrect(cToneMapped); + vec3 cGamma = gammaCorrect(cToneMapped); return vec4(cGamma, baseColor.a); } @@ -321,10 +321,10 @@ void main() lights[2].linearAttenuation = 0.0; lights[2].quadraticAttenuation = 0.0; - highp vec3 color = vertColor; - highp float alpha = vertAlpha; + vec3 color = vertColor; + float alpha = vertAlpha; if (textureEnabled == 1) { - highp vec4 textColor = texture2D(textureId, vertTexCoord); + vec4 textColor = texture2D(textureId, vertTexCoord); color = textColor.rgb; alpha = textColor.a; } @@ -335,7 +335,7 @@ void main() } color = pow(color, vec3(gamma)); - highp vec3 normal = vertNormal; + vec3 normal = vertNormal; if (normalMapEnabled == 1) { normal = texture2D(normalMapId, vertTexCoord).rgb; normal = normalize(normal * 2.0 - 1.0); @@ -345,17 +345,17 @@ void main() // Green: Roughness // Blue: Metallic - highp float metalness = vertMetalness; + float metalness = vertMetalness; if (metalnessMapEnabled == 1) { metalness = texture2D(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).b; } - highp float roughness = vertRoughness; + float roughness = vertRoughness; if (roughnessMapEnabled == 1) { roughness = texture2D(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).g; } - highp float ambientOcclusion = 1.0; + float ambientOcclusion = 1.0; if (ambientOcclusionMapEnabled == 1) { ambientOcclusion = texture2D(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).r; } diff --git a/shaders/default.vert b/shaders/default.vert index f0ccbf7c..e9e86e49 100644 --- a/shaders/default.vert +++ b/shaders/default.vert @@ -1,28 +1,28 @@ -attribute highp vec4 vertex; -attribute highp vec3 normal; -attribute highp vec3 color; -attribute highp vec2 texCoord; -attribute highp float metalness; -attribute highp float roughness; -attribute highp vec3 tangent; -attribute highp float alpha; -varying highp vec3 vert; -varying highp vec3 vertRaw; -varying highp vec3 vertNormal; -varying highp vec3 vertColor; -varying highp vec2 vertTexCoord; -varying highp float vertMetalness; -varying highp float vertRoughness; -varying highp vec3 cameraPos; -varying highp vec3 firstLightPos; -varying highp vec3 secondLightPos; -varying highp vec3 thirdLightPos; -varying highp float vertAlpha; -uniform highp mat4 projectionMatrix; -uniform highp mat4 modelMatrix; -uniform highp mat3 normalMatrix; -uniform highp mat4 viewMatrix; -uniform highp int normalMapEnabled; +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; mat3 transpose(mat3 m) { diff --git a/src/ddsfile.cpp b/src/ddsfile.cpp new file mode 100644 index 00000000..331ce473 --- /dev/null +++ b/src/ddsfile.cpp @@ -0,0 +1,523 @@ +#include +#include +#include +#include +#include +#include +#include "ddsfile.h" + +#ifndef _WIN32 +typedef quint32 DWORD; +typedef quint32 UINT; +#endif + +// DDS data struct copy from +// https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide + +typedef struct { + DWORD dwSize; + DWORD dwFlags; + DWORD dwFourCC; + DWORD dwRGBBitCount; + DWORD dwRBitMask; + DWORD dwGBitMask; + DWORD dwBBitMask; + DWORD dwABitMask; +} DDS_PIXELFORMAT; + +typedef enum { + DDSCAPS2_CUBEMAP = 0x200, + DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, + DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, + DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, + DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, + DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, + DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, + DDSCAPS2_VOLUME = 0x200000 +} DDS_CAPS2_FLAGS; + +typedef struct { + DWORD dwSize; + DWORD dwFlags; + DWORD dwHeight; + DWORD dwWidth; + DWORD dwPitchOrLinearSize; + DWORD dwDepth; + DWORD dwMipMapCount; + DWORD dwReserved1[11]; + DDS_PIXELFORMAT ddspf; + DWORD dwCaps; + DWORD dwCaps2; + DWORD dwCaps3; + DWORD dwCaps4; + DWORD dwReserved2; +} DDS_HEADER; + +typedef enum { + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_TYPELESS, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32_TYPELESS, + DXGI_FORMAT_R32G32B32_FLOAT, + DXGI_FORMAT_R32G32B32_UINT, + DXGI_FORMAT_R32G32B32_SINT, + DXGI_FORMAT_R16G16B16A16_TYPELESS, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_SNORM, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_R32G32_TYPELESS, + DXGI_FORMAT_R32G32_FLOAT, + DXGI_FORMAT_R32G32_UINT, + DXGI_FORMAT_R32G32_SINT, + DXGI_FORMAT_R32G8X24_TYPELESS, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT, + DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, + DXGI_FORMAT_X32_TYPELESS_G8X24_UINT, + DXGI_FORMAT_R10G10B10A2_TYPELESS, + DXGI_FORMAT_R10G10B10A2_UNORM, + DXGI_FORMAT_R10G10B10A2_UINT, + DXGI_FORMAT_R11G11B10_FLOAT, + DXGI_FORMAT_R8G8B8A8_TYPELESS, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_SNORM, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_R16G16_TYPELESS, + DXGI_FORMAT_R16G16_FLOAT, + DXGI_FORMAT_R16G16_UNORM, + DXGI_FORMAT_R16G16_UINT, + DXGI_FORMAT_R16G16_SNORM, + DXGI_FORMAT_R16G16_SINT, + DXGI_FORMAT_R32_TYPELESS, + DXGI_FORMAT_D32_FLOAT, + DXGI_FORMAT_R32_FLOAT, + DXGI_FORMAT_R32_UINT, + DXGI_FORMAT_R32_SINT, + DXGI_FORMAT_R24G8_TYPELESS, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + DXGI_FORMAT_X24_TYPELESS_G8_UINT, + DXGI_FORMAT_R8G8_TYPELESS, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8G8_UINT, + DXGI_FORMAT_R8G8_SNORM, + DXGI_FORMAT_R8G8_SINT, + DXGI_FORMAT_R16_TYPELESS, + DXGI_FORMAT_R16_FLOAT, + DXGI_FORMAT_D16_UNORM, + DXGI_FORMAT_R16_UNORM, + DXGI_FORMAT_R16_UINT, + DXGI_FORMAT_R16_SNORM, + DXGI_FORMAT_R16_SINT, + DXGI_FORMAT_R8_TYPELESS, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R8_UINT, + DXGI_FORMAT_R8_SNORM, + DXGI_FORMAT_R8_SINT, + DXGI_FORMAT_A8_UNORM, + DXGI_FORMAT_R1_UNORM, + DXGI_FORMAT_R9G9B9E5_SHAREDEXP, + DXGI_FORMAT_R8G8_B8G8_UNORM, + DXGI_FORMAT_G8R8_G8B8_UNORM, + DXGI_FORMAT_BC1_TYPELESS, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_BC2_TYPELESS, + DXGI_FORMAT_BC2_UNORM, + DXGI_FORMAT_BC2_UNORM_SRGB, + DXGI_FORMAT_BC3_TYPELESS, + DXGI_FORMAT_BC3_UNORM, + DXGI_FORMAT_BC3_UNORM_SRGB, + DXGI_FORMAT_BC4_TYPELESS, + DXGI_FORMAT_BC4_UNORM, + DXGI_FORMAT_BC4_SNORM, + DXGI_FORMAT_BC5_TYPELESS, + DXGI_FORMAT_BC5_UNORM, + DXGI_FORMAT_BC5_SNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B5G5R5A1_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8X8_UNORM, + DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, + DXGI_FORMAT_B8G8R8A8_TYPELESS, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + DXGI_FORMAT_B8G8R8X8_TYPELESS, + DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, + DXGI_FORMAT_BC6H_TYPELESS, + DXGI_FORMAT_BC6H_UF16, + DXGI_FORMAT_BC6H_SF16, + DXGI_FORMAT_BC7_TYPELESS, + DXGI_FORMAT_BC7_UNORM, + DXGI_FORMAT_BC7_UNORM_SRGB, + DXGI_FORMAT_AYUV, + DXGI_FORMAT_Y410, + DXGI_FORMAT_Y416, + DXGI_FORMAT_NV12, + DXGI_FORMAT_P010, + DXGI_FORMAT_P016, + DXGI_FORMAT_420_OPAQUE, + DXGI_FORMAT_YUY2, + DXGI_FORMAT_Y210, + DXGI_FORMAT_Y216, + DXGI_FORMAT_NV11, + DXGI_FORMAT_AI44, + DXGI_FORMAT_IA44, + DXGI_FORMAT_P8, + DXGI_FORMAT_A8P8, + DXGI_FORMAT_B4G4R4A4_UNORM, + DXGI_FORMAT_P208, + DXGI_FORMAT_V208, + DXGI_FORMAT_V408, + DXGI_FORMAT_FORCE_UINT +} DXGI_FORMAT; + +static const char *DxgiFormatToString(DXGI_FORMAT dxgiFormat) +{ + static const char *names[] = { + "DXGI_FORMAT_UNKNOWN", + "DXGI_FORMAT_R32G32B32A32_TYPELESS", + "DXGI_FORMAT_R32G32B32A32_FLOAT", + "DXGI_FORMAT_R32G32B32A32_UINT", + "DXGI_FORMAT_R32G32B32A32_SINT", + "DXGI_FORMAT_R32G32B32_TYPELESS", + "DXGI_FORMAT_R32G32B32_FLOAT", + "DXGI_FORMAT_R32G32B32_UINT", + "DXGI_FORMAT_R32G32B32_SINT", + "DXGI_FORMAT_R16G16B16A16_TYPELESS", + "DXGI_FORMAT_R16G16B16A16_FLOAT", + "DXGI_FORMAT_R16G16B16A16_UNORM", + "DXGI_FORMAT_R16G16B16A16_UINT", + "DXGI_FORMAT_R16G16B16A16_SNORM", + "DXGI_FORMAT_R16G16B16A16_SINT", + "DXGI_FORMAT_R32G32_TYPELESS", + "DXGI_FORMAT_R32G32_FLOAT", + "DXGI_FORMAT_R32G32_UINT", + "DXGI_FORMAT_R32G32_SINT", + "DXGI_FORMAT_R32G8X24_TYPELESS", + "DXGI_FORMAT_D32_FLOAT_S8X24_UINT", + "DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS", + "DXGI_FORMAT_X32_TYPELESS_G8X24_UINT", + "DXGI_FORMAT_R10G10B10A2_TYPELESS", + "DXGI_FORMAT_R10G10B10A2_UNORM", + "DXGI_FORMAT_R10G10B10A2_UINT", + "DXGI_FORMAT_R11G11B10_FLOAT", + "DXGI_FORMAT_R8G8B8A8_TYPELESS", + "DXGI_FORMAT_R8G8B8A8_UNORM", + "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", + "DXGI_FORMAT_R8G8B8A8_UINT", + "DXGI_FORMAT_R8G8B8A8_SNORM", + "DXGI_FORMAT_R8G8B8A8_SINT", + "DXGI_FORMAT_R16G16_TYPELESS", + "DXGI_FORMAT_R16G16_FLOAT", + "DXGI_FORMAT_R16G16_UNORM", + "DXGI_FORMAT_R16G16_UINT", + "DXGI_FORMAT_R16G16_SNORM", + "DXGI_FORMAT_R16G16_SINT", + "DXGI_FORMAT_R32_TYPELESS", + "DXGI_FORMAT_D32_FLOAT", + "DXGI_FORMAT_R32_FLOAT", + "DXGI_FORMAT_R32_UINT", + "DXGI_FORMAT_R32_SINT", + "DXGI_FORMAT_R24G8_TYPELESS", + "DXGI_FORMAT_D24_UNORM_S8_UINT", + "DXGI_FORMAT_R24_UNORM_X8_TYPELESS", + "DXGI_FORMAT_X24_TYPELESS_G8_UINT", + "DXGI_FORMAT_R8G8_TYPELESS", + "DXGI_FORMAT_R8G8_UNORM", + "DXGI_FORMAT_R8G8_UINT", + "DXGI_FORMAT_R8G8_SNORM", + "DXGI_FORMAT_R8G8_SINT", + "DXGI_FORMAT_R16_TYPELESS", + "DXGI_FORMAT_R16_FLOAT", + "DXGI_FORMAT_D16_UNORM", + "DXGI_FORMAT_R16_UNORM", + "DXGI_FORMAT_R16_UINT", + "DXGI_FORMAT_R16_SNORM", + "DXGI_FORMAT_R16_SINT", + "DXGI_FORMAT_R8_TYPELESS", + "DXGI_FORMAT_R8_UNORM", + "DXGI_FORMAT_R8_UINT", + "DXGI_FORMAT_R8_SNORM", + "DXGI_FORMAT_R8_SINT", + "DXGI_FORMAT_A8_UNORM", + "DXGI_FORMAT_R1_UNORM", + "DXGI_FORMAT_R9G9B9E5_SHAREDEXP", + "DXGI_FORMAT_R8G8_B8G8_UNORM", + "DXGI_FORMAT_G8R8_G8B8_UNORM", + "DXGI_FORMAT_BC1_TYPELESS", + "DXGI_FORMAT_BC1_UNORM", + "DXGI_FORMAT_BC1_UNORM_SRGB", + "DXGI_FORMAT_BC2_TYPELESS", + "DXGI_FORMAT_BC2_UNORM", + "DXGI_FORMAT_BC2_UNORM_SRGB", + "DXGI_FORMAT_BC3_TYPELESS", + "DXGI_FORMAT_BC3_UNORM", + "DXGI_FORMAT_BC3_UNORM_SRGB", + "DXGI_FORMAT_BC4_TYPELESS", + "DXGI_FORMAT_BC4_UNORM", + "DXGI_FORMAT_BC4_SNORM", + "DXGI_FORMAT_BC5_TYPELESS", + "DXGI_FORMAT_BC5_UNORM", + "DXGI_FORMAT_BC5_SNORM", + "DXGI_FORMAT_B5G6R5_UNORM", + "DXGI_FORMAT_B5G5R5A1_UNORM", + "DXGI_FORMAT_B8G8R8A8_UNORM", + "DXGI_FORMAT_B8G8R8X8_UNORM", + "DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM", + "DXGI_FORMAT_B8G8R8A8_TYPELESS", + "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB", + "DXGI_FORMAT_B8G8R8X8_TYPELESS", + "DXGI_FORMAT_B8G8R8X8_UNORM_SRGB", + "DXGI_FORMAT_BC6H_TYPELESS", + "DXGI_FORMAT_BC6H_UF16", + "DXGI_FORMAT_BC6H_SF16", + "DXGI_FORMAT_BC7_TYPELESS", + "DXGI_FORMAT_BC7_UNORM", + "DXGI_FORMAT_BC7_UNORM_SRGB", + "DXGI_FORMAT_AYUV", + "DXGI_FORMAT_Y410", + "DXGI_FORMAT_Y416", + "DXGI_FORMAT_NV12", + "DXGI_FORMAT_P010", + "DXGI_FORMAT_P016", + "DXGI_FORMAT_420_OPAQUE", + "DXGI_FORMAT_YUY2", + "DXGI_FORMAT_Y210", + "DXGI_FORMAT_Y216", + "DXGI_FORMAT_NV11", + "DXGI_FORMAT_AI44", + "DXGI_FORMAT_IA44", + "DXGI_FORMAT_P8", + "DXGI_FORMAT_A8P8", + "DXGI_FORMAT_B4G4R4A4_UNORM", + "DXGI_FORMAT_P208", + "DXGI_FORMAT_V208", + "DXGI_FORMAT_V408", + "DXGI_FORMAT_FORCE_UINT", + }; + int index = (int)dxgiFormat; + if (index >= 0 && index < sizeof(names) / sizeof(names[0])) + return names[index]; + return "(Unknown)"; +} + +typedef enum { + D3D10_RESOURCE_DIMENSION_UNKNOWN, + D3D10_RESOURCE_DIMENSION_BUFFER, + D3D10_RESOURCE_DIMENSION_TEXTURE1D, + D3D10_RESOURCE_DIMENSION_TEXTURE2D, + D3D10_RESOURCE_DIMENSION_TEXTURE3D +} D3D10_RESOURCE_DIMENSION; + +static const char *ResourceDimensionToString(D3D10_RESOURCE_DIMENSION resourceDimension) +{ + static const char *names[] = { + "D3D10_RESOURCE_DIMENSION_UNKNOWN", + "D3D10_RESOURCE_DIMENSION_BUFFER", + "D3D10_RESOURCE_DIMENSION_TEXTURE1D", + "D3D10_RESOURCE_DIMENSION_TEXTURE2D", + "D3D10_RESOURCE_DIMENSION_TEXTURE3D", + }; + int index = (int)resourceDimension; + if (index >= 0 && index < sizeof(names) / sizeof(names[0])) + return names[index]; + return "(Unknown)"; +} + +typedef enum { + D3D10_RESOURCE_MISC_GENERATE_MIPS, + D3D10_RESOURCE_MISC_SHARED, + D3D10_RESOURCE_MISC_TEXTURECUBE, + D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX, + D3D10_RESOURCE_MISC_GDI_COMPATIBLE +} D3D10_RESOURCE_MISC_FLAG; + +static const char *MiscFlagToString(UINT miscFlag) +{ + static const char *names[] = { + "D3D10_RESOURCE_MISC_GENERATE_MIPS", + "D3D10_RESOURCE_MISC_SHARED", + "D3D10_RESOURCE_MISC_TEXTURECUBE", + "D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX", + "D3D10_RESOURCE_MISC_GDI_COMPATIBLE", + }; + int index = (int)miscFlag; + if (index >= 0 && index < sizeof(names) / sizeof(names[0])) + return names[index]; + return "(Unknown)"; +} + +typedef struct { + DXGI_FORMAT dxgiFormat; + D3D10_RESOURCE_DIMENSION resourceDimension; + UINT miscFlag; + UINT arraySize; + UINT miscFlags2; +} DDS_HEADER_DXT10; + +typedef struct { + DWORD dwMagic; + DDS_HEADER header; + DDS_HEADER_DXT10 header10; +} DDS_FILE_HEADER; + +DdsFileReader::DdsFileReader(const QString &filename) : + m_filename(filename) +{ +} + +QOpenGLTexture *DdsFileReader::createOpenGLTexture() +{ + QFile file(m_filename); + + if (!file.open(QIODevice::ReadOnly)) { + qDebug() << "Open" << m_filename << "failed"; + return nullptr; + } + + DDS_FILE_HEADER fileHeader; + if (sizeof(fileHeader) != file.read((char *)&fileHeader, sizeof(fileHeader))) { + qDebug() << "Read DDS file hader failed"; + return nullptr; + } + + if (0x20534444 != qFromLittleEndian(&fileHeader.dwMagic)) { + qDebug() << "Not a DDS file"; + return nullptr; + } + + if (0x30315844 != qFromLittleEndian(&fileHeader.header.ddspf.dwFourCC)) { + qDebug() << "Unsupported DDS file, expected DX10 file"; + return nullptr; + } + + auto caps2 = qFromLittleEndian(&fileHeader.header.dwCaps2); + if (!(DDSCAPS2_CUBEMAP & caps2)) { + qDebug() << "Unsupported DDS file, expected CUBEMAP file"; + return nullptr; + } + + //qDebug() << "Start anyalize DDS file..."; + + int width = qFromLittleEndian(&fileHeader.header.dwWidth); + int height = qFromLittleEndian(&fileHeader.header.dwHeight); + + //qDebug() << "DDS size:" << width << "X" << height; + + //auto pitchOrLinearSize = qFromLittleEndian(&fileHeader.header.dwPitchOrLinearSize); + //qDebug() << "DDS pitch or linear size:" << pitchOrLinearSize; + + auto arraySize = qFromLittleEndian(&fileHeader.header10.arraySize); + //qDebug() << "DDS array size:" << arraySize; + + auto mipMapCount = qFromLittleEndian(&fileHeader.header.dwMipMapCount); + //qDebug() << "DDS mip map count:" << mipMapCount; + + DXGI_FORMAT dxgiFormat = (DXGI_FORMAT)qFromLittleEndian(&fileHeader.header10.dxgiFormat); + //qDebug() << "DDS dxgi format:" << DxgiFormatToString(dxgiFormat); + //qDebug() << "DDS resource dimension:" << ResourceDimensionToString((D3D10_RESOURCE_DIMENSION)qFromLittleEndian(&fileHeader.header10.resourceDimension)); + //qDebug() << "DDS misc flag:" << MiscFlagToString((UINT)qFromLittleEndian(&fileHeader.header10.miscFlag)); + + auto faces = 0; + if (DDSCAPS2_CUBEMAP_POSITIVEX & caps2) { + //qDebug() << "DDS found +x"; + ++faces; + } + if (DDSCAPS2_CUBEMAP_NEGATIVEX & caps2) { + //qDebug() << "DDS found -x"; + ++faces; + } + if (DDSCAPS2_CUBEMAP_POSITIVEY & caps2) { + //qDebug() << "DDS found +y"; + ++faces; + } + if (DDSCAPS2_CUBEMAP_NEGATIVEY & caps2) { + //qDebug() << "DDS found -y"; + ++faces; + } + if (DDSCAPS2_CUBEMAP_POSITIVEZ & caps2) { + //qDebug() << "DDS found +z"; + ++faces; + } + if (DDSCAPS2_CUBEMAP_NEGATIVEZ & caps2) { + //qDebug() << "DDS found -z"; + ++faces; + } + + if (6 != faces) { + qDebug() << "Unsupported DDS file, expected six faces"; + return nullptr; + } + + if (1 != arraySize) { + qDebug() << "Unsupported DDS file, expected one layer"; + return nullptr; + } + + if (DXGI_FORMAT_R16G16B16A16_FLOAT != dxgiFormat) { + qDebug() << "Unsupported DDS file, expected dxgi format: DXGI_FORMAT_R16G16B16A16_FLOAT"; + return nullptr; + } + int components = 8; + int oneFaceSize = 0; + auto calculateOneFaceSizeAtLevel = [=](int level) { + return qMax(width >> level, 1) * qMax(height >> level, 1) * components; + }; + for (auto level = 0; level < mipMapCount; ++level) { + oneFaceSize += calculateOneFaceSizeAtLevel(level); + } + int totalSize = arraySize * faces * oneFaceSize; + const QByteArray data = file.read(totalSize); + if (data.size() < totalSize) { + qDebug() << "DDS file invalid, expected total size:" << totalSize << "read size:" << data.size(); + return nullptr; + } + + int depth = 1; + + QOpenGLTexture* texture = new QOpenGLTexture(QOpenGLTexture::TargetCubeMap); + texture->setFormat(QOpenGLTexture::RGBA16F); + texture->setSize(width, height, depth); + texture->setAutoMipMapGenerationEnabled(false); + texture->setMipBaseLevel(0); + texture->setMipMaxLevel(mipMapCount - 1); + texture->setMipLevels(mipMapCount); + + if (!texture->create()) { + qDebug() << "QOpenGLTexture::create failed"; + delete texture; + return nullptr; + } + + texture->allocateStorage(); + if (!texture->isStorageAllocated()) { + qDebug() << "QOpenGLTexture::isStorageAllocated false"; + delete texture; + return nullptr; + } + + uint64_t dataOffset = 0; + for (int layer = 0; layer < arraySize; ++layer) { + for (int face = 0; face < faces; ++face) { + for (int level = 0; level < mipMapCount; ++level) { + QOpenGLPixelTransferOptions uploadOptions; + uploadOptions.setAlignment(1); + texture->setData(level, + layer, + static_cast(QOpenGLTexture::CubeMapPositiveX + face), + QOpenGLTexture::RGBA, + QOpenGLTexture::Float16, + data.constData() + dataOffset, + &uploadOptions); + dataOffset += calculateOneFaceSizeAtLevel(level); + } + } + } + + return texture; +} \ No newline at end of file diff --git a/src/ddsfile.h b/src/ddsfile.h new file mode 100644 index 00000000..ad916fae --- /dev/null +++ b/src/ddsfile.h @@ -0,0 +1,15 @@ +#ifndef DUST3D_DDS_FILE_H +#define DUST3D_DDS_FILE_H +#include +#include + +class DdsFileReader +{ +public: + DdsFileReader(const QString &filename); + QOpenGLTexture *createOpenGLTexture(); +private: + QString m_filename; +}; + +#endif \ No newline at end of file diff --git a/src/document.cpp b/src/document.cpp index 877241ae..44cc65ec 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include "document.h" @@ -57,7 +57,6 @@ Document::Document() : m_postProcessedOutcome(new Outcome), m_resultTextureMesh(nullptr), m_textureImageUpdateVersion(0), - m_sharedContextWidget(nullptr), m_allPositionRelatedLocksEnabled(true), m_smoothNormal(!Preferences::instance().flatShading()), m_rigGenerator(nullptr), @@ -3311,11 +3310,6 @@ void Document::checkExportReadyState() emit exportReady(); } -void Document::setSharedContextWidget(QOpenGLWidget *sharedContextWidget) -{ - m_sharedContextWidget = sharedContextWidget; -} - void Document::collectComponentDescendantParts(QUuid componentId, std::vector &partIds) const { const Component *component = findComponent(componentId); diff --git a/src/document.h b/src/document.h index 780dbf58..bba6df61 100644 --- a/src/document.h +++ b/src/document.h @@ -9,7 +9,6 @@ #include #include #include -#include #include #include "snapshot.h" #include "meshloader.h" @@ -577,7 +576,6 @@ public: const std::vector *resultRigBones() const; const std::map *resultRigWeights() const; void updateTurnaround(const QImage &image); - void setSharedContextWidget(QOpenGLWidget *sharedContextWidget); bool hasPastableMaterialsInClipboard() const; bool hasPastablePosesInClipboard() const; bool hasPastableMotionsInClipboard() const; @@ -781,7 +779,6 @@ private: // need initialize Outcome *m_postProcessedOutcome; MeshLoader *m_resultTextureMesh; unsigned long long m_textureImageUpdateVersion; - QOpenGLWidget *m_sharedContextWidget; QUuid m_currentCanvasComponentId; bool m_allPositionRelatedLocksEnabled; bool m_smoothNormal; diff --git a/src/documentwindow.cpp b/src/documentwindow.cpp index 888a63d2..7e1c66ed 100644 --- a/src/documentwindow.cpp +++ b/src/documentwindow.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include @@ -311,6 +311,7 @@ DocumentWindow::DocumentWindow() : m_modelRenderWidget->move(DocumentWindow::m_modelRenderWidgetInitialX, DocumentWindow::m_modelRenderWidgetInitialY); m_modelRenderWidget->setMousePickRadius(m_document->mousePickRadius()); m_modelRenderWidget->toggleWireframe(); + m_modelRenderWidget->enableEnvironmentLight(); connect(m_modelRenderWidget, &ModelWidget::mouseRayChanged, m_document, [=](const QVector3D &nearPosition, const QVector3D &farPosition) { @@ -343,8 +344,6 @@ DocumentWindow::DocumentWindow() : m_graphicsWidget->setModelWidget(m_modelRenderWidget); containerWidget->setModelWidget(m_modelRenderWidget); - m_document->setSharedContextWidget(m_modelRenderWidget); - setTabPosition(Qt::RightDockWidgetArea, QTabWidget::East); QDockWidget *partTreeDocker = new QDockWidget(tr("Parts"), this); diff --git a/src/fbxfile.cpp b/src/fbxfile.cpp index 46353af5..3a54630c 100644 --- a/src/fbxfile.cpp +++ b/src/fbxfile.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include "fbxfile.h" diff --git a/src/glbfile.cpp b/src/glbfile.cpp index 2381a8cb..9044fd65 100644 --- a/src/glbfile.cpp +++ b/src/glbfile.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "glbfile.h" #include "version.h" #include "util.h" diff --git a/src/imageforever.cpp b/src/imageforever.cpp index 57e67c52..efa88a16 100644 --- a/src/imageforever.cpp +++ b/src/imageforever.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "imageforever.h" struct ImageForeverItem diff --git a/src/main.cpp b/src/main.cpp index 40cbca34..1882165b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,10 +19,10 @@ int main(int argc, char ** argv) if (translator.load(QLocale(), QLatin1String("dust3d"), QLatin1String("_"), QLatin1String(":/languages"))) app.installTranslator(&translator); - //QSurfaceFormat format = QSurfaceFormat::defaultFormat(); - //format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); - //format.setVersion(3, 3); - //QSurfaceFormat::setDefaultFormat(format); + QSurfaceFormat format = QSurfaceFormat::defaultFormat(); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); + format.setVersion(3, 3); + QSurfaceFormat::setDefaultFormat(format); // QuantumCD/Qt 5 Dark Fusion Palette // https://gist.github.com/QuantumCD/6245215 diff --git a/src/materialeditwidget.cpp b/src/materialeditwidget.cpp index 2655ff34..db3390ad 100644 --- a/src/materialeditwidget.cpp +++ b/src/materialeditwidget.cpp @@ -48,6 +48,7 @@ MaterialEditWidget::MaterialEditWidget(const Document *document, QWidget *parent m_previewWidget->setMinimumSize(128, 128); m_previewWidget->resize(512, 512); m_previewWidget->move(-128, -128); + m_previewWidget->enableEnvironmentLight(); QFont nameFont; nameFont.setWeight(QFont::Light); diff --git a/src/materialwidget.cpp b/src/materialwidget.cpp index ed9ce133..9f55b0e2 100644 --- a/src/materialwidget.cpp +++ b/src/materialwidget.cpp @@ -12,6 +12,7 @@ MaterialWidget::MaterialWidget(const Document *document, QUuid materialId) : m_previewWidget->setFixedSize(Theme::materialPreviewImageSize, Theme::materialPreviewImageSize); m_previewWidget->enableMove(false); m_previewWidget->enableZoom(false); + m_previewWidget->enableEnvironmentLight(); m_nameLabel = new QLabel; m_nameLabel->setAlignment(Qt::AlignCenter); diff --git a/src/modelmeshbinder.cpp b/src/modelmeshbinder.cpp index 8ceaaf33..72fff97d 100644 --- a/src/modelmeshbinder.cpp +++ b/src/modelmeshbinder.cpp @@ -5,8 +5,9 @@ #include #include #include +#include #include "modelmeshbinder.h" -#include "ds3file.h" +#include "ddsfile.h" ModelMeshBinder::ModelMeshBinder(bool toolEnabled) : m_toolEnabled(toolEnabled) @@ -20,6 +21,8 @@ ModelMeshBinder::~ModelMeshBinder() delete m_texture; delete m_normalMap; delete m_metalnessRoughnessAmbientOcclusionMap; + delete m_environmentIrradianceMap; + delete m_environmentSpecularMap; } void ModelMeshBinder::updateMesh(MeshLoader *mesh) @@ -53,6 +56,11 @@ void ModelMeshBinder::initialize() m_vaoTool.create(); } +void ModelMeshBinder::enableEnvironmentLight() +{ + m_environmentLightEnabled = true; +} + void ModelMeshBinder::paint(ModelShaderProgram *program) { MeshLoader *newMesh = nullptr; @@ -72,7 +80,6 @@ void ModelMeshBinder::paint(ModelShaderProgram *program) delete m_mesh; m_mesh = newMesh; if (m_mesh) { - m_hasTexture = nullptr != m_mesh->textureImage(); delete m_texture; m_texture = nullptr; @@ -101,7 +108,20 @@ void ModelMeshBinder::paint(ModelShaderProgram *program) 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)) { + DdsFileReader irradianceFile(":/resources/cedar_bridge_irradiance.dds"); + m_environmentIrradianceMap = irradianceFile.createOpenGLTexture(); + DdsFileReader specularFile(":/resources/cedar_bridge_specular.dds"); + m_environmentSpecularMap = specularFile.createOpenGLTexture(); + } + { QOpenGLVertexArrayObject::Binder vaoBinder(&m_vaoTriangle); if (m_vboTriangle.isCreated()) @@ -215,6 +235,10 @@ void ModelMeshBinder::paint(ModelShaderProgram *program) 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); } } @@ -246,6 +270,22 @@ void ModelMeshBinder::paint(ModelShaderProgram *program) 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) { + m_environmentIrradianceMap->bind(3); + program->setUniformValue(program->environmentIrradianceMapIdLoc(), 3); + program->setUniformValue(program->environmentIrradianceMapEnabledLoc(), 1); + } else { + program->setUniformValue(program->environmentIrradianceMapEnabledLoc(), 0); + } + if (nullptr != m_environmentSpecularMap) { + m_environmentSpecularMap->bind(4); + program->setUniformValue(program->environmentSpecularMapIdLoc(), 4); + program->setUniformValue(program->environmentSpecularMapEnabledLoc(), 1); + } else { + program->setUniformValue(program->environmentSpecularMapEnabledLoc(), 0); + } + } f->glDrawArrays(GL_TRIANGLES, 0, m_renderTriangleVertexCount); } if (m_toolEnabled) { @@ -257,6 +297,10 @@ void ModelMeshBinder::paint(ModelShaderProgram *program) 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); } } diff --git a/src/modelmeshbinder.h b/src/modelmeshbinder.h index de4eb113..dc03de9a 100644 --- a/src/modelmeshbinder.h +++ b/src/modelmeshbinder.h @@ -22,6 +22,7 @@ public: bool isWireframesVisible(); void enableCheckUv(); void disableCheckUv(); + void enableEnvironmentLight(); bool isCheckUvEnabled(); void reloadMesh(); private: @@ -42,6 +43,9 @@ private: QOpenGLTexture *m_metalnessRoughnessAmbientOcclusionMap = nullptr; bool m_toolEnabled = false; bool m_checkUvEnabled = false; + bool m_environmentLightEnabled = false; + QOpenGLTexture *m_environmentIrradianceMap = nullptr; + QOpenGLTexture *m_environmentSpecularMap = nullptr; private: QOpenGLVertexArrayObject m_vaoTriangle; QOpenGLBuffer m_vboTriangle; diff --git a/src/modelshaderprogram.cpp b/src/modelshaderprogram.cpp index 5f268ef0..e068cbfa 100644 --- a/src/modelshaderprogram.cpp +++ b/src/modelshaderprogram.cpp @@ -17,11 +17,17 @@ const QString &ModelShaderProgram::loadShaderSource(const QString &name) return insertResult.first->second; } +bool ModelShaderProgram::isCoreProfile() +{ + return m_isCoreProfile; +} + ModelShaderProgram::ModelShaderProgram() { if (QSurfaceFormat::defaultFormat().profile() == QSurfaceFormat::CoreProfile) { this->addShaderFromSourceCode(QOpenGLShader::Vertex, loadShaderSource(":/shaders/default.core.vert")); this->addShaderFromSourceCode(QOpenGLShader::Fragment, loadShaderSource(":/shaders/default.core.frag")); + m_isCoreProfile = true; } else { this->addShaderFromSourceCode(QOpenGLShader::Vertex, loadShaderSource(":/shaders/default.vert")); this->addShaderFromSourceCode(QOpenGLShader::Fragment, loadShaderSource(":/shaders/default.frag")); @@ -53,6 +59,12 @@ ModelShaderProgram::ModelShaderProgram() m_mousePickEnabledLoc = this->uniformLocation("mousePickEnabled"); m_mousePickTargetPositionLoc = this->uniformLocation("mousePickTargetPosition"); m_mousePickRadiusLoc = this->uniformLocation("mousePickRadius"); + 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() @@ -134,3 +146,24 @@ 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; +} + diff --git a/src/modelshaderprogram.h b/src/modelshaderprogram.h index 7dec642d..a0d81f36 100644 --- a/src/modelshaderprogram.h +++ b/src/modelshaderprogram.h @@ -23,24 +23,34 @@ public: int mousePickEnabledLoc(); int mousePickTargetPositionLoc(); int mousePickRadiusLoc(); + int environmentIrradianceMapIdLoc(); + int environmentIrradianceMapEnabledLoc(); + int environmentSpecularMapIdLoc(); + int environmentSpecularMapEnabledLoc(); + bool isCoreProfile(); static const QString &loadShaderSource(const QString &name); private: - int m_projectionMatrixLoc; - int m_modelMatrixLoc; - int m_normalMatrixLoc; - int m_viewMatrixLoc; - int m_lightPosLoc; - int m_textureIdLoc; - int m_textureEnabledLoc; - int m_normalMapEnabledLoc; - int m_normalMapIdLoc; - int m_metalnessMapEnabledLoc; - int m_roughnessMapEnabledLoc; - int m_ambientOcclusionMapEnabledLoc; - int m_metalnessRoughnessAmbientOcclusionMapIdLoc; - int m_mousePickEnabledLoc; - int m_mousePickTargetPositionLoc; - int m_mousePickRadiusLoc; + bool m_isCoreProfile = false; + int m_projectionMatrixLoc = 0; + int m_modelMatrixLoc = 0; + int m_normalMatrixLoc = 0; + int m_viewMatrixLoc = 0; + int m_lightPosLoc = 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; }; #endif diff --git a/src/modelwidget.cpp b/src/modelwidget.cpp index f9afaa72..3c8f8c97 100644 --- a/src/modelwidget.cpp +++ b/src/modelwidget.cpp @@ -211,6 +211,12 @@ void ModelWidget::toggleWireframe() update(); } +void ModelWidget::enableEnvironmentLight() +{ + m_meshBinder.enableEnvironmentLight(); + update(); +} + void ModelWidget::toggleRotation() { if (nullptr != m_rotationTimer) { diff --git a/src/modelwidget.h b/src/modelwidget.h index 8dac79c8..87e32649 100644 --- a/src/modelwidget.h +++ b/src/modelwidget.h @@ -39,6 +39,7 @@ public: void toggleWireframe(); void toggleRotation(); void toggleUvCheck(); + void enableEnvironmentLight(); void enableMove(bool enabled); void enableZoom(bool enabled); void enableMousePicking(bool enabled);