diff --git a/docs/Materials.md.html b/docs/Materials.md.html
index 154c54e62f..46b8d6d43e 100644
--- a/docs/Materials.md.html
+++ b/docs/Materials.md.html
@@ -1395,7 +1395,7 @@ struct MaterialVertexInputs {
float2 uv0; // if the uv0 attribute is required
float2 uv1; // if the uv1 attribute is required
float3 worldNormal; // only if the shading model is not unlit
- float4 worldPosition; // always available
+ float4 worldPosition; // always available (see note below about world-space)
// variable* names are replaced with actual names
float4 variable0; // if 1 or more variables is defined
float4 variable1; // if 2 or more variables is defined
@@ -1404,6 +1404,11 @@ struct MaterialVertexInputs {
};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! TIP: worldPosition
+ To achieve good precision, the `worldPosition` coordinate in the vertex shader is shifted by the
+ camera position. To get the true world-space position, users can add this to
+ `getWorldOffset()`.
+
!!! TIP: UV attributes
By default the vertex shader of a material will flip the Y coordinate of the UV attributes
of the current mesh: `material.uv0 = vec2(mesh_uv0.x, 1.0 - mesh_uv0.y)`. You can control
@@ -1570,12 +1575,18 @@ type aliases:
:-----------------------------------|:--------:|:------------------------------------
**getResolution()** | float4 | Resolution of the view in pixels: `width`, `height`, `1 / width`, `1 / height`
**getWorldCameraPosition()** | float3 | Position of the camera/eye in world space
+**getWorldOffset()** | float3 | The shift required to obtain API-level world space
**getTime()** | float | Current time in seconds, may be reset regularly to avoid precision loss
**getUserTime()** | float4 | Current time in seconds: `time`, `(double)time - time`, `0`, `0`
**getUserTimeMode(float m)** | float | Current time modulo m in seconds
**getExposure()** | float | Photometric exposure of the camera
**getEV100()** | float | [Exposure value at ISO 100](https://en.wikipedia.org/wiki/Exposure_value) of the camera
+!!! TIP: world space
+ To achieve good precision, the "world space" in Filament's shading system does not necessarily
+ match the API-level world space. To obtain the position of the API-level camera, custom
+ materials can add `getWorldOffset()` to `getWorldCameraPosition()`.
+
### Vertex only
The following APIs are only available from the vertex block:
@@ -1594,7 +1605,7 @@ The following APIs are only available from the fragment block:
Name | Type | Description
:-----------------------------------|:--------:|:------------------------------------
**getWorldTangentFrame()** | float3x3 | Matrix containing in each column the `tangent` (`frame[0]`), `bi-tangent` (`frame[1]`) and `normal` (`frame[2]`) of the vertex in world space. If the material does not compute a tangent space normal for bump mapping or if the shading is not anisotropic, only the `normal` is valid in this matrix.
-**getWorldPosition()** | float3 | Position of the fragment in world space
+**getWorldPosition()** | float3 | Position of the fragment in world space (see note below about world-space)
**getWorldViewVector()** | float3 | Normalized vector in world space from the fragment position to the eye
**getWorldNormalVector()** | float3 | Normalized normal in world space, after bump mapping (must be used after `prepareMaterial()`)
**getWorldGeometricNormalVector()** | float3 | Normalized normal in world space, before bump mapping (can be used before `prepareMaterial()`)
@@ -1608,6 +1619,10 @@ The following APIs are only available from the fragment block:
**inverseTonemapSRGB(float3)** | float3 | Applies the inverse tone mapping operator to the specified non-linear sRGB color and returns a linear sRGB color. This operation may be an approximation
**luminance(float3)** | float | Computes the luminance of the specified linear sRGB color
+!!! TIP: world space
+ To obtain API-level world space coordinates, custom materials should add `getWorldOffset()` to
+ `getWorldPosition()` (et al).
+
# Compiling materials
Material packages can be compiled from material definitions using the command line tool called
diff --git a/filament/src/View.cpp b/filament/src/View.cpp
index bef3b3d2b2..4f7d87d617 100644
--- a/filament/src/View.cpp
+++ b/filament/src/View.cpp
@@ -460,6 +460,8 @@ void FView::prepare(FEngine& engine, backend::DriverApi& driver, ArenaScope& are
.zf = camera->getCullingFar(),
// exposure
.ev100 = Exposure::ev100(*camera),
+ // world offset to allow users to determine the API-level camera position
+ .worldOffset = camera->getPosition(),
// world origin transform, use only for debugging
.worldOrigin = worldOriginCamera
};
@@ -629,6 +631,7 @@ void FView::prepareCamera(const CameraInfo& camera, const filament::Viewport& vi
u.setUniform(offsetof(PerViewUib, origin), float2{ viewport.left, viewport.bottom });
u.setUniform(offsetof(PerViewUib, cameraPosition), float3{camera.getPosition()});
+ u.setUniform(offsetof(PerViewUib, worldOffset), camera.worldOffset);
}
void FView::prepareSSAO(Handle ssao) const noexcept {
diff --git a/filament/src/details/Camera.h b/filament/src/details/Camera.h
index 41bbd07359..6748f30a04 100644
--- a/filament/src/details/Camera.h
+++ b/filament/src/details/Camera.h
@@ -162,6 +162,7 @@ struct CameraInfo {
float zn;
float zf;
float ev100 = 0.0f;
+ math::float3 worldOffset;
math::float3 const& getPosition() const noexcept { return model[3].xyz; }
math::float3 getForwardVector() const noexcept { return normalize(-model[2].xyz); }
diff --git a/libs/filabridge/include/private/filament/UibGenerator.h b/libs/filabridge/include/private/filament/UibGenerator.h
index 8b9256bd7e..30fa981a61 100644
--- a/libs/filabridge/include/private/filament/UibGenerator.h
+++ b/libs/filabridge/include/private/filament/UibGenerator.h
@@ -54,7 +54,7 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
filament::math::float4 resolution; // viewport width, height, 1/width, 1/height
- filament::math::float3 cameraPosition;
+ filament::math::float3 cameraPosition; // this is (0,0,0) when camera_at_origin is enabled
float time; // time in seconds, with a 1 second period
filament::math::float4 lightColorIntensity; // directional light
@@ -84,8 +84,11 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
filament::math::float2 iblMaxMipLevel; // maxlevel, float(1<