diff --git a/examples/tutorials/hello-gltf/app.ts b/examples/tutorials/hello-gltf/app.ts index 345b67a4e8..27da1b0602 100644 --- a/examples/tutorials/hello-gltf/app.ts +++ b/examples/tutorials/hello-gltf/app.ts @@ -56,17 +56,19 @@ export default class AppAnimationLoopTemplate extends AnimationLoopTemplate { const eye = worldMatrix.transformAsPoint(vantage); const center = worldMatrix.transformAsPoint(this.center); const viewMatrix = new Matrix4().lookAt({eye, center}); - const u_MVPMatrix = new Matrix4(projectionMatrix) + const modelViewProjectionMatrix = new Matrix4(projectionMatrix) .multiplyRight(viewMatrix) .multiplyRight(worldMatrix); - model.setUniforms({ - u_Camera: eye, - u_MVPMatrix, - u_ModelMatrix: worldMatrix, - u_NormalMatrix: new Matrix4(worldMatrix).invert().transpose() - }); - model.updateModuleSettings({lightSources}); + model.shaderInputs.setProps({ + lighting: lightSources, + pbrProjection: { + camera: eye, + modelViewProjectionMatrix, + modelMatrix: worldMatrix, + normalMatrix: new Matrix4(worldMatrix).invert().transpose() + } + }); model.draw(renderPass); }); renderPass.end(); @@ -77,7 +79,7 @@ export default class AppAnimationLoopTemplate extends AnimationLoopTemplate { canvas.style.opacity = '0.1'; const gltf = await load( - `https://github.khronos.org/glTF-Sample-Viewer-Release/assets/models/Models/${modelName}/glTF/${modelName}.gltf`, + `https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/${modelName}/glTF/${modelName}.gltf`, GLTFLoader ); const processedGLTF = postProcessGLTF(gltf); @@ -109,17 +111,16 @@ const lightSources: LightingProps = { type: 'ambient' }, directionalLights: [ + // @ts-expect-error Remove once npm package updated with new types { color: [222, 244, 255], direction: [1, -0.5, 0.5], intensity: 10, - position: [0, 0, 0], type: 'directional' } ], pointLights: [ { - attenuation: 0, color: [255, 222, 222], position: [3, 10, 0], intensity: 5, diff --git a/modules/gltf/src/gltf/create-gltf-model.ts b/modules/gltf/src/gltf/create-gltf-model.ts index 3e581f249a..ce24ae59a2 100644 --- a/modules/gltf/src/gltf/create-gltf-model.ts +++ b/modules/gltf/src/gltf/create-gltf-model.ts @@ -1,7 +1,8 @@ import {Device, RenderPipelineParameters, log} from '@luma.gl/core'; -import {pbr} from '@luma.gl/shadertools'; +import {pbrMaterial} from '@luma.gl/shadertools'; import {Geometry, Model, ModelNode, ModelProps} from '@luma.gl/engine'; import {ParsePBRMaterialOptions, parsePBRMaterial} from '../pbr/parse-pbr-material'; +import {ShaderModule} from '@luma.gl/shadertools'; // TODO rename attributes to POSITION/NORMAL etc // See gpu-geometry.ts: getAttributeBuffersFromGeometry() @@ -48,7 +49,7 @@ const vs = ` #endif pbr_setPositionNormalTangentUV(positions, _NORMAL, _TANGENT, _TEXCOORD_0); - gl_Position = u_MVPMatrix * positions; + gl_Position = pbrProjection.modelViewProjectionMatrix * positions; } `; @@ -100,18 +101,26 @@ export function createGLTFModel(device: Device, options: CreateGLTFModelOptions) geometry, topology: geometry.topology, vertexCount, - modules: [pbr], + modules: [pbrMaterial as unknown as ShaderModule], vs: addVersionToShader(device, vs), fs: addVersionToShader(device, fs), + // TODO can this be removed? Does deck need it? ...modelOptions, - bindings: {...parsedMaterial.bindings, ...modelOptions.bindings}, defines: {...parsedMaterial.defines, ...modelOptions.defines}, - parameters: {...parameters, ...parsedMaterial.parameters, ...modelOptions.parameters}, - uniforms: {...parsedMaterial.uniforms, ...modelOptions.uniforms} + parameters: {...parameters, ...parsedMaterial.parameters, ...modelOptions.parameters} }; const model = new Model(device, modelProps); + + const {camera, ...pbrMaterialProps} = { + ...parsedMaterial.uniforms, + ...modelOptions.uniforms, + ...parsedMaterial.bindings, + ...modelOptions.bindings + }; + + model.shaderInputs.setProps({pbrMaterial: pbrMaterialProps, pbrProjection: {camera}}); return new ModelNode({managedResources, model}); } diff --git a/modules/gltf/src/pbr/parse-pbr-material.ts b/modules/gltf/src/pbr/parse-pbr-material.ts index 172911b733..4bb8efb5af 100644 --- a/modules/gltf/src/pbr/parse-pbr-material.ts +++ b/modules/gltf/src/pbr/parse-pbr-material.ts @@ -1,6 +1,7 @@ -import type {Device, Texture, Binding, Parameters} from '@luma.gl/core'; +import type {Device, Texture, Parameters} from '@luma.gl/core'; import {log} from '@luma.gl/core'; import {PBREnvironment} from './pbr-environment'; +import {PBRMaterialBindings, PBRMaterialUniforms, PBRProjectionProps} from '@luma.gl/shadertools'; /* eslint-disable camelcase */ @@ -17,8 +18,8 @@ export type ParsePBRMaterialOptions = { export type ParsedPBRMaterial = { readonly defines: Record; - readonly bindings: Record; - readonly uniforms: Record; + readonly bindings: Partial; + readonly uniforms: Partial; readonly parameters: Parameters; readonly glParameters: Record; /** List of all generated textures, makes it easy to destroy them later */ @@ -57,9 +58,9 @@ export function parsePBRMaterial( bindings: {}, uniforms: { // TODO: find better values? - u_Camera: [0, 0, 0], // Model should override + camera: [0, 0, 0], // Model should override - u_MetallicRoughnessValues: [1, 1] // Default is 1 and 1 + metallicRoughnessValues: [1, 1] // Default is 1 and 1 }, parameters: {}, glParameters: {}, @@ -71,17 +72,18 @@ export function parsePBRMaterial( const {imageBasedLightingEnvironment} = options; if (imageBasedLightingEnvironment) { - parsedMaterial.bindings.u_DiffuseEnvSampler = imageBasedLightingEnvironment.diffuseEnvSampler; - parsedMaterial.bindings.u_SpecularEnvSampler = imageBasedLightingEnvironment.specularEnvSampler; - parsedMaterial.bindings.u_brdfLUT = imageBasedLightingEnvironment.brdfLutTexture; - parsedMaterial.uniforms.u_ScaleIBLAmbient = [1, 1]; + parsedMaterial.bindings.pbr_diffuseEnvSampler = imageBasedLightingEnvironment.diffuseEnvSampler; + parsedMaterial.bindings.pbr_specularEnvSampler = + imageBasedLightingEnvironment.specularEnvSampler; + parsedMaterial.bindings.pbr_BrdfLUT = imageBasedLightingEnvironment.brdfLutTexture; + parsedMaterial.uniforms.scaleIBLAmbient = [1, 1]; } if (options?.pbrDebug) { parsedMaterial.defines.PBR_DEBUG = 1; // Override final color for reference app visualization of various parameters in the lighting equation. - parsedMaterial.uniforms.u_ScaleDiffBaseMR = [0, 0, 0, 0]; - parsedMaterial.uniforms.u_ScaleFGDSpec = [0, 0, 0, 0]; + parsedMaterial.uniforms.scaleDiffBaseMR = [0, 0, 0, 0]; + parsedMaterial.uniforms.scaleFGDSpec = [0, 0, 0, 0]; } if (attributes.NORMAL) parsedMaterial.defines.HAS_NORMALS = 1; @@ -100,45 +102,51 @@ export function parsePBRMaterial( /** Parse GLTF material record */ function parseMaterial(device: Device, material, parsedMaterial: ParsedPBRMaterial): void { - parsedMaterial.uniforms.pbr_uUnlit = Boolean(material.unlit); + parsedMaterial.uniforms.unlit = Boolean(material.unlit); if (material.pbrMetallicRoughness) { parsePbrMetallicRoughness(device, material.pbrMetallicRoughness, parsedMaterial); } if (material.normalTexture) { - addTexture(device, material.normalTexture, 'u_NormalSampler', 'HAS_NORMALMAP', parsedMaterial); + addTexture( + device, + material.normalTexture, + 'pbr_normalSampler', + 'HAS_NORMALMAP', + parsedMaterial + ); const {scale = 1} = material.normalTexture; - parsedMaterial.uniforms.u_NormalScale = scale; + parsedMaterial.uniforms.normalScale = scale; } if (material.occlusionTexture) { addTexture( device, material.occlusionTexture, - 'u_OcclusionSampler', + 'pbr_occlusionSampler', 'HAS_OCCLUSIONMAP', parsedMaterial ); const {strength = 1} = material.occlusionTexture; - parsedMaterial.uniforms.u_OcclusionStrength = strength; + parsedMaterial.uniforms.occlusionStrength = strength; } if (material.emissiveTexture) { addTexture( device, material.emissiveTexture, - 'u_EmissiveSampler', + 'pbr_emissiveSampler', 'HAS_EMISSIVEMAP', parsedMaterial ); - parsedMaterial.uniforms.u_EmissiveFactor = material.emissiveFactor || [0, 0, 0]; + parsedMaterial.uniforms.emissiveFactor = material.emissiveFactor || [0, 0, 0]; } switch (material.alphaMode) { case 'MASK': const {alphaCutoff = 0.5} = material; parsedMaterial.defines.ALPHA_CUTOFF = 1; - parsedMaterial.uniforms.u_AlphaCutoff = alphaCutoff; + parsedMaterial.uniforms.alphaCutoff = alphaCutoff; break; case 'BLEND': log.warn('glTF BLEND alphaMode might not work well because it requires mesh sorting')(); @@ -176,24 +184,24 @@ function parsePbrMetallicRoughness( addTexture( device, pbrMetallicRoughness.baseColorTexture, - 'u_BaseColorSampler', + 'pbr_baseColorSampler', 'HAS_BASECOLORMAP', parsedMaterial ); } - parsedMaterial.uniforms.u_BaseColorFactor = pbrMetallicRoughness.baseColorFactor || [1, 1, 1, 1]; + parsedMaterial.uniforms.baseColorFactor = pbrMetallicRoughness.baseColorFactor || [1, 1, 1, 1]; if (pbrMetallicRoughness.metallicRoughnessTexture) { addTexture( device, pbrMetallicRoughness.metallicRoughnessTexture, - 'u_MetallicRoughnessSampler', + 'pbr_metallicRoughnessSampler', 'HAS_METALROUGHNESSMAP', parsedMaterial ); } const {metallicFactor = 1, roughnessFactor = 1} = pbrMetallicRoughness; - parsedMaterial.uniforms.u_MetallicRoughnessValues = [metallicFactor, roughnessFactor]; + parsedMaterial.uniforms.metallicRoughnessValues = [metallicFactor, roughnessFactor]; } /** Create a texture from a glTF texture/sampler/image combo and add it to bindings */ @@ -268,9 +276,9 @@ export class PBRMaterialParser { this.uniforms = { // TODO: find better values? - u_Camera: [0, 0, 0], // Model should override + camera: [0, 0, 0], // Model should override - u_MetallicRoughnessValues: [1, 1] // Default is 1 and 1 + metallicRoughnessValues: [1, 1] // Default is 1 and 1 }; this.bindings = {}; @@ -279,17 +287,17 @@ export class PBRMaterialParser { this.generatedTextures = []; if (imageBasedLightingEnvironment) { - this.bindings.u_DiffuseEnvSampler = imageBasedLightingEnvironment.getDiffuseEnvSampler(); - this.bindings.u_SpecularEnvSampler = imageBasedLightingEnvironment.getSpecularEnvSampler(); - this.bindings.u_brdfLUT = imageBasedLightingEnvironment.getBrdfTexture(); - this.uniforms.u_ScaleIBLAmbient = [1, 1]; + this.bindings.pbr_diffuseEnvSampler = imageBasedLightingEnvironment.getDiffuseEnvSampler(); + this.bindings.pbr_specularEnvSampler = imageBasedLightingEnvironment.getSpecularEnvSampler(); + this.bindings.pbr_BrdfLUT = imageBasedLightingEnvironment.getBrdfTexture(); + this.uniforms.scaleIBLAmbient = [1, 1]; } if (pbrDebug) { // Override final color for reference app visualization // of various parameters in the lighting equation. - this.uniforms.u_ScaleDiffBaseMR = [0, 0, 0, 0]; - this.uniforms.u_ScaleFGDSpec = [0, 0, 0, 0]; + this.uniforms.scaleDiffBaseMR = [0, 0, 0, 0]; + this.uniforms.scaleFGDSpec = [0, 0, 0, 0]; } this.defineIfPresent(attributes.NORMAL, 'HAS_NORMALS'); @@ -321,31 +329,31 @@ export class PBRMaterialParser { /** Parse GLTF material record * parseMaterial(material) { - this.uniforms.pbr_uUnlit = Boolean(material.unlit); + this.uniforms.unlit = Boolean(material.unlit); if (material.pbrMetallicRoughness) { this.parsePbrMetallicRoughness(material.pbrMetallicRoughness); } if (material.normalTexture) { - this.addTexture(material.normalTexture, 'u_NormalSampler', 'HAS_NORMALMAP'); + this.addTexture(material.normalTexture, 'pbr_normalSampler', 'HAS_NORMALMAP'); const {scale = 1} = material.normalTexture; - this.uniforms.u_NormalScale = scale; + this.uniforms.normalScale = scale; } if (material.occlusionTexture) { - this.addTexture(material.occlusionTexture, 'u_OcclusionSampler', 'HAS_OCCLUSIONMAP'); + this.addTexture(material.occlusionTexture, 'pbr_occlusionSampler', 'HAS_OCCLUSIONMAP'); const {strength = 1} = material.occlusionTexture; - this.uniforms.u_OcclusionStrength = strength; + this.uniforms.occlusionStrength = strength; } if (material.emissiveTexture) { - this.addTexture(material.emissiveTexture, 'u_EmissiveSampler', 'HAS_EMISSIVEMAP'); - this.uniforms.u_EmissiveFactor = material.emissiveFactor || [0, 0, 0]; + this.addTexture(material.emissiveTexture, 'pbr_emissiveSampler', 'HAS_EMISSIVEMAP'); + this.uniforms.emissiveFactor = material.emissiveFactor || [0, 0, 0]; } if (material.alphaMode === 'MASK') { const {alphaCutoff = 0.5} = material; this.defines.ALPHA_CUTOFF = 1; - this.uniforms.u_AlphaCutoff = alphaCutoff; + this.uniforms.alphaCutoff = alphaCutoff; } else if (material.alphaMode === 'BLEND') { log.warn('BLEND alphaMode might not work well because it requires mesh sorting')(); Object.assign(this.parameters, { @@ -361,21 +369,21 @@ export class PBRMaterialParser { if (pbrMetallicRoughness.baseColorTexture) { this.addTexture( pbrMetallicRoughness.baseColorTexture, - 'u_BaseColorSampler', + 'pbr_baseColorSampler', 'HAS_BASECOLORMAP' ); } - this.uniforms.u_BaseColorFactor = pbrMetallicRoughness.baseColorFactor || [1, 1, 1, 1]; + this.uniforms.baseColorFactor = pbrMetallicRoughness.baseColorFactor || [1, 1, 1, 1]; if (pbrMetallicRoughness.metallicRoughnessTexture) { this.addTexture( pbrMetallicRoughness.metallicRoughnessTexture, - 'u_MetallicRoughnessSampler', + 'pbr_metallicRoughnessSampler', 'HAS_METALROUGHNESSMAP' ); } const {metallicFactor = 1, roughnessFactor = 1} = pbrMetallicRoughness; - this.uniforms.u_MetallicRoughnessValues = [metallicFactor, roughnessFactor]; + this.uniforms.metallicRoughnessValues = [metallicFactor, roughnessFactor]; } /** Create a texture from a glTF texture/sampler/image combo and add it to bindings * diff --git a/modules/shadertools/src/index.ts b/modules/shadertools/src/index.ts index 8801ec36a3..b8738d9eb8 100644 --- a/modules/shadertools/src/index.ts +++ b/modules/shadertools/src/index.ts @@ -75,7 +75,13 @@ export type {GouraudMaterialProps} from './modules/lighting/gouraud-material/gou export {gouraudMaterial} from './modules/lighting/gouraud-material/gouraud-material'; export type {PhongMaterialProps} from './modules/lighting/phong-material/phong-material'; export {phongMaterial} from './modules/lighting/phong-material/phong-material'; -// export type {PBRMaterialSettings, PBRMaterialUniforms} from './modules/lighting/pbr-material/pbr'; +export type { + PBRMaterialBindings, + PBRMaterialProps, + PBRMaterialUniforms +} from './modules/lighting/pbr-material/pbr-material'; +export type {PBRProjectionProps} from './modules/lighting/pbr-material/pbr-projection'; + export {pbrMaterial} from './modules/lighting/pbr-material/pbr-material'; // POST PROCESSING / SHADER PASS MODULES diff --git a/modules/shadertools/src/modules/lighting/pbr-material/pbr-fragment-glsl.ts b/modules/shadertools/src/modules/lighting/pbr-material/pbr-fragment-glsl.ts index 89765837a7..7131cc3c45 100644 --- a/modules/shadertools/src/modules/lighting/pbr-material/pbr-fragment-glsl.ts +++ b/modules/shadertools/src/modules/lighting/pbr-material/pbr-fragment-glsl.ts @@ -14,12 +14,7 @@ import {glsl} from '../../../lib/glsl-utils/highlight'; export const fs = glsl`\ precision highp float; -uniform Projection { - // Projection - uniform vec3 u_Camera; -}; - -uniform pbrMaterial { +uniform pbrMaterialUniforms { // Material is unlit bool unlit; @@ -51,40 +46,40 @@ uniform pbrMaterial { vec4 scaleDiffBaseMR; vec4 scaleFGDSpec; // #endif -} u_pbrMaterial; +} pbrMaterial; // Samplers #ifdef HAS_BASECOLORMAP -uniform sampler2D u_BaseColorSampler; +uniform sampler2D pbr_baseColorSampler; #endif #ifdef HAS_NORMALMAP -uniform sampler2D u_NormalSampler; +uniform sampler2D pbr_normalSampler; #endif #ifdef HAS_EMISSIVEMAP -uniform sampler2D u_EmissiveSampler; +uniform sampler2D pbr_emissiveSampler; #endif #ifdef HAS_METALROUGHNESSMAP -uniform sampler2D u_MetallicRoughnessSampler; +uniform sampler2D pbr_metallicRoughnessSampler; #endif #ifdef HAS_OCCLUSIONMAP -uniform sampler2D u_OcclusionSampler; +uniform sampler2D pbr_occlusionSampler; #endif #ifdef USE_IBL -uniform samplerCube u_DiffuseEnvSampler; -uniform samplerCube u_SpecularEnvSampler; -uniform sampler2D u_brdfLUT; +uniform samplerCube pbr_diffuseEnvSampler; +uniform samplerCube pbr_specularEnvSampler; +uniform sampler2D pbr_brdfLUT; #endif // Inputs from vertex shader -varying vec3 pbr_vPosition; -varying vec2 pbr_vUV; +in vec3 pbr_vPosition; +in vec2 pbr_vUV; #ifdef HAS_NORMALS #ifdef HAS_TANGENTS -varying mat3 pbr_vTBN; +in mat3 pbr_vTBN; #else -varying vec3 pbr_vNormal; +in vec3 pbr_vNormal; #endif #endif @@ -152,8 +147,8 @@ vec3 getNormal() #endif #ifdef HAS_NORMALMAP - vec3 n = texture2D(u_NormalSampler, pbr_vUV).rgb; - n = normalize(tbn * ((2.0 * n - 1.0) * vec3(u_pbrMaterial.normalScale, u_pbrMaterial.normalScale, 1.0))); + vec3 n = texture(pbr_normalSampler, pbr_vUV).rgb; + n = normalize(tbn * ((2.0 * n - 1.0) * vec3(pbrMaterial.normalScale, pbrMaterial.normalScale, 1.0))); #else // The tbn matrix is linearly interpolated, so we need to re-normalize vec3 n = normalize(tbn[2].xyz); @@ -171,22 +166,22 @@ vec3 getIBLContribution(PBRInfo pbrInfo, vec3 n, vec3 reflection) float mipCount = 9.0; // resolution of 512x512 float lod = (pbrInfo.perceptualRoughness * mipCount); // retrieve a scale and bias to F0. See [1], Figure 3 - vec3 brdf = SRGBtoLINEAR(texture2D(u_brdfLUT, + vec3 brdf = SRGBtoLINEAR(texture(pbr_brdfLUT, vec2(pbrInfo.NdotV, 1.0 - pbrInfo.perceptualRoughness))).rgb; - vec3 diffuseLight = SRGBtoLINEAR(textureCube(u_DiffuseEnvSampler, n)).rgb; + vec3 diffuseLight = SRGBtoLINEAR(texture(pbr_diffuseEnvSampler, n)).rgb; #ifdef USE_TEX_LOD - vec3 specularLight = SRGBtoLINEAR(textureCubeLod(u_SpecularEnvSampler, reflection, lod)).rgb; + vec3 specularLight = SRGBtoLINEAR(texture(pbr_specularEnvSampler, reflection, lod)).rgb; #else - vec3 specularLight = SRGBtoLINEAR(textureCube(u_SpecularEnvSampler, reflection)).rgb; + vec3 specularLight = SRGBtoLINEAR(texture(pbr_specularEnvSampler, reflection)).rgb; #endif vec3 diffuse = diffuseLight * pbrInfo.diffuseColor; vec3 specular = specularLight * (pbrInfo.specularColor * brdf.x + brdf.y); // For presentation, this allows us to disable IBL terms - diffuse *= u_pbrMaterial.scaleIBLAmbient.x; - specular *= u_pbrMaterial.scaleIBLAmbient.y; + diffuse *= pbrMaterial.scaleIBLAmbient.x; + specular *= pbrMaterial.scaleIBLAmbient.y; return diffuse + specular; } @@ -278,32 +273,32 @@ vec4 pbr_filterColor(vec4 colorUnused) { // The albedo may be defined from a base texture or a flat color #ifdef HAS_BASECOLORMAP - vec4 baseColor = SRGBtoLINEAR(texture2D(u_BaseColorSampler, pbr_vUV)) * u_pbrMaterial.baseColorFactor; + vec4 baseColor = SRGBtoLINEAR(texture(pbr_baseColorSampler, pbr_vUV)) * pbrMaterial.baseColorFactor; #else - vec4 baseColor = u_pbrMaterial.baseColorFactor; + vec4 baseColor = pbrMaterial.baseColorFactor; #endif #ifdef ALPHA_CUTOFF - if (baseColor.a < u_pbrMaterial.alphaCutoff) { + if (baseColor.a < pbrMaterial.alphaCutoff) { discard; } #endif vec3 color = vec3(0, 0, 0); - if(u_pbrMaterial.unlit){ + if(pbrMaterial.unlit){ color.rgb = baseColor.rgb; } else{ // Metallic and Roughness material properties are packed together // In glTF, these factors can be specified by fixed scalar values // or from a metallic-roughness map - float perceptualRoughness = u_pbrMaterial.metallicRoughnessValues.y; - float metallic = u_pbrMaterial.metallicRoughnessValues.x; + float perceptualRoughness = pbrMaterial.metallicRoughnessValues.y; + float metallic = pbrMaterial.metallicRoughnessValues.x; #ifdef HAS_METALROUGHNESSMAP // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. // This layout intentionally reserves the 'r' channel for (optional) occlusion map data - vec4 mrSample = texture2D(u_MetallicRoughnessSampler, pbr_vUV); + vec4 mrSample = texture(pbr_metallicRoughnessSampler, pbr_vUV); perceptualRoughness = mrSample.g * perceptualRoughness; metallic = mrSample.b * metallic; #endif @@ -330,7 +325,7 @@ vec4 pbr_filterColor(vec4 colorUnused) vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90; vec3 n = getNormal(); // normal at surface point - vec3 v = normalize(u_Camera - pbr_vPosition); // Vector from surface point to camera + vec3 v = normalize(pbrProjection.camera - pbr_vPosition); // Vector from surface point to camera float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0); vec3 reflection = -normalize(reflect(v, n)); @@ -352,47 +347,48 @@ vec4 pbr_filterColor(vec4 colorUnused) v ); + #ifdef USE_LIGHTS // Apply ambient light PBRInfo_setAmbientLight(pbrInfo); - color += calculateFinalColor(pbrInfo, lighting_uAmbientLight.color); + color += calculateFinalColor(pbrInfo, lighting.ambientColor); // Apply directional light - for(int i = 0; i < lighting_uDirectionalLightCount; i++) { - if (i < lighting_uDirectionalLightCount) { - PBRInfo_setDirectionalLight(pbrInfo, lighting_uDirectionalLight[i].direction); - color += calculateFinalColor(pbrInfo, lighting_uDirectionalLight[i].color); + for(int i = 0; i < lighting.directionalLightCount; i++) { + if (i < lighting.directionalLightCount) { + PBRInfo_setDirectionalLight(pbrInfo, lighting_getDirectionalLight(i).direction); + color += calculateFinalColor(pbrInfo, lighting_getDirectionalLight(i).color); } } // Apply point light - for(int i = 0; i < lighting_uPointLightCount; i++) { - if (i < lighting_uPointLightCount) { - PBRInfo_setPointLight(pbrInfo, lighting_uPointLight[i]); - float attenuation = getPointLightAttenuation(lighting_uPointLight[i], distance(lighting_uPointLight[i].position, pbr_vPosition)); - color += calculateFinalColor(pbrInfo, lighting_uPointLight[i].color / attenuation); + for(int i = 0; i < lighting.pointLightCount; i++) { + if (i < lighting.pointLightCount) { + PBRInfo_setPointLight(pbrInfo, lighting_getPointLight(i)); + float attenuation = getPointLightAttenuation(lighting_getPointLight(i), distance(lighting_getPointLight(i).position, pbr_vPosition)); + color += calculateFinalColor(pbrInfo, lighting_getPointLight(i).color / attenuation); } } #endif // Calculate lighting contribution from image based lighting source (IBL) #ifdef USE_IBL - if (u_pbrMateral.IBLEnabled) { + if (pbrMaterial.IBLenabled) { color += getIBLContribution(pbrInfo, n, reflection); } #endif - // Apply optional PBR terms for additional (optional) shading + // Apply optional PBR terms for additional (optional) shading #ifdef HAS_OCCLUSIONMAP - if (u_pbrMaterial.occlusionMapEnabled) { - float ao = texture2D(u_OcclusionSampler, pbr_vUV).r; - color = mix(color, color * ao, u_pbrMaterial.occlusionStrength); + if (pbrMaterial.occlusionMapEnabled) { + float ao = texture(pbr_occlusionSampler, pbr_vUV).r; + color = mix(color, color * ao, pbrMaterial.occlusionStrength); } #endif #ifdef HAS_EMISSIVEMAP - if (u_pbrMaterial.emmissiveMapEnabled) { - vec3 emissive = SRGBtoLINEAR(texture2D(u_EmissiveSampler, pbr_vUV)).rgb * u_pbrMaterial.emissiveFactor; + if (pbrMaterial.emissiveMapEnabled) { + vec3 emissive = SRGBtoLINEAR(texture(pbr_emissiveSampler, pbr_vUV)).rgb * pbrMaterial.emissiveFactor; color += emissive; } #endif @@ -402,15 +398,15 @@ vec4 pbr_filterColor(vec4 colorUnused) #ifdef PBR_DEBUG // TODO: Figure out how to debug multiple lights - // color = mix(color, F, u_ScaleFGDSpec.x); - // color = mix(color, vec3(G), u_ScaleFGDSpec.y); - // color = mix(color, vec3(D), u_ScaleFGDSpec.z); - // color = mix(color, specContrib, u_ScaleFGDSpec.w); + // color = mix(color, F, pbr_scaleFGDSpec.x); + // color = mix(color, vec3(G), pbr_scaleFGDSpec.y); + // color = mix(color, vec3(D), pbr_scaleFGDSpec.z); + // color = mix(color, specContrib, pbr_scaleFGDSpec.w); - // color = mix(color, diffuseContrib, u_ScaleDiffBaseMR.x); - color = mix(color, baseColor.rgb, u_pbrMaterial.scaleDiffBaseMR.y); - color = mix(color, vec3(metallic), u_pbrMaterial.scaleDiffBaseMR.z); - color = mix(color, vec3(perceptualRoughness), u_pbrMaterial.scaleDiffBaseMR.w); + // color = mix(color, diffuseContrib, pbr_scaleDiffBaseMR.x); + color = mix(color, baseColor.rgb, pbrMaterial.scaleDiffBaseMR.y); + color = mix(color, vec3(metallic), pbrMaterial.scaleDiffBaseMR.z); + color = mix(color, vec3(perceptualRoughness), pbrMaterial.scaleDiffBaseMR.w); #endif } diff --git a/modules/shadertools/src/modules/lighting/pbr-material/pbr-material.ts b/modules/shadertools/src/modules/lighting/pbr-material/pbr-material.ts index c9b2da6f68..168e4c0c64 100644 --- a/modules/shadertools/src/modules/lighting/pbr-material/pbr-material.ts +++ b/modules/shadertools/src/modules/lighting/pbr-material/pbr-material.ts @@ -13,52 +13,21 @@ import {lighting} from '../lights/lighting-uniforms'; import {vs} from './pbr-vertex-glsl'; import {fs} from './pbr-fragment-glsl'; - -export type PBRMaterialProps = PBRMaterialBindings & { - unlit: boolean; - - // Base color map - baseColorMapEnabled: boolean; - baseColorFactor: Readonly; - - normalMapEnabled: boolean; - normalScale: number; // #ifdef HAS_NORMALMAP - - emissiveMapEnabled: boolean; - emissiveFactor: Readonly; // #ifdef HAS_EMISSIVEMAP - - metallicRoughnessValues: Readonly; - metallicRoughnessMapEnabled: boolean; - - occlusionMapEnabled: boolean; - occlusionStrength: number; // #ifdef HAS_OCCLUSIONMAP - - alphaCutoffEnabled: boolean; - alphaCutoff: number; // #ifdef ALPHA_CUTOFF - - // IBL - IBLenabled: boolean; - scaleIBLAmbient: Readonly; // #ifdef USE_IBL - - // debugging flags used for shader output of intermediate PBR variables - // #ifdef PBR_DEBUG - scaleDiffBaseMR: Readonly; - scaleFGDSpec: Readonly; -}; +import {pbrProjection} from './pbr-projection'; /** Non-uniform block bindings for pbr module */ -type PBRMaterialBindings = { +export type PBRMaterialBindings = { // Samplers - baseColorSampler?: Texture | null; // #ifdef HAS_BASECOLORMAP - normalSampler?: Texture | null; // #ifdef HAS_NORMALMAP - emissiveSampler?: Texture | null; // #ifdef HAS_EMISSIVEMAP - metallicRoughnessSampler?: Texture | null; // #ifdef HAS_METALROUGHNESSMAP - occlusionSampler?: Texture | null; // #ifdef HAS_OCCLUSIONMAP + pbr_baseColorSampler?: Texture | null; // #ifdef HAS_BASECOLORMAP + pbr_normalSampler?: Texture | null; // #ifdef HAS_NORMALMAP + pbr_emissiveSampler?: Texture | null; // #ifdef HAS_EMISSIVEMAP + pbr_metallicRoughnessSampler?: Texture | null; // #ifdef HAS_METALROUGHNESSMAP + pbr_occlusionSampler?: Texture | null; // #ifdef HAS_OCCLUSIONMAP // IBL Samplers - diffuseEnvSampler: Texture | null; // #ifdef USE_IBL (samplerCube) - specularEnvSampler: Texture | null; // #ifdef USE_IBL (samplerCube) - brdfLUT?: Texture | null; // #ifdef USE_IBL + pbr_diffuseEnvSampler?: Texture | null; // #ifdef USE_IBL (samplerCube) + pbr_specularEnvSampler?: Texture | null; // #ifdef USE_IBL (samplerCube) + pbr_BrdfLUT?: Texture | null; // #ifdef USE_IBL }; export type PBRMaterialUniforms = { @@ -93,25 +62,29 @@ export type PBRMaterialUniforms = { scaleFGDSpec: Readonly; }; +export type PBRMaterialProps = PBRMaterialBindings & PBRMaterialUniforms; + /** * An implementation of PBR (Physically-Based Rendering). * Physically Based Shading of a microfacet surface defined by a glTF material. */ export const pbrMaterial: ShaderModule = { - name: 'pbr', + name: 'pbrMaterial', vs, fs, defines: { - LIGHTING_FRAGMENT: 1, - HAS_NORMALMAP: 0, - HAS_EMISSIVEMAP: 0, - HAS_OCCLUSIONMAP: 0, - HAS_BASECOLORMAP: 0, - HAS_METALROUGHNESSMAP: 0, - ALPHA_CUTOFF: 0, - USE_IBL: 0, - PBR_DEBUG: 0 + LIGHTING_FRAGMENT: 1 + // TODO defining these as 0 breaks shader + // HAS_NORMALMAP: 0 + // HAS_EMISSIVEMAP: 0, + // HAS_OCCLUSIONMAP: 0, + // HAS_BASECOLORMAP: 0, + // HAS_METALROUGHNESSMAP: 0, + // ALPHA_CUTOFF: 0 + // USE_IBL: 0 + // PBR_DEBUG: 0 }, + getUniforms: props => props, uniformTypes: { // Material is unlit unlit: 'i32', @@ -144,5 +117,5 @@ export const pbrMaterial: ShaderModule = scaleDiffBaseMR: 'vec4', scaleFGDSpec: 'vec4' }, - dependencies: [lighting] + dependencies: [lighting, pbrProjection] }; diff --git a/modules/shadertools/src/modules/lighting/pbr-material/pbr-projection.ts b/modules/shadertools/src/modules/lighting/pbr-material/pbr-projection.ts new file mode 100644 index 0000000000..f46fcd9a7d --- /dev/null +++ b/modules/shadertools/src/modules/lighting/pbr-material/pbr-projection.ts @@ -0,0 +1,41 @@ +// luma.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +/* eslint-disable camelcase */ + +import type {NumberArray3, NumberArray16} from '../../../lib/utils/uniform-types'; + +import {ShaderModule} from '../../../lib/shader-module/shader-module'; + +import {glsl} from '../../../lib/glsl-utils/highlight'; + +const uniformBlock = glsl`\ +uniform pbrProjectionUniforms { + mat4 modelViewProjectionMatrix; + mat4 modelMatrix; + mat4 normalMatrix; + vec3 camera; +} pbrProjection; +`; + +export type PBRProjectionProps = { + modelViewProjectionMatrix: NumberArray16; + modelMatrix: NumberArray16; + normalMatrix: NumberArray16; + camera: NumberArray3; +}; + +export const pbrProjection: ShaderModule = { + name: 'pbrProjection', + vs: uniformBlock, + fs: uniformBlock, + // TODO why is this needed? + getUniforms: props => props, + uniformTypes: { + modelViewProjectionMatrix: 'mat4x4', + modelMatrix: 'mat4x4', + normalMatrix: 'mat4x4', + camera: 'vec3' + } +}; diff --git a/modules/shadertools/src/modules/lighting/pbr-material/pbr-uniforms-glsl.ts b/modules/shadertools/src/modules/lighting/pbr-material/pbr-uniforms-glsl.ts deleted file mode 100644 index 1daf5529c2..0000000000 --- a/modules/shadertools/src/modules/lighting/pbr-material/pbr-uniforms-glsl.ts +++ /dev/null @@ -1,69 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import {glsl} from '../../../lib/glsl-utils/highlight'; - -export const pbrMaterialUniforms = glsl`\ -uniform Projection { - // Projection - vec3 u_Camera; -}; - -uniform pbrMaterialUniforms { - // Material is unlit - bool unlit; - - // Base color map - bool baseColorMapEnabled; - vec4 baseColorFactor; - - bool normalMapEnabled; - float normalScale; // #ifdef HAS_NORMALMAP - - bool emissiveMapEnabled; - vec3 emissiveFactor; // #ifdef HAS_EMISSIVEMAP - - vec2 metallicRoughnessValues; - bool metallicRoughnessMapEnabled; - - bool occlusionMapEnabled; - float occlusionStrength; // #ifdef HAS_OCCLUSIONMAP - - bool alphaCutoffEnabled; - float alphaCutoff; // #ifdef ALPHA_CUTOFF - - // IBL - bool IBLenabled; - vec2 scaleIBLAmbient; // #ifdef USE_IBL - - // debugging flags used for shader output of intermediate PBR variables - // #ifdef PBR_DEBUG - vec4 scaleDiffBaseMR; - vec4 scaleFGDSpec; - // #endif -}; - -// Samplers -#ifdef HAS_BASECOLORMAP -uniform sampler2D u_BaseColorSampler; -#endif -#ifdef HAS_NORMALMAP -uniform sampler2D u_NormalSampler; -#endif -#ifdef HAS_EMISSIVEMAP -uniform sampler2D u_EmissiveSampler; -#endif -#ifdef HAS_METALROUGHNESSMAP -uniform sampler2D u_MetallicRoughnessSampler; -#endif -#ifdef HAS_OCCLUSIONMAP -uniform sampler2D u_OcclusionSampler; -#endif -#ifdef USE_IBL -uniform samplerCube u_DiffuseEnvSampler; -uniform samplerCube u_SpecularEnvSampler; -uniform sampler2D u_brdfLUT; -#endif - -`; diff --git a/modules/shadertools/src/modules/lighting/pbr-material/pbr-vertex-glsl.ts b/modules/shadertools/src/modules/lighting/pbr-material/pbr-vertex-glsl.ts index bb8cf2e488..81d191d6dc 100644 --- a/modules/shadertools/src/modules/lighting/pbr-material/pbr-vertex-glsl.ts +++ b/modules/shadertools/src/modules/lighting/pbr-material/pbr-vertex-glsl.ts @@ -5,38 +5,30 @@ import {glsl} from '../../../lib/glsl-utils/highlight'; export const vs = glsl`\ -uniform projection { - mat4 u_MVPMatrix; - mat4 u_ModelMatrix; - mat4 u_NormalMatrix; - // Projection - vec3 u_Camera; -} - -varying vec3 pbr_vPosition; -varying vec2 pbr_vUV; +out vec3 pbr_vPosition; +out vec2 pbr_vUV; #ifdef HAS_NORMALS # ifdef HAS_TANGENTS -varying mat3 pbr_vTBN; +out mat3 pbr_vTBN; # else -varying vec3 pbr_vNormal; +out vec3 pbr_vNormal; # endif #endif void pbr_setPositionNormalTangentUV(vec4 position, vec4 normal, vec4 tangent, vec2 uv) { - vec4 pos = u_ModelMatrix * position; + vec4 pos = pbrProjection.modelMatrix * position; pbr_vPosition = vec3(pos.xyz) / pos.w; #ifdef HAS_NORMALS #ifdef HAS_TANGENTS - vec3 normalW = normalize(vec3(u_NormalMatrix * vec4(normal.xyz, 0.0))); - vec3 tangentW = normalize(vec3(u_ModelMatrix * vec4(tangent.xyz, 0.0))); + vec3 normalW = normalize(vec3(pbrProjection.normalMatrix * vec4(normal.xyz, 0.0))); + vec3 tangentW = normalize(vec3(pbrProjection.modelMatrix * vec4(tangent.xyz, 0.0))); vec3 bitangentW = cross(normalW, tangentW) * tangent.w; pbr_vTBN = mat3(tangentW, bitangentW, normalW); #else // HAS_TANGENTS != 1 - pbr_vNormal = normalize(vec3(u_ModelMatrix * vec4(normal.xyz, 0.0))); + pbr_vNormal = normalize(vec3(pbrProjection.modelMatrix * vec4(normal.xyz, 0.0))); #endif #endif diff --git a/modules/shadertools/src/modules/lighting/phong-material/phong-shaders-glsl.ts b/modules/shadertools/src/modules/lighting/phong-material/phong-shaders-glsl.ts index 7639704392..f63005ae60 100644 --- a/modules/shadertools/src/modules/lighting/phong-material/phong-shaders-glsl.ts +++ b/modules/shadertools/src/modules/lighting/phong-material/phong-shaders-glsl.ts @@ -59,5 +59,4 @@ vec3 lighting_getLightColor(vec3 surfaceColor, vec3 cameraPosition, vec3 positio return lightColor; } - `;