Skip to content

Environment map cleanup: No infinite mipmaps, wider epsilons for unit tests #12606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Change Log

## 1.130 - 2025-06-01

### @cesium/engine

#### Fixes :wrench:

- Fixed error with `DynamicEnvironmentMapManager` when `ContextLimits.maximumCubeMapSize` is zero.

## 1.129 - 2025-05-01

### @cesium/engine
Expand Down
64 changes: 40 additions & 24 deletions packages/engine/Source/Scene/DynamicEnvironmentMapManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import ConvolveSpecularMapVS from "../Shaders/ConvolveSpecularMapVS.js";
* @typedef {object} DynamicEnvironmentMapManager.ConstructorOptions
* Options for the DynamicEnvironmentMapManager constructor
* @property {boolean} [enabled=true] If true, the environment map and related properties will continue to update.
* @property {number} [mipmapLevels=7] The number of mipmap levels to generate for specular maps. More mipmap levels will produce a higher resolution specular reflection.
* @property {number} [mipmapLevels=7] The maximum desired number of mipmap levels to generate for specular maps. More mipmap levels will produce a higher resolution specular reflection. The actual number of mipmaps used will be bounded by the cubemap texture size supported on the client machine. The number of mipmaps must be at least one for the environment map to be generated.
* @property {number} [maximumSecondsDifference=3600] The maximum amount of elapsed seconds before a new environment map is created.
* @property {number} [maximumPositionEpsilon=1000] The maximum difference in position before a new environment map is created, in meters. Small differences in position will not visibly affect results.
* @property {number} [atmosphereScatteringIntensity=2.0] The intensity of the scattered light emitted from the atmosphere. This should be adjusted relative to the value of {@link Scene.light} intensity.
Expand Down Expand Up @@ -81,14 +81,21 @@ function DynamicEnvironmentMapManager(options) {

options = options ?? Frozen.EMPTY_OBJECT;

const mipmapLevels = Math.min(
options.mipmapLevels ?? 7,
Math.log2(ContextLimits.maximumCubeMapSize),
const mipmapLevels = Math.max(
Math.floor(
Math.min(
options.mipmapLevels ?? 7,
Math.log2(ContextLimits.maximumCubeMapSize),
),
),
0,
);

this._mipmapLevels = mipmapLevels;

const arrayLength = Math.max(mipmapLevels - 1, 0) * 6;
this._radianceMapComputeCommands = new Array(6);
this._convolutionComputeCommands = new Array((mipmapLevels - 1) * 6);
this._convolutionComputeCommands = new Array(arrayLength);
this._irradianceComputeCommand = undefined;

this._radianceMapFS = undefined;
Expand All @@ -97,15 +104,15 @@ function DynamicEnvironmentMapManager(options) {
this._va = undefined;

this._radianceMapTextures = new Array(6);
this._specularMapTextures = new Array((mipmapLevels - 1) * 6);
this._specularMapTextures = new Array(arrayLength);
this._radianceCubeMap = undefined;
this._irradianceMapTexture = undefined;

this._sphericalHarmonicCoefficients =
DynamicEnvironmentMapManager.DEFAULT_SPHERICAL_HARMONIC_COEFFICIENTS.slice();

this._lastTime = new JulianDate();
const width = Math.pow(2, mipmapLevels - 1);
const width = Math.max(Math.pow(2, mipmapLevels - 1), 1);
this._textureDimensions = new Cartesian2(width, width);

this._radiiAndDynamicAtmosphereColor = new Cartesian3();
Expand Down Expand Up @@ -621,6 +628,28 @@ function updateSpecularMaps(manager, frameState) {
const context = frameState.context;

let facesCopied = 0;
const checkComplete = () => {
// All faces for each mipmap level have been copied
const length = manager._specularMapTextures.length;
if (facesCopied >= length) {
manager._irradianceCommandDirty = true;

if (mipmapLevels > 1) {
radianceCubeMap.sampler = new Sampler({
minificationFilter: TextureMinificationFilter.LINEAR_MIPMAP_LINEAR,
});

manager._shouldRegenerateShaders = true;

// Cleanup shared resources
manager._va.destroy();
manager._va = undefined;
manager._convolveSP.destroy();
manager._convolveSP = undefined;
}
}
};

const getPostExecute = (command, index, texture, face, level) => () => {
if (manager.isDestroyed() || command.canceled) {
DynamicEnvironmentMapManager._activeComputeCommandCount--;
Expand All @@ -638,22 +667,7 @@ function updateSpecularMaps(manager, frameState) {
texture.destroy();
manager._specularMapTextures[index] = undefined;

// All faces for each mipmap level have been copied
const length = manager._specularMapTextures.length;
if (facesCopied >= length) {
manager._irradianceCommandDirty = true;
radianceCubeMap.sampler = new Sampler({
minificationFilter: TextureMinificationFilter.LINEAR_MIPMAP_LINEAR,
});

manager._shouldRegenerateShaders = true;

// Cleanup shared resources
manager._va.destroy();
manager._va = undefined;
manager._convolveSP.destroy();
manager._convolveSP = undefined;
}
checkComplete();
};

let index = 0;
Expand Down Expand Up @@ -721,6 +735,7 @@ function updateSpecularMaps(manager, frameState) {
width /= 2;
height /= 2;
}
checkComplete();
}

const irradianceTextureDimensions = new Cartesian2(3, 3); // 9 coefficients
Expand Down Expand Up @@ -841,7 +856,8 @@ DynamicEnvironmentMapManager.prototype.update = function (frameState) {
const isSupported =
// A FrameState type works here because the function only references the context parameter.
// @ts-ignore
DynamicEnvironmentMapManager.isDynamicUpdateSupported(frameState);
DynamicEnvironmentMapManager.isDynamicUpdateSupported(frameState) &&
this._mipmapLevels >= 1;

if (
!isSupported ||
Expand Down
Loading