Skip to content

Commit

Permalink
feat: make light's shadow quality a configurable option
Browse files Browse the repository at this point in the history
  • Loading branch information
Gugustinette committed Oct 23, 2024
1 parent 098c2bc commit 5b02f2e
Show file tree
Hide file tree
Showing 12 changed files with 81 additions and 30 deletions.
9 changes: 8 additions & 1 deletion apps/playground-2d/src/classes/Character.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FCharacterControllerKP, FSprite } from '@fibbojs/2d'
import type { FScene } from '@fibbojs/2d'
import type { FRigidBodyOptions, FScene } from '@fibbojs/2d'

export default class Character extends FSprite {
constructor(scene: FScene) {
Expand All @@ -15,4 +15,11 @@ export default class Character extends FSprite {
component: this,
})
}

initSensor(options?: FRigidBodyOptions): void {
super.initSensor({
scaleOffset: { x: 0.1, y: 0.1 },
...options,
})
}
}
6 changes: 4 additions & 2 deletions apps/playground-3d/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,18 @@ import Character from './classes/Character'
new FDirectionalLight(scene, {
position: { x: 20, y: 20, z: 0 },
color: 0xFFFFFF,
intensity: 2,
intensity: 3,
shadowQuality: 12,
})
// Add spot light
new FSpotLight(scene, {
position: { x: 4, y: 4, z: 4 },
angle: 1,
distance: 8,
color: 0xFFFFFF,
intensity: 20,
intensity: 30,
lookAt: { x: 8, y: 0, z: 8 },
shadowQuality: 7,
})
// Add ambient light
new FAmbientLight(scene, {
Expand Down
13 changes: 11 additions & 2 deletions docs/guide/core/lights.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,18 @@ import { FAmbientLight, FDirectionalLight, FSpotLight } from '@fibbojs/3d'
new FDirectionalLight(scene, {
position: { x: 20, y: 20, z: 0 },
color: 0xFFFFFF,
intensity: 2,
intensity: 3,
shadowQuality: 12,
})
// Add spot light
new FSpotLight(scene, {
position: { x: 4, y: 4, z: 4 },
angle: 1,
distance: 8,
color: 0xFFFFFF,
intensity: 20,
intensity: 30,
lookAt: { x: 8, y: 0, z: 8 },
shadowQuality: 7,
})
// Add ambient light
new FAmbientLight(scene, {
Expand All @@ -55,6 +57,13 @@ They can also be removed using the `removeLight` method.
scene.removeLight(light)
```

::: tip
The shadow quality is a very important parameter. The higher the quality, the better the shadows will look, but the more resources will be used.

It will be interpreted as a power of 2, so for example the default value of 5 will result in a shadow map of 32x32 pixels.
Generally, the farther the light is from the objects, the higher the quality should be.
:::

### Available lights

Here are the available lights in 3D :
Expand Down
1 change: 0 additions & 1 deletion packages/2d/src/controllers/FCharacterController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ export abstract class FCharacterController extends FController {
// Initialize a sensor
this.component.initSensor({
shape: FShapes.RECTANGLE,
scale: { x: 1.1, y: 1.1 },
})
}
}
25 changes: 17 additions & 8 deletions packages/3d/src/core/FCollider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,17 @@ export class FCollider {

frame(_delta: number): void {
// As the collider should have moved, update the transform to sync with the collider
this.transform.position = this.__COLLIDER__.translation()
this.transform.rotation = new THREE.Euler().setFromQuaternion(new THREE.Quaternion().copy(this.__COLLIDER__.rotation()))
this.transform.__POSITION__ = this.__COLLIDER__.translation()
this.transform.__ROTATION__ = new THREE.Euler().setFromQuaternion(new THREE.Quaternion().copy(this.__COLLIDER__.rotation()))
// Propagate the position and rotation update if the collider is attached to a component
if (this.component) {
// Propagate the position update
this.component.__UPDATE_POSITION__()
this.component.sensor?.__UPDATE_POSITION__()
// Propagate the rotation update
this.component.__UPDATE_ROTATION__()
this.component.sensor?.__UPDATE_ROTATION__()
}
}

/**
Expand All @@ -181,9 +190,9 @@ export class FCollider {
__UPDATE_POSITION__(initiator: boolean = false): void {
// If the collider is the initiator
if (initiator) {
// Update the collider position
this.__SET_POSITION__(this.transform.position)
if (this.component) {
// Update the collider position
this.__SET_POSITION__(this.transform.position)
// Propagate the position update
this.component.__UPDATE_POSITION__()
this.component.sensor?.__UPDATE_POSITION__()
Expand Down Expand Up @@ -211,9 +220,9 @@ export class FCollider {
__UPDATE_ROTATION__(initiator: boolean = false): void {
// If the collider is the initiator
if (initiator) {
// Update the collider rotation
this.__SET_ROTATION__(this.transform.rotation)
if (this.component) {
// Update the collider rotation
this.__SET_ROTATION__(this.transform.rotation)
// Propagate the rotation update
this.component.__UPDATE_ROTATION__()
this.component.sensor?.__UPDATE_ROTATION__()
Expand Down Expand Up @@ -241,9 +250,9 @@ export class FCollider {
__UPDATE_SCALE__(initiator: boolean = false): void {
// If the collider is the initiator
if (initiator) {
// Update the collider scale
this.__SET_SCALE__(this.transform.scale)
if (this.component) {
// Update the collider scale
this.__SET_SCALE__(this.transform.scale)
// Propagate the scale update
this.component.__UPDATE_SCALE__()
this.component.sensor?.__UPDATE_SCALE__()
Expand Down
2 changes: 1 addition & 1 deletion packages/3d/src/core/FComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ export abstract class FComponent extends FComponentCore {
// Define default values
const DEFAULT_OPTIONS = {
position: { x: 0, y: 1, z: 0 },
scale: { x: 1, y: 1, z: 1 },
rotation: { x: 0, y: 0, z: 0 },
scale: { x: 1, y: 1, z: 1 },
}
// Apply default options
options = { ...DEFAULT_OPTIONS, ...options }
Expand Down
21 changes: 15 additions & 6 deletions packages/3d/src/core/FRigidBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,17 @@ export class FRigidBody {

frame(_delta: number): void {
// As the rigidBody should have moved, update the transform to sync with the rigidBody
this.transform.position = this.__RIGIDBODY__.translation()
this.transform.rotation = new THREE.Euler().setFromQuaternion(new THREE.Quaternion().copy(this.__RIGIDBODY__.rotation()))
this.transform.__POSITION__ = this.__RIGIDBODY__.translation()
this.transform.__ROTATION__ = new THREE.Euler().setFromQuaternion(new THREE.Quaternion().copy(this.__RIGIDBODY__.rotation()))
// Propagate the position and rotation update if the rigidBody is attached to a component
if (this.component) {
// Propagate the position update
this.component.__UPDATE_POSITION__()
this.component.sensor?.__UPDATE_POSITION__()
// Propagate the rotation update
this.component.__UPDATE_ROTATION__()
this.component.sensor?.__UPDATE_ROTATION__()
}
}

/**
Expand Down Expand Up @@ -232,9 +241,9 @@ export class FRigidBody {
__UPDATE_POSITION__(initiator: boolean = false): void {
// If the rigidBody is the initiator
if (initiator) {
// Update the rigidBody position
this.__SET_POSITION__(this.transform.position)
if (this.component) {
// Update the rigidBody position
this.__SET_POSITION__(this.transform.position)
// Propagate the position update
this.component.__UPDATE_POSITION__()
this.component.sensor?.__UPDATE_POSITION__()
Expand Down Expand Up @@ -262,9 +271,9 @@ export class FRigidBody {
__UPDATE_ROTATION__(initiator: boolean = false): void {
// If the rigidBody is the initiator
if (initiator) {
// Update the rigidBody rotation
this.__SET_ROTATION__(this.transform.rotation)
if (this.component) {
// Update the rigidBody rotation
this.__SET_ROTATION__(this.transform.rotation)
// Propagate the rotation update
this.component.__UPDATE_ROTATION__()
this.component.sensor?.__UPDATE_ROTATION__()
Expand Down
4 changes: 2 additions & 2 deletions packages/3d/src/lights/FDirectionalLight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export class FDirectionalLight extends FLight {
this.__LIGHT__.shadow.camera.right = 100
this.__LIGHT__.shadow.camera.top = 100
this.__LIGHT__.shadow.camera.bottom = -100
this.__LIGHT__.shadow.mapSize.width = 16384
this.__LIGHT__.shadow.mapSize.height = 16384
this.__LIGHT__.shadow.mapSize.width = 2 ** this.shadowQuality
this.__LIGHT__.shadow.mapSize.height = 2 ** this.shadowQuality
}
}

Expand Down
18 changes: 17 additions & 1 deletion packages/3d/src/lights/FLight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface FLightOptions extends FTransformOptions {
color?: THREE.ColorRepresentation
intensity?: number
lookAt?: FVector3
shadowQuality?: number
}

/**
Expand Down Expand Up @@ -44,6 +45,11 @@ export abstract class FLight extends FLightCore {
*/
__LOOK_AT__: FVector3 | undefined

/**
* Quality of the shadow. Default is 5.
*/
__SHADOW_QUALITY__: number

constructor(scene: FScene, options?: FLightOptions) {
super(scene)

Expand All @@ -52,11 +58,12 @@ export abstract class FLight extends FLightCore {
position: { x: 5, y: 5, z: 5 },
rotation: { x: 0, y: 0, z: 0 },
scale: { x: 1, y: 1, z: 1 },
shadowQuality: 5,
}
// Apply default options
options = { ...DEFAULT_OPTIONS, ...options }
// Validate options
if (!options.position)
if (!options.position || !options.shadowQuality)
throw new Error('FibboError: FLight requires position and lookAt options.')

// Store scene
Expand All @@ -73,6 +80,7 @@ export abstract class FLight extends FLightCore {
this.transform.onScaleUpdated(() => this.__UPDATE_SCALE__())

this.__LOOK_AT__ = options.lookAt
this.__SHADOW_QUALITY__ = options.shadowQuality
}

/**
Expand Down Expand Up @@ -138,4 +146,12 @@ export abstract class FLight extends FLightCore {
this.__LIGHT__.lookAt(lookAt.x, lookAt.y, lookAt.z)
}
}

get shadowQuality(): number {
return this.__SHADOW_QUALITY__
}

set shadowQuality(quality: number) {
this.__SHADOW_QUALITY__ = quality
}
}
4 changes: 2 additions & 2 deletions packages/3d/src/lights/FLightProbe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ export class FLightProbe extends FLight {
if (this.scene.__ENABLE_SHADOWS__) {
this.__LIGHT__.castShadow = true
if (this.__LIGHT__.shadow) {
this.__LIGHT__.shadow.mapSize.width = 65536
this.__LIGHT__.shadow.mapSize.height = 65536
this.__LIGHT__.shadow.mapSize.width = 2 ** this.shadowQuality
this.__LIGHT__.shadow.mapSize.height = 2 ** this.shadowQuality
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/3d/src/lights/FPointLight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export class FPointLight extends FLight {
if (this.scene.__ENABLE_SHADOWS__) {
this.__LIGHT__.castShadow = true
if (this.__LIGHT__.shadow) {
this.__LIGHT__.shadow.mapSize.width = 65536
this.__LIGHT__.shadow.mapSize.height = 65536
this.__LIGHT__.shadow.mapSize.width = 2 ** this.shadowQuality
this.__LIGHT__.shadow.mapSize.height = 2 ** this.shadowQuality
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/3d/src/lights/FSpotLight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ export class FSpotLight extends FLight {
if (this.scene.__ENABLE_SHADOWS__) {
this.__LIGHT__.castShadow = true
if (this.__LIGHT__.shadow) {
this.__LIGHT__.shadow.mapSize.width = 16384
this.__LIGHT__.shadow.mapSize.height = 16384
this.__LIGHT__.shadow.mapSize.width = 2 ** this.shadowQuality
this.__LIGHT__.shadow.mapSize.height = 2 ** this.shadowQuality
}
}

Expand Down

0 comments on commit 5b02f2e

Please sign in to comment.