react-three-game 0.0.70 → 0.0.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +9 -5
- package/dist/index.js +5 -2
- package/dist/tools/prefabeditor/EditorTree.js +2 -12
- package/dist/tools/prefabeditor/EditorTreeMenus.js +1 -19
- package/dist/tools/prefabeditor/EditorUI.js +2 -1
- package/dist/tools/prefabeditor/PrefabEditor.d.ts +1 -3
- package/dist/tools/prefabeditor/PrefabEditor.js +23 -42
- package/dist/tools/prefabeditor/PrefabRoot.d.ts +39 -13
- package/dist/tools/prefabeditor/PrefabRoot.js +105 -49
- package/dist/tools/prefabeditor/components/AmbientLightComponent.js +10 -7
- package/dist/tools/prefabeditor/components/CameraComponent.js +11 -15
- package/dist/tools/prefabeditor/components/ClickComponent.js +5 -1
- package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +15 -1
- package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +127 -53
- package/dist/tools/prefabeditor/components/EnvironmentComponent.js +5 -3
- package/dist/tools/prefabeditor/components/MaterialComponent.js +9 -6
- package/dist/tools/prefabeditor/components/ModelComponent.js +4 -2
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +6 -3
- package/dist/tools/prefabeditor/components/PointLightComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/PointLightComponent.js +57 -0
- package/dist/tools/prefabeditor/components/SoundComponent.js +21 -16
- package/dist/tools/prefabeditor/components/SpotLightComponent.js +49 -24
- package/dist/tools/prefabeditor/components/index.js +2 -0
- package/dist/tools/prefabeditor/components/lightUtils.d.ts +13 -0
- package/dist/tools/prefabeditor/components/lightUtils.js +64 -0
- package/dist/tools/prefabeditor/prefab.d.ts +37 -0
- package/dist/tools/prefabeditor/prefab.js +229 -0
- package/dist/tools/prefabeditor/prefabStore.d.ts +3 -16
- package/dist/tools/prefabeditor/prefabStore.js +29 -168
- package/dist/tools/prefabeditor/{sceneApi.d.ts → scene.d.ts} +6 -2
- package/dist/tools/prefabeditor/{sceneApi.js → scene.js} +13 -19
- package/dist/tools/prefabeditor/utils.d.ts +0 -4
- package/dist/tools/prefabeditor/utils.js +0 -37
- package/package.json +1 -1
|
@@ -11,7 +11,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
13
|
import { useHelper } from "@react-three/drei";
|
|
14
|
-
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
14
|
+
import { forwardRef, createContext, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
15
15
|
import { BoxHelper, Euler, Matrix4, } from "three";
|
|
16
16
|
import { useStore } from "zustand";
|
|
17
17
|
import { useClickValid } from "./useClickValid";
|
|
@@ -22,13 +22,62 @@ import { loadModel, loadSound, loadTexture } from "../dragdrop";
|
|
|
22
22
|
import { GameInstance, GameInstanceProvider, getRepeatAxesFromModelProperties, useInstanceCheck } from "./InstanceProvider";
|
|
23
23
|
import { composeTransform, decompose } from "./utils";
|
|
24
24
|
import { isPhysicsProps } from "./components/PhysicsComponent";
|
|
25
|
-
import {
|
|
25
|
+
import { denormalizePrefab } from "./prefab";
|
|
26
|
+
import { createPrefabStore, PrefabStoreProvider, useOptionalPrefabStoreApi, usePrefabChildIds, usePrefabNode, usePrefabRootId } from "./prefabStore";
|
|
26
27
|
import { sound as soundManager } from "../../helpers/SoundManager";
|
|
27
28
|
components.forEach(registerComponent);
|
|
28
29
|
const IDENTITY = new Matrix4();
|
|
29
30
|
const EMPTY_MODELS = {};
|
|
30
31
|
const EMPTY_TEXTURES = {};
|
|
31
32
|
const EMPTY_SOUNDS = {};
|
|
33
|
+
const AssetRuntimeContext = createContext(null);
|
|
34
|
+
const EntityRuntimeContext = createContext(null);
|
|
35
|
+
/** Access scene-wide shared services from within a component View. */
|
|
36
|
+
export function useAssetRuntime() {
|
|
37
|
+
const ctx = useContext(AssetRuntimeContext);
|
|
38
|
+
if (!ctx)
|
|
39
|
+
throw new Error("useAssetRuntime must be used inside <PrefabRoot>");
|
|
40
|
+
return ctx;
|
|
41
|
+
}
|
|
42
|
+
/** Access the current node's runtime from within a component View. */
|
|
43
|
+
export function useEntityRuntime() {
|
|
44
|
+
const ctx = useContext(EntityRuntimeContext);
|
|
45
|
+
if (!ctx)
|
|
46
|
+
throw new Error("useEntityRuntime must be used inside a component View rendered by <PrefabRoot>");
|
|
47
|
+
return ctx;
|
|
48
|
+
}
|
|
49
|
+
/** Read the current component's Object3D through a live ref-like accessor. */
|
|
50
|
+
export function useEntityObjectRef() {
|
|
51
|
+
const { getObject } = useEntityRuntime();
|
|
52
|
+
return useMemo(() => ({
|
|
53
|
+
get current() {
|
|
54
|
+
return getObject();
|
|
55
|
+
},
|
|
56
|
+
}), [getObject]);
|
|
57
|
+
}
|
|
58
|
+
/** Read the current component's rigid body through a live ref-like accessor. */
|
|
59
|
+
export function useEntityRigidBodyRef() {
|
|
60
|
+
const { getRigidBody } = useEntityRuntime();
|
|
61
|
+
return useMemo(() => ({
|
|
62
|
+
get current() {
|
|
63
|
+
return getRigidBody();
|
|
64
|
+
},
|
|
65
|
+
}), [getRigidBody]);
|
|
66
|
+
}
|
|
67
|
+
function EntityRuntimeScope({ nodeId, editMode, isSelected, children, }) {
|
|
68
|
+
const assetRuntime = useContext(AssetRuntimeContext);
|
|
69
|
+
if (!assetRuntime)
|
|
70
|
+
throw new Error("EntityRuntimeScope must be used inside <PrefabRoot>");
|
|
71
|
+
const { getObject, getRigidBody } = assetRuntime;
|
|
72
|
+
const value = useMemo(() => ({
|
|
73
|
+
nodeId,
|
|
74
|
+
editMode,
|
|
75
|
+
isSelected,
|
|
76
|
+
getObject: () => getObject(nodeId),
|
|
77
|
+
getRigidBody: () => getRigidBody(nodeId),
|
|
78
|
+
}), [editMode, getObject, getRigidBody, isSelected, nodeId]);
|
|
79
|
+
return _jsx(EntityRuntimeContext.Provider, { value: value, children: children });
|
|
80
|
+
}
|
|
32
81
|
/** Resolve a relative or absolute asset file path against a base path. */
|
|
33
82
|
function resolveAssetPath(basePath, file) {
|
|
34
83
|
if (file.startsWith("http://") || file.startsWith("https://"))
|
|
@@ -43,11 +92,14 @@ function isNodeReady(node, loadedModels) {
|
|
|
43
92
|
return true;
|
|
44
93
|
return Boolean(loadedModels[model.properties.filename]);
|
|
45
94
|
}
|
|
46
|
-
export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSelect, onClick,
|
|
95
|
+
export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSelect, onClick, basePath = "" }, ref) => {
|
|
47
96
|
var _a;
|
|
48
97
|
const [models, setModels] = useState({});
|
|
49
98
|
const [textures, setTextures] = useState({});
|
|
50
99
|
const [sounds, setSounds] = useState({});
|
|
100
|
+
const [injectedModels, setInjectedModels] = useState(EMPTY_MODELS);
|
|
101
|
+
const [injectedTextures, setInjectedTextures] = useState(EMPTY_TEXTURES);
|
|
102
|
+
const [injectedSounds, setInjectedSounds] = useState(EMPTY_SOUNDS);
|
|
51
103
|
const loading = useRef(new Set());
|
|
52
104
|
const failedModels = useRef(new Set());
|
|
53
105
|
const failedTextures = useRef(new Set());
|
|
@@ -56,7 +108,7 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
56
108
|
const rigidBodyRefs = useRef(new Map());
|
|
57
109
|
const rootRef = useRef(null);
|
|
58
110
|
const parentStore = useOptionalPrefabStoreApi();
|
|
59
|
-
const [ownedStore] = useState(() => { var _a, _b; return createPrefabStore(data !== null && data !== void 0 ? data :
|
|
111
|
+
const [ownedStore] = useState(() => { var _a, _b; return createPrefabStore(data !== null && data !== void 0 ? data : denormalizePrefab((_b = (_a = store === null || store === void 0 ? void 0 : store.getState()) !== null && _a !== void 0 ? _a : parentStore === null || parentStore === void 0 ? void 0 : parentStore.getState()) !== null && _b !== void 0 ? _b : missingStoreState())); });
|
|
60
112
|
const resolvedStore = (_a = store !== null && store !== void 0 ? store : parentStore) !== null && _a !== void 0 ? _a : ownedStore;
|
|
61
113
|
const usesOwnedStore = resolvedStore === ownedStore;
|
|
62
114
|
const shouldProvideStoreContext = !parentStore || parentStore !== resolvedStore;
|
|
@@ -64,19 +116,24 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
64
116
|
const availableModels = useMemo(() => (Object.assign(Object.assign({}, models), injectedModels)), [models, injectedModels]);
|
|
65
117
|
const availableTextures = useMemo(() => (Object.assign(Object.assign({}, textures), injectedTextures)), [textures, injectedTextures]);
|
|
66
118
|
const availableSounds = useMemo(() => (Object.assign(Object.assign({}, sounds), injectedSounds)), [sounds, injectedSounds]);
|
|
119
|
+
const getObject = useCallback((id) => {
|
|
120
|
+
var _a;
|
|
121
|
+
return (_a = objectRefs.current[id]) !== null && _a !== void 0 ? _a : null;
|
|
122
|
+
}, []);
|
|
67
123
|
useImperativeHandle(ref, () => ({
|
|
68
124
|
root: rootRef.current,
|
|
69
|
-
|
|
70
|
-
getObject: (nodeId) => { var _a; return (_a = objectRefs.current[nodeId]) !== null && _a !== void 0 ? _a : null; },
|
|
125
|
+
getObject,
|
|
71
126
|
getRigidBody: (nodeId) => { var _a; return (_a = rigidBodyRefs.current.get(nodeId)) !== null && _a !== void 0 ? _a : null; },
|
|
72
|
-
|
|
73
|
-
|
|
127
|
+
addModel: (path, model) => setInjectedModels(prev => (Object.assign(Object.assign({}, prev), { [path]: model }))),
|
|
128
|
+
addTexture: (path, texture) => setInjectedTextures(prev => (Object.assign(Object.assign({}, prev), { [path]: texture }))),
|
|
129
|
+
addSound: (path, sound) => {
|
|
130
|
+
soundManager.setBuffer(path, sound);
|
|
131
|
+
setInjectedSounds(prev => (Object.assign(Object.assign({}, prev), { [path]: sound })));
|
|
132
|
+
},
|
|
133
|
+
}), [getObject]);
|
|
74
134
|
const registerRef = useCallback((id, obj) => {
|
|
75
135
|
objectRefs.current[id] = obj;
|
|
76
|
-
|
|
77
|
-
onSelectedObjectChange === null || onSelectedObjectChange === void 0 ? void 0 : onSelectedObjectChange(obj);
|
|
78
|
-
}
|
|
79
|
-
}, [onSelectedObjectChange, selectedId]);
|
|
136
|
+
}, []);
|
|
80
137
|
const registerRigidBodyRef = useCallback((id, rb) => {
|
|
81
138
|
rigidBodyRefs.current.set(id, rb);
|
|
82
139
|
}, []);
|
|
@@ -155,11 +212,31 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
155
212
|
};
|
|
156
213
|
syncAssets();
|
|
157
214
|
}, [resolvedStore, assetManifestKey, basePath, injectedModels, injectedSounds, injectedTextures, models, sounds, textures]);
|
|
158
|
-
|
|
215
|
+
// Keep refs current so context getters are always fresh without changing context identity
|
|
216
|
+
const availableModelsRef = useRef(availableModels);
|
|
217
|
+
availableModelsRef.current = availableModels;
|
|
218
|
+
const availableTexturesRef = useRef(availableTextures);
|
|
219
|
+
availableTexturesRef.current = availableTextures;
|
|
220
|
+
const availableSoundsRef = useRef(availableSounds);
|
|
221
|
+
availableSoundsRef.current = availableSounds;
|
|
222
|
+
const assetRuntime = useMemo(() => ({
|
|
223
|
+
getObject,
|
|
224
|
+
getRigidBody,
|
|
225
|
+
registerRigidBodyRef,
|
|
226
|
+
getModel: (path) => { var _a; return (_a = availableModelsRef.current[path]) !== null && _a !== void 0 ? _a : null; },
|
|
227
|
+
getTexture: (path) => { var _a; return (_a = availableTexturesRef.current[path]) !== null && _a !== void 0 ? _a : null; },
|
|
228
|
+
getSound: (path) => { var _a; return (_a = availableSoundsRef.current[path]) !== null && _a !== void 0 ? _a : null; },
|
|
229
|
+
getAssetRevision: () => {
|
|
230
|
+
const modelKeys = Object.keys(availableModelsRef.current).sort().join('|');
|
|
231
|
+
const textureKeys = Object.keys(availableTexturesRef.current).sort().join('|');
|
|
232
|
+
return `${textureKeys}::${modelKeys}`;
|
|
233
|
+
},
|
|
234
|
+
}), [getObject, getRigidBody, registerRigidBodyRef]);
|
|
235
|
+
const content = (_jsx("group", { ref: rootRef, children: _jsx(GameInstanceProvider, { models: availableModels, selectedId: selectedId, editMode: editMode, onSelect: editMode ? onSelect : undefined, registerRef: registerRef, children: _jsx(StoreRootNode, { selectedId: selectedId, onSelect: editMode ? onSelect : undefined, onClick: onClick, registerRef: registerRef, loadedModels: availableModels, editMode: editMode, parentMatrix: IDENTITY }) }) }));
|
|
159
236
|
if (!shouldProvideStoreContext) {
|
|
160
|
-
return content;
|
|
237
|
+
return _jsx(AssetRuntimeContext.Provider, { value: assetRuntime, children: content });
|
|
161
238
|
}
|
|
162
|
-
return _jsx(PrefabStoreProvider, { store: resolvedStore, children: content });
|
|
239
|
+
return _jsx(PrefabStoreProvider, { store: resolvedStore, children: _jsx(AssetRuntimeContext.Provider, { value: assetRuntime, children: content }) });
|
|
163
240
|
});
|
|
164
241
|
function StoreRootNode(props) {
|
|
165
242
|
const rootId = usePrefabRootId();
|
|
@@ -218,7 +295,7 @@ function InstancedNode({ nodeId, parentMatrix = IDENTITY, editMode, registerRef,
|
|
|
218
295
|
}
|
|
219
296
|
return (_jsx(_Fragment, { children: instances.map(instance => (_jsx(GameInstance, { id: instance.id, sourceId: gameObject.id, clickable: clickable, clickEventName: clickEventName, modelUrl: instance.modelUrl, position: instance.position, rotation: instance.rotation, scale: instance.scale, locked: isLocked, physics: instance.physics }, instance.id))) }));
|
|
220
297
|
}
|
|
221
|
-
function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef,
|
|
298
|
+
function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, loadedModels, editMode, parentMatrix = IDENTITY, }) {
|
|
222
299
|
var _a, _b;
|
|
223
300
|
const gameObject = usePrefabNode(nodeId);
|
|
224
301
|
const childIds = usePrefabChildIds(nodeId);
|
|
@@ -246,18 +323,12 @@ function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, regi
|
|
|
246
323
|
const physicsDef = hasPhysics ? getComponentDef(physics.type) : null;
|
|
247
324
|
const isInstanced = (_b = (_a = findComponent(gameObject, "Model")) === null || _a === void 0 ? void 0 : _a.properties) === null || _b === void 0 ? void 0 : _b.instanced;
|
|
248
325
|
const physicsKey = `physics_${nodeId}_${isInstanced ? 'instanced' : 'standard'}`;
|
|
249
|
-
const renderCtx = { loadedModels,
|
|
326
|
+
const renderCtx = { loadedModels, editMode, registerRef };
|
|
250
327
|
const childNodes = getChildHostComponents(gameObject).length > 0
|
|
251
328
|
? _jsx(CompositionChildren, { childIds: childIds, selectedId: selectedId, ctx: renderCtx, parentMatrix: world })
|
|
252
|
-
: _jsx(ChildNodes, { childIds: childIds, parentMatrix: world, selectedId: selectedId, onSelect: onSelect, onClick: onClick, registerRef: registerRef,
|
|
253
|
-
const inner = (_jsx("group", Object.assign({}, clickHandlers, { children: renderCompositionNode(gameObject, renderCtx,
|
|
254
|
-
|
|
255
|
-
return (_jsxs(_Fragment, { children: [_jsx("group", { ref: groupRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: _jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }) }), _jsx("group", { ref: helperRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner }), hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) ? (_jsx(physicsDef.View, { properties: physics.properties, position: transform.position, rotation: transform.rotation, scale: transform.scale, editMode: editMode, nodeId: nodeId, registerRigidBodyRef: registerRigidBodyRef, children: inner }, physicsKey)) : null] }));
|
|
256
|
-
}
|
|
257
|
-
if (hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View)) {
|
|
258
|
-
return (_jsx(physicsDef.View, { properties: physics.properties, position: transform.position, rotation: transform.rotation, scale: transform.scale, editMode: editMode, nodeId: nodeId, registerRigidBodyRef: registerRigidBodyRef, children: inner }, physicsKey));
|
|
259
|
-
}
|
|
260
|
-
return (_jsx("group", { ref: groupRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner }));
|
|
329
|
+
: _jsx(ChildNodes, { childIds: childIds, parentMatrix: world, selectedId: selectedId, onSelect: onSelect, onClick: onClick, registerRef: registerRef, loadedModels: loadedModels, editMode: editMode });
|
|
330
|
+
const inner = (_jsx("group", Object.assign({}, clickHandlers, { children: renderCompositionNode(gameObject, renderCtx, childNodes) })));
|
|
331
|
+
return (_jsx(EntityRuntimeScope, { nodeId: nodeId, editMode: editMode, isSelected: isSelected, children: editMode ? (_jsxs(_Fragment, { children: [_jsx("group", { ref: groupRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: _jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }) }), _jsx("group", { ref: helperRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner }), hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) ? (_jsx(physicsDef.View, { properties: physics.properties, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner }, physicsKey)) : null] })) : hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) ? (_jsx(physicsDef.View, { properties: physics.properties, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner }, physicsKey)) : (_jsx("group", { ref: groupRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner })) }));
|
|
261
332
|
}
|
|
262
333
|
function getChildHostComponents(gameObject) {
|
|
263
334
|
var _a;
|
|
@@ -346,7 +417,7 @@ function renderCompositionSubtree(gameObject, ctx, isSelected, childIds, parentM
|
|
|
346
417
|
const transform = getNodeTransformProps(gameObject);
|
|
347
418
|
const world = parentMatrix.clone().multiply(compose(gameObject));
|
|
348
419
|
const childNodes = _jsx(CompositionChildren, { childIds: childIds, ctx: ctx, parentMatrix: world });
|
|
349
|
-
return (_jsx("group", { position: transform.position, rotation: transform.rotation, scale: transform.scale, children: renderCompositionNode(gameObject, ctx,
|
|
420
|
+
return (_jsx(EntityRuntimeScope, { nodeId: gameObject.id, editMode: ctx.editMode, isSelected: isSelected, children: _jsx("group", { position: transform.position, rotation: transform.rotation, scale: transform.scale, children: renderCompositionNode(gameObject, ctx, childNodes) }, gameObject.id) }));
|
|
350
421
|
}
|
|
351
422
|
function CompositionChildren({ childIds, selectedId, ctx, parentMatrix, }) {
|
|
352
423
|
return childIds.map(childId => (_jsx(CompositionSubtree, { nodeId: childId, selectedId: selectedId, ctx: ctx, parentMatrix: parentMatrix }, childId)));
|
|
@@ -359,37 +430,22 @@ function CompositionSubtree({ nodeId, selectedId, ctx, parentMatrix, }) {
|
|
|
359
430
|
return null;
|
|
360
431
|
return renderCompositionSubtree(gameObject, ctx, isSelected, childIds, parentMatrix);
|
|
361
432
|
}
|
|
362
|
-
function renderCompositionNode(gameObject, ctx,
|
|
363
|
-
const ownContent = renderNodeOwnContent(gameObject
|
|
364
|
-
return wrapWithChildHosts(gameObject,
|
|
365
|
-
}
|
|
366
|
-
function buildContextProps(gameObject, ctx, isSelected, parentMatrix) {
|
|
367
|
-
return {
|
|
368
|
-
loadedModels: ctx.loadedModels,
|
|
369
|
-
loadedSounds: ctx.loadedSounds,
|
|
370
|
-
loadedTextures: ctx.loadedTextures,
|
|
371
|
-
editMode: ctx.editMode,
|
|
372
|
-
isSelected,
|
|
373
|
-
nodeId: gameObject.id,
|
|
374
|
-
parentMatrix,
|
|
375
|
-
registerRef: ctx.registerRef,
|
|
376
|
-
getRigidBody: ctx.getRigidBody,
|
|
377
|
-
};
|
|
433
|
+
function renderCompositionNode(gameObject, ctx, childNodes) {
|
|
434
|
+
const ownContent = renderNodeOwnContent(gameObject);
|
|
435
|
+
return wrapWithChildHosts(gameObject, _jsxs(_Fragment, { children: [ownContent, childNodes] }));
|
|
378
436
|
}
|
|
379
|
-
function renderNodeOwnContent(gameObject
|
|
437
|
+
function renderNodeOwnContent(gameObject) {
|
|
380
438
|
const geometry = findComponent(gameObject, "Geometry");
|
|
381
439
|
const material = findComponent(gameObject, "Material");
|
|
382
440
|
const geometryDef = geometry && getComponentDef(geometry.type);
|
|
383
441
|
const materialDef = material && getComponentDef(material.type);
|
|
384
442
|
if (!geometry || !(geometryDef === null || geometryDef === void 0 ? void 0 : geometryDef.View))
|
|
385
443
|
return null;
|
|
386
|
-
|
|
387
|
-
return (_jsxs("mesh", { castShadow: true, receiveShadow: true, children: [_jsx(geometryDef.View, Object.assign({ properties: geometry.properties }, contextProps)), material && (materialDef === null || materialDef === void 0 ? void 0 : materialDef.View) && (_jsx(materialDef.View, Object.assign({ properties: material.properties }, contextProps), "material"))] }));
|
|
444
|
+
return (_jsxs("mesh", { castShadow: true, receiveShadow: true, children: [_jsx(geometryDef.View, { properties: geometry.properties }), material && (materialDef === null || materialDef === void 0 ? void 0 : materialDef.View) && (_jsx(materialDef.View, { properties: material.properties }, "material"))] }));
|
|
388
445
|
}
|
|
389
|
-
function wrapWithChildHosts(gameObject,
|
|
390
|
-
const contextProps = buildContextProps(gameObject, ctx, isSelected, parentMatrix);
|
|
446
|
+
function wrapWithChildHosts(gameObject, subtree) {
|
|
391
447
|
const childHosts = getChildHostComponents(gameObject);
|
|
392
|
-
return childHosts.reduce((acc, { key, View, properties }) => (_jsx(View,
|
|
448
|
+
return childHosts.reduce((acc, { key, View, properties }) => (_jsx(View, { properties: properties, children: acc }, key)), subtree);
|
|
393
449
|
}
|
|
394
450
|
export default PrefabRoot;
|
|
395
451
|
function missingStoreState() {
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { ColorField,
|
|
2
|
+
import { ColorField, NumberField } from "./Input";
|
|
3
|
+
import { LightSection, mergeWithDefaults } from "./lightUtils";
|
|
4
|
+
const ambientLightDefaults = {
|
|
5
|
+
color: '#ffffff',
|
|
6
|
+
intensity: 1,
|
|
7
|
+
};
|
|
3
8
|
function AmbientLightComponentEditor({ component, onUpdate, }) {
|
|
4
|
-
|
|
9
|
+
const values = mergeWithDefaults(ambientLightDefaults, component.properties);
|
|
10
|
+
return (_jsxs(LightSection, { title: "Light", children: [_jsx(ColorField, { name: "color", label: "Color", values: values, onChange: onUpdate }), _jsx(NumberField, { name: "intensity", label: "Intensity", values: values, onChange: onUpdate, min: 0, step: 0.1, fallback: 1 })] }));
|
|
5
11
|
}
|
|
6
12
|
function AmbientLightComponentView({ properties, children }) {
|
|
7
|
-
const { color
|
|
13
|
+
const { color, intensity } = mergeWithDefaults(ambientLightDefaults, properties);
|
|
8
14
|
return (_jsxs(_Fragment, { children: [_jsx("ambientLight", { color: color, intensity: intensity }), children] }));
|
|
9
15
|
}
|
|
10
16
|
const AmbientLightComponent = {
|
|
11
17
|
name: 'AmbientLight',
|
|
12
18
|
Editor: AmbientLightComponentEditor,
|
|
13
19
|
View: AmbientLightComponentView,
|
|
14
|
-
defaultProperties: {
|
|
15
|
-
color: '#ffffff',
|
|
16
|
-
intensity: 1,
|
|
17
|
-
},
|
|
20
|
+
defaultProperties: {},
|
|
18
21
|
};
|
|
19
22
|
export default AmbientLightComponent;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { PerspectiveCamera } from '@react-three/drei';
|
|
3
|
-
import {
|
|
2
|
+
import { PerspectiveCamera, useHelper } from '@react-three/drei';
|
|
3
|
+
import { useRef } from 'react';
|
|
4
4
|
import { CameraHelper } from 'three';
|
|
5
5
|
import { useFrame } from '@react-three/fiber';
|
|
6
|
+
import { useEntityRuntime } from '../PrefabRoot';
|
|
6
7
|
import { FieldGroup, NumberField } from './Input';
|
|
7
8
|
const cameraDefaults = {
|
|
8
9
|
fov: 50,
|
|
@@ -14,27 +15,22 @@ function CameraComponentEditor({ component, onUpdate }) {
|
|
|
14
15
|
const values = Object.assign(Object.assign({}, cameraDefaults), component.properties);
|
|
15
16
|
return (_jsxs(FieldGroup, { children: [_jsx(NumberField, { name: "fov", label: "FOV", values: values, onChange: onUpdate, fallback: 50, min: 1, max: 179, step: 1 }), _jsx(NumberField, { name: "near", label: "Near", values: values, onChange: onUpdate, fallback: 0.1, min: 0.001, step: 0.1 }), _jsx(NumberField, { name: "zoom", label: "Zoom", values: values, onChange: onUpdate, fallback: 1, min: 0.01, step: 0.1 }), _jsx(NumberField, { name: "far", label: "Far", values: values, onChange: onUpdate, fallback: 1000, min: 0.1, step: 1 })] }));
|
|
16
17
|
}
|
|
17
|
-
function CameraComponentView({ properties, children
|
|
18
|
+
function CameraComponentView({ properties, children }) {
|
|
19
|
+
const { editMode, isSelected } = useEntityRuntime();
|
|
18
20
|
const merged = Object.assign(Object.assign({}, cameraDefaults), properties);
|
|
19
21
|
const fov = merged.fov;
|
|
20
22
|
const near = merged.near;
|
|
21
23
|
const zoom = merged.zoom;
|
|
22
24
|
const far = merged.far;
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
return () => {
|
|
27
|
-
cameraHelper === null || cameraHelper === void 0 ? void 0 : cameraHelper.dispose();
|
|
28
|
-
};
|
|
29
|
-
}, [cameraHelper]);
|
|
25
|
+
const cameraRef = useRef(null);
|
|
26
|
+
useHelper(editMode && isSelected ? cameraRef : null, CameraHelper);
|
|
30
27
|
useFrame(() => {
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
cameraHelper.update();
|
|
28
|
+
if (cameraRef.current && editMode && isSelected) {
|
|
29
|
+
cameraRef.current.updateProjectionMatrix();
|
|
30
|
+
cameraRef.current.updateMatrixWorld();
|
|
35
31
|
}
|
|
36
32
|
});
|
|
37
|
-
return (_jsxs(_Fragment, { children: [_jsx(PerspectiveCamera, { ref:
|
|
33
|
+
return (_jsxs(_Fragment, { children: [_jsx(PerspectiveCamera, { ref: cameraRef, makeDefault: !editMode, fov: fov, near: near, zoom: zoom, far: far }), editMode ? (_jsxs("group", { children: [_jsxs("mesh", { children: [_jsx("boxGeometry", { args: [0.3, 0.3, 0.5] }), _jsx("meshBasicMaterial", { color: '#22d3ee', wireframe: true })] }), _jsxs("mesh", { position: [0, 0, -0.25], rotation: [Math.PI / 2, 0, 0], children: [_jsx("coneGeometry", { args: [0.08, 0.16, 16] }), _jsx("meshBasicMaterial", { color: '#22d3ee', wireframe: true })] })] })) : null, children] }));
|
|
38
34
|
}
|
|
39
35
|
const CameraComponent = {
|
|
40
36
|
name: 'Camera',
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useRef } from 'react';
|
|
3
3
|
import { gameEvents } from '../GameEvents';
|
|
4
|
+
import { useEntityRuntime } from '../PrefabRoot';
|
|
4
5
|
import { FieldGroup, StringField } from './Input';
|
|
5
6
|
function ClickComponentEditor({ component, onUpdate }) {
|
|
6
7
|
return (_jsxs(FieldGroup, { children: [_jsx("div", { style: { fontSize: 12, opacity: 0.8 }, children: "Emits a game event in play mode when this entity is clicked." }), _jsx(StringField, { name: "eventName", label: "Emit Event", values: component.properties, onChange: onUpdate, placeholder: "click" })] }));
|
|
7
8
|
}
|
|
8
|
-
function ClickComponentView({ children,
|
|
9
|
+
function ClickComponentView({ children, properties }) {
|
|
9
10
|
const clickValid = useRef(false);
|
|
11
|
+
const { editMode, nodeId } = useEntityRuntime();
|
|
10
12
|
const eventName = (properties === null || properties === void 0 ? void 0 : properties.eventName) || 'click';
|
|
11
13
|
const emitClick = (event) => {
|
|
12
14
|
if (!nodeId)
|
|
@@ -27,6 +29,8 @@ function ClickComponentView({ children, editMode, nodeId, properties }) {
|
|
|
27
29
|
return (_jsx("group", { onPointerDown: (event) => {
|
|
28
30
|
event.stopPropagation();
|
|
29
31
|
clickValid.current = true;
|
|
32
|
+
}, onClick: (event) => {
|
|
33
|
+
event.stopPropagation();
|
|
30
34
|
}, onPointerMove: () => {
|
|
31
35
|
clickValid.current = false;
|
|
32
36
|
}, onPointerUp: (event) => {
|
|
@@ -4,6 +4,19 @@ export type AssetRef = {
|
|
|
4
4
|
type: "model" | "texture" | "sound";
|
|
5
5
|
path: string;
|
|
6
6
|
};
|
|
7
|
+
/** Props every component View receives from the renderer. */
|
|
8
|
+
export interface ComponentViewProps<P = Record<string, any>> {
|
|
9
|
+
/** This component's own data from the prefab JSON. */
|
|
10
|
+
properties: P;
|
|
11
|
+
/** Children to render (for wrapper / child-host components). */
|
|
12
|
+
children?: React.ReactNode;
|
|
13
|
+
/** Entity local position (passed to wrapper components like Physics). */
|
|
14
|
+
position?: [number, number, number];
|
|
15
|
+
/** Entity local rotation in radians (passed to wrapper components like Physics). */
|
|
16
|
+
rotation?: [number, number, number];
|
|
17
|
+
/** Entity local scale (passed to wrapper components like Physics). */
|
|
18
|
+
scale?: [number, number, number];
|
|
19
|
+
}
|
|
7
20
|
export interface Component {
|
|
8
21
|
name: string;
|
|
9
22
|
Editor: FC<{
|
|
@@ -13,9 +26,10 @@ export interface Component {
|
|
|
13
26
|
basePath?: string;
|
|
14
27
|
}>;
|
|
15
28
|
defaultProperties: any;
|
|
16
|
-
View?: FC<
|
|
29
|
+
View?: FC<ComponentViewProps>;
|
|
17
30
|
/** When true, this component wraps child entities (e.g. Physics wraps children in RigidBody). */
|
|
18
31
|
isWrapper?: boolean;
|
|
32
|
+
/** Declare which asset paths this component references (for asset loading). */
|
|
19
33
|
getAssetRefs?: (properties: Record<string, any>) => AssetRef[];
|
|
20
34
|
}
|
|
21
35
|
export declare function registerComponent(component: Component): void;
|
|
@@ -1,59 +1,116 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useHelper } from "@react-three/drei";
|
|
3
|
+
import { useRef, useEffect, useState } from "react";
|
|
3
4
|
import { useFrame } from "@react-three/fiber";
|
|
4
5
|
import { CameraHelper, Vector3 } from "three";
|
|
5
|
-
import {
|
|
6
|
-
|
|
6
|
+
import { useEntityRuntime } from "../PrefabRoot";
|
|
7
|
+
import { BooleanField, ColorField, NumberField, NumberInput, Vector3Input } from "./Input";
|
|
8
|
+
import { LightSection, ShadowBiasField, mergeWithDefaults } from "./lightUtils";
|
|
9
|
+
import { colors } from "../styles";
|
|
7
10
|
const directionalLightDefaults = {
|
|
8
11
|
color: '#ffffff',
|
|
9
12
|
intensity: 1,
|
|
10
|
-
castShadow:
|
|
11
|
-
shadowMapSize:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
castShadow: false,
|
|
14
|
+
shadowMapSize: 512,
|
|
15
|
+
shadowBias: 0,
|
|
16
|
+
shadowNormalBias: 0,
|
|
17
|
+
shadowAutoUpdate: true,
|
|
18
|
+
shadowCameraNear: 0.5,
|
|
19
|
+
shadowCameraFar: 500,
|
|
20
|
+
shadowCameraTop: 5,
|
|
21
|
+
shadowCameraBottom: -5,
|
|
22
|
+
shadowCameraLeft: -5,
|
|
23
|
+
shadowCameraRight: 5,
|
|
18
24
|
targetOffset: [0, -5, 0],
|
|
19
25
|
};
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
26
|
+
const frustumLabelStyle = {
|
|
27
|
+
fontSize: 10,
|
|
28
|
+
textTransform: 'uppercase',
|
|
29
|
+
letterSpacing: '0.06em',
|
|
30
|
+
color: colors.textMuted,
|
|
31
|
+
textAlign: 'center',
|
|
32
|
+
};
|
|
33
|
+
const frustumCellStyle = {
|
|
34
|
+
display: 'flex',
|
|
35
|
+
alignItems: 'center',
|
|
36
|
+
justifyContent: 'center',
|
|
37
|
+
};
|
|
38
|
+
const frustumInputStyle = {
|
|
39
|
+
width: 62,
|
|
40
|
+
minWidth: 62,
|
|
41
|
+
textAlign: 'center',
|
|
42
|
+
};
|
|
43
|
+
const centerLockButtonStyle = {
|
|
44
|
+
width: 34,
|
|
45
|
+
height: 34,
|
|
46
|
+
borderRadius: 999,
|
|
47
|
+
border: `1px solid ${colors.border}`,
|
|
48
|
+
background: colors.bgInput,
|
|
49
|
+
color: colors.textMuted,
|
|
50
|
+
cursor: 'pointer',
|
|
51
|
+
fontSize: 14,
|
|
52
|
+
lineHeight: 1,
|
|
53
|
+
padding: 0,
|
|
54
|
+
};
|
|
55
|
+
function areFrustumSidesLocked(values) {
|
|
56
|
+
const top = Math.abs(values.shadowCameraTop);
|
|
57
|
+
const bottom = Math.abs(values.shadowCameraBottom);
|
|
58
|
+
const left = Math.abs(values.shadowCameraLeft);
|
|
59
|
+
const right = Math.abs(values.shadowCameraRight);
|
|
60
|
+
return top === bottom && top === left && top === right;
|
|
61
|
+
}
|
|
62
|
+
function ShadowFrustumField({ values, onChange, }) {
|
|
63
|
+
const [locked, setLocked] = useState(() => areFrustumSidesLocked(values));
|
|
64
|
+
const updateSide = (side, nextValue) => {
|
|
65
|
+
if (!locked) {
|
|
66
|
+
onChange({ [side]: nextValue });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const magnitude = Math.abs(nextValue);
|
|
70
|
+
onChange({
|
|
71
|
+
shadowCameraTop: magnitude,
|
|
72
|
+
shadowCameraBottom: -magnitude,
|
|
73
|
+
shadowCameraLeft: -magnitude,
|
|
74
|
+
shadowCameraRight: magnitude,
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
const toggleLocked = () => {
|
|
78
|
+
setLocked(current => {
|
|
79
|
+
const nextLocked = !current;
|
|
80
|
+
if (nextLocked) {
|
|
81
|
+
const magnitude = Math.max(Math.abs(values.shadowCameraTop), Math.abs(values.shadowCameraBottom), Math.abs(values.shadowCameraLeft), Math.abs(values.shadowCameraRight));
|
|
82
|
+
onChange({
|
|
83
|
+
shadowCameraTop: magnitude,
|
|
84
|
+
shadowCameraBottom: -magnitude,
|
|
85
|
+
shadowCameraLeft: -magnitude,
|
|
86
|
+
shadowCameraRight: magnitude,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return nextLocked;
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 6 }, children: [_jsx("div", { style: Object.assign(Object.assign({}, frustumLabelStyle), { textAlign: 'left' }), children: "Shadow Frustum" }), _jsxs("div", { style: {
|
|
93
|
+
display: 'grid',
|
|
94
|
+
gridTemplateColumns: '1fr auto 1fr',
|
|
95
|
+
gridTemplateRows: 'auto auto auto',
|
|
96
|
+
gap: 8,
|
|
97
|
+
alignItems: 'center',
|
|
98
|
+
}, children: [_jsx("div", {}), _jsx("div", { style: frustumCellStyle, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'center' }, children: [_jsx("div", { style: frustumLabelStyle, children: "Top" }), _jsx(NumberInput, { value: values.shadowCameraTop, onChange: nextValue => updateSide('shadowCameraTop', nextValue), step: 0.5, style: frustumInputStyle })] }) }), _jsx("div", {}), _jsx("div", { style: frustumCellStyle, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'center' }, children: [_jsx("div", { style: frustumLabelStyle, children: "Left" }), _jsx(NumberInput, { value: values.shadowCameraLeft, onChange: nextValue => updateSide('shadowCameraLeft', nextValue), step: 0.5, style: frustumInputStyle })] }) }), _jsx("div", { style: frustumCellStyle, children: _jsx("button", { type: "button", onClick: toggleLocked, style: Object.assign(Object.assign({}, centerLockButtonStyle), { color: locked ? colors.accent : colors.textMuted, borderColor: locked ? colors.accentBorder : colors.border, background: locked ? colors.accentBg : colors.bgInput }), title: locked ? 'Frustum sides locked' : 'Frustum sides unlocked', children: locked ? '🔒' : '🔓' }) }), _jsx("div", { style: frustumCellStyle, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'center' }, children: [_jsx("div", { style: frustumLabelStyle, children: "Right" }), _jsx(NumberInput, { value: values.shadowCameraRight, onChange: nextValue => updateSide('shadowCameraRight', nextValue), step: 0.5, style: frustumInputStyle })] }) }), _jsx("div", {}), _jsx("div", { style: frustumCellStyle, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'center' }, children: [_jsx("div", { style: frustumLabelStyle, children: "Bottom" }), _jsx(NumberInput, { value: values.shadowCameraBottom, onChange: nextValue => updateSide('shadowCameraBottom', nextValue), step: 0.5, style: frustumInputStyle })] }) }), _jsx("div", {})] })] }));
|
|
99
|
+
}
|
|
44
100
|
function DirectionalLightComponentEditor({ component, onUpdate }) {
|
|
45
|
-
const values =
|
|
46
|
-
|
|
47
|
-
? directionalLightFields
|
|
48
|
-
: directionalLightFields.filter(field => field.name !== '_shadowCamera');
|
|
49
|
-
return (_jsx(FieldRenderer, { fields: fields, values: values, onChange: onUpdate }));
|
|
101
|
+
const values = mergeWithDefaults(directionalLightDefaults, component.properties);
|
|
102
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [_jsxs(LightSection, { title: "Light", children: [_jsx(ColorField, { name: "color", label: "Color", values: values, onChange: onUpdate }), _jsx(NumberField, { name: "intensity", label: "Intensity", values: values, onChange: onUpdate, min: 0, step: 0.1, fallback: 1 }), _jsx(Vector3Input, { label: "Target Offset", value: values.targetOffset, onChange: targetOffset => onUpdate({ targetOffset }), snap: 0.5 })] }), _jsxs(LightSection, { title: "Shadow", children: [_jsx(BooleanField, { name: "castShadow", label: "Cast Shadow", values: values, onChange: onUpdate, fallback: false }), values.castShadow ? (_jsxs(_Fragment, { children: [_jsx(BooleanField, { name: "shadowAutoUpdate", label: "Auto Update", values: values, onChange: onUpdate, fallback: true }), _jsx(NumberField, { name: "shadowMapSize", label: "Map Size", values: values, onChange: onUpdate, min: 128, step: 128, fallback: 512 }), _jsx(ShadowBiasField, { name: "shadowBias", label: "Bias", values: values, onChange: onUpdate, fallback: 0 }), _jsx(ShadowBiasField, { name: "shadowNormalBias", label: "Normal Bias", values: values, onChange: onUpdate, fallback: 0 }), _jsx(NumberField, { name: "shadowCameraNear", label: "Near", values: values, onChange: onUpdate, min: 0.001, step: 0.1, fallback: 0.5 }), _jsx(NumberField, { name: "shadowCameraFar", label: "Far", values: values, onChange: onUpdate, min: 0.1, step: 1, fallback: 500 }), _jsx(ShadowFrustumField, { values: values, onChange: onUpdate })] })) : null] })] }));
|
|
50
103
|
}
|
|
51
|
-
function DirectionalLightView({ properties, children
|
|
52
|
-
const
|
|
104
|
+
function DirectionalLightView({ properties, children }) {
|
|
105
|
+
const { editMode, isSelected } = useEntityRuntime();
|
|
106
|
+
const merged = mergeWithDefaults(directionalLightDefaults, properties);
|
|
53
107
|
const color = merged.color;
|
|
54
108
|
const intensity = merged.intensity;
|
|
55
109
|
const castShadow = merged.castShadow;
|
|
56
110
|
const shadowMapSize = merged.shadowMapSize;
|
|
111
|
+
const shadowBias = merged.shadowBias;
|
|
112
|
+
const shadowNormalBias = merged.shadowNormalBias;
|
|
113
|
+
const shadowAutoUpdate = merged.shadowAutoUpdate;
|
|
57
114
|
const shadowCameraNear = merged.shadowCameraNear;
|
|
58
115
|
const shadowCameraFar = merged.shadowCameraFar;
|
|
59
116
|
const shadowCameraTop = merged.shadowCameraTop;
|
|
@@ -63,31 +120,48 @@ function DirectionalLightView({ properties, children, editMode, isSelected }) {
|
|
|
63
120
|
const targetOffset = merged.targetOffset;
|
|
64
121
|
const directionalLightRef = useRef(null);
|
|
65
122
|
const targetRef = useRef(null);
|
|
123
|
+
const shadowCameraRef = useRef(null);
|
|
66
124
|
const [shadowCamera, setShadowCamera] = useState(null);
|
|
67
|
-
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
return () => {
|
|
70
|
-
shadowCameraHelper === null || shadowCameraHelper === void 0 ? void 0 : shadowCameraHelper.dispose();
|
|
71
|
-
};
|
|
72
|
-
}, [shadowCameraHelper]);
|
|
125
|
+
useHelper(editMode && isSelected && castShadow ? shadowCameraRef : null, CameraHelper);
|
|
73
126
|
// Use a local target object so node transforms rotate the light direction naturally.
|
|
74
127
|
useEffect(() => {
|
|
75
128
|
if (directionalLightRef.current && targetRef.current) {
|
|
76
129
|
directionalLightRef.current.target = targetRef.current;
|
|
77
|
-
|
|
130
|
+
const nextShadowCamera = directionalLightRef.current.shadow.camera;
|
|
131
|
+
shadowCameraRef.current = nextShadowCamera;
|
|
132
|
+
setShadowCamera(nextShadowCamera);
|
|
78
133
|
}
|
|
79
134
|
}, []);
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
var _a;
|
|
137
|
+
const shadow = (_a = directionalLightRef.current) === null || _a === void 0 ? void 0 : _a.shadow;
|
|
138
|
+
if (!shadow)
|
|
139
|
+
return;
|
|
140
|
+
shadow.needsUpdate = true;
|
|
141
|
+
shadow.camera.updateProjectionMatrix();
|
|
142
|
+
}, [
|
|
143
|
+
castShadow,
|
|
144
|
+
shadowMapSize,
|
|
145
|
+
shadowBias,
|
|
146
|
+
shadowNormalBias,
|
|
147
|
+
shadowAutoUpdate,
|
|
148
|
+
shadowCameraNear,
|
|
149
|
+
shadowCameraFar,
|
|
150
|
+
shadowCameraTop,
|
|
151
|
+
shadowCameraBottom,
|
|
152
|
+
shadowCameraLeft,
|
|
153
|
+
shadowCameraRight,
|
|
154
|
+
]);
|
|
80
155
|
useFrame(() => {
|
|
81
156
|
if (!directionalLightRef.current || !targetRef.current)
|
|
82
157
|
return;
|
|
83
158
|
directionalLightRef.current.target.updateMatrixWorld();
|
|
84
|
-
if (shadowCamera &&
|
|
159
|
+
if (shadowCamera && castShadow) {
|
|
85
160
|
shadowCamera.updateProjectionMatrix();
|
|
86
161
|
shadowCamera.updateMatrixWorld();
|
|
87
|
-
shadowCameraHelper.update();
|
|
88
162
|
}
|
|
89
163
|
});
|
|
90
|
-
return (_jsxs(_Fragment, { children: [_jsx("directionalLight", { ref: directionalLightRef, color: color, intensity: intensity, castShadow: castShadow, "shadow-mapSize-width": shadowMapSize, "shadow-mapSize-height": shadowMapSize, "shadow-camera-near": shadowCameraNear, "shadow-camera-far": shadowCameraFar, "shadow-camera-top": shadowCameraTop, "shadow-camera-bottom": shadowCameraBottom, "shadow-camera-left": shadowCameraLeft, "shadow-camera-right": shadowCameraRight, "shadow-bias":
|
|
164
|
+
return (_jsxs(_Fragment, { children: [_jsx("directionalLight", { ref: directionalLightRef, color: color, intensity: intensity, castShadow: castShadow, "shadow-mapSize-width": shadowMapSize, "shadow-mapSize-height": shadowMapSize, "shadow-camera-near": shadowCameraNear, "shadow-camera-far": shadowCameraFar, "shadow-camera-top": shadowCameraTop, "shadow-camera-bottom": shadowCameraBottom, "shadow-camera-left": shadowCameraLeft, "shadow-camera-right": shadowCameraRight, "shadow-bias": shadowBias, "shadow-normalBias": shadowNormalBias, "shadow-autoUpdate": shadowAutoUpdate }), _jsx("object3D", { ref: targetRef, position: targetOffset }), editMode && isSelected && (_jsxs(_Fragment, { children: [_jsxs("mesh", { children: [_jsx("sphereGeometry", { args: [0.3, 8, 6] }), _jsx("meshBasicMaterial", { color: color, wireframe: true })] }), _jsxs("mesh", { position: targetOffset, children: [_jsx("sphereGeometry", { args: [0.2, 8, 6] }), _jsx("meshBasicMaterial", { color: color, wireframe: true, opacity: 0.5, transparent: true })] }), _jsxs("line", { children: [_jsx("bufferGeometry", { onUpdate: (geo) => {
|
|
91
165
|
const points = [
|
|
92
166
|
new Vector3(0, 0, 0),
|
|
93
167
|
new Vector3(targetOffset[0], targetOffset[1], targetOffset[2])
|
|
@@ -99,6 +173,6 @@ const DirectionalLightComponent = {
|
|
|
99
173
|
name: 'DirectionalLight',
|
|
100
174
|
Editor: DirectionalLightComponentEditor,
|
|
101
175
|
View: DirectionalLightView,
|
|
102
|
-
defaultProperties:
|
|
176
|
+
defaultProperties: {}
|
|
103
177
|
};
|
|
104
178
|
export default DirectionalLightComponent;
|