|
| 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 | +} |
0 commit comments