Skip to content

Commit 547eba1

Browse files
committed
add lighting and shadow example
1 parent 4a07f53 commit 547eba1

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

src/examples/ShadowExample.tsx

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import { GLTF } from '@gltf-transform/core'
2+
import {
3+
Entity,
4+
EntityUUID,
5+
UUIDComponent,
6+
UndefinedEntity,
7+
getComponent,
8+
removeEntity,
9+
setComponent,
10+
useOptionalComponent
11+
} from '@ir-engine/ecs'
12+
import { GLTFAssetState, GLTFSourceState } from '@ir-engine/engine/src/gltf/GLTFState'
13+
import { RenderSettingsComponent } from '@ir-engine/engine/src/scene/components/RenderSettingsComponent'
14+
import { ShadowComponent } from '@ir-engine/engine/src/scene/components/ShadowComponent'
15+
import { getMutableState, none, useHookstate, useMutableState } from '@ir-engine/hyperflux'
16+
import {
17+
DirectionalLightComponent,
18+
PointLightComponent,
19+
SpotLightComponent,
20+
TransformComponent
21+
} from '@ir-engine/spatial'
22+
import { EngineState } from '@ir-engine/spatial/src/EngineState'
23+
import { NameComponent } from '@ir-engine/spatial/src/common/NameComponent'
24+
import { RendererComponent } from '@ir-engine/spatial/src/renderer/WebGLRendererSystem'
25+
import { addObjectToGroup } from '@ir-engine/spatial/src/renderer/components/GroupComponent'
26+
import { MeshComponent } from '@ir-engine/spatial/src/renderer/components/MeshComponent'
27+
import { SceneComponent } from '@ir-engine/spatial/src/renderer/components/SceneComponents'
28+
import { VisibleComponent } from '@ir-engine/spatial/src/renderer/components/VisibleComponent'
29+
import React, { useEffect } from 'react'
30+
import { BoxGeometry, Cache, Color, Euler, Mesh, MeshLambertMaterial, Quaternion, Vector3 } from 'three'
31+
import { useExampleEntity } from './utils/common/entityUtils'
32+
33+
const createSceneGLTF = (id: string): GLTF.IGLTF => ({
34+
asset: {
35+
version: '2.0',
36+
generator: 'iR Engine'
37+
},
38+
scenes: [{ nodes: [] }],
39+
scene: 0,
40+
nodes: [],
41+
extensionsUsed: []
42+
})
43+
44+
const SceneReactor = (props: { sceneEntity: Entity }) => {
45+
const settingsEntity = useExampleEntity(props.sceneEntity)
46+
const platformEntity = useExampleEntity(props.sceneEntity)
47+
const boxEntity = useExampleEntity(props.sceneEntity)
48+
const directionalLightEntity = useExampleEntity(props.sceneEntity)
49+
const spotLightEntity = useExampleEntity(props.sceneEntity)
50+
const pointLightEntity = useExampleEntity(props.sceneEntity)
51+
52+
useEffect(() => {
53+
setComponent(settingsEntity, RenderSettingsComponent, {
54+
primaryLight: getComponent(directionalLightEntity, UUIDComponent)
55+
}) // required for CSM
56+
setComponent(platformEntity, TransformComponent, {
57+
position: new Vector3(0, -0.5, 0),
58+
scale: new Vector3(10, 0.1, 10)
59+
})
60+
setComponent(platformEntity, VisibleComponent)
61+
setComponent(platformEntity, NameComponent, 'Platform')
62+
setComponent(platformEntity, MeshComponent, new Mesh(new BoxGeometry(), new MeshLambertMaterial()))
63+
addObjectToGroup(platformEntity, getComponent(platformEntity, MeshComponent))
64+
setComponent(platformEntity, ShadowComponent, { cast: false })
65+
66+
setComponent(boxEntity, TransformComponent, { position: new Vector3(0, 0.5, 0) })
67+
setComponent(boxEntity, VisibleComponent)
68+
setComponent(boxEntity, NameComponent, 'Box')
69+
setComponent(boxEntity, MeshComponent, new Mesh(new BoxGeometry(), new MeshLambertMaterial()))
70+
addObjectToGroup(boxEntity, getComponent(boxEntity, MeshComponent))
71+
setComponent(boxEntity, ShadowComponent, { receive: false })
72+
73+
setComponent(directionalLightEntity, TransformComponent, {
74+
position: new Vector3(1, 2, -3),
75+
rotation: new Quaternion().setFromEuler(
76+
new Euler().setFromVector3(new Vector3(Math.PI * 0.5, -Math.PI * 0.25).normalize())
77+
)
78+
})
79+
setComponent(directionalLightEntity, NameComponent, 'Directional Light')
80+
setComponent(directionalLightEntity, VisibleComponent)
81+
setComponent(directionalLightEntity, DirectionalLightComponent, {
82+
intensity: 0.5,
83+
castShadow: true,
84+
color: new Color('cyan')
85+
})
86+
setComponent(directionalLightEntity, ShadowComponent, { receive: false })
87+
88+
setComponent(spotLightEntity, TransformComponent, {
89+
position: new Vector3(1, 2, 2),
90+
rotation: new Quaternion().setFromEuler(
91+
new Euler().setFromVector3(new Vector3(Math.PI * 0.75, -Math.PI * 0.1, 0))
92+
)
93+
})
94+
setComponent(spotLightEntity, NameComponent, 'Spot Light')
95+
setComponent(spotLightEntity, VisibleComponent)
96+
setComponent(spotLightEntity, SpotLightComponent, {
97+
castShadow: true,
98+
decay: 1,
99+
range: 10,
100+
intensity: 10,
101+
color: new Color('green')
102+
})
103+
104+
setComponent(pointLightEntity, TransformComponent, { position: new Vector3(0, 2, -2) })
105+
setComponent(pointLightEntity, NameComponent, 'Point Light')
106+
setComponent(pointLightEntity, VisibleComponent)
107+
setComponent(pointLightEntity, PointLightComponent, {
108+
castShadow: true,
109+
decay: 2,
110+
range: 5,
111+
intensity: 10,
112+
color: new Color('red')
113+
})
114+
}, [])
115+
116+
return <></>
117+
}
118+
119+
export default function ShadowExampleEntry() {
120+
const entity = useHookstate(UndefinedEntity)
121+
const engine = useMutableState(EngineState)
122+
const renderer = useOptionalComponent(engine.viewerEntity.value, RendererComponent)
123+
124+
useEffect(() => {
125+
if (!renderer?.value) return
126+
127+
const sceneID = `scene`
128+
const gltf = createSceneGLTF(sceneID)
129+
130+
const sceneURL = `/${sceneID}.gltf`
131+
132+
Cache.add(sceneURL, gltf)
133+
134+
const gltfEntity = GLTFSourceState.load(sceneURL, sceneURL as EntityUUID)
135+
renderer.scenes.merge([gltfEntity])
136+
setComponent(gltfEntity, SceneComponent)
137+
getMutableState(GLTFAssetState)[sceneURL].set(gltfEntity)
138+
139+
entity.set(gltfEntity)
140+
141+
return () => {
142+
const idx = renderer.scenes.value.indexOf(gltfEntity)
143+
renderer.scenes[idx].set(none)
144+
removeEntity(gltfEntity)
145+
}
146+
}, [!!renderer?.scenes.value])
147+
148+
if (!entity.value) return null
149+
150+
return <SceneReactor sceneEntity={entity.value} />
151+
}

src/examplesRoute.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import MultipleCanvasCameras from './examples/MultipleCanvasCameras'
99
import MultipleCanvasScenes from './examples/MultipleCanvasScenes'
1010
import P2PConnection from './examples/P2PConnection'
1111
import PhysicsDynamicObjects from './examples/PhysicsDynamicObjects'
12+
import ShadowExampleEntry from './examples/ShadowExample'
1213
import AvatarMocapEntry from './examples/avatarMocap'
1314
import AvatarSimpleEntry from './examples/avatarSimple'
1415
import AvatarTestEntry from './examples/avatarTest'
@@ -78,6 +79,11 @@ export const examples: RouteCategories = [
7879
{
7980
category: 'Scene',
8081
routes: [
82+
{
83+
name: 'Shadows',
84+
description: 'Cast shadows from directional, point, and spot lights',
85+
entry: ShadowExampleEntry
86+
},
8187
{
8288
name: 'GLTF Viewer',
8389
description: 'Drag and drop GLTF files',

0 commit comments

Comments
 (0)