From 271a2bb9775dd8a4a6e5a232f27af86ca7ffd83e Mon Sep 17 00:00:00 2001 From: David Thompson Date: Fri, 7 May 2021 21:17:59 -0400 Subject: model: Improve PBR material handling for glTF models. --- chickadee/graphics/model.scm | 81 +++++++++++++++++++++++--------------------- chickadee/graphics/pbr.scm | 53 ++++++++++++++++++----------- data/shaders/pbr-frag.glsl | 73 +++++++++++++++++++++++++++++++-------- 3 files changed, 134 insertions(+), 73 deletions(-) diff --git a/chickadee/graphics/model.scm b/chickadee/graphics/model.scm index ea4533f..caec045 100644 --- a/chickadee/graphics/model.scm +++ b/chickadee/graphics/model.scm @@ -43,7 +43,9 @@ #:use-module (rnrs bytevectors) #:use-module (rnrs io ports) #:use-module (srfi srfi-9) + #:use-module (srfi srfi-11) #:use-module ((srfi srfi-43) #:select (vector-every)) + #:use-module (web uri) #:export (scene-node? scene-node-name scene-node-mesh @@ -770,7 +772,7 @@ ((string-prefix? base64-prefix uri) (base64-decode (substring uri (string-length base64-prefix)))) (uri - (call-with-input-file (scope-file uri) + (call-with-input-file (scope-file (uri-decode uri)) (lambda (port) (get-bytevector-n port length)))) (else @@ -870,7 +872,7 @@ (let ((image (vector-ref images (number-ref obj "source"))) (sampler (vector-ref samplers (or (number-ref/optional obj "sampler") 0)))) - (load-image (scope-file (string-ref image "uri")) + (load-image (scope-file (uri-decode (string-ref image "uri"))) #:min-filter (texture-filter (number-ref/optional sampler "minFilter")) #:mag-filter (texture-filter @@ -885,46 +887,24 @@ (let ((v (or (number-array-ref/optional pbrmr "baseColorFactor") #(1.0 1.0 1.0 1.0)))) (vec3 (vector-ref v 0) (vector-ref v 1) (vector-ref v 2)))) - (base-color-texture - (match (object-ref/optional pbrmr "baseColorTexture") - (#f null-texture) - (obj - (vector-ref textures (number-ref obj "index"))))) (metallic-factor (or (number-ref/optional pbrmr "metallicFactor") 1.0)) (roughness-factor (or (number-ref/optional pbrmr "roughnessFactor") 1.0)) - (metallic-roughness-texture - (match (object-ref/optional pbrmr "metallicRoughnessTexture") - (#f #f) - (obj - (vector-ref textures (number-ref obj "index"))))) (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)))) - (normal-texture - (match (object-ref/optional obj "normalTexture") - (#f #f) - (obj (vector-ref textures (number-ref obj "index"))))) (occlusion-factor (let ((v (or (array-ref/optional obj "occlusionFactor") #(1.0 1.0 1.0)))) (vec3 (vector-ref v 0) (vector-ref v 1) (vector-ref v 2)))) - (occlusion-texture - (match (object-ref/optional obj "occlusionTexture") - (#f #f) - (obj (vector-ref textures (number-ref obj "index"))))) (emissive-factor (let ((v (or (array-ref/optional obj "emissiveFactor") #(1.0 1.0 1.0)))) (vec3 (vector-ref v 0) (vector-ref v 1) (vector-ref v 2)))) - (emissive-texture - (match (object-ref/optional obj "emissiveTexture") - (#f #f) - (obj (vector-ref textures (number-ref obj "index"))))) (alpha-mode (match (or (string-ref/optional obj "alphaMode") "BLEND") ("OPAQUE" 'opaque) @@ -934,21 +914,44 @@ (double-sided? (boolean-ref/optional obj "doubleSided")) (extensions (object-ref/optional obj "extensions")) (extras (assoc-ref obj "extras"))) - (make-pbr-material #:name name - #:base-color-factor base-color-factor - #:base-color-texture base-color-texture - #:metallic-factor metallic-factor - #:roughness-factor roughness-factor - #:metallic-roughness-texture metallic-roughness-texture - #:normal-factor normal-factor - #:normal-texture normal-texture - #:occlusion-factor occlusion-factor - #:occlusion-texture occlusion-texture - #:emissive-factor emissive-factor - #:emissive-texture emissive-texture - #:alpha-mode alpha-mode - #:alpha-cutoff alpha-cutoff - #:double-sided? double-sided?))) + (define (parse-texture obj key) + (match (object-ref/optional obj key) + (#f (values null-texture 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")) + ((normal-texture normal-texcoord) + (parse-texture obj "normalTexture")) + ((occlusion-texture occlusion-texcoord) + (parse-texture obj "occlusionTexture")) + ((emissive-texture emissive-texcoord) + (parse-texture obj "emissiveTexture"))) + (make-pbr-material #:name name + #:base-color-factor base-color-factor + #:base-color-texture base-color-texture + #:base-color-texture-enabled (non-null-texture? base-color-texture) + #:base-color-texcoord base-color-texcoord + #:metallic-factor metallic-factor + #:roughness-factor roughness-factor + #:normal-factor normal-factor + #:normal-texture normal-texture + #:normal-texture-enabled (non-null-texture? normal-texture) + #:normal-texcoord normal-texcoord + #:occlusion-factor occlusion-factor + #:occlusion-texture occlusion-texture + #:occlusion-texture-enabled (non-null-texture? occlusion-texture) + #:occlusion-texcoord occlusion-texcoord + #:emissive-factor emissive-factor + #:emissive-texture emissive-texture + #:emissive-texture-enabled (non-null-texture? emissive-texture) + #:emissive-texcoord emissive-texcoord + #:alpha-mode alpha-mode + #:alpha-cutoff alpha-cutoff + #:double-sided? double-sided?)))) (define (attribute-name->index name) (let ((shader (graphics-variable-ref pbr-shader))) (match name diff --git a/chickadee/graphics/pbr.scm b/chickadee/graphics/pbr.scm index 1ed3777..4b5b192 100644 --- a/chickadee/graphics/pbr.scm +++ b/chickadee/graphics/pbr.scm @@ -27,6 +27,7 @@ #:use-module (chickadee graphics buffer) #:use-module (chickadee graphics color) #:use-module (chickadee graphics engine) + #:use-module (chickadee graphics polygon) #:use-module (chickadee graphics shader) #:use-module (chickadee graphics texture) #:use-module (srfi srfi-9) @@ -35,15 +36,18 @@ pbr-material-name pbr-material-base-color-factor pbr-material-base-color-texture + pbr-material-base-color-texcoord pbr-material-metallic-factor pbr-material-roughness-factor - pbr-material-metallic-roughness-texture pbr-material-normal-factor pbr-material-normal-texture + pbr-material-normal-texcoord pbr-material-occlusion-facgor pbr-material-occlusion-texture + pbr-material-occlusion-texcoord pbr-material-emissive-factor pbr-material-emissive-texture + pbr-material-emissive-texcoord pbr-material-alpha-mode pbr-material-alpha-cutoff pbr-material-double-sided? @@ -57,34 +61,48 @@ (local-field name pbr-material-name) (float-vec3 base-color-factor pbr-material-base-color-factor) (local-field base-color-texture pbr-material-base-color-texture) + (bool base-color-texture-enabled pbr-material-base-color-texture-enabled?) + (int base-color-texcoord pbr-material-base-color-texcoord) (float metallic-factor pbr-material-metallic-factor) (float roughness-factor pbr-material-roughness-factor) - (local-field metallic-roughness-texture pbr-material-metallic-roughness-texture) (float-vec3 normal-factor pbr-material-normal-factor) (local-field normal-texture pbr-material-normal-texture) + (bool normal-texture-enabled pbr-material-normal-texture-enabled) + (int normal-texcoord pbr-material-normal-texcoord) (float-vec3 occlusion-factor pbr-material-occlusion-factor) (local-field occlusion-texture pbr-material-occlusion-texture) + (bool occlusion-texture-enabled pbr-material-occlusion-texture-enabled) + (int occlusion-texcoord pbr-material-occlusion-texcoord) (float-vec3 emissive-factor pbr-material-emissive-factor) (local-field emissive-texture pbr-material-emissive-texture) + (bool emissive-texture-enabled pbr-material-emissive-texture-enabled) + (int emissive-texcoord pbr-material-emissive-texcoord) (local-field alpha-mode pbr-material-alpha-mode) (float alpha-cutoff pbr-material-alpha-cutoff) - (bool double-sided? pbr-material-double-sided?)) + (local-field double-sided? pbr-material-double-sided?)) (define default-pbr-material (make-pbr-material #:name "default" #:base-color-factor #v(1.0 1.0 1.0) #:base-color-texture null-texture + #:base-color-texture-enabled #f + #:base-color-texcoord 0 #:metallic-factor 1.0 #:roughness-factor 1.0 - #:metallic-roughness-texture #f #:normal-factor #v(1.0 1.0 1.0) - #:normal-texture #f + #:normal-texture null-texture + #:normal-texture-enabled #f + #:normal-texcoord 0 #:occlusion-factor #v(1.0 1.0 1.0) - #:occlusion-texture #f + #:occlusion-texture null-texture + #:occlusion-texture-enabled #f + #:occlusion-texcoord 0 #:emissive-factor #v(1.0 1.0 1.0) - #:emissive-texture #f + #:emissive-texture null-texture + #:emissive-texture-enabled #f + #:emissive-texcoord 0 #:alpha-mode 'opaque - #:alpha-cutoff 0.5 + #:alpha-cutoff 1.0 #:double-sided? #f)) (define-graphics-variable pbr-shader @@ -93,24 +111,21 @@ (define (shader-apply/pbr vertex-array material model-matrix view-matrix) (let* ((shader (graphics-variable-ref pbr-shader)) - (base-color-texture (pbr-material-base-color-texture material)) - (secondary-texture (or (pbr-material-metallic-roughness-texture material) - (pbr-material-normal-texture material) - (pbr-material-occlusion-texture material) - (pbr-material-emissive-texture material) - null-texture)) (vattrs (vertex-array-attributes vertex-array)) (sattrs (shader-attributes shader))) - (with-graphics-state ((g:texture-0 base-color-texture) - (g:texture-1 secondary-texture)) + (with-graphics-state ((g:cull-face-mode (if (pbr-material-double-sided? material) + no-cull-face-mode + back-cull-face-mode)) + (g:texture-0 (pbr-material-base-color-texture material)) + (g:texture-1 (pbr-material-normal-texture material)) + (g:texture-2 (pbr-material-occlusion-texture material)) + (g:texture-3 (pbr-material-emissive-texture material))) (shader-apply shader vertex-array #:model model-matrix #:view view-matrix #:projection (current-projection) - #:textured0 (not (eq? base-color-texture null-texture)) - #:textured1 (not (eq? secondary-texture null-texture)) #:vertex-colored (buffer-view? (assv-ref vattrs (attribute-location (hash-ref sattrs "color0")))) - #:base-color-factor (pbr-material-base-color-factor material))))) + #:material material)))) diff --git a/data/shaders/pbr-frag.glsl b/data/shaders/pbr-frag.glsl index 813f9a9..ce252ab 100644 --- a/data/shaders/pbr-frag.glsl +++ b/data/shaders/pbr-frag.glsl @@ -1,5 +1,23 @@ // -*- mode: c -*- +struct Material { + vec3 baseColorFactor; + bool baseColorTextureEnabled; + int baseColorTexcoord; + float metallicFactor; + float roughnessFactor; + vec3 normalFactor; + bool normalTextureEnabled; + int normalTexcoord; + vec3 occlusionFactor; + bool occlusionTextureEnabled; + int occlusionTexcoord; + vec3 emissiveFactor; + bool emissiveTextureEnabled; + int emissiveTexcoord; + float alphaCutoff; +}; + #ifdef GLSL120 attribute vec2 fragTexcoord0; attribute vec2 fragTexcoord1 @@ -14,26 +32,51 @@ in vec4 fragColor0; out vec4 fragColor; #endif -uniform bool textured0; -uniform bool textured1; +uniform Material material; uniform bool vertexColored; -uniform vec3 baseColorFactor; -uniform sampler2D texture0; -uniform sampler2D texture1; +uniform sampler2D baseColorTexture; +uniform sampler2D normalTexture; +uniform sampler2D occlusionTexture; +uniform sampler2D emissiveTexture; + +vec4 sampleTexture(sampler2D tex, bool enabled, int texcoord, vec3 factor, vec4 defaultColor) { + if(enabled && texcoord == 0) { + return texture(tex, fragTexcoord0) * vec4(factor, 1.0); + } else if(enabled && texcoord == 1) { + return texture(tex, fragTexcoord1) * vec4(factor, 1.0); + } else { + return defaultColor; + } +} -void main (void) { - vec4 finalColor = vec4(baseColorFactor, 1.0); - // Vertex coloring. +void main(void) { + vec4 finalColor = sampleTexture(baseColorTexture, + material.baseColorTextureEnabled, + material.baseColorTexcoord, + material.baseColorFactor, + vec4(1.0, 1.0, 1.0, 1.0)); + + // Mix in vertex color, if present. if(vertexColored) { finalColor *= fragColor0; } - // Texture sampling. - if(textured0) { - finalColor *= texture(texture0, fragTexcoord0); - } - if(textured1) { - finalColor += texture(texture1, fragTexcoord1); - } + + // TODO: Actually apply PBR calculations. + finalColor += sampleTexture(normalTexture, + material.normalTextureEnabled, + material.normalTexcoord, + material.normalFactor, + vec4(0.0, 0.0, 0.0, 0.0)) * 0.1; + finalColor += sampleTexture(occlusionTexture, + material.occlusionTextureEnabled, + material.occlusionTexcoord, + material.occlusionFactor, + vec4(0.0, 0.0, 0.0, 0.0)) * 0.1; + finalColor += sampleTexture(emissiveTexture, + material.emissiveTextureEnabled, + material.emissiveTexcoord, + material.emissiveFactor, + vec4(0.0, 0.0, 0.0, 0.0)); #ifdef GLSL330 fragColor = finalColor; #else -- cgit v1.2.3