x3dom / x3dom

X3DOM. A framework for integrating and manipulating X3D scenes as HTML5/DOM elements.
http://x3dom.org
Other
813 stars 271 forks source link

support KHR_lights_punctual, KHR_materials_emissive_strength, EXT_meshopt_compression, EXT_texture_webp #1259

Closed andreasplesch closed 9 months ago

andreasplesch commented 1 year ago

These glTF extensions are fairly straightforward to implement:

andreasplesch commented 10 months ago

https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual/README.md

directional -> DirectionalLight point -> PointLight spot -> SpotLight color -> color name -> DEF ? intensity -> intensity, may need adjustment range -> point: radius spot: radius innerConeAngle: beamWidth outerConeAngle: cutOffAngle "Conforming implementations will model this angular attenuation with a curve that follows a steeper decline in brightness before leveling off when moving from the inner to the outer angle." ->

angle = the angle between the Spotlight's direction vector and
            the vector from the Spotlight location to the point to be illuminated
    if (angle ≥ cutOffAngle):
        multiplier = 0
    else if (angle ≤ beamWidth):
        multiplier = 1
    else:
        multiplier = (angle - cutOffAngle) / (beamWidth - cutOffAngle)
    intensity(angle) = SpotLight.intensity × multiplier

attenuation = max( min( 1.0 - ( current_distance / range )^4, 1 ), 0 ) / current_distance^2 -> 1 /max(attenuation[0] + attenuation[1] × r + attenuation[2] × r^2 , 1 )

andreasplesch commented 10 months ago

Distance Attenuation

glTF and x3d treat attenuation with distance somewhat differently. Both have an absolute cutoff and both have inverse square falloff. But glTF additionally has additionally a smoother transition close the absolute cutoff. castle just uses x3d defaults: https://github.com/castle-engine/castle-engine/blob/57a899edd0436bfb0ae990ed1078420ed8d97fb9/src/scene/load/x3dloadinternalgltf.pas#L757

x3d: image image image image image image image image image image

A parabola shifted by -b/2a in x (distance) and c/a - b^2/(4a^2) in y (1/attenuation).

image image

It is not possible to approximate the additional gltf falloff near the range in x3d. Therefore x3d attenuation factors should be 0,0,1. So at 10m distance the attenuation is already 0.01. The intensity has be high for spotlights and pointlights.

glTF has effectively fixed attenuation. So for a large scene, it is necessary to have high intensity lights.

andreasplesch commented 10 months ago

Angular Attenuation

X3D:

angle = the angle between the Spotlight's direction vector and
            the vector from the Spotlight location to the point to be illuminated
    if (angle ≥ cutOffAngle):
        multiplier = 0
    else if (angle ≤ beamWidth):
        multiplier = 1
    else:
        multiplier = (angle - cutOffAngle) / (beamWidth - cutOffAngle)
    intensity(angle) = SpotLight.intensity × multiplier

image

glTF: interpolation of cosines

// These two values can be calculated on the CPU and passed into the shader
float lightAngleScale = 1.0f / max(0.001f, cos(innerConeAngle) - cos(outerConeAngle));
float lightAngleOffset = -cos(outerConeAngle) * lightAngleScale;

// Then, in the shader:
float cd = dot(spotlightDir, normalizedLightVector); // cos(angle)
float angularAttenuation = saturate(cd * lightAngleScale + lightAngleOffset);
// cos(angle) / (cos(beamWidth) - cos(cutOff)) - cos(cufOff)/(cos(beamWidth) - cos(cutOff))

// (cos(angle)-cos(cutOff))/(cos(beamWidth) - cos(cutOff))

angularAttenuation *= angularAttenuation;

In short, X3D interpolates uses angle difference ratios which glTF uses ratio of the differences of the cosines, then squared for sharper falloff.

Let's see how this compares: image

X3D defaults: image

glTF defaults: image

andreasplesch commented 10 months ago

Examples

https://github.com/castle-engine/demo-models/tree/master/gltf/punctual_lights https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter11LightingEnvironmentalEffects/SpotLightVisualizationIndex.html https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/LightsPunctualLamp https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/IridescenceSuzanne

andreasplesch commented 10 months ago

pointlight.zip by threejs editor 3js: image babylonjs: image khronos: image castle: pointlight_0 x3dom: image

andreasplesch commented 10 months ago

spotlight.zip threejs: image

bjs:image

khronos:image

view3dscene: spotlight_0

x3dom: image

andreasplesch commented 9 months ago

The Khronos gltf viewer uses a slightly modified version of the recommendation in the glTF spec. for angular attenuation:

float getSpotAttenuation(vec3 pointToLight, vec3 spotDirection, float outerConeCos, float innerConeCos) {
    float actualCos = dot(normalize(spotDirection), normalize(-pointToLight));
    if (actualCos > outerConeCos) {
        if (actualCos < innerConeCos) {
            return smoothstep(outerConeCos, innerConeCos, actualCos);
        }
        return 1.0;
    }
    return 0.0;
}

https://github.com/KhronosGroup/glTF-Sample-Viewer/issues/486

andreasplesch commented 9 months ago

directional light and point light with specular https://raw.githubusercontent.com/KhronosGroup/glTF/main/extensions/2.0/Khronos/KHR_lights_punctual/schema/examples/lights.gltf https://github.com/andreasplesch/x3dom/raw/lights_punctual/test/functional/media/data/lights.glb

khronos: image

view3dscene: image

x3dom: image

bjs: image

threejs: image

andreasplesch commented 9 months ago

PR #1292

andreasplesch commented 9 months ago

https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/EmissiveStrengthTest https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/EmissiveStrengthTest/glTF-Binary/EmissiveStrengthTest.glb

andreasplesch commented 9 months ago

PR #1293

brutzman commented 9 months ago

Wondering if there are corresponding changes in rendering hardware and APIs.

When ready, we should be prepared to propose potential additions for X3D 4.1. Once fully ready for ISO with multiple implementations and corresponding examples, mature capabilities can be designated as an X3D Suggested Practice or Web3D Recommended Practice.

If possible, a single simple parameter for appropriate nodes and node types might be useful. For example, with backwards compatibility:

andreasplesch commented 9 months ago

I believe you are referring to the light attenuation changes of glTF relative to X3D. Not sure API/hardware/OpenGL changes. Perhaps the fixed function pipeline had something related as Michalis was referring to it but that is ancient, eg. prepre webGL history. Certainly no recent changes. glTF made these choices from trends in 3d/game engines I believe. For a single parameter, another option would be a scalar weighting factor [0-1] for mixing x3d and gltf attenuation: 0=x3d, 1=gltf, 0.5 intermediate, SFFloat attenuationSmoothness 0. But a boolean with a good name would be simpler.

andreasplesch commented 9 months ago

webp example:

https://playground.babylonjs.com/#LSAUH2#2

https://github.com/CesiumGS/cesium/blob/bd8be76b7707ddb9c858ae39538c18064c218f98/Specs/Data/Models/Box-Textured-Webp/CesiumBoxWebp.gltf with embedded image data

https://raw.githubusercontent.com/CesiumGS/cesium/bd8be76b7707ddb9c858ae39538c18064c218f98/Specs/Data/Models/Box-Textured-Webp/CesiumBoxWebp.gltf

andreasplesch commented 9 months ago

range attenuation: 0,0,1 at radius 100, identical at 0 to 10m distance image at 50 to 100m distance strong attenuation and small differences image

1,0,0 at radius 100: at 0 to 10: almost identical, no or very minor attenuation image at 50 to 100m distance step with x3d and parabolic transition with gltf image

infinite range (gltf default): 0,0,1 image 1,0,0 image for both attenuation settings, gltf and x3d are mathematically the same

andreasplesch commented 9 months ago

Meshopt example: https://github.com/zeux/meshoptimizer/tree/master/demo https://raw.githubusercontent.com/zeux/meshoptimizer/master/demo/pirate.glb

https://github.com/mrdoob/three.js/blob/e6304f37428aca97fab71ff74d52e73cbc8b90e3/examples/models/gltf/coffeemat.glb https://raw.githubusercontent.com/mrdoob/three.js/e6304f37428aca97fab71ff74d52e73cbc8b90e3/examples/models/gltf/coffeemat.glb but needs ktx extension

https://github.com/rdurnin/DebugMeshesLibrary/tree/d4050c3dfbb93e63ee129f3b13ed3cabc2dbbcf3/optmesh const https://media.githubusercontent.com/media/rdurnin/DebugMeshesLibrary/d4050c3dfbb93e63ee129f3b13ed3cabc2dbbcf3/optmesh/Rage_Q1_NoInstances_packed.glb https://media.githubusercontent.com/media/rdurnin/DebugMeshesLibrary/d4050c3dfbb93e63ee129f3b13ed3cabc2dbbcf3/optmesh/Rage_Q2_Instances_packed.glb https://media.githubusercontent.com/media/rdurnin/DebugMeshesLibrary/d4050c3dfbb93e63ee129f3b13ed3cabc2dbbcf3/optmesh/Rage_Q3_Q4_Combined_packed.glb

https://playground.babylonjs.com/#CIYTF6#0 https://assets.babylonjs.com/meshes/Buggy/glTF-MeshOpt/Buggy.gltf

andreasplesch commented 9 months ago
  1. combine compressed buffer as is with other buffers, update bufferview compressed byteoffsets, isMeshOpt=true (compressor=MeshOopt/Draco/None)
  2. in binarysetup, decompress view

Or (preferred)

Decompress views in Loader, and reassemble buffer and bufferviews. If no buffer.uri, create empty buffer with byteLength. Combine all buffers, store offset into superbuffer decompress into superbuffer

andreasplesch commented 9 months ago

meshopt_compression is often/almost always used together with mesh_quantization. mesh_quantization was already implemented and needed only to be recognized as supported.

1292

1293

1294

1295

This concludes efforts on these 'simpler' gltf extensions.