You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1337 lines
41 KiB
JavaScript
1337 lines
41 KiB
JavaScript
import { BoundingSphere } from "../../Source/Cesium.js";
|
|
import { BoxGeometry } from "../../Source/Cesium.js";
|
|
import { Cartesian3 } from "../../Source/Cesium.js";
|
|
import { Color } from "../../Source/Cesium.js";
|
|
import { ColorGeometryInstanceAttribute } from "../../Source/Cesium.js";
|
|
import { ComponentDatatype } from "../../Source/Cesium.js";
|
|
import { EllipsoidTerrainProvider } from "../../Source/Cesium.js";
|
|
import { GeometryInstance } from "../../Source/Cesium.js";
|
|
import { HeadingPitchRange } from "../../Source/Cesium.js";
|
|
import { HeadingPitchRoll } from "../../Source/Cesium.js";
|
|
import { HeightmapTerrainData } from "../../Source/Cesium.js";
|
|
import { JulianDate } from "../../Source/Cesium.js";
|
|
import { Math as CesiumMath } from "../../Source/Cesium.js";
|
|
import { OrthographicOffCenterFrustum } from "../../Source/Cesium.js";
|
|
import { PixelFormat } from "../../Source/Cesium.js";
|
|
import { Transforms } from "../../Source/Cesium.js";
|
|
import { WebGLConstants } from "../../Source/Cesium.js";
|
|
import { Context } from "../../Source/Cesium.js";
|
|
import { Framebuffer } from "../../Source/Cesium.js";
|
|
import { PixelDatatype } from "../../Source/Cesium.js";
|
|
import { Texture } from "../../Source/Cesium.js";
|
|
import { Camera } from "../../Source/Cesium.js";
|
|
import { DirectionalLight } from "../../Source/Cesium.js";
|
|
import { Globe } from "../../Source/Cesium.js";
|
|
import { Model } from "../../Source/Cesium.js";
|
|
import { PerInstanceColorAppearance } from "../../Source/Cesium.js";
|
|
import { Primitive } from "../../Source/Cesium.js";
|
|
import { ShadowMap } from "../../Source/Cesium.js";
|
|
import { ShadowMode } from "../../Source/Cesium.js";
|
|
import createScene from "../createScene.js";
|
|
import pollToPromise from "../pollToPromise.js";
|
|
import { when } from "../../Source/Cesium.js";
|
|
|
|
describe(
|
|
"Scene/ShadowMap",
|
|
function () {
|
|
var scene;
|
|
var sunShadowMap;
|
|
var backgroundColor = [0, 0, 0, 255];
|
|
|
|
var longitude = -1.31968;
|
|
var latitude = 0.4101524;
|
|
var height = 0.0;
|
|
var boxHeight = 4.0;
|
|
var floorHeight = -1.0;
|
|
|
|
var boxUrl = "./Data/Models/Shadows/Box.gltf";
|
|
var boxTranslucentUrl = "./Data/Models/Shadows/BoxTranslucent.gltf";
|
|
var boxCutoutUrl = "./Data/Models/Shadows/BoxCutout.gltf";
|
|
var boxInvertedUrl = "./Data/Models/Shadows/BoxInverted.gltf";
|
|
|
|
var box;
|
|
var boxTranslucent;
|
|
var boxCutout;
|
|
var room;
|
|
var floor;
|
|
var floorTranslucent;
|
|
|
|
var primitiveBox;
|
|
var primitiveBoxRTC;
|
|
var primitiveBoxTranslucent;
|
|
var primitiveFloor;
|
|
var primitiveFloorRTC;
|
|
|
|
beforeAll(function () {
|
|
scene = createScene();
|
|
scene.frameState.scene3DOnly = true;
|
|
Color.unpack(backgroundColor, 0, scene.backgroundColor);
|
|
|
|
sunShadowMap = scene.shadowMap;
|
|
|
|
var boxOrigin = new Cartesian3.fromRadians(
|
|
longitude,
|
|
latitude,
|
|
boxHeight
|
|
);
|
|
var boxTransform = Transforms.headingPitchRollToFixedFrame(
|
|
boxOrigin,
|
|
new HeadingPitchRoll()
|
|
);
|
|
|
|
var floorOrigin = new Cartesian3.fromRadians(
|
|
longitude,
|
|
latitude,
|
|
floorHeight
|
|
);
|
|
var floorTransform = Transforms.headingPitchRollToFixedFrame(
|
|
floorOrigin,
|
|
new HeadingPitchRoll()
|
|
);
|
|
|
|
var roomOrigin = new Cartesian3.fromRadians(longitude, latitude, height);
|
|
var roomTransform = Transforms.headingPitchRollToFixedFrame(
|
|
roomOrigin,
|
|
new HeadingPitchRoll()
|
|
);
|
|
|
|
var modelPromises = [];
|
|
modelPromises.push(
|
|
loadModel({
|
|
url: boxUrl,
|
|
modelMatrix: boxTransform,
|
|
scale: 0.5,
|
|
show: false,
|
|
}).then(function (model) {
|
|
box = model;
|
|
})
|
|
);
|
|
modelPromises.push(
|
|
loadModel({
|
|
url: boxTranslucentUrl,
|
|
modelMatrix: boxTransform,
|
|
scale: 0.5,
|
|
show: false,
|
|
}).then(function (model) {
|
|
boxTranslucent = model;
|
|
})
|
|
);
|
|
modelPromises.push(
|
|
loadModel({
|
|
url: boxCutoutUrl,
|
|
modelMatrix: boxTransform,
|
|
scale: 0.5,
|
|
incrementallyLoadTextures: false,
|
|
show: false,
|
|
}).then(function (model) {
|
|
boxCutout = model;
|
|
})
|
|
);
|
|
modelPromises.push(
|
|
loadModel({
|
|
url: boxUrl,
|
|
modelMatrix: floorTransform,
|
|
scale: 2.0,
|
|
show: false,
|
|
}).then(function (model) {
|
|
floor = model;
|
|
})
|
|
);
|
|
modelPromises.push(
|
|
loadModel({
|
|
url: boxTranslucentUrl,
|
|
modelMatrix: floorTransform,
|
|
scale: 2.0,
|
|
show: false,
|
|
}).then(function (model) {
|
|
floorTranslucent = model;
|
|
})
|
|
);
|
|
modelPromises.push(
|
|
loadModel({
|
|
url: boxInvertedUrl,
|
|
modelMatrix: roomTransform,
|
|
scale: 8.0,
|
|
show: false,
|
|
}).then(function (model) {
|
|
room = model;
|
|
})
|
|
);
|
|
|
|
primitiveBox = createPrimitive(boxTransform, 0.5, Color.RED);
|
|
primitiveBoxRTC = createPrimitiveRTC(boxTransform, 0.5, Color.RED);
|
|
primitiveBoxTranslucent = createPrimitive(
|
|
boxTransform,
|
|
0.5,
|
|
Color.RED.withAlpha(0.5)
|
|
);
|
|
primitiveFloor = createPrimitive(floorTransform, 2.0, Color.RED);
|
|
primitiveFloorRTC = createPrimitiveRTC(floorTransform, 2.0, Color.RED);
|
|
|
|
return when.all(modelPromises);
|
|
});
|
|
|
|
function createPrimitive(transform, size, color) {
|
|
return scene.primitives.add(
|
|
new Primitive({
|
|
geometryInstances: new GeometryInstance({
|
|
geometry: BoxGeometry.fromDimensions({
|
|
dimensions: new Cartesian3(size, size, size),
|
|
vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
|
|
}),
|
|
modelMatrix: transform,
|
|
attributes: {
|
|
color: ColorGeometryInstanceAttribute.fromColor(color),
|
|
},
|
|
}),
|
|
appearance: new PerInstanceColorAppearance({
|
|
translucent: false,
|
|
closed: true,
|
|
}),
|
|
asynchronous: false,
|
|
show: false,
|
|
shadows: ShadowMode.ENABLED,
|
|
})
|
|
);
|
|
}
|
|
|
|
function createPrimitiveRTC(transform, size, color) {
|
|
var boxGeometry = BoxGeometry.createGeometry(
|
|
BoxGeometry.fromDimensions({
|
|
vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
|
|
dimensions: new Cartesian3(size, size, size),
|
|
})
|
|
);
|
|
|
|
var positions = boxGeometry.attributes.position.values;
|
|
var newPositions = new Float32Array(positions.length);
|
|
for (var i = 0; i < positions.length; ++i) {
|
|
newPositions[i] = positions[i];
|
|
}
|
|
boxGeometry.attributes.position.values = newPositions;
|
|
boxGeometry.attributes.position.componentDatatype =
|
|
ComponentDatatype.FLOAT;
|
|
|
|
BoundingSphere.transform(
|
|
boxGeometry.boundingSphere,
|
|
transform,
|
|
boxGeometry.boundingSphere
|
|
);
|
|
|
|
var boxGeometryInstance = new GeometryInstance({
|
|
geometry: boxGeometry,
|
|
attributes: {
|
|
color: ColorGeometryInstanceAttribute.fromColor(color),
|
|
},
|
|
});
|
|
|
|
return scene.primitives.add(
|
|
new Primitive({
|
|
geometryInstances: boxGeometryInstance,
|
|
appearance: new PerInstanceColorAppearance({
|
|
translucent: false,
|
|
closed: true,
|
|
}),
|
|
asynchronous: false,
|
|
rtcCenter: boxGeometry.boundingSphere.center,
|
|
show: false,
|
|
shadows: ShadowMode.ENABLED,
|
|
})
|
|
);
|
|
}
|
|
|
|
function loadModel(options) {
|
|
var model = scene.primitives.add(Model.fromGltf(options));
|
|
return pollToPromise(
|
|
function () {
|
|
// Render scene to progressively load the model
|
|
scene.render();
|
|
return model.ready;
|
|
},
|
|
{ timeout: 10000 }
|
|
).then(function () {
|
|
return model;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Repeatedly calls render until the load queue is empty. Returns a promise that resolves
|
|
* when the load queue is empty.
|
|
*/
|
|
function loadGlobe() {
|
|
return pollToPromise(function () {
|
|
scene.render();
|
|
var globe = scene.globe;
|
|
return (
|
|
globe._surface.tileProvider.ready &&
|
|
globe._surface._tileLoadQueueHigh.length === 0 &&
|
|
globe._surface._tileLoadQueueMedium.length === 0 &&
|
|
globe._surface._tileLoadQueueLow.length === 0 &&
|
|
globe._surface._debug.tilesWaitingForChildren === 0
|
|
);
|
|
});
|
|
}
|
|
|
|
afterAll(function () {
|
|
scene.destroyForSpecs();
|
|
});
|
|
|
|
afterEach(function () {
|
|
var length = scene.primitives.length;
|
|
for (var i = 0; i < length; ++i) {
|
|
scene.primitives.get(i).show = false;
|
|
}
|
|
|
|
scene.globe = undefined;
|
|
scene.shadowMap = scene.shadowMap && scene.shadowMap.destroy();
|
|
});
|
|
|
|
function createCascadedShadowMap() {
|
|
var center = new Cartesian3.fromRadians(longitude, latitude, height);
|
|
scene.camera.lookAt(
|
|
center,
|
|
new HeadingPitchRange(0.0, CesiumMath.toRadians(-70.0), 5.0)
|
|
);
|
|
|
|
// Create light camera pointing straight down
|
|
var lightCamera = new Camera(scene);
|
|
lightCamera.lookAt(center, new Cartesian3(0.0, 0.0, 1.0));
|
|
|
|
scene.shadowMap = new ShadowMap({
|
|
context: scene.context,
|
|
lightCamera: lightCamera,
|
|
});
|
|
}
|
|
|
|
function createSingleCascadeShadowMap() {
|
|
var center = new Cartesian3.fromRadians(longitude, latitude, height);
|
|
scene.camera.lookAt(
|
|
center,
|
|
new HeadingPitchRange(0.0, CesiumMath.toRadians(-70.0), 5.0)
|
|
);
|
|
|
|
// Create light camera pointing straight down
|
|
var lightCamera = new Camera(scene);
|
|
lightCamera.lookAt(center, new Cartesian3(0.0, 0.0, 1.0));
|
|
|
|
scene.shadowMap = new ShadowMap({
|
|
context: scene.context,
|
|
lightCamera: lightCamera,
|
|
numberOfCascades: 1,
|
|
});
|
|
}
|
|
|
|
function createShadowMapForDirectionalLight() {
|
|
var center = new Cartesian3.fromRadians(longitude, latitude, height);
|
|
scene.camera.lookAt(
|
|
center,
|
|
new HeadingPitchRange(0.0, CesiumMath.toRadians(-70.0), 5.0)
|
|
);
|
|
|
|
var frustum = new OrthographicOffCenterFrustum();
|
|
frustum.left = -50.0;
|
|
frustum.right = 50.0;
|
|
frustum.bottom = -50.0;
|
|
frustum.top = 50.0;
|
|
frustum.near = 1.0;
|
|
frustum.far = 1000;
|
|
|
|
// Create light camera pointing straight down
|
|
var lightCamera = new Camera(scene);
|
|
lightCamera.frustum = frustum;
|
|
lightCamera.lookAt(center, new Cartesian3(0.0, 0.0, 20.0));
|
|
|
|
scene.shadowMap = new ShadowMap({
|
|
context: scene.context,
|
|
lightCamera: lightCamera,
|
|
cascadesEnabled: false,
|
|
});
|
|
}
|
|
|
|
function createShadowMapForSpotLight() {
|
|
var center = new Cartesian3.fromRadians(longitude, latitude, height);
|
|
scene.camera.lookAt(
|
|
center,
|
|
new HeadingPitchRange(0.0, CesiumMath.toRadians(-70.0), 5.0)
|
|
);
|
|
|
|
var lightCamera = new Camera(scene);
|
|
lightCamera.frustum.fov = CesiumMath.PI_OVER_TWO;
|
|
lightCamera.frustum.aspectRatio = 1.0;
|
|
lightCamera.frustum.near = 1.0;
|
|
lightCamera.frustum.far = 1000.0;
|
|
lightCamera.lookAt(center, new Cartesian3(0.0, 0.0, 20.0));
|
|
|
|
scene.shadowMap = new ShadowMap({
|
|
context: scene.context,
|
|
lightCamera: lightCamera,
|
|
cascadesEnabled: false,
|
|
});
|
|
}
|
|
|
|
function createShadowMapForPointLight() {
|
|
var center = new Cartesian3.fromRadians(longitude, latitude, height);
|
|
scene.camera.lookAt(
|
|
center,
|
|
new HeadingPitchRange(0.0, CesiumMath.toRadians(-70.0), 5.0)
|
|
);
|
|
|
|
var lightCamera = new Camera(scene);
|
|
lightCamera.position = center;
|
|
|
|
scene.shadowMap = new ShadowMap({
|
|
context: scene.context,
|
|
lightCamera: lightCamera,
|
|
isPointLight: true,
|
|
});
|
|
}
|
|
|
|
function renderAndExpect(rgba, time) {
|
|
expect({
|
|
scene: scene,
|
|
time: time,
|
|
primeShadowMap: true,
|
|
}).toRender(rgba);
|
|
}
|
|
|
|
function renderAndReadPixels() {
|
|
var color;
|
|
|
|
expect({
|
|
scene: scene,
|
|
primeShadowMap: true,
|
|
}).toRenderAndCall(function (rgba) {
|
|
color = rgba;
|
|
});
|
|
|
|
return color;
|
|
}
|
|
|
|
function renderAndCall(expectationCallback, time) {
|
|
expect({
|
|
scene: scene,
|
|
time: time,
|
|
primeShadowMap: true,
|
|
}).toRenderAndCall(function (rgba) {
|
|
expectationCallback(rgba);
|
|
});
|
|
}
|
|
|
|
function verifyShadows(caster, receiver) {
|
|
caster.shadows = ShadowMode.ENABLED;
|
|
receiver.shadows = ShadowMode.ENABLED;
|
|
|
|
// Render without shadows
|
|
scene.shadowMap.enabled = false;
|
|
var unshadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
unshadowedColor = rgba;
|
|
expect(unshadowedColor).not.toEqual(backgroundColor);
|
|
});
|
|
|
|
// Render with shadows
|
|
scene.shadowMap.enabled = true;
|
|
var shadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
shadowedColor = rgba;
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
});
|
|
|
|
// Turn shadow casting off/on
|
|
caster.shadows = ShadowMode.DISABLED;
|
|
renderAndExpect(unshadowedColor);
|
|
caster.shadows = ShadowMode.ENABLED;
|
|
renderAndExpect(shadowedColor);
|
|
|
|
// Turn shadow receiving off/on
|
|
receiver.shadows = ShadowMode.DISABLED;
|
|
renderAndExpect(unshadowedColor);
|
|
receiver.shadows = ShadowMode.ENABLED;
|
|
renderAndExpect(shadowedColor);
|
|
|
|
// Move the camera away from the shadow
|
|
scene.camera.moveRight(0.5);
|
|
renderAndExpect(unshadowedColor);
|
|
}
|
|
|
|
it("sets default shadow map properties", function () {
|
|
scene.shadowMap = new ShadowMap({
|
|
context: scene.context,
|
|
lightCamera: new Camera(scene),
|
|
});
|
|
|
|
expect(scene.shadowMap.enabled).toBe(true);
|
|
expect(scene.shadowMap.softShadows).toBe(false);
|
|
expect(scene.shadowMap.isPointLight).toBe(false);
|
|
expect(scene.shadowMap._isSpotLight).toBe(false);
|
|
expect(scene.shadowMap._cascadesEnabled).toBe(true);
|
|
expect(scene.shadowMap._numberOfCascades).toBe(4);
|
|
expect(scene.shadowMap._normalOffset).toBe(true);
|
|
});
|
|
|
|
it("throws without options.context", function () {
|
|
expect(function () {
|
|
scene.shadowMap = new ShadowMap({
|
|
lightCamera: new Camera(scene),
|
|
});
|
|
}).toThrowDeveloperError();
|
|
});
|
|
|
|
it("throws without options.lightCamera", function () {
|
|
expect(function () {
|
|
scene.shadowMap = new ShadowMap({
|
|
context: scene.context,
|
|
});
|
|
}).toThrowDeveloperError();
|
|
});
|
|
|
|
it("throws when options.numberOfCascades is not one or four", function () {
|
|
expect(function () {
|
|
scene.shadowMap = new ShadowMap({
|
|
context: scene.context,
|
|
lightCamera: new Camera(scene),
|
|
numberOfCascades: 3,
|
|
});
|
|
}).toThrowDeveloperError();
|
|
});
|
|
|
|
it("model casts shadows onto another model", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createCascadedShadowMap();
|
|
verifyShadows(box, floor);
|
|
});
|
|
|
|
it("translucent model casts shadows onto another model", function () {
|
|
boxTranslucent.show = true;
|
|
floor.show = true;
|
|
createCascadedShadowMap();
|
|
verifyShadows(boxTranslucent, floor);
|
|
});
|
|
|
|
it("model with cutout texture casts shadows onto another model", function () {
|
|
boxCutout.show = true;
|
|
floor.show = true;
|
|
createCascadedShadowMap();
|
|
|
|
// Render without shadows
|
|
scene.shadowMap.enabled = false;
|
|
|
|
var unshadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
unshadowedColor = rgba;
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
});
|
|
|
|
// Render with shadows. The area should not be shadowed because the box's texture is transparent in the center.
|
|
scene.shadowMap.enabled = true;
|
|
renderAndExpect(unshadowedColor);
|
|
|
|
// Move the camera into the shadowed area
|
|
scene.camera.moveRight(0.2);
|
|
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
});
|
|
|
|
// Move the camera away from the shadow
|
|
scene.camera.moveRight(0.3);
|
|
renderAndExpect(unshadowedColor);
|
|
});
|
|
|
|
it("primitive casts shadows onto another primitive", function () {
|
|
primitiveBox.show = true;
|
|
primitiveFloor.show = true;
|
|
createCascadedShadowMap();
|
|
verifyShadows(primitiveBox, primitiveFloor);
|
|
});
|
|
|
|
it("RTC primitive casts shadows onto another RTC primitive", function () {
|
|
primitiveBoxRTC.show = true;
|
|
primitiveFloorRTC.show = true;
|
|
createCascadedShadowMap();
|
|
verifyShadows(primitiveBoxRTC, primitiveFloorRTC);
|
|
});
|
|
|
|
it("translucent primitive casts shadows onto another primitive", function () {
|
|
primitiveBoxTranslucent.show = true;
|
|
primitiveFloor.show = true;
|
|
createCascadedShadowMap();
|
|
verifyShadows(primitiveBoxTranslucent, primitiveFloor);
|
|
});
|
|
|
|
it("model casts shadow onto globe", function () {
|
|
box.show = true;
|
|
scene.globe = new Globe();
|
|
scene.camera.frustum._sseDenominator = 0.005;
|
|
createCascadedShadowMap();
|
|
|
|
return loadGlobe().then(function () {
|
|
verifyShadows(box, scene.globe);
|
|
});
|
|
});
|
|
|
|
it("globe casts shadow onto globe", function () {
|
|
scene.globe = new Globe();
|
|
scene.camera.frustum._sseDenominator = 0.01;
|
|
|
|
var center = new Cartesian3.fromRadians(longitude, latitude, height);
|
|
scene.camera.lookAt(
|
|
center,
|
|
new HeadingPitchRange(0.0, CesiumMath.toRadians(-70.0), 5.0)
|
|
);
|
|
|
|
// Create light camera that is angled horizontally
|
|
var lightCamera = new Camera(scene);
|
|
lightCamera.lookAt(center, new Cartesian3(1.0, 0.0, 0.1));
|
|
|
|
scene.shadowMap = new ShadowMap({
|
|
context: scene.context,
|
|
lightCamera: lightCamera,
|
|
});
|
|
|
|
// Instead of the default flat tile, add a ridge that will cast shadows
|
|
spyOn(
|
|
EllipsoidTerrainProvider.prototype,
|
|
"requestTileGeometry"
|
|
).and.callFake(function () {
|
|
var width = 16;
|
|
var height = 16;
|
|
var buffer = new Uint8Array(width * height);
|
|
for (var i = 0; i < buffer.length; ++i) {
|
|
var row = i % width;
|
|
if (row > 6 && row < 10) {
|
|
buffer[i] = 1;
|
|
}
|
|
}
|
|
return new HeightmapTerrainData({
|
|
buffer: buffer,
|
|
width: width,
|
|
height: height,
|
|
});
|
|
});
|
|
|
|
return loadGlobe().then(function () {
|
|
// Render without shadows
|
|
scene.shadowMap.enabled = false;
|
|
|
|
var unshadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
unshadowedColor = rgba;
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
});
|
|
|
|
// Render with globe casting off
|
|
scene.shadowMap.enabled = true;
|
|
scene.globe.shadows = ShadowMode.DISABLED;
|
|
renderAndExpect(unshadowedColor);
|
|
|
|
// Render with globe casting on
|
|
scene.globe.shadows = ShadowMode.ENABLED;
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
});
|
|
});
|
|
});
|
|
|
|
it("changes light direction", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
|
|
var center = new Cartesian3.fromRadians(longitude, latitude, height);
|
|
scene.camera.lookAt(
|
|
center,
|
|
new HeadingPitchRange(0.0, CesiumMath.toRadians(-70.0), 5.0)
|
|
);
|
|
|
|
// Create light camera pointing straight down
|
|
var lightCamera = new Camera(scene);
|
|
lightCamera.lookAt(center, new Cartesian3(0.0, 0.0, 1.0));
|
|
|
|
scene.shadowMap = new ShadowMap({
|
|
context: scene.context,
|
|
lightCamera: lightCamera,
|
|
});
|
|
|
|
// Render with shadows
|
|
var shadowedColor = renderAndReadPixels();
|
|
|
|
// Move the camera away from the shadow
|
|
scene.camera.moveLeft(0.5);
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(shadowedColor);
|
|
});
|
|
|
|
// Change the light direction so the unshadowed area is now shadowed
|
|
lightCamera.lookAt(center, new Cartesian3(0.1, 0.0, 1.0));
|
|
renderAndExpect(shadowedColor);
|
|
});
|
|
|
|
it("sun shadow map works", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
|
|
var startTime = new JulianDate(2457561.211806); // Sun pointing straight above
|
|
var endTime = new JulianDate(2457561.276389); // Sun at an angle
|
|
|
|
var center = new Cartesian3.fromRadians(longitude, latitude, height);
|
|
scene.camera.lookAt(
|
|
center,
|
|
new HeadingPitchRange(0.0, CesiumMath.toRadians(-70.0), 5.0)
|
|
);
|
|
|
|
// Use the default shadow map which uses the sun as a light source
|
|
scene.shadowMap = sunShadowMap;
|
|
|
|
// Render without shadows
|
|
scene.shadowMap.enabled = false;
|
|
|
|
var unshadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
unshadowedColor = rgba;
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
});
|
|
|
|
// Render with shadows
|
|
scene.shadowMap.enabled = true;
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
}, startTime);
|
|
|
|
// Change the time so that the shadows are no longer pointing straight down
|
|
renderAndExpect(unshadowedColor, endTime);
|
|
|
|
scene.shadowMap = undefined;
|
|
});
|
|
|
|
it("uses scene's light source", function () {
|
|
var originalLight = scene.light;
|
|
|
|
box.show = true;
|
|
floor.show = true;
|
|
|
|
var lightDirectionAbove = new Cartesian3(
|
|
-0.22562675028973597,
|
|
0.8893549458095356,
|
|
-0.3976686433675793
|
|
); // Light pointing straight above
|
|
var lightDirectionAngle = new Cartesian3(
|
|
0.14370705890272903,
|
|
0.9062077731227641,
|
|
-0.3976628636840613
|
|
); // Light at an angle
|
|
|
|
var center = new Cartesian3.fromRadians(longitude, latitude, height);
|
|
scene.camera.lookAt(
|
|
center,
|
|
new HeadingPitchRange(0.0, CesiumMath.toRadians(-70.0), 5.0)
|
|
);
|
|
|
|
// Use the default shadow map which uses the scene's light source
|
|
scene.light = new DirectionalLight({
|
|
direction: lightDirectionAbove,
|
|
});
|
|
scene.shadowMap = sunShadowMap;
|
|
|
|
// Render without shadows
|
|
scene.shadowMap.enabled = false;
|
|
|
|
var unshadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
unshadowedColor = rgba;
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
});
|
|
|
|
// Render with shadows
|
|
scene.shadowMap.enabled = true;
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
});
|
|
|
|
// Change the light so that the shadows are no longer pointing straight down
|
|
scene.light = new DirectionalLight({
|
|
direction: lightDirectionAngle,
|
|
});
|
|
renderAndExpect(unshadowedColor);
|
|
|
|
scene.shadowMap = undefined;
|
|
scene.light = originalLight;
|
|
});
|
|
|
|
it("single cascade shadow map", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createSingleCascadeShadowMap();
|
|
verifyShadows(box, floor);
|
|
});
|
|
|
|
it("directional shadow map", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createShadowMapForDirectionalLight();
|
|
verifyShadows(box, floor);
|
|
});
|
|
|
|
it("spot light shadow map", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createShadowMapForSpotLight();
|
|
verifyShadows(box, floor);
|
|
});
|
|
|
|
it("point light shadows", function () {
|
|
// Check that shadows are cast from all directions.
|
|
// Place the point light in the middle of an enclosed area and place a box on each side.
|
|
room.show = true;
|
|
createShadowMapForPointLight();
|
|
|
|
var longitudeSpacing = 0.0000003419296208325038;
|
|
var latitudeSpacing = 0.000000315782;
|
|
var heightSpacing = 2.0;
|
|
|
|
var origins = [
|
|
Cartesian3.fromRadians(longitude, latitude + latitudeSpacing, height),
|
|
Cartesian3.fromRadians(longitude, latitude - latitudeSpacing, height),
|
|
Cartesian3.fromRadians(longitude + longitudeSpacing, latitude, height),
|
|
Cartesian3.fromRadians(longitude - longitudeSpacing, latitude, height),
|
|
Cartesian3.fromRadians(longitude, latitude, height - heightSpacing),
|
|
Cartesian3.fromRadians(longitude, latitude, height + heightSpacing),
|
|
];
|
|
|
|
var offsets = [
|
|
new HeadingPitchRange(0.0, 0.0, 0.1),
|
|
new HeadingPitchRange(CesiumMath.PI, 0.0, 0.1),
|
|
new HeadingPitchRange(CesiumMath.PI_OVER_TWO, 0.0, 0.1),
|
|
new HeadingPitchRange(CesiumMath.THREE_PI_OVER_TWO, 0.0, 0.1),
|
|
new HeadingPitchRange(0, -CesiumMath.PI_OVER_TWO, 0.1),
|
|
new HeadingPitchRange(0, CesiumMath.PI_OVER_TWO, 0.1),
|
|
];
|
|
|
|
for (var i = 0; i < 6; ++i) {
|
|
var box = scene.primitives.add(
|
|
Model.fromGltf({
|
|
url: boxUrl,
|
|
modelMatrix: Transforms.headingPitchRollToFixedFrame(
|
|
origins[i],
|
|
new HeadingPitchRoll()
|
|
),
|
|
scale: 0.2,
|
|
})
|
|
);
|
|
scene.render(); // Model is pre-loaded, render one frame to make it ready
|
|
|
|
scene.camera.lookAt(origins[i], offsets[i]);
|
|
scene.camera.moveForward(0.5);
|
|
|
|
// Render without shadows
|
|
scene.shadowMap.enabled = false;
|
|
var unshadowedColor;
|
|
//eslint-disable-next-line no-loop-func
|
|
renderAndCall(function (rgba) {
|
|
unshadowedColor = rgba;
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
});
|
|
|
|
// Render with shadows
|
|
scene.shadowMap.enabled = true;
|
|
//eslint-disable-next-line no-loop-func
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
});
|
|
|
|
// Check that setting a smaller radius works
|
|
var radius = scene.shadowMap._pointLightRadius;
|
|
scene.shadowMap._pointLightRadius = 3.0;
|
|
renderAndExpect(unshadowedColor);
|
|
scene.shadowMap._pointLightRadius = radius;
|
|
|
|
// Move the camera away from the shadow
|
|
scene.camera.moveRight(0.5);
|
|
renderAndExpect(unshadowedColor);
|
|
|
|
scene.primitives.remove(box);
|
|
}
|
|
});
|
|
|
|
it("changes size", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createCascadedShadowMap();
|
|
|
|
// Render with shadows
|
|
var shadowedColor = renderAndReadPixels();
|
|
|
|
// Change size
|
|
scene.shadowMap.size = 256;
|
|
renderAndExpect(shadowedColor);
|
|
|
|
// Cascaded shadows combine four maps into one texture
|
|
expect(scene.shadowMap._shadowMapTexture.width).toBe(512);
|
|
expect(scene.shadowMap._shadowMapTexture.height).toBe(512);
|
|
expect(scene.shadowMap.size).toBe(256);
|
|
});
|
|
|
|
it("enable debugCascadeColors", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createCascadedShadowMap();
|
|
|
|
// Render with shadows
|
|
var shadowedColor = renderAndReadPixels();
|
|
|
|
// Render cascade colors
|
|
scene.shadowMap.debugCascadeColors = true;
|
|
expect(scene.shadowMap.dirty).toBe(true);
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(shadowedColor);
|
|
});
|
|
});
|
|
|
|
it("enable soft shadows", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createCascadedShadowMap();
|
|
|
|
// Render without shadows
|
|
scene.shadowMap.enabled = false;
|
|
var unshadowedColor = renderAndReadPixels();
|
|
|
|
// Render with shadows
|
|
scene.shadowMap.enabled = true;
|
|
expect(scene.shadowMap.dirty).toBe(true);
|
|
var shadowedColor = renderAndReadPixels();
|
|
|
|
// Render with soft shadows
|
|
scene.shadowMap.softShadows = true;
|
|
scene.shadowMap.size = 256; // Make resolution smaller to more easily verify soft edges
|
|
scene.camera.moveRight(0.25);
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
expect(rgba).not.toEqual(shadowedColor);
|
|
});
|
|
});
|
|
|
|
it("changes darkness", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createCascadedShadowMap();
|
|
|
|
// Render without shadows
|
|
scene.shadowMap.enabled = false;
|
|
var unshadowedColor = renderAndReadPixels();
|
|
|
|
// Render with shadows
|
|
scene.shadowMap.enabled = true;
|
|
var shadowedColor = renderAndReadPixels();
|
|
|
|
scene.shadowMap.darkness = 0.5;
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
expect(rgba).not.toEqual(shadowedColor);
|
|
});
|
|
});
|
|
|
|
function depthFramebufferSupported() {
|
|
var framebuffer = new Framebuffer({
|
|
context: scene.context,
|
|
depthStencilTexture: new Texture({
|
|
context: scene.context,
|
|
width: 1,
|
|
height: 1,
|
|
pixelFormat: PixelFormat.DEPTH_STENCIL,
|
|
pixelDatatype: PixelDatatype.UNSIGNED_INT_24_8,
|
|
}),
|
|
});
|
|
|
|
return framebuffer.status === WebGLConstants.FRAMEBUFFER_COMPLETE;
|
|
}
|
|
|
|
it("defaults to color texture if depth texture extension is not supported", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
|
|
createCascadedShadowMap();
|
|
|
|
renderAndCall(function (rgba) {
|
|
if (scene.context.depthTexture) {
|
|
if (depthFramebufferSupported()) {
|
|
expect(scene.shadowMap._usesDepthTexture).toBe(true);
|
|
expect(scene.shadowMap._shadowMapTexture.pixelFormat).toEqual(
|
|
PixelFormat.DEPTH_STENCIL
|
|
);
|
|
} else {
|
|
// Depth texture extension is supported, but it fails to create create a depth-only FBO
|
|
expect(scene.shadowMap._usesDepthTexture).toBe(false);
|
|
expect(scene.shadowMap._shadowMapTexture.pixelFormat).toEqual(
|
|
PixelFormat.RGBA
|
|
);
|
|
}
|
|
}
|
|
});
|
|
|
|
scene.shadowMap = scene.shadowMap && scene.shadowMap.destroy();
|
|
|
|
// Disable extension
|
|
var depthTexture = scene.context._depthTexture;
|
|
scene.context._depthTexture = false;
|
|
createCascadedShadowMap();
|
|
|
|
renderAndCall(function (rgba) {
|
|
expect(scene.shadowMap._usesDepthTexture).toBe(false);
|
|
expect(scene.shadowMap._shadowMapTexture.pixelFormat).toEqual(
|
|
PixelFormat.RGBA
|
|
);
|
|
});
|
|
|
|
// Re-enable extension
|
|
scene.context._depthTexture = depthTexture;
|
|
});
|
|
|
|
it("does not render shadows when the camera is far away from any shadow receivers", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createCascadedShadowMap();
|
|
|
|
renderAndCall(function (rgba) {
|
|
expect(scene.shadowMap.outOfView).toBe(false);
|
|
});
|
|
|
|
var center = new Cartesian3.fromRadians(longitude, latitude, 200000);
|
|
scene.camera.lookAt(
|
|
center,
|
|
new HeadingPitchRange(0.0, CesiumMath.toRadians(-70.0), 5.0)
|
|
);
|
|
|
|
renderAndCall(function (rgba) {
|
|
expect(scene.shadowMap.outOfView).toBe(true);
|
|
});
|
|
});
|
|
|
|
it("does not render shadows when the light direction is below the horizon", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
|
|
var center = new Cartesian3.fromRadians(longitude, latitude, height);
|
|
scene.camera.lookAt(
|
|
center,
|
|
new HeadingPitchRange(0.0, CesiumMath.toRadians(-70.0), 5.0)
|
|
);
|
|
|
|
// Create light camera pointing straight down
|
|
var lightCamera = new Camera(scene);
|
|
lightCamera.lookAt(center, new Cartesian3(0.0, 0.0, 1.0));
|
|
|
|
scene.shadowMap = new ShadowMap({
|
|
context: scene.context,
|
|
lightCamera: lightCamera,
|
|
});
|
|
|
|
renderAndCall(function (rgba) {
|
|
expect(scene.shadowMap.outOfView).toBe(false);
|
|
});
|
|
|
|
// Change light direction
|
|
lightCamera.lookAt(center, new Cartesian3(0.0, 0.0, -1.0));
|
|
renderAndCall(function (rgba) {
|
|
expect(scene.shadowMap.outOfView).toBe(true);
|
|
});
|
|
});
|
|
|
|
it("enable debugShow for cascaded shadow map", function () {
|
|
createCascadedShadowMap();
|
|
|
|
// Shadow overlay command, shadow volume outline, camera outline, four cascade outlines, four cascade planes
|
|
scene.shadowMap.debugShow = true;
|
|
scene.shadowMap.debugFreezeFrame = true;
|
|
renderAndCall(function (rgba) {
|
|
expect(scene.frameState.commandList.length).toBe(13);
|
|
});
|
|
|
|
scene.shadowMap.debugShow = false;
|
|
renderAndCall(function (rgba) {
|
|
expect(scene.frameState.commandList.length).toBe(0);
|
|
});
|
|
});
|
|
|
|
it("enable debugShow for fixed shadow map", function () {
|
|
createShadowMapForDirectionalLight();
|
|
|
|
// Overlay command, shadow volume outline, shadow volume planes
|
|
scene.shadowMap.debugShow = true;
|
|
renderAndCall(function (rgba) {
|
|
expect(scene.frameState.commandList.length).toBe(3);
|
|
});
|
|
|
|
scene.shadowMap.debugShow = false;
|
|
renderAndCall(function (rgba) {
|
|
expect(scene.frameState.commandList.length).toBe(0);
|
|
});
|
|
});
|
|
|
|
it("enable debugShow for point light shadow map", function () {
|
|
createShadowMapForPointLight();
|
|
|
|
// Overlay command and shadow volume outline
|
|
scene.shadowMap.debugShow = true;
|
|
renderAndCall(function (rgba) {
|
|
expect(scene.frameState.commandList.length).toBe(2);
|
|
});
|
|
|
|
scene.shadowMap.debugShow = false;
|
|
renderAndCall(function (rgba) {
|
|
expect(scene.frameState.commandList.length).toBe(0);
|
|
});
|
|
});
|
|
|
|
it("enable fitNearFar", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createShadowMapForDirectionalLight();
|
|
scene.shadowMap._fitNearFar = true; // True by default
|
|
|
|
var shadowNearFit;
|
|
var shadowFarFit;
|
|
renderAndCall(function (rgba) {
|
|
shadowNearFit = scene.shadowMap._sceneCamera.frustum.near;
|
|
shadowFarFit = scene.shadowMap._sceneCamera.frustum.far;
|
|
});
|
|
|
|
scene.shadowMap._fitNearFar = false;
|
|
renderAndCall(function (rgba) {
|
|
var shadowNear = scene.shadowMap._sceneCamera.frustum.near;
|
|
var shadowFar = scene.shadowMap._sceneCamera.frustum.far;
|
|
|
|
// When fitNearFar is true the shadowed region is smaller
|
|
expect(shadowNear).toBeLessThan(shadowNearFit);
|
|
expect(shadowFar).toBeGreaterThan(shadowFarFit);
|
|
});
|
|
});
|
|
|
|
it("set normalOffset", function () {
|
|
createCascadedShadowMap();
|
|
scene.shadowMap.normalOffset = false;
|
|
|
|
expect(scene.shadowMap._normalOffset, false);
|
|
expect(scene.shadowMap._terrainBias, false);
|
|
expect(scene.shadowMap._primitiveBias, false);
|
|
expect(scene.shadowMap._pointBias, false);
|
|
});
|
|
|
|
it("set maximumDistance", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createCascadedShadowMap();
|
|
|
|
// Render without shadows
|
|
scene.shadowMap.enabled = false;
|
|
var unshadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
unshadowedColor = rgba;
|
|
});
|
|
|
|
// Render with shadows
|
|
scene.shadowMap.enabled = true;
|
|
var shadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
});
|
|
|
|
// Set a maximum distance where the shadows start to fade out
|
|
scene.shadowMap.maximumDistance = 6.0;
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
expect(rgba).not.toEqual(shadowedColor);
|
|
});
|
|
|
|
// Set a maximimum distance where the shadows are not visible
|
|
scene.shadowMap.maximumDistance = 3.0;
|
|
renderAndExpect(unshadowedColor);
|
|
});
|
|
|
|
it("shadows are disabled during the pick pass", function () {
|
|
var spy = spyOn(Context.prototype, "draw").and.callThrough();
|
|
|
|
boxTranslucent.show = true;
|
|
floorTranslucent.show = true;
|
|
|
|
createCascadedShadowMap();
|
|
|
|
// Render normally and expect every model shader program to be shadow related.
|
|
renderAndCall(function (rgba) {
|
|
var count = spy.calls.count();
|
|
for (var i = 0; i < count; ++i) {
|
|
var drawCommand = spy.calls.argsFor(i)[0];
|
|
if (drawCommand.owner.primitive instanceof Model) {
|
|
expect(
|
|
drawCommand.shaderProgram._fragmentShaderText.indexOf(
|
|
"czm_shadow"
|
|
) !== -1
|
|
).toBe(true);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Do the pick pass and expect every model shader program to not be shadow related. This also checks
|
|
// that there are no shadow cast commands.
|
|
spy.calls.reset();
|
|
expect(scene).toPickAndCall(function (result) {
|
|
var count = spy.calls.count();
|
|
for (var i = 0; i < count; ++i) {
|
|
var drawCommand = spy.calls.argsFor(i)[0];
|
|
if (drawCommand.owner.primitive instanceof Model) {
|
|
expect(
|
|
drawCommand.shaderProgram._fragmentShaderText.indexOf(
|
|
"czm_shadow"
|
|
) !== -1
|
|
).toBe(false);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
it("model updates derived commands when the shadow map is dirty", function () {
|
|
var spy1 = spyOn(
|
|
ShadowMap,
|
|
"createReceiveDerivedCommand"
|
|
).and.callThrough();
|
|
var spy2 = spyOn(ShadowMap, "createCastDerivedCommand").and.callThrough();
|
|
|
|
box.show = true;
|
|
floor.show = true;
|
|
createCascadedShadowMap();
|
|
|
|
// Render without shadows
|
|
scene.shadowMap.enabled = false;
|
|
var unshadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
unshadowedColor = rgba;
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
});
|
|
|
|
// Render with shadows
|
|
scene.shadowMap.enabled = true;
|
|
var shadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
shadowedColor = rgba;
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
});
|
|
|
|
// Hide floor temporarily and change the shadow map
|
|
floor.show = false;
|
|
scene.shadowMap.debugCascadeColors = true;
|
|
|
|
// Render a few frames
|
|
var i;
|
|
for (i = 0; i < 6; ++i) {
|
|
scene.render();
|
|
}
|
|
|
|
// Show the floor and render. The receive shadows shader should now be up-to-date.
|
|
floor.show = true;
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
expect(rgba).not.toEqual(shadowedColor);
|
|
});
|
|
|
|
// Render a few more frames
|
|
for (i = 0; i < 6; ++i) {
|
|
scene.render();
|
|
}
|
|
|
|
// When using WebGL, this value is 8. When using the stub, this value is 4.
|
|
expect(spy1.calls.count()).toBeLessThanOrEqualTo(8);
|
|
expect(spy2.calls.count()).toEqual(4);
|
|
|
|
box.show = false;
|
|
floor.show = false;
|
|
});
|
|
|
|
it("does not receive shadows if fromLightSource is false", function () {
|
|
box.show = true;
|
|
floorTranslucent.show = true;
|
|
createCascadedShadowMap();
|
|
scene.shadowMap.fromLightSource = false;
|
|
|
|
// Render without shadows
|
|
scene.shadowMap.enabled = false;
|
|
var unshadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
unshadowedColor = rgba;
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
});
|
|
|
|
// Render with shadows
|
|
scene.shadowMap.enabled = true;
|
|
renderAndCall(function (rgba) {
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).toEqual(unshadowedColor);
|
|
});
|
|
});
|
|
|
|
it("tweaking shadow bias parameters works", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createCascadedShadowMap();
|
|
|
|
// Render without shadows
|
|
scene.shadowMap.enabled = false;
|
|
var unshadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
unshadowedColor = rgba;
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
});
|
|
|
|
// Render with shadows
|
|
scene.shadowMap.enabled = true;
|
|
var shadowedColor;
|
|
renderAndCall(function (rgba) {
|
|
shadowedColor = rgba;
|
|
expect(rgba).not.toEqual(backgroundColor);
|
|
expect(rgba).not.toEqual(unshadowedColor);
|
|
});
|
|
|
|
scene.shadowMap._primitiveBias.polygonOffsetFactor = 1.2;
|
|
scene.shadowMap._primitiveBias.polygonOffsetFactor = 4.1;
|
|
scene.shadowMap._primitiveBias.normalOffsetScale = 2.1;
|
|
scene.shadowMap._primitiveBias.normalShadingSmooth = 0.4;
|
|
scene.shadowMap.debugCreateRenderStates();
|
|
scene.shadowMap.dirty = true;
|
|
renderAndExpect(shadowedColor);
|
|
|
|
scene.shadowMap._primitiveBias.normalOffset = false;
|
|
scene.shadowMap._primitiveBias.normalShading = false;
|
|
scene.shadowMap._primitiveBias.polygonOffset = false;
|
|
scene.shadowMap.debugCreateRenderStates();
|
|
scene.shadowMap.dirty = true;
|
|
renderAndExpect(shadowedColor);
|
|
});
|
|
|
|
it("destroys", function () {
|
|
box.show = true;
|
|
floor.show = true;
|
|
createCascadedShadowMap();
|
|
|
|
expect(scene.shadowMap.isDestroyed()).toEqual(false);
|
|
scene.shadowMap.destroy();
|
|
expect(scene.shadowMap.isDestroyed()).toEqual(true);
|
|
scene.shadowMap = undefined;
|
|
});
|
|
},
|
|
"WebGL"
|
|
);
|