import { Cartesian3, defined } from "../../Source/Cesium.js"; import { ComputeEngine } from "../../Source/Cesium.js"; import { Pass } from "../../Source/Cesium.js"; import { OctahedralProjectedCubeMap } from "../../Source/Cesium.js"; import createContext from "../createContext.js"; import createFrameState from "../createFrameState.js"; import pollToPromise from "../pollToPromise.js"; describe( "Scene/OctahedralProjectedCubeMap", function () { var context; var computeEngine; var octahedralMap; var environmentMapUrl = "./Data/EnvironmentMap/kiara_6_afternoon_2k_ibl.ktx2"; var fsOctahedralMap = "uniform sampler2D projectedMap;" + "uniform vec2 textureSize;" + "uniform vec3 direction;" + "uniform float lod;" + "uniform float maxLod;" + "void main() {" + " vec3 color = czm_sampleOctahedralProjection(projectedMap, textureSize, direction, lod, maxLod);" + " gl_FragColor = vec4(color, 1.0);" + "}"; var fsCubeMap = "uniform samplerCube cubeMap;" + "uniform vec3 direction;" + "void main() {" + " vec4 rgba = textureCube(cubeMap, direction);" + " gl_FragColor = vec4(rgba.rgb, 1.0);" + "}"; beforeAll(function () { context = createContext(); computeEngine = new ComputeEngine(context); }); afterAll(function () { context.destroyForSpecs(); computeEngine.destroy(); }); afterEach(function () { octahedralMap = octahedralMap && octahedralMap.destroy(); context.textureCache.destroyReleasedTextures(); }); function executeCommands(frameState) { var length = frameState.commandList.length; for (var i = 0; i < length; ++i) { var command = frameState.commandList[i]; if (command.pass === Pass.COMPUTE) { command.execute(computeEngine); } else { command.execute(context); } } frameState.commandList.length = 0; } function sampleOctahedralMap(octahedralMap, direction, lod, callback) { expect({ context: context, fragmentShader: fsOctahedralMap, uniformMap: { projectedMap: function () { return octahedralMap.texture; }, textureSize: function () { return octahedralMap.texture.dimensions; }, direction: function () { return direction; }, lod: function () { return lod; }, maxLod: function () { return octahedralMap.maximumMipmapLevel; }, }, }).contextToRenderAndCall(callback); } function sampleCubeMap(cubeMap, direction, callback) { expect({ context: context, fragmentShader: fsCubeMap, uniformMap: { cubeMap: function () { return cubeMap; }, direction: function () { return direction; }, }, }).contextToRenderAndCall(callback); } function expectCubeMapAndOctahedralMapEqual(octahedralMap, direction, lod) { return sampleCubeMap(octahedralMap._cubeMaps[lod], direction, function ( cubeMapColor ) { var directionFlipY = direction.clone(); directionFlipY.y *= -1; sampleOctahedralMap(octahedralMap, directionFlipY, lod, function ( octahedralMapColor ) { return expect(cubeMapColor).toEqualEpsilon(octahedralMapColor, 6); }); }); } it("creates a packed texture with the right dimensions", function () { if (!OctahedralProjectedCubeMap.isSupported(context)) { return; } octahedralMap = new OctahedralProjectedCubeMap(environmentMapUrl); var frameState = createFrameState(context); return pollToPromise(function () { octahedralMap.update(frameState); return octahedralMap.ready; }).then(function () { expect(octahedralMap.texture.width).toEqual(770); expect(octahedralMap.texture.height).toEqual(512); expect(octahedralMap.maximumMipmapLevel).toEqual(5); }); }); it("correctly projects the given cube map and all mip levels", function () { if (!OctahedralProjectedCubeMap.isSupported(context)) { return; } octahedralMap = new OctahedralProjectedCubeMap(environmentMapUrl); var frameState = createFrameState(context); return pollToPromise(function () { // We manually call update and execute the commands // because calling scene.renderForSpecs does not // actually execute these commands, and we need // to get the output of the texture. octahedralMap.update(frameState); executeCommands(frameState); return octahedralMap.ready; }).then(function () { var directions = { positiveX: new Cartesian3(1, 0, 0), negativeX: new Cartesian3(-1, 0, 0), positiveY: new Cartesian3(0, 1, 0), negativeY: new Cartesian3(0, -1, 0), positiveZ: new Cartesian3(0, 0, 1), negativeZ: new Cartesian3(0, 0, -1), }; for ( var mipLevel = 0; mipLevel < octahedralMap.maximumMipmapLevel; mipLevel++ ) { for (var key in directions) { if (directions.hasOwnProperty(key)) { var direction = directions[key]; expectCubeMapAndOctahedralMapEqual( octahedralMap, direction, mipLevel ); } } } }); }); it("caches projected textures", function () { if (!OctahedralProjectedCubeMap.isSupported(context)) { return; } var projection = new OctahedralProjectedCubeMap(environmentMapUrl); var frameState = createFrameState(context); return pollToPromise(function () { projection.update(frameState); return projection.ready; }) .then(function () { var projection2 = new OctahedralProjectedCubeMap(environmentMapUrl); projection2.update(frameState); expect(projection2.ready).toEqual(true); expect(projection.texture).toEqual(projection2.texture); projection2.destroy(); }) .always(function () { projection.destroy(); }); }); it("rejects when environment map fails to load.", function () { if (!OctahedralProjectedCubeMap.isSupported(context)) { return; } var projection = new OctahedralProjectedCubeMap("http://invalid.url"); var frameState = createFrameState(context); var error; projection.readyPromise .then(function () { fail("Should not resolve."); }) .otherwise(function (e) { error = e; expect(error).toBeDefined(); expect(projection.ready).toEqual(false); }); return pollToPromise(function () { projection.update(frameState); return defined(error); }); }); }, "WebGL" );