From 8925bd867e1a8791801698b1abaec4a46180656e Mon Sep 17 00:00:00 2001 From: David Thompson Date: Thu, 12 Aug 2021 20:25:25 -0400 Subject: graphics: Always use normal/ambient/etc. maps. If models don't specify their own textures, use noop textures as appropriate. --- chickadee/graphics/model.scm | 102 +++++++++++++++++-------------------------- chickadee/graphics/pbr.scm | 38 +++++----------- chickadee/graphics/phong.scm | 23 +++------- data/shaders/pbr-frag.glsl | 80 ++++++++++++--------------------- data/shaders/phong-frag.glsl | 62 +++++++++----------------- 5 files changed, 103 insertions(+), 202 deletions(-) diff --git a/chickadee/graphics/model.scm b/chickadee/graphics/model.scm index 77d67b8..8b7cbda 100644 --- a/chickadee/graphics/model.scm +++ b/chickadee/graphics/model.scm @@ -207,23 +207,15 @@ (define (maybe-add-material) (let ((name (assq-ref opts 'name))) (when name - (let* ((ambient (assq-ref opts 'ambient-map)) - (diffuse (assq-ref opts 'diffuse-map)) - (specular (assq-ref opts 'specular-map)) - (normals (assq-ref opts 'normal-map)) + (let* ((ambient (or (assq-ref opts 'ambient-map) (white-texture))) + (diffuse (or (assq-ref opts 'diffuse-map) (white-texture))) + (specular (or (assq-ref opts 'specular-map) (white-texture))) + (normals (or (assq-ref opts 'normal-map) (flat-texture))) (properties (make-phong-properties #:ambient (assq-ref opts 'ambient) - #:use-ambient-map - (assq-ref opts 'use-ambient-map?) #:diffuse (assq-ref opts 'diffuse) - #:use-diffuse-map - (assq-ref opts 'use-diffuse-map?) #:specular (assq-ref opts 'specular) - #:use-specular-map - (assq-ref opts 'use-specular-map?) - #:shininess (assq-ref opts 'shininess) - #:use-normal-map - (assq-ref opts 'use-normal-map?))) + #:shininess (assq-ref opts 'shininess))) (material (make-material #:name name #:shader (phong-shader) @@ -288,8 +280,7 @@ #:min-filter 'linear #:mag-filter 'linear #:flip? #f))) - (loop (cons* (cons 'ambient-map texture) - (cons 'use-ambient-map? #t) + (loop (cons (cons 'ambient-map texture) opts)))) (("map_Kd" . args) ; diffuse map (let* ((diffuse-opts (parse-map-args args)) @@ -299,9 +290,8 @@ #:min-filter 'linear #:mag-filter 'linear #:flip? #f))) - (loop (cons* (cons 'diffuse-map texture) - (cons 'use-diffuse-map? #t) - opts)))) + (loop (cons (cons 'diffuse-map texture) + opts)))) (("map_Ks" . args) ; specular map (let* ((specular-opts (parse-map-args args)) (file (scope-file (assq-ref specular-opts @@ -310,9 +300,8 @@ #:min-filter 'linear #:mag-filter 'linear #:flip? #f))) - (loop (cons* (cons 'specular-map texture) - (cons 'use-specular-map? #t) - opts)))) + (loop (cons (cons 'specular-map texture) + opts)))) (((or "map_Bump" "map_bump" "bump") . args) ; normal map (let* ((normal-opts (parse-map-args args)) (file (scope-file (assq-ref normal-opts @@ -321,25 +310,20 @@ #:min-filter 'linear #:mag-filter 'linear #:flip? #f))) - (loop (cons* (cons 'normal-map texture) - (cons 'use-normal-map? #t) - opts)))) + (loop (cons (cons 'normal-map texture) + opts)))) (("newmtl" new-name) ;; Begin new material (maybe-add-material) (loop `((name . ,new-name) (ambient . ,(vec3 1.0 1.0 1.0)) (ambient-map . ,null-texture) - (use-ambient-map? . #f) (diffuse . ,(vec3 1.0 1.0 1.0)) (diffuse-map . ,null-texture) - (use-diffuse-map? . #f) (specular . ,(vec3 1.0 1.0 1.0)) (specular-map . ,null-texture) - (use-specular-map? . #f) (shininess . 1.0) - (normal-map . ,null-texture) - (use-normal-map? . #f)))) + (normal-map . ,null-texture)))) (data (format (current-error-port) "warning: ~a:~d: unsupported MTL data: ~s~%" @@ -556,7 +540,14 @@ (or (hash-ref material-map material) (hash-ref material-map "default")))))) ;; Register default material - (hash-set! material-map "default" default-phong-properties) + (hash-set! material-map "default" + (make-material #:name "default" + #:shader (phong-shader) + #:texture-0 (white-texture) + #:texture-1 (white-texture) + #:texture-2 (white-texture) + #:texture-3 (flat-texture) + #:properties default-phong-properties)) ;; Parse file. (let loop ((material "default")) (match (read-line port) @@ -853,10 +844,6 @@ (roughness-factor (or (number-ref/optional pbrmr "roughnessFactor") 1.0)) - (normal-factor - (let ((v (or (array-ref/optional obj "normalFactor") - #(1.0 1.0 1.0)))) - (vec3 (vector-ref v 0) (vector-ref v 1) (vector-ref v 2)))) (emissive-factor (let ((v (or (array-ref/optional obj "emissiveFactor") #(1.0 1.0 1.0)))) @@ -873,24 +860,22 @@ (double-sided? (boolean-ref/optional obj "doubleSided")) (extensions (object-ref/optional obj "extensions")) (extras (assoc-ref obj "extras"))) - (define (parse-texture obj key) + (define (parse-texture obj key default) (match (object-ref/optional obj key) - (#f (values null-texture 0)) + (#f (values (default) 0)) (texture (values (vector-ref textures (number-ref texture "index")) (or (number-ref/optional texture "texCoord") 0))))) - (define (non-null-texture? texture) - (not (eq? texture null-texture))) (let-values (((base-color-texture base-color-texcoord) - (parse-texture pbrmr "baseColorTexture")) + (parse-texture pbrmr "baseColorTexture" white-texture)) ((metal-rough-texture metal-rough-texcoord) - (parse-texture pbrmr "metallicRoughnessTexture")) + (parse-texture pbrmr "metallicRoughnessTexture" white-texture)) ((normal-texture normal-texcoord) - (parse-texture obj "normalTexture")) + (parse-texture obj "normalTexture" flat-texture)) ((occlusion-texture occlusion-texcoord) - (parse-texture obj "occlusionTexture")) + (parse-texture obj "occlusionTexture" white-texture)) ((emissive-texture emissive-texcoord) - (parse-texture obj "emissiveTexture"))) + (parse-texture obj "emissiveTexture" black-texture))) (make-material #:name name #:shader (pbr-shader) @@ -905,19 +890,13 @@ #:texture-4 emissive-texture #:properties (make-pbr-properties #:base-color-factor base-color-factor - #:base-color-texture-enabled (non-null-texture? base-color-texture) #:base-color-texcoord base-color-texcoord #:metallic-factor metallic-factor #:roughness-factor roughness-factor - #:metallic-roughness-texture-enabled (non-null-texture? metal-rough-texture) #:metallic-roughness-texcoord metal-rough-texcoord - #:normal-factor normal-factor - #:normal-texture-enabled (non-null-texture? normal-texture) #:normal-texcoord normal-texcoord - #:occlusion-texture-enabled (non-null-texture? occlusion-texture) #:occlusion-texcoord occlusion-texcoord #:emissive-factor emissive-factor - #:emissive-texture-enabled (non-null-texture? emissive-texture) #:emissive-texcoord emissive-texcoord #:alpha-mode alpha-mode #:alpha-cutoff alpha-cutoff))))) @@ -930,33 +909,32 @@ ("NORMAL" (attribute-location (hash-ref (shader-attributes shader) "normal"))) - ("TANGENT" 10) ("TEXCOORD_0" (attribute-location (hash-ref (shader-attributes shader) "texcoord0"))) ("TEXCOORD_1" (attribute-location (hash-ref (shader-attributes shader) "texcoord1"))) - ("TEXCOORD_2" 11) - ("TEXCOORD_3" 12) ("COLOR_0" (attribute-location (hash-ref (shader-attributes shader) "color0"))) - ("JOINTS_0" 13) - ("WEIGHTS_0" 14)))) + ;; TODO + ("TANGENT" #f) + ("JOINTS_0" #f) + ("WEIGHTS_0" #f) + (_ #f)))) ;; TODO: When normals are not specified, generate flat normals. ;; ;; TODO: When positions are not specified, skip the entire ;; primitive. - ;; - ;; TODO: When tangents are not specified, calculate them using - ;; default MikkTSpace algorithms. http://www.mikktspace.com/ (define (parse-primitive obj materials accessors) - (let ((attributes (map (match-lambda - ((name . n) - (cons (attribute-name->index name) - (vector-ref accessors n)))) - (object-ref obj "attributes"))) + (let ((attributes (filter-map (match-lambda + ((name . n) + (let ((attr (attribute-name->index name))) + (and attr + (cons attr + (vector-ref accessors n)))))) + (object-ref obj "attributes"))) (indices (match (number-ref/optional obj "indices") (#f #f) (n (vector-ref accessors n)))) diff --git a/chickadee/graphics/pbr.scm b/chickadee/graphics/pbr.scm index 16b5878..e1641ec 100644 --- a/chickadee/graphics/pbr.scm +++ b/chickadee/graphics/pbr.scm @@ -35,19 +35,13 @@ #:export (make-pbr-properties pbr-properties? pbr-properties-base-color-factor - pbr-properties-base-color-texture-enabled? pbr-properties-base-color-texcoord pbr-properties-metallic-factor pbr-properties-roughness-factor - pbr-properties-metallic-roughness-texture-enabled? pbr-properties-metallic-roughness-texcoord - pbr-properties-normal-factor - pbr-properties-normal-texture-enabled? pbr-properties-normal-texcoord - pbr-properties-occlusion-texture-enabled? pbr-properties-occlusion-texcoord pbr-properties-emissive-factor - pbr-properties-emissive-texture-enabled? pbr-properties-emissive-texcoord pbr-properties-alpha-mode pbr-properties-alpha-cutoff @@ -58,41 +52,29 @@ make-pbr-properties pbr-properties? (float-vec3 base-color-factor pbr-properties-base-color-factor) - (bool base-color-texture-enabled pbr-properties-base-color-texture-enabled?) (int base-color-texcoord pbr-properties-base-color-texcoord) (float metallic-factor pbr-properties-metallic-factor) (float roughness-factor pbr-properties-roughness-factor) - (bool metallic-roughness-texture-enabled pbr-properties-metallic-roughness-texture-enabled?) (int metallic-roughness-texcoord pbr-properties-metallic-roughness-texcoord) - (float-vec3 normal-factor pbr-properties-normal-factor) - (bool normal-texture-enabled pbr-properties-normal-texture-enabled) (int normal-texcoord pbr-properties-normal-texcoord) - (bool occlusion-texture-enabled pbr-properties-occlusion-texture-enabled) (int occlusion-texcoord pbr-properties-occlusion-texcoord) (float-vec3 emissive-factor pbr-properties-emissive-factor) - (bool emissive-texture-enabled pbr-properties-emissive-texture-enabled) (int emissive-texcoord pbr-properties-emissive-texcoord) (int alpha-mode pbr-properties-alpha-mode) (float alpha-cutoff pbr-properties-alpha-cutoff)) (define default-pbr-properties (make-pbr-properties #:base-color-factor #v(1.0 1.0 1.0) - #:base-color-texture-enabled #f - #:base-color-texcoord 0 - #:metallic-factor 1.0 - #:roughness-factor 1.0 - #:metallic-roughness-texture-enabled #f - #:metallic-roughness-texcoord 0 - #:normal-factor #v(1.0 1.0 1.0) - #:normal-texture-enabled #f - #:normal-texcoord 0 - #:occlusion-texture-enabled #f - #:occlusion-texcoord 0 - #:emissive-factor #v(1.0 1.0 1.0) - #:emissive-texture-enabled #f - #:emissive-texcoord 0 - #:alpha-mode 0 - #:alpha-cutoff 0.5)) + #:base-color-texcoord 0 + #:metallic-factor 1.0 + #:roughness-factor 1.0 + #:metallic-roughness-texcoord 0 + #:normal-texcoord 0 + #:occlusion-texcoord 0 + #:emissive-factor #v(1.0 1.0 1.0) + #:emissive-texcoord 0 + #:alpha-mode 0 + #:alpha-cutoff 0.5)) (define %pbr-shader (delay (load-shader (scope-datadir "shaders/pbr-vert.glsl") diff --git a/chickadee/graphics/phong.scm b/chickadee/graphics/phong.scm index edb8686..e3deba2 100644 --- a/chickadee/graphics/phong.scm +++ b/chickadee/graphics/phong.scm @@ -34,14 +34,9 @@ phong-properties? phong-properties-name phong-properties-ambient - phong-properties-use-ambient-map? phong-properties-diffuse - phong-properties-use-diffuse-map? phong-properties-specular - phong-properties-specular-map? - phong-properties-use-specular-map? - phong-properties-specular-exponent - phong-properties-use-normal-map? + phong-properties-shininess default-phong-properties phong-shader)) @@ -54,23 +49,15 @@ make-phong-properties phong-properties? (float-vec3 ambient phong-properties-ambient) - (bool use-ambient-map phong-properties-use-ambient-map?) (float-vec3 diffuse phong-properties-diffuse) - (bool use-diffuse-map phong-properties-use-diffuse-map?) (float-vec3 specular phong-properties-specular) - (bool use-specular-map phong-properties-use-specular-map?) - (float shininess phong-properties-shininess) - (bool use-normal-map phong-properties-use-normal-map?)) + (float shininess phong-properties-shininess)) (define default-phong-properties - (make-phong-properties #:ambient (vec3 0.5 0.5 0.5) - #:use-ambient-map #f - #:diffuse (vec3 0.8 0.8 0.8) - #:use-diffuse-map #f + (make-phong-properties #:ambient (vec3 1.0 1.0 1.0) + #:diffuse (vec3 1.0 1.0 1.0) #:specular (vec3 1.0 1.0 1.0) - #:use-specular-map #f - #:shininess 32.0 - #:use-normal-map #f)) + #:shininess 32.0)) ;;; diff --git a/data/shaders/pbr-frag.glsl b/data/shaders/pbr-frag.glsl index 478c40a..c474981 100644 --- a/data/shaders/pbr-frag.glsl +++ b/data/shaders/pbr-frag.glsl @@ -2,19 +2,13 @@ struct Material { vec3 baseColorFactor; - bool baseColorTextureEnabled; int baseColorTexcoord; float metallicFactor; float roughnessFactor; - bool metallicRoughnessTextureEnabled; int metallicRoughnessTexcoord; - vec3 normalFactor; - bool normalTextureEnabled; int normalTexcoord; - bool occlusionTextureEnabled; int occlusionTexcoord; vec3 emissiveFactor; - bool emissiveTextureEnabled; int emissiveTexcoord; int alphaMode; float alphaCutoff; @@ -142,34 +136,25 @@ vec3 toneMap(vec3 color) { float materialMetallic() { float m = material.metallicFactor; - - if(material.metallicRoughnessTextureEnabled) { - m *= texture(metallicRoughnessTexture, - texcoord(material.metallicRoughnessTexcoord)).b; - } - + m *= texture(metallicRoughnessTexture, + texcoord(material.metallicRoughnessTexcoord)).b; return m; } float materialRoughness() { float r = material.roughnessFactor; - if(material.metallicRoughnessTextureEnabled) { - r *= texture(metallicRoughnessTexture, - texcoord(material.metallicRoughnessTexcoord)).g; - } + r *= texture(metallicRoughnessTexture, + texcoord(material.metallicRoughnessTexcoord)).g; return r; } vec4 materialAlbedo() { - vec4 color = vec4(0.0, 0.0, 1.0, 1.0); - - if(material.baseColorTextureEnabled) { - vec4 texColor = texture(baseColorTexture, - texcoord(material.baseColorTexcoord)); - color = sRGBtoLinear(texColor); - } + vec4 color = vec4(1.0, 1.0, 1.0, 1.0); + vec4 texColor = texture(baseColorTexture, + texcoord(material.baseColorTexcoord)); + color = sRGBtoLinear(texColor); color *= vec4(material.baseColorFactor, 1.0); @@ -183,44 +168,33 @@ vec4 materialAlbedo() { vec3 materialEmissive() { vec3 color = vec3(0.0); - if(material.emissiveTextureEnabled) { - vec4 texColor = texture(emissiveTexture, - texcoord(material.emissiveTexcoord)); - color = sRGBtoLinear(texColor).rgb; - } + vec4 texColor = texture(emissiveTexture, + texcoord(material.emissiveTexcoord)); + color = sRGBtoLinear(texColor).rgb; return color * material.emissiveFactor; } vec3 materialOcclusion() { - if(material.occlusionTextureEnabled) { - return vec3(texture(occlusionTexture, - texcoord(material.occlusionTexcoord)).r); - } else { - return vec3(1.0); - } + return vec3(texture(occlusionTexture, + texcoord(material.occlusionTexcoord)).r); } vec3 materialNormal() { - if(material.normalTextureEnabled) { - // See: http://www.thetenthplanet.de/archives/1180 - vec2 t = texcoord(material.normalTexcoord); - vec3 tangentNormal = texture(normalTexture, t).xyz * 2.0 - 1.0; - - vec3 q1 = dFdx(fragWorldPos); - vec3 q2 = dFdy(fragWorldPos); - vec2 st1 = dFdx(fragTexcoord0); - vec2 st2 = dFdy(fragTexcoord0); - - vec3 N = normalize(fragNormal); - vec3 T = normalize(q1 * st2.t - q2 * st1.t); - vec3 B = -normalize(cross(N, T)); - mat3 TBN = mat3(T, B, N); - - return normalize(TBN * tangentNormal); - } else { - return normalize(fragNormal); - } + // See: https://github.com/SaschaWillems/Vulkan-glTF-PBR/blob/master/data/shaders/pbr_khr.frag + // See: http://www.thetenthplanet.de/archives/1180 + vec2 uv = texcoord(material.normalTexcoord); + vec3 tangentNormal = texture(normalTexture, uv).xyz * 2.0 - 1.0; + vec3 q1 = dFdx(fragWorldPos); + vec3 q2 = dFdy(fragWorldPos); + vec2 st1 = dFdx(uv); + vec2 st2 = dFdy(uv); + vec3 N = normalize(fragNormal); + vec3 T = normalize(q1 * st2.t - q2 * st1.t); + vec3 B = -normalize(cross(N, T)); + mat3 TBN = mat3(T, B, N); + + return normalize(TBN * tangentNormal); } vec3 lightDirection(Light light) { diff --git a/data/shaders/phong-frag.glsl b/data/shaders/phong-frag.glsl index 363c4e7..0beb75b 100644 --- a/data/shaders/phong-frag.glsl +++ b/data/shaders/phong-frag.glsl @@ -2,13 +2,9 @@ struct Material { vec3 ambient; - bool useAmbientMap; vec3 diffuse; - bool useDiffuseMap; vec3 specular; - bool useSpecularMap; float shininess; - bool useNormalMap; }; struct Light { @@ -100,53 +96,37 @@ vec3 lightRadiance(Light light, vec3 direction) { } vec3 materialAmbient() { - if(material.useAmbientMap) { - return texture(ambientMap, fragTex).rgb; - } else { - return material.ambient; - } + return texture(ambientMap, fragTex).rgb * material.ambient; } vec3 materialDiffuse() { - if(material.useDiffuseMap) { - vec4 color = texture(diffuseMap, fragTex); - // discard transparent fragments. - if(color.a == 0.0) { - discard; - } - return color.rgb; - } else { - return material.diffuse; + vec4 color = texture(diffuseMap, fragTex); + // discard transparent fragments. + if(color.a == 0.0) { + discard; } + return color.rgb * material.diffuse; } vec3 materialSpecular() { - if(material.useSpecularMap) { - return texture(specularMap, fragTex).rgb; - } else { - return material.specular; - } + return texture(specularMap, fragTex).rgb * material.specular; } vec3 materialNormal() { - if(material.useNormalMap) { - // Compute tangent space using fragment data rather than relying - // on tangent attributes. See: - // http://www.thetenthplanet.de/archives/1180 - vec3 tangentNormal = normalize(texture(normalMap, fragTex).xyz * 2.0 - 1.0); - vec3 q1 = dFdx(fragWorldPos); - vec3 q2 = dFdy(fragWorldPos); - vec2 st1 = dFdx(fragTex); - vec2 st2 = dFdy(fragTex); - vec3 N = normalize(fragNorm); - vec3 T = normalize(q1 * st2.t - q2 * st1.t); - vec3 B = -normalize(cross(N, T)); - mat3 TBN = mat3(T, B, N); - - return normalize(TBN * tangentNormal); - } else { - return normalize(fragNorm); - } + // Compute tangent space using fragment data rather than relying + // on tangent attributes. See: + // http://www.thetenthplanet.de/archives/1180 + vec3 tangentNormal = normalize(texture(normalMap, fragTex).xyz * 2.0 - 1.0); + vec3 q1 = dFdx(fragWorldPos); + vec3 q2 = dFdy(fragWorldPos); + vec2 st1 = dFdx(fragTex); + vec2 st2 = dFdy(fragTex); + vec3 N = normalize(fragNorm); + vec3 T = normalize(q1 * st2.t - q2 * st1.t); + vec3 B = -normalize(cross(N, T)); + mat3 TBN = mat3(T, B, N); + + return normalize(TBN * tangentNormal); } void main() { -- cgit v1.2.3