Skip to content

Commit 7b93161

Browse files
authored
Merge pull request #12070 from CesiumGS/ibl-lod
Fix LOD selection for image-based lighting
2 parents a0ef08f + ba2da20 commit 7b93161

File tree

5 files changed

+39
-42
lines changed

5 files changed

+39
-42
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
##### Fixes :wrench:
88

99
- Updated geometric self-shadowing function to improve direct lighting on models using physically-based rendering. [#12063](https://github.com/CesiumGS/cesium/pull/12063)
10+
- Fixed environment map LOD selection in image-based lighting. [#12070](https://github.com/CesiumGS/cesium/pull/12070)
1011

1112
### 1.119 - 2024-07-01
1213

packages/engine/Source/Renderer/AutomaticUniforms.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,7 @@ const AutomaticUniforms = {
14541454
* // Example: For a given roughness and NdotV value, find the material's BRDF information in the red and green channels
14551455
* float roughness = 0.5;
14561456
* float NdotV = dot(normal, view);
1457-
* vec2 brdfLut = texture(czm_brdfLut, vec2(NdotV, 1.0 - roughness)).rg;
1457+
* vec2 brdfLut = texture(czm_brdfLut, vec2(NdotV, roughness)).rg;
14581458
*/
14591459
czm_brdfLut: new AutomaticUniform({
14601460
size: 1,

packages/engine/Source/Scene/OctahedralProjectedCubeMap.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -337,11 +337,10 @@ OctahedralProjectedCubeMap.prototype.update = function (frameState) {
337337
},
338338
});
339339

340-
// We only need up to 6 mip levels to avoid artifacts.
341-
const length = Math.min(cubeMapBuffers.length, 6);
342-
this._maximumMipmapLevel = length - 1;
343-
const cubeMaps = (this._cubeMaps = new Array(length));
344-
const mipTextures = (this._mipTextures = new Array(length));
340+
const mipLevels = cubeMapBuffers.length;
341+
this._maximumMipmapLevel = mipLevels - 1;
342+
const cubeMaps = (this._cubeMaps = new Array(mipLevels));
343+
const mipTextures = (this._mipTextures = new Array(mipLevels));
345344
const originalSize = cubeMapBuffers[0].positiveX.width * 2.0;
346345
const uniformMap = {
347346
originalSize: function () {
@@ -350,7 +349,7 @@ OctahedralProjectedCubeMap.prototype.update = function (frameState) {
350349
};
351350

352351
// First we project each cubemap onto a flat octahedron, and write that to a texture.
353-
for (let i = 0; i < length; ++i) {
352+
for (let i = 0; i < mipLevels; ++i) {
354353
// Swap +Y/-Y faces since the octahedral projection expects this order.
355354
const positiveY = cubeMapBuffers[i].positiveY;
356355
cubeMapBuffers[i].positiveY = cubeMapBuffers[i].negativeY;

packages/engine/Source/Shaders/Builtin/Functions/sampleOctahedralProjection.glsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ vec3 czm_sampleOctahedralProjectionWithFiltering(sampler2D projectedMap, vec2 te
6868
* @returns {vec3} The color of the cube map at the direction.
6969
*/
7070
vec3 czm_sampleOctahedralProjection(sampler2D projectedMap, vec2 textureSize, vec3 direction, float lod, float maxLod) {
71-
float currentLod = floor(lod + 0.5);
71+
float currentLod = floor(lod);
7272
float nextLod = min(currentLod + 1.0, maxLod);
7373

7474
vec3 colorCurrentLod = czm_sampleOctahedralProjectionWithFiltering(projectedMap, textureSize, direction, currentLod);

packages/engine/Specs/Scene/OctahedralProjectedCubeMapSpec.js

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -120,33 +120,32 @@ describe(
120120
});
121121
}
122122

123-
it("creates a packed texture with the right dimensions", function () {
123+
it("creates a packed texture with the right dimensions", async function () {
124124
if (!OctahedralProjectedCubeMap.isSupported(context)) {
125125
return;
126126
}
127127

128128
octahedralMap = new OctahedralProjectedCubeMap(environmentMapUrl);
129129
const frameState = createFrameState(context);
130130

131-
return pollToPromise(function () {
131+
await pollToPromise(function () {
132132
octahedralMap.update(frameState);
133133
return octahedralMap.ready;
134-
}).then(function () {
135-
expect(octahedralMap.texture.width).toEqual(770);
136-
expect(octahedralMap.texture.height).toEqual(512);
137-
expect(octahedralMap.maximumMipmapLevel).toEqual(5);
138134
});
135+
expect(octahedralMap.texture.width).toEqual(770);
136+
expect(octahedralMap.texture.height).toEqual(512);
137+
expect(octahedralMap.maximumMipmapLevel).toEqual(7);
139138
});
140139

141-
it("correctly projects the given cube map and all mip levels", function () {
140+
it("correctly projects the given cube map and all mip levels", async function () {
142141
if (!OctahedralProjectedCubeMap.isSupported(context)) {
143142
return;
144143
}
145144

146145
octahedralMap = new OctahedralProjectedCubeMap(environmentMapUrl);
147146
const frameState = createFrameState(context);
148147

149-
return pollToPromise(function () {
148+
await pollToPromise(function () {
150149
// We manually call update and execute the commands
151150
// because calling scene.renderForSpecs does not
152151
// actually execute these commands, and we need
@@ -155,34 +154,32 @@ describe(
155154
executeCommands(frameState);
156155

157156
return octahedralMap.ready;
158-
}).then(function () {
159-
const directions = {
160-
positiveX: new Cartesian3(1, 0, 0),
161-
negativeX: new Cartesian3(-1, 0, 0),
162-
positiveY: new Cartesian3(0, 1, 0),
163-
negativeY: new Cartesian3(0, -1, 0),
164-
positiveZ: new Cartesian3(0, 0, 1),
165-
negativeZ: new Cartesian3(0, 0, -1),
166-
};
167-
168-
for (
169-
let mipLevel = 0;
170-
mipLevel < octahedralMap.maximumMipmapLevel;
171-
mipLevel++
172-
) {
173-
for (const key in directions) {
174-
if (directions.hasOwnProperty(key)) {
175-
const direction = directions[key];
176-
177-
expectCubeMapAndOctahedralMapEqual(
178-
octahedralMap,
179-
direction,
180-
mipLevel
181-
);
182-
}
157+
});
158+
const directions = {
159+
positiveX: new Cartesian3(1, 0, 0),
160+
negativeX: new Cartesian3(-1, 0, 0),
161+
positiveY: new Cartesian3(0, 1, 0),
162+
negativeY: new Cartesian3(0, -1, 0),
163+
positiveZ: new Cartesian3(0, 0, 1),
164+
negativeZ: new Cartesian3(0, 0, -1),
165+
};
166+
167+
// The projection is less accurate for the last mip levels,
168+
// where the input cubemap only has a few samples.
169+
const lastAccurateMip = octahedralMap.maximumMipmapLevel - 2;
170+
for (let mipLevel = 0; mipLevel < lastAccurateMip; mipLevel++) {
171+
for (const key in directions) {
172+
if (directions.hasOwnProperty(key)) {
173+
const direction = directions[key];
174+
175+
expectCubeMapAndOctahedralMapEqual(
176+
octahedralMap,
177+
direction,
178+
mipLevel
179+
);
183180
}
184181
}
185-
});
182+
}
186183
});
187184

188185
it("caches projected textures", function () {

0 commit comments

Comments
 (0)