diff --git a/src/editor/assets/assets-migrate.ts b/src/editor/assets/assets-migrate.ts
index 8bc5d6439..9e35977bc 100644
--- a/src/editor/assets/assets-migrate.ts
+++ b/src/editor/assets/assets-migrate.ts
@@ -151,6 +151,10 @@ editor.once('load', () => {
asset.set('data.alphaToCoverage', false);
}
+ if (!asset.has('data.twoSidedLighting')) {
+ asset.set('data.twoSidedLighting', false);
+ }
+
if (!asset.has('data.opacityFadesSpecular')) {
asset.set('data.opacityFadesSpecular', true);
}
diff --git a/src/editor/attributes/reference/assets/material.ts b/src/editor/attributes/reference/assets/material.ts
index d0b3dcff5..9f3075e9f 100644
--- a/src/editor/attributes/reference/assets/material.ts
+++ b/src/editor/attributes/reference/assets/material.ts
@@ -1321,4 +1321,10 @@ export const fields: AttributeReference[] = [{
subTitle: '{Number}',
description: 'Use alphaFade to fade out materials that do not use opacity to fade specular (opacityFadesSpecular is false).',
url: 'https://api.playcanvas.com/engine/classes/StandardMaterial.html#alphafade'
+}, {
+ name: 'asset:material:twoSidedLighting',
+ title: 'twoSidedLighting',
+ subTitle: '{Boolean}',
+ description: 'Calculate proper normals on the backface. When cull mode is set to None, this enables lighting to be calculated for the backside of the mesh.',
+ url: 'https://api.playcanvas.com/engine/classes/StandardMaterial.html#twosidedlighting'
}];
diff --git a/src/editor/attributes/reference/components/light.ts b/src/editor/attributes/reference/components/light.ts
index f386825f7..f5f2ab39f 100644
--- a/src/editor/attributes/reference/components/light.ts
+++ b/src/editor/attributes/reference/components/light.ts
@@ -231,6 +231,12 @@ export const fields: AttributeReference[] = [{
subTitle: '{pc.Vec2}',
description: 'Spotlight cookie scale.',
url: 'https://api.playcanvas.com/engine/classes/LightComponent.html#cookiescale'
+}, {
+ name: 'light:penumbraSize',
+ title: 'penumbraSize',
+ subTitle: '{Number}',
+ description: 'The size of the penumbra for PCSS (Percentage Closer Soft Shadows). A larger value produces softer shadow edges. Only applies when shadows are enabled.',
+ url: 'https://api.playcanvas.com/engine/classes/LightComponent.html#penumbrasize'
}, {
name: 'light:layers',
title: 'layers',
diff --git a/src/editor/attributes/reference/components/rigidbody.ts b/src/editor/attributes/reference/components/rigidbody.ts
index b928f3fc8..777f37cf4 100644
--- a/src/editor/attributes/reference/components/rigidbody.ts
+++ b/src/editor/attributes/reference/components/rigidbody.ts
@@ -65,4 +65,10 @@ export const fields: AttributeReference[] = [{
Kinematic (pc.BODYTYPE_KINEMATIC): Controlled by code. Not affected by physics but can push dynamic bodies.
`,
url: 'https://api.playcanvas.com/engine/classes/RigidBodyComponent.html#type'
+}, {
+ name: 'rigidbody:rollingFriction',
+ title: 'rollingFriction',
+ subTitle: '{Number}',
+ description: 'Sets a torsional friction orthogonal to the contact point. This prevents round objects (spheres, cylinders) from rolling indefinitely.',
+ url: 'https://api.playcanvas.com/engine/classes/RigidBodyComponent.html#rollingfriction'
}];
diff --git a/src/editor/attributes/reference/settings.ts b/src/editor/attributes/reference/settings.ts
index cd0480d49..85daaa5e4 100644
--- a/src/editor/attributes/reference/settings.ts
+++ b/src/editor/attributes/reference/settings.ts
@@ -158,6 +158,12 @@ editor.once('load', () => {
subTitle: '{Number}',
description: 'Mip level of the prefiltered skybox. Higher values select lower-resolution, more prefiltered (blurred) mips.',
url: 'https://api.playcanvas.com/engine/classes/Scene.html#skyboxmip'
+ }, {
+ name: 'settings:skyDepthWrite',
+ title: 'skyDepthWrite',
+ subTitle: '{Boolean}',
+ description: 'Whether the sky writes to the depth buffer. Disable to allow 3D geometry to render on top of the sky.',
+ url: 'https://api.playcanvas.com/engine/classes/Scene.html#sky'
}, {
name: 'settings:skyboxRotation',
title: 'skyboxRotation',
diff --git a/src/editor/entities/entities-migrations.ts b/src/editor/entities/entities-migrations.ts
index 0629e371b..b7d1486b4 100644
--- a/src/editor/entities/entities-migrations.ts
+++ b/src/editor/entities/entities-migrations.ts
@@ -124,6 +124,11 @@ editor.once('load', () => {
entity.set('components.light.vsmBias', 0.01 * 0.25);
}
+ // penumbraSize
+ if (!entity.has('components.light.penumbraSize')) {
+ entity.set('components.light.penumbraSize', 1);
+ }
+
// cookieAsset
if (!entity.has('components.light.cookieAsset')) {
entity.set('components.light.cookieAsset', null);
@@ -171,6 +176,14 @@ editor.once('load', () => {
}
}
+ // rigidbody
+ if (entity.has('components.rigidbody')) {
+ // rollingFriction
+ if (!entity.has('components.rigidbody.rollingFriction')) {
+ entity.set('components.rigidbody.rollingFriction', 0);
+ }
+ }
+
// model
if (entity.has('components.model')) {
// isStatic
diff --git a/src/editor/inspector/assets/material.ts b/src/editor/inspector/assets/material.ts
index a132bdccc..864c325fe 100644
--- a/src/editor/inspector/assets/material.ts
+++ b/src/editor/inspector/assets/material.ts
@@ -882,6 +882,11 @@ const OTHER_ATTRIBUTES: (Attribute | Divider)[] = [{
}]
},
reference: 'asset:material:cull'
+}, {
+ label: 'Two Sided Lighting',
+ path: 'data.twoSidedLighting',
+ type: 'boolean',
+ reference: 'asset:material:twoSidedLighting'
}, {
label: 'Use Fog',
path: 'data.useFog',
diff --git a/src/editor/inspector/components/light.ts b/src/editor/inspector/components/light.ts
index 96aad5106..7423f792c 100644
--- a/src/editor/inspector/components/light.ts
+++ b/src/editor/inspector/components/light.ts
@@ -6,6 +6,7 @@ import {
SHADOW_PCF1_32F,
SHADOW_PCF3_32F,
SHADOW_PCF5_32F,
+ SHADOW_PCSS_32F,
SHADOW_VSM_16F,
SHADOW_VSM_32F,
SHADOWUPDATE_REALTIME,
@@ -336,6 +337,16 @@ const ATTRIBUTES: (Attribute | Divider)[] = [{
precision: 3,
step: 0.001
}
+}, {
+ label: 'Penumbra Size',
+ path: 'components.light.penumbraSize',
+ reference: 'light:penumbraSize',
+ type: 'number',
+ args: {
+ precision: 2,
+ step: 0.1,
+ min: 0
+ }
}, {
type: 'divider',
alias: 'components.light.cookieDivider'
@@ -589,6 +600,8 @@ class LightComponentInspector extends ComponentInspector {
this._field(field).parent.hidden = !castShadows || shadowTypeVsm;
});
+ this._field('penumbraSize').parent.hidden = !castShadows || shadowType !== SHADOW_PCSS_32F;
+
this._btnUpdateShadow.hidden = this._field('shadowUpdateMode').value !== SHADOWUPDATE_THISFRAME;
}
diff --git a/src/editor/inspector/components/rigidbody.ts b/src/editor/inspector/components/rigidbody.ts
index fd86e0ea7..772758f8f 100644
--- a/src/editor/inspector/components/rigidbody.ts
+++ b/src/editor/inspector/components/rigidbody.ts
@@ -97,6 +97,16 @@ const ATTRIBUTES: Attribute[] = [{
min: 0,
max: 1
}
+}, {
+ label: 'Rolling Friction',
+ path: 'components.rigidbody.rollingFriction',
+ reference: 'rigidbody:rollingFriction',
+ type: 'number',
+ args: {
+ precision: 2,
+ step: 0.01,
+ min: 0
+ }
}];
class RigidbodyComponentInspector extends ComponentInspector {
diff --git a/src/editor/inspector/settings-panels/rendering.ts b/src/editor/inspector/settings-panels/rendering.ts
index 5b7644e76..7b17b4160 100644
--- a/src/editor/inspector/settings-panels/rendering.ts
+++ b/src/editor/inspector/settings-panels/rendering.ts
@@ -143,6 +143,13 @@ const ATTRIBUTES: (Attribute | Divider)[] = [
]
}
},
+ {
+ observer: 'sceneSettings',
+ label: 'Sky Depth Write',
+ path: 'render.skyDepthWrite',
+ reference: 'settings:skyDepthWrite',
+ type: 'boolean'
+ },
{
type: 'divider'
},
diff --git a/src/editor/viewport/viewport-scene-settings.ts b/src/editor/viewport/viewport-scene-settings.ts
index f1bd47f3d..1503c3f9e 100644
--- a/src/editor/viewport/viewport-scene-settings.ts
+++ b/src/editor/viewport/viewport-scene-settings.ts
@@ -20,6 +20,12 @@ editor.once('load', () => {
// apply scene settings
app.applySceneSettings(sceneSettings.json());
+ // apply sky depth write (not yet handled by engine's applySettings)
+ const skyDepthWrite = sceneSettings.get('render.skyDepthWrite');
+ if (skyDepthWrite !== undefined) {
+ app.scene.sky.depthWrite = skyDepthWrite;
+ }
+
// need to update all materials on scene settings change
app.assets.filter((asset) => {
return asset.type === 'material' && asset.resource;
diff --git a/src/launch/viewport/viewport-binding-scene.ts b/src/launch/viewport/viewport-binding-scene.ts
index 3d511e819..a62d05653 100644
--- a/src/launch/viewport/viewport-binding-scene.ts
+++ b/src/launch/viewport/viewport-binding-scene.ts
@@ -12,6 +12,12 @@ editor.once('load', () => {
updating = false;
app.applySceneSettings(sceneSettings.json());
+
+ // apply sky depth write (not yet handled by engine's applySettings)
+ const skyDepthWrite = sceneSettings.get('render.skyDepthWrite');
+ if (skyDepthWrite !== undefined) {
+ app.scene.sky.depthWrite = skyDepthWrite;
+ }
};
// queue settings apply