From ca4e6be8daeb88144d1a70a32f8202a2da3e7465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jhonny=20Go=CC=88ransson?= Date: Tue, 7 Oct 2025 13:37:42 +0200 Subject: [PATCH 1/5] PBR manual entry --- .../material-constants.png | Bin 0 -> 32621 bytes docs/en/manuals/physically-based-rendering.md | 415 ++++++++++++++++++ 2 files changed, 415 insertions(+) create mode 100644 docs/en/manuals/images/physically-based-rendering/material-constants.png create mode 100644 docs/en/manuals/physically-based-rendering.md diff --git a/docs/en/manuals/images/physically-based-rendering/material-constants.png b/docs/en/manuals/images/physically-based-rendering/material-constants.png new file mode 100644 index 0000000000000000000000000000000000000000..a722ac877265b6e84b4b66e2d45553727218aede GIT binary patch literal 32621 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 z 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 D`ovp~ literal 0 HcmV?d00001 diff --git a/docs/en/manuals/physically-based-rendering.md b/docs/en/manuals/physically-based-rendering.md new file mode 100644 index 00000000..bb397d54 --- /dev/null +++ b/docs/en/manuals/physically-based-rendering.md @@ -0,0 +1,415 @@ +--- +title: Physically based rendering in Defold +brief: This manual explains the basics of how to access material data for physically based rendering in Defold. +--- + +# Physically Based Rendering (PBR) + +Physically Based Rendering (PBR) is a shading approach that models how light interacts with surfaces using real-world physical principles. It produces consistent, realistic lighting across different environments and allows assets to look correct under a wide range of lighting conditions. + +Defold’s PBR implementation follows the glTF 2.0 material specification and associated Khronos extensions. When you import glTF assets into Defold, material properties are automatically parsed and stored as structured material data that can be accessed in shaders at runtime. + +PBR materials can include effects such as metallic reflections, surface roughness, transmission, clearcoat, subsurface scattering, iridescence, and more. + +::: sidenote +Embedded textures from GLTF files are not yet exposed or accessible for assignment in Defold. This will come at a later stage, for now only the material data is exposed to the shaders. +::: + +## Material properties overview + +The material properties are parsed from the GLTF 2.0 source files assigned to a model component. Not all properties are considered standard properties, some of these are explicitly exposed via GLTF extensions that may or may not be enabled by the application that exported the gltf files. The relevant extension is denoted in parentheses after the property name below. + +Metallic roughness +: Describes how light interact with the material. The default PBR model. + +Specular glossiness (KHR_materials_pbrSpecularGlossiness) +: An alternative to metallic roughness. Often used in older assets. + +Clearcoat (KHR_materials_clearcoat) +: Adds a transparent coating layer with its own roughness and normal map. + +Ior (KHR_materials_ior) +: Adds an index of refraction. + +Specular (KHR_materials_specular) +: Adds a dedicated specular intensity and color channel. + +Iridescence (KHR_materials_iridescence) +: Simulates thin-film interference for materials like soap bubbles or pearls. + +Sheen (KHR_materials_sheen) +: Models fabric-like micro-surface reflections. + +Transmission (KHR_materials_transmission) +: Models light transmission for transparent or glass-like materials. + +Volume (KHR_materials_volume) +: Supports volumetric effects like thickness and attenuation. + +Emissive strength (KHR_materials_emissive_strength) +: Controls emissive brightness independent of base color. + +Normal map +: Normal map for surface detail. + +Occlusion map +: Ambient occlusion map. + +Emissive map +: Self-emissive texture for glowing surfaces. + +Emissive factor +: RGB multiplier for emissive intensity + +Alpha cutoff +: Threshold for masked transparency. + +Alpha mode +: Opaque, Masked, or Blended transparency modes. + +Double sided +: If true, both sides of the surface are rendered. + +Unlit +: If true, the material bypasses lighting calculations. + +::: sidenote +Some of these properties provides hints on how the material should be rendered. The data for the properties (alpha cutoff, alpha mode, double sided and unlit) is available in the shaders, but does not affect how the material is rendered in Defold. +::: + +## Shader integration + +The PBR material data is exposed to the shaders based on types and name convention. First of all, the base material struct must be a separate uniform block in the shader named 'PbrMaterial': + +```glsl +uniform PbrMaterial +{ + // Material properties +}; +``` + +The various features of the material is specified as fixed structs in the shader. Data has been packed as much as possible in vec4's since that is how constants are set internally in Defold. In those cases where data has been packed, it is denoted as comments in the shader snippets for each feature below: + +```glsl +struct PbrMetallicRoughness +{ + vec4 baseColorFactor; + // R: metallic (Default=1.0), G: roughness (Default=1.0) + vec4 metallicAndRoughnessFactor; + // R: use baseColorTexture, G: use metallicRoughnessTexture + vec4 metallicRoughnessTextures; +}; + +struct PbrSpecularGlossiness +{ + vec4 diffuseFactor; + // RGB: specular (Default=1.0), A: glossiness (Default=1.0) + vec4 specularAndSpecularGlossinessFactor; + // R: use diffuseTexture, G: use specularGlossinessTexture + vec4 specularGlossinessTextures; +}; + +struct PbrClearCoat +{ + // R: clearCoat (Default=0.0), G: clearCoatRoughness (Default=0.0) + vec4 clearCoatAndClearCoatRoughnessFactor; + // R: use clearCoatTexture, G: use clearCoatRoughnessTexture, B: use clearCoatNormalTexture + vec4 clearCoatTextures; +}; + +struct PbrTransmission +{ + // R: transmission (Default=0.0) + vec4 transmissionFactor; + // R: use transmissionTexture + vec4 transmissionTextures; +}; + +struct PbrIor +{ + // R: ior (Default=0.0) + vec4 ior; +}; + +struct PbrSpecular +{ + // RGB: specularColor, A: specularFactor (Default=1.0); + vec4 specularColorAndSpecularFactor; + // R: use specularTexture, G: use specularColorTexture + vec4 specularTextures; +}; + +struct PbrVolume +{ + // R: thicknessFactor (Default=0.0), RGB: attenuationColor + vec4 thicknessFactorAndAttenuationColor; + // R: attentuationDistance (Default=-1.0) + vec4 attenuationDistance; + // R: use thicknessTexture + vec4 volumeTextures; +}; + +struct PbrSheen +{ + // RGB: sheenColor, A: sheenRoughnessFactor (Default=0.0) + vec4 sheenColorAndRoughnessFactor; + // R: use sheenColorTexture, G: use sheenRoughnessTexture + vec4 sheenTextures; +}; + +struct PbrEmissiveStrength +{ + // R: emissiveStrength (Default=1.0) + vec4 emissiveStrength; +}; + +struct PbrIridescence +{ + // R: iridescenceFactor (Default=0.0), G: iridescenceIor (Default=1.3), B: iridescenceThicknessMin (Default=100.0), A: iridescenceThicknessMax (Default=400.0) + vec4 iridescenceFactorAndIorAndThicknessMinMax; + // R: use iridescenceTexture, G: use iridescenceThicknessTexture + vec4 iridescenceTextures; +}; +``` + +Texture usage is also exposed to the shaders, but as previously mentioned, textures from the GLTF containers are not automatically set during rendering. You need to assign the textures to the models yourself for this to properly work. Naming for textures are a bit differently since you cannot store texture uniforms inside structs. In this case, the naming scheme is `_texture`: + +```glsl +// PbrMetallicRoughness +uniform sampler2D PbrMetallicRoughness_baseColorTexture; +uniform sampler2D PbrMetallicRoughness_metallicRoughnessTexture; + +// PbrSpecularGlossiness +uniform sampler2D PbrSpecularGlossiness_diffuseTexture; +uniform sampler2D PbrSpecularGlossiness_specularGlossinessTexture; + +// PbrClearCoat +uniform sampler2D PbrClearcoat_clearcoatTexture; +uniform sampler2D PbrClearcoat_clearcoatRoughnessTexture; +uniform sampler2D PbrClearcoat_clearcoatNormalTexture; + +// PbrTransmission +uniform sampler2D PbrTransmission_transmissionTexture; + +// PbrSpecular +uniform sampler2D PbrSpecular_specularTexture; +uniform sampler2D PbrSpecular_specularColorTexture; + +// PbrVolume +uniform sampler2D PbrVolume_thicknessTexture; + +// PbrSheen +uniform sampler2D PbrSheen_sheenColorTexture; +uniform sampler2D PbrSheen_sheenRoughnessTexture; + +// PbrIridescence +uniform sampler2D PbrEmissive_iridescenceTexture; +uniform sampler2D PbrEmissive_iridescenceThicknessTexture; +``` + +The common properties are set on the material uniform itself (and once again, note the data packing into vec4). Textures follow a similar pattern as we've already seen: + +```glsl +// Common textures +uniform sampler2D PbrMaterial_normalTexture; +uniform sampler2D PbrMaterial_occlusionTexture; +uniform sampler2D PbrMaterial_emissiveTexture; + +uniform PbrMaterial +{ + // Common properties: + + // R: alphaCutoff (Default=0.5), G: doubleSided (Default=false), B: unlit (Default=false) + vec4 pbrAlphaCutoffAndDoubleSidedAndIsUnlit; + // R: use normalTexture, G: use occlusionTexture, B: use emissiveTexture + vec4 pbrCommonTextures; + + // Other properties... +}; +``` + +### Example shader + +Here is an example shader that contains all textures and features. Note that you can turn off features simply by using defines around each member of the PbrMaterial itself, as shown in the example below: + +```glsl +// Feature flags, comment or remove these to slim down the shader. +#define PBR_METALLIC_ROUGHNESS +#define PBR_SPECULAR_GLOSSINESS +#define PBR_CLEARCOAT +#define PBR_TRANSMISSION +#define PBR_IOR +#define PBR_SPECULAR +#define PBR_VOLUME +#define PBR_SHEEN +#define PBR_EMISSIVE_STRENGTH +#define PBR_IRIDESCENCE + +// Common +uniform sampler2D PbrMaterial_normalTexture; +uniform sampler2D PbrMaterial_occlusionTexture; +uniform sampler2D PbrMaterial_emissiveTexture; + +// PbrMetallicRoughness +uniform sampler2D PbrMetallicRoughness_baseColorTexture; +uniform sampler2D PbrMetallicRoughness_metallicRoughnessTexture; + +struct PbrMetallicRoughness +{ + vec4 baseColorFactor; + // R: metallic (Default=1.0), G: roughness (Default=1.0) + vec4 metallicAndRoughnessFactor; + // R: use baseColorTexture, G: use metallicRoughnessTexture + vec4 metallicRoughnessTextures; +}; + +// PbrSpecularGlossiness +uniform sampler2D PbrSpecularGlossiness_diffuseTexture; +uniform sampler2D PbrSpecularGlossiness_specularGlossinessTexture; + +struct PbrSpecularGlossiness +{ + vec4 diffuseFactor; + // RGB: specular (Default=1.0), A: glossiness (Default=1.0) + vec4 specularAndSpecularGlossinessFactor; + // R: use diffuseTexture, G: use specularGlossinessTexture + vec4 specularGlossinessTextures; +}; + +// PbrClearCoat +uniform sampler2D PbrClearcoat_clearcoatTexture; +uniform sampler2D PbrClearcoat_clearcoatRoughnessTexture; +uniform sampler2D PbrClearcoat_clearcoatNormalTexture; + +struct PbrClearCoat +{ + // R: clearCoat (Default=0.0), G: clearCoatRoughness (Default=0.0) + vec4 clearCoatAndClearCoatRoughnessFactor; + // R: use clearCoatTexture, G: use clearCoatRoughnessTexture, B: use clearCoatNormalTexture + vec4 clearCoatTextures; +}; + +// PbrTransmission +uniform sampler2D PbrTransmission_transmissionTexture; + +struct PbrTransmission +{ + // R: transmission (Default=0.0) + vec4 transmissionFactor; + // R: use transmissionTexture + vec4 transmissionTextures; +}; + +struct PbrIor +{ + // R: ior (Default=0.0) + vec4 ior; +}; + +// PbrSpecular +uniform sampler2D PbrSpecular_specularTexture; +uniform sampler2D PbrSpecular_specularColorTexture; + +struct PbrSpecular +{ + // RGB: specularColor, A: specularFactor (Default=1.0); + vec4 specularColorAndSpecularFactor; + // R: use specularTexture, G: use specularColorTexture + vec4 specularTextures; +}; + +// PbrVolume +uniform sampler2D PbrVolume_thicknessTexture; + +struct PbrVolume +{ + // R: thicknessFactor (Default=0.0), RGB: attenuationColor + vec4 thicknessFactorAndAttenuationColor; + // R: attentuationDistance (Default=-1.0) + vec4 attenuationDistance; + // R: use thicknessTexture + vec4 volumeTextures; +}; + +// PbrSheen +uniform sampler2D PbrSheen_sheenColorTexture; +uniform sampler2D PbrSheen_sheenRoughnessTexture; + +struct PbrSheen +{ + // RGB: sheenColor, A: sheenRoughnessFactor (Default=0.0) + vec4 sheenColorAndRoughnessFactor; + // R: use sheenColorTexture, G: use sheenRoughnessTexture + vec4 sheenTextures; +}; + +struct PbrEmissiveStrength +{ + // R: emissiveStrength (Default=1.0) + vec4 emissiveStrength; +}; + +// PbrIridescence +uniform sampler2D PbrEmissive_iridescenceTexture; +uniform sampler2D PbrEmissive_iridescenceThicknessTexture; + +struct PbrIridescence +{ + // R: iridescenceFactor (Default=0.0), G: iridescenceIor (Default=1.3), B: iridescenceThicknessMin (Default=100.0), A: iridescenceThicknessMax (Default=400.0) + vec4 iridescenceFactorAndIorAndThicknessMinMax; + // R: use iridescenceTexture, G: use iridescenceThicknessTexture + vec4 iridescenceTextures; +}; + +uniform PbrMaterial +{ + // Common properties + // R: alphaCutoff (Default=0.5), G: doubleSided (Default=false), B: unlit (Default=false) + vec4 pbrAlphaCutoffAndDoubleSidedAndIsUnlit; + // R: use normalTexture, G: use occlusionTexture, B: use emissiveTexture + vec4 pbrCommonTextures; + + // Features +#ifdef PBR_METALLIC_ROUGHNESS + PbrMetallicRoughness pbrMetallicRoughness; +#endif +#ifdef PBR_SPECULAR_GLOSSINESS + PbrSpecularGlossiness pbrSpecularGlossiness; +#endif +#ifdef PBR_CLEARCOAT + PbrClearCoat pbrClearCoat; +#endif +#ifdef PBR_TRANSMISSION + PbrTransmission pbrTransmission; +#endif +#ifdef PBR_IOR + PbrIor pbrIor; +#endif +#ifdef PBR_SPECULAR + PbrSpecular pbrSpecular; +#endif +#ifdef PBR_VOLUME + PbrVolume pbrVolume; +#endif +#ifdef PBR_SHEEN + PbrSheen pbrSheen; +#endif +#ifdef PBR_EMISSIVE_STRENGTH + PbrEmissiveStrength pbrEmissiveStrength; +#endif +#ifdef PBR_IRIDESCENCE + PbrIridescence pbrIridescence; +#endif +}; +``` + +::: sidenote +If specific data points in the material struct are not found, the data for those features will not be set. E.g if there is no `pbrClearCoat` in the material struct, no clear coat data will be set. If the uniform block is not found, no data at all will be set during rendering. +::: + +### Constants + +Since all of the properties are represented internally by render constants, materials can specify different default values when these values are not present. To do this, you can use the following naming pattern: ´pbrFeature.structMember`: + +![Material constants](images/physically-based-rendering/material-constants.png) + From c525ad8e125faf495c7f147dbed064e936cdd3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jhonny=20Go=CC=88ransson?= Date: Tue, 7 Oct 2025 13:51:16 +0200 Subject: [PATCH 2/5] polish --- docs/en/manuals/physically-based-rendering.md | 66 +++++++------------ 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/docs/en/manuals/physically-based-rendering.md b/docs/en/manuals/physically-based-rendering.md index bb397d54..c30a6f50 100644 --- a/docs/en/manuals/physically-based-rendering.md +++ b/docs/en/manuals/physically-based-rendering.md @@ -12,12 +12,16 @@ Defold’s PBR implementation follows the glTF 2.0 material specification and as PBR materials can include effects such as metallic reflections, surface roughness, transmission, clearcoat, subsurface scattering, iridescence, and more. ::: sidenote -Embedded textures from GLTF files are not yet exposed or accessible for assignment in Defold. This will come at a later stage, for now only the material data is exposed to the shaders. +Defold currently exposes PBR material data to shaders, but does not provide a built-in PBR lighting model. You can use this data in your own lighting and reflection shaders to achieve physically based rendering. A default PBR lighting model will be added to Defold at a later stage. +::: + +::: sidenote +Embedded textures from glTF files are currently not automatically assigned in Defold. Only material parameters are exposed to shaders. You can still manually assign textures to model components and sample them in your shader. ::: ## Material properties overview -The material properties are parsed from the GLTF 2.0 source files assigned to a model component. Not all properties are considered standard properties, some of these are explicitly exposed via GLTF extensions that may or may not be enabled by the application that exported the gltf files. The relevant extension is denoted in parentheses after the property name below. +The material properties are parsed from the glTF 2.0 source files assigned to a model component. Not all properties are standard. Some are provided through optional glTF extensions that may or may not be included by the tool used to export the glTF file. The relevant extension is denoted in parentheses after the property name below. Metallic roughness : Describes how light interact with the material. The default PBR model. @@ -79,7 +83,7 @@ Some of these properties provides hints on how the material should be rendered. ## Shader integration -The PBR material data is exposed to the shaders based on types and name convention. First of all, the base material struct must be a separate uniform block in the shader named 'PbrMaterial': +The PBR material data is exposed to the shaders based on types and name convention. The PBR material system provides all parsed material parameters to shaders via a structured uniform block named `PbrMaterial`. Each supported glTF extension corresponds to a struct within this block, which can be conditionally compiled using #define flags. ```glsl uniform PbrMaterial @@ -172,42 +176,7 @@ struct PbrIridescence }; ``` -Texture usage is also exposed to the shaders, but as previously mentioned, textures from the GLTF containers are not automatically set during rendering. You need to assign the textures to the models yourself for this to properly work. Naming for textures are a bit differently since you cannot store texture uniforms inside structs. In this case, the naming scheme is `_texture`: - -```glsl -// PbrMetallicRoughness -uniform sampler2D PbrMetallicRoughness_baseColorTexture; -uniform sampler2D PbrMetallicRoughness_metallicRoughnessTexture; - -// PbrSpecularGlossiness -uniform sampler2D PbrSpecularGlossiness_diffuseTexture; -uniform sampler2D PbrSpecularGlossiness_specularGlossinessTexture; - -// PbrClearCoat -uniform sampler2D PbrClearcoat_clearcoatTexture; -uniform sampler2D PbrClearcoat_clearcoatRoughnessTexture; -uniform sampler2D PbrClearcoat_clearcoatNormalTexture; - -// PbrTransmission -uniform sampler2D PbrTransmission_transmissionTexture; - -// PbrSpecular -uniform sampler2D PbrSpecular_specularTexture; -uniform sampler2D PbrSpecular_specularColorTexture; - -// PbrVolume -uniform sampler2D PbrVolume_thicknessTexture; - -// PbrSheen -uniform sampler2D PbrSheen_sheenColorTexture; -uniform sampler2D PbrSheen_sheenRoughnessTexture; - -// PbrIridescence -uniform sampler2D PbrEmissive_iridescenceTexture; -uniform sampler2D PbrEmissive_iridescenceThicknessTexture; -``` - -The common properties are set on the material uniform itself (and once again, note the data packing into vec4). Textures follow a similar pattern as we've already seen: +The common properties are set on the material uniform itself (and once again, note the data packing into vec4). ```glsl // Common textures @@ -230,7 +199,7 @@ uniform PbrMaterial ### Example shader -Here is an example shader that contains all textures and features. Note that you can turn off features simply by using defines around each member of the PbrMaterial itself, as shown in the example below: +Here is an example shader that contains all features and a proposed naming scheme for texture bindings (again, this must be handled manually). Note that you can turn off features simply by using defines around each member of the PbrMaterial itself, as shown in the example below: ```glsl // Feature flags, comment or remove these to slim down the shader. @@ -277,9 +246,9 @@ struct PbrSpecularGlossiness }; // PbrClearCoat -uniform sampler2D PbrClearcoat_clearcoatTexture; -uniform sampler2D PbrClearcoat_clearcoatRoughnessTexture; -uniform sampler2D PbrClearcoat_clearcoatNormalTexture; +uniform sampler2D PbrClearCoat_clearcoatTexture; +uniform sampler2D PbrClearCoat_clearcoatRoughnessTexture; +uniform sampler2D PbrClearCoat_clearcoatNormalTexture; struct PbrClearCoat { @@ -409,7 +378,16 @@ If specific data points in the material struct are not found, the data for those ### Constants -Since all of the properties are represented internally by render constants, materials can specify different default values when these values are not present. To do this, you can use the following naming pattern: ´pbrFeature.structMember`: +Each material property corresponds to an internal render constant in Defold. You can override default values by defining constants on the material resource itself, following the naming pattern `pbrFeature.structMember`. These values will be applied automatically if the matching data is missing in the glTF material. ![Material constants](images/physically-based-rendering/material-constants.png) +## Next steps + +To use the material data for physically based lighting, implement a BRDF in your fragment shader using the parameters provided in the `PbrMaterial` block. +See also: + +* [Shaders manual](/manuals/shader) +* [Render manual](/manuals/render) +* [glTF 2.0 specification](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html) + From f62287d55e9a966f8dcbe5534c818d3d1c76bf9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jhonny=20Go=CC=88ransson?= Date: Tue, 7 Oct 2025 13:53:25 +0200 Subject: [PATCH 3/5] Link to PBR entry --- docs/en/en.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/en.json b/docs/en/en.json index 677d8286..6cf5fb42 100644 --- a/docs/en/en.json +++ b/docs/en/en.json @@ -1433,6 +1433,10 @@ { "path": "/manuals/texture-filtering", "name": "Texture filtering" + }, + { + "path": "/manuals/physically-based-rendering", + "name": "Physically Based Rendering" } ], "divider": true From 041a368438c802e4f33756db366e559982305e66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jhonny=20Go=CC=88ransson?= Date: Tue, 7 Oct 2025 14:01:26 +0200 Subject: [PATCH 4/5] Maybe spell fix --- .wordlist.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.wordlist.txt b/.wordlist.txt index dda3633c..52253f98 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -196,6 +196,8 @@ ICOConvert iconified idfa Ierusalimschy +Ior +ior ImageMagick ImageView imageview @@ -227,6 +229,7 @@ keymap keypress keypresses keystore +KHR khronos KiB Klayton @@ -298,6 +301,9 @@ OSX OTF particlefx particlefxs +PbrMaterial +PBR +pbrSpecularGlossiness PEM performant Phaser @@ -390,6 +396,8 @@ SL slerp solvability Sovapps +Specular +specular spawner spinejson spinescene @@ -400,6 +408,8 @@ SSL Stateful Steamworks STL +struct +structs stylesheet stylesheets subdirectories @@ -475,6 +485,7 @@ UV UVs Vararg varyings +vec VictoriaMetrics videogame videoplayer From 09ce8c53429376950405d3cb00912100606afe8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jhonny=20Go=CC=88ransson?= Date: Tue, 7 Oct 2025 14:03:05 +0200 Subject: [PATCH 5/5] More spellchecks --- .wordlist.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.wordlist.txt b/.wordlist.txt index 52253f98..e5867ff1 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -51,6 +51,7 @@ bmGlyph bodypart booleans breakpoint +BRDF builtins bundler bundletool @@ -124,6 +125,8 @@ dropdown dSYM EDN EFIGS +Emissive +emissive emscripten enum esc