diff --git a/Extensions/3D/DirectionalLight.ts b/Extensions/3D/DirectionalLight.ts index 287e72f9c9..8743532046 100644 --- a/Extensions/3D/DirectionalLight.ts +++ b/Extensions/3D/DirectionalLight.ts @@ -414,6 +414,9 @@ namespace gdjs { if (parameterName === 'top') { this._top = value; } + if (parameterName === 'shadowRenderingMode') { + this._isShadowFittedToCamera = value === 'fittedToCameraView'; + } if (parameterName === 'shadowQuality') { if (value === 'low' && this._shadowMapSize !== 512) { this._shadowMapSize = 512; @@ -443,8 +446,6 @@ namespace gdjs { updateBooleanParameter(parameterName: string, value: boolean): void { if (parameterName === 'isCastingShadow') { this._light.castShadow = value; - } else if (parameterName === 'isShadowFittedToCamera') { - this._isShadowFittedToCamera = value; } } getNetworkSyncData(): DirectionalLightFilterNetworkSyncData { diff --git a/Extensions/3D/JsExtension.js b/Extensions/3D/JsExtension.js index 9a1c89c31b..cd7d308fb1 100644 --- a/Extensions/3D/JsExtension.js +++ b/Extensions/3D/JsExtension.js @@ -2299,15 +2299,20 @@ module.exports = { .setType('choice') .setGroup(_('Shadows')); properties - .getOrCreate('isShadowFittedToCamera') - .setValue('false') - .setLabel(_('Fit shadows to the camera view')) + .getOrCreate('shadowRenderingMode') + .setValue('centeredAroundCamera') + .addChoice('fittedToCameraView', _('Fitted to camera view (default)')) + .addChoice( + 'centeredAroundCamera', + _("Centered around camera (legacy - don't use anymore)") + ) + .setLabel(_('Rendering mode')) .setDescription( _( - 'Draw shadows only for what the camera sees, up to the shadow distance, for sharper shadows. Always recommended: this will become the only mode in the future.' + 'Fitted to camera view draws shadows only for what the camera sees, up to the shadow distance, for sharper shadows. The legacy mode will be removed in the future.' ) ) - .setType('boolean') + .setType('choice') .setGroup(_('Shadows')); properties .getOrCreate('shadowDistance') @@ -2315,7 +2320,7 @@ module.exports = { .setLabel(_('Shadow distance')) .setDescription( _( - 'Distance from the camera up to which shadows are drawn, when they are fitted to the camera view. The smaller it is, the sharper shadows are.' + 'Distance from the camera up to which shadows are drawn. The smaller it is, the sharper shadows are. Not used by the legacy rendering mode.' ) ) .setType('number') @@ -2362,7 +2367,7 @@ module.exports = { .setLabel(_('Shadow frustum size')) .setDescription( _( - 'Size of the area around the camera where shadows are drawn, when they are not fitted to the camera view. Prefer fitting shadows to the camera view, which gives sharper shadows.' + 'Size of the area around the camera where shadows are drawn. Only used by the legacy rendering mode.' ) ) .setType('number') diff --git a/Extensions/3D/tests/DirectionalLight.spec.js b/Extensions/3D/tests/DirectionalLight.spec.js index 4afa613846..ac5596b203 100644 --- a/Extensions/3D/tests/DirectionalLight.spec.js +++ b/Extensions/3D/tests/DirectionalLight.spec.js @@ -3,17 +3,14 @@ describe('Scene3D::DirectionalLight', () => { /** * @param {'Z+' | 'Y-'} top - * @param {{isShadowFittedToCamera?: boolean}} [options] + * @param {'fittedToCameraView' | 'centeredAroundCamera'} shadowRenderingMode * @returns {EffectData} */ - const makeDirectionalLightEffectData = ( - top, - { isShadowFittedToCamera = false } = {} - ) => ({ + const makeDirectionalLightEffectData = (top, shadowRenderingMode) => ({ name: 'Sun', effectType: 'Scene3D::DirectionalLight', - stringParameters: { top, shadowQuality: 'medium' }, - booleanParameters: { isCastingShadow: true, isShadowFittedToCamera }, + stringParameters: { top, shadowQuality: 'medium', shadowRenderingMode }, + booleanParameters: { isCastingShadow: true }, doubleParameters: { // A vertical light is a special case for the "Y-" top. elevation: top === 'Y-' ? 90 : 37, @@ -104,10 +101,13 @@ describe('Scene3D::DirectionalLight', () => { }; for (const top of /** @type {Array<'Z+' | 'Y-'>} */ (['Z+', 'Y-'])) { - for (const isShadowFittedToCamera of [false, true]) { - it(`keeps shadow map texels in place when the camera moves (top: ${top}, fitted to camera: ${isShadowFittedToCamera})`, () => { + for (const shadowRenderingMode of /** @type {Array<'fittedToCameraView' | 'centeredAroundCamera'>} */ ([ + 'fittedToCameraView', + 'centeredAroundCamera', + ])) { + it(`keeps shadow map texels in place when the camera moves (top: ${top}, rendering mode: ${shadowRenderingMode})`, () => { const layer = make3DLayerWithEffect( - makeDirectionalLightEffectData(top, { isShadowFittedToCamera }) + makeDirectionalLightEffectData(top, shadowRenderingMode) ); const light = getDirectionalLight(layer); const shadowCaster = new THREE.Mesh( @@ -136,7 +136,7 @@ describe('Scene3D::DirectionalLight', () => { it('covers what the camera sees up to the shadow distance, with a smaller shadow map area', () => { const layer = make3DLayerWithEffect( - makeDirectionalLightEffectData('Z+', { isShadowFittedToCamera: true }) + makeDirectionalLightEffectData('Z+', 'fittedToCameraView') ); const light = getDirectionalLight(layer); const threeCamera = layer.getRenderer().getThreeCamera(); @@ -186,7 +186,9 @@ describe('Scene3D::DirectionalLight', () => { }); it('applies the shadow intensity and softness', () => { - const layer = make3DLayerWithEffect(makeDirectionalLightEffectData('Z+')); + const layer = make3DLayerWithEffect( + makeDirectionalLightEffectData('Z+', 'centeredAroundCamera') + ); const light = getDirectionalLight(layer); expect(light.shadow.intensity).to.be(0.6); expect(light.shadow.radius).to.be(2.5); @@ -198,7 +200,9 @@ describe('Scene3D::DirectionalLight', () => { }); it('applies a shadow frustum size changed after the first rendering', () => { - const layer = make3DLayerWithEffect(makeDirectionalLightEffectData('Z+')); + const layer = make3DLayerWithEffect( + makeDirectionalLightEffectData('Z+', 'centeredAroundCamera') + ); const light = getDirectionalLight(layer); renderLayer(layer); // The world scale is 100. diff --git a/newIDE/app/src/EffectsList/EnumerateEffects.js b/newIDE/app/src/EffectsList/EnumerateEffects.js index 099e02f15c..3ab28536b9 100644 --- a/newIDE/app/src/EffectsList/EnumerateEffects.js +++ b/newIDE/app/src/EffectsList/EnumerateEffects.js @@ -84,10 +84,10 @@ export const enumerateEffectNames = ( * them. */ const parameterValuesForNewEffects: { - [effectType: string]: {| booleanParameters: { [string]: boolean } |}, + [effectType: string]: {| stringParameters: { [string]: string } |}, } = { 'Scene3D::DirectionalLight': { - booleanParameters: { isShadowFittedToCamera: true }, + stringParameters: { shadowRenderingMode: 'fittedToCameraView' }, }, }; @@ -117,10 +117,10 @@ export const setEffectDefaultParameters = ( const parameterValues = parameterValuesForNewEffects[effect.getEffectType()]; if (parameterValues) { - Object.keys(parameterValues.booleanParameters).forEach(parameterName => { - effect.setBooleanParameter( + Object.keys(parameterValues.stringParameters).forEach(parameterName => { + effect.setStringParameter( parameterName, - parameterValues.booleanParameters[parameterName] + parameterValues.stringParameters[parameterName] ); }); } diff --git a/newIDE/app/src/ProjectCreation/CreateProject.js b/newIDE/app/src/ProjectCreation/CreateProject.js index 03603cb29e..c49ee4dfa9 100644 --- a/newIDE/app/src/ProjectCreation/CreateProject.js +++ b/newIDE/app/src/ProjectCreation/CreateProject.js @@ -57,7 +57,10 @@ export const addDefaultLightToLayer = (layer: gdLayer): void => { directionalLight.setDoubleParameter('minimumShadowBias', 0); directionalLight.setDoubleParameter('distanceFromCamera', 1500); directionalLight.setDoubleParameter('frustumSize', 4000); - directionalLight.setBooleanParameter('isShadowFittedToCamera', true); + directionalLight.setStringParameter( + 'shadowRenderingMode', + 'fittedToCameraView' + ); directionalLight.setDoubleParameter('shadowDistance', 2000); const ambientLight = layer