react-three-game 0.0.99 → 0.0.100
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/tools/prefabeditor/components/CameraComponent.js +1 -14
- package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +31 -119
- package/dist/tools/prefabeditor/components/Input.d.ts +1 -0
- package/dist/tools/prefabeditor/components/PointLightComponent.js +19 -25
- package/dist/tools/prefabeditor/components/SpotLightComponent.js +27 -42
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { OrthographicCamera, PerspectiveCamera, useHelper } from '@react-three/drei';
|
|
3
3
|
import { useRef } from 'react';
|
|
4
4
|
import { CameraHelper } from 'three';
|
|
5
|
-
import {
|
|
5
|
+
import { useThree } from '@react-three/fiber';
|
|
6
6
|
import { useNode } from '../assetRuntime';
|
|
7
7
|
import { FieldGroup, NumberField, SelectField } from './Input';
|
|
8
8
|
const CAMERA_PROJECTION_OPTIONS = [
|
|
@@ -46,19 +46,6 @@ function CameraComponentView({ properties, children }) {
|
|
|
46
46
|
? { current: activeCamera }
|
|
47
47
|
: null;
|
|
48
48
|
useHelper(helperTarget, CameraHelper);
|
|
49
|
-
useFrame(() => {
|
|
50
|
-
if (!editMode || !isSelected)
|
|
51
|
-
return;
|
|
52
|
-
if (projection === 'orthographic' && orthographicCameraRef.current) {
|
|
53
|
-
orthographicCameraRef.current.updateProjectionMatrix();
|
|
54
|
-
orthographicCameraRef.current.updateMatrixWorld();
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
if (perspectiveCameraRef.current) {
|
|
58
|
-
perspectiveCameraRef.current.updateProjectionMatrix();
|
|
59
|
-
perspectiveCameraRef.current.updateMatrixWorld();
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
49
|
const helperContent = 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;
|
|
63
50
|
if (projection === 'orthographic') {
|
|
64
51
|
return (_jsxs(OrthographicCamera, { ref: orthographicCameraRef, makeDefault: !editMode, near: near, zoom: zoom, far: far, left: -halfWidth, right: halfWidth, top: halfHeight, bottom: -halfHeight, children: [helperContent, children] }));
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useHelper } from "@react-three/drei";
|
|
3
|
-
import {
|
|
4
|
-
import { useFrame } from "@react-three/fiber";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
5
4
|
import { CameraHelper } from "three";
|
|
6
5
|
import { useNode } from "../assetRuntime";
|
|
7
6
|
import { BooleanField, ColorField, NumberField, NumberInput, Vector3Input } from "./Input";
|
|
@@ -23,141 +22,54 @@ const directionalLightDefaults = {
|
|
|
23
22
|
shadowCameraRight: 5,
|
|
24
23
|
targetOffset: [0, -5, 0],
|
|
25
24
|
};
|
|
26
|
-
|
|
27
|
-
|
|
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: 0,
|
|
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", {})] })] }));
|
|
25
|
+
function ShadowFrustumField({ values, onChange }) {
|
|
26
|
+
// Minimal, no lock UI for simplicity (can add back if needed)
|
|
27
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 6 }, children: [_jsx("div", { style: { fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.06em', color: colors.textMuted, textAlign: 'left' }, children: "Shadow Frustum" }), _jsxs("div", { style: { display: 'flex', gap: 8 }, children: [_jsx(NumberInput, { value: values.shadowCameraTop, onChange: v => onChange({ shadowCameraTop: v }), step: 0.5, style: { width: 62, minWidth: 62, textAlign: 'center' }, label: "Top" }), _jsx(NumberInput, { value: values.shadowCameraBottom, onChange: v => onChange({ shadowCameraBottom: v }), step: 0.5, style: { width: 62, minWidth: 62, textAlign: 'center' }, label: "Bottom" }), _jsx(NumberInput, { value: values.shadowCameraLeft, onChange: v => onChange({ shadowCameraLeft: v }), step: 0.5, style: { width: 62, minWidth: 62, textAlign: 'center' }, label: "Left" }), _jsx(NumberInput, { value: values.shadowCameraRight, onChange: v => onChange({ shadowCameraRight: v }), step: 0.5, style: { width: 62, minWidth: 62, textAlign: 'center' }, label: "Right" })] })] }));
|
|
99
28
|
}
|
|
100
29
|
function DirectionalLightComponentEditor({ component, onUpdate }) {
|
|
101
30
|
const values = mergeWithDefaults(directionalLightDefaults, component.properties);
|
|
102
31
|
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] })] }));
|
|
103
32
|
}
|
|
104
33
|
function DirectionalLightView({ properties, children }) {
|
|
34
|
+
var _a;
|
|
105
35
|
const { editMode, isSelected } = useNode();
|
|
106
36
|
const merged = mergeWithDefaults(directionalLightDefaults, properties);
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
37
|
+
const lightProps = {
|
|
38
|
+
color: merged.color,
|
|
39
|
+
intensity: merged.intensity,
|
|
40
|
+
castShadow: merged.castShadow,
|
|
41
|
+
"shadow-mapSize-width": merged.shadowMapSize,
|
|
42
|
+
"shadow-mapSize-height": merged.shadowMapSize,
|
|
43
|
+
"shadow-bias": merged.shadowBias,
|
|
44
|
+
"shadow-normalBias": merged.shadowNormalBias,
|
|
45
|
+
"shadow-autoUpdate": merged.shadowAutoUpdate,
|
|
46
|
+
"shadow-camera-near": merged.shadowCameraNear,
|
|
47
|
+
"shadow-camera-far": merged.shadowCameraFar,
|
|
48
|
+
"shadow-camera-top": merged.shadowCameraTop,
|
|
49
|
+
"shadow-camera-bottom": merged.shadowCameraBottom,
|
|
50
|
+
"shadow-camera-left": merged.shadowCameraLeft,
|
|
51
|
+
"shadow-camera-right": merged.shadowCameraRight,
|
|
52
|
+
};
|
|
121
53
|
const directionalLightRef = useRef(null);
|
|
122
54
|
const targetRef = useRef(null);
|
|
123
55
|
const shadowCameraRef = useRef(null);
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
: null;
|
|
56
|
+
// Show CameraHelper only in edit mode, selected, and castShadow
|
|
57
|
+
const showHelper = editMode && isSelected && merged.castShadow;
|
|
58
|
+
const helperTarget = showHelper && shadowCameraRef.current ? { current: shadowCameraRef.current } : null;
|
|
128
59
|
useHelper(helperTarget, CameraHelper);
|
|
129
|
-
// Use a local target object so node transforms rotate the light direction naturally.
|
|
130
|
-
useEffect(() => {
|
|
131
|
-
if (directionalLightRef.current && targetRef.current) {
|
|
132
|
-
directionalLightRef.current.target = targetRef.current;
|
|
133
|
-
const nextShadowCamera = directionalLightRef.current.shadow.camera;
|
|
134
|
-
shadowCameraRef.current = nextShadowCamera;
|
|
135
|
-
setShadowCamera(castShadow ? nextShadowCamera : null);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
60
|
useEffect(() => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (!shadow)
|
|
142
|
-
return;
|
|
143
|
-
shadow.needsUpdate = true;
|
|
144
|
-
shadow.camera.updateProjectionMatrix();
|
|
145
|
-
});
|
|
146
|
-
useFrame(() => {
|
|
147
|
-
if (!directionalLightRef.current || !targetRef.current)
|
|
148
|
-
return;
|
|
149
|
-
directionalLightRef.current.target.updateMatrixWorld();
|
|
150
|
-
if (shadowCamera && castShadow) {
|
|
151
|
-
shadowCamera.updateProjectionMatrix();
|
|
152
|
-
shadowCamera.updateMatrixWorld();
|
|
61
|
+
if (directionalLightRef.current) {
|
|
62
|
+
shadowCameraRef.current = directionalLightRef.current.shadow.camera;
|
|
153
63
|
}
|
|
154
|
-
});
|
|
155
|
-
return (_jsxs(
|
|
64
|
+
}, []);
|
|
65
|
+
return (_jsxs("group", { children: [_jsxs("directionalLight", Object.assign({ ref: directionalLightRef }, lightProps, {
|
|
66
|
+
// Attach the target object
|
|
67
|
+
target: (_a = targetRef.current) !== null && _a !== void 0 ? _a : undefined, children: [children, editMode && isSelected && (_jsxs(_Fragment, { children: [_jsxs("mesh", { children: [_jsx("sphereGeometry", { args: [0.3, 8, 6] }), _jsx("meshBasicMaterial", { color: merged.color, wireframe: true })] }), _jsxs("mesh", { position: merged.targetOffset, children: [_jsx("sphereGeometry", { args: [0.2, 8, 6] }), _jsx("meshBasicMaterial", { color: merged.color, wireframe: true, opacity: 0.5, transparent: true })] }), _jsxs("line", { children: [_jsx("bufferGeometry", { children: _jsx("bufferAttribute", { attach: "attributes-position", args: [new Float32Array([0, 0, 0, merged.targetOffset[0], merged.targetOffset[1], merged.targetOffset[2]]), 3] }) }), _jsx("lineBasicMaterial", { color: merged.color, opacity: 0.6, transparent: true })] })] }))] })), _jsx("object3D", { ref: targetRef, position: merged.targetOffset })] }));
|
|
156
68
|
}
|
|
157
69
|
const DirectionalLightComponent = {
|
|
158
70
|
name: 'DirectionalLight',
|
|
159
71
|
Editor: DirectionalLightComponentEditor,
|
|
160
72
|
View: DirectionalLightView,
|
|
161
|
-
defaultProperties: {}
|
|
73
|
+
defaultProperties: {},
|
|
162
74
|
};
|
|
163
75
|
export default DirectionalLightComponent;
|
|
@@ -57,6 +57,7 @@ interface InputProps {
|
|
|
57
57
|
min?: number;
|
|
58
58
|
max?: number;
|
|
59
59
|
style?: React.CSSProperties;
|
|
60
|
+
label?: string;
|
|
60
61
|
}
|
|
61
62
|
export declare function NumberInput({ value, onChange, step, min, max, style }: InputProps): import("react/jsx-runtime").JSX.Element;
|
|
62
63
|
export declare function Label({ children }: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useRef } from 'react';
|
|
3
3
|
import { useHelper } from '@react-three/drei';
|
|
4
4
|
import { PointLightHelper } from 'three';
|
|
5
5
|
import { useNode } from '../assetRuntime';
|
|
@@ -25,31 +25,25 @@ function PointLightComponentEditor({ component, onUpdate }) {
|
|
|
25
25
|
function PointLightView({ properties, children }) {
|
|
26
26
|
const { editMode, isSelected } = useNode();
|
|
27
27
|
const merged = mergeWithDefaults(pointLightDefaults, properties);
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
28
|
+
const lightProps = {
|
|
29
|
+
color: merged.color,
|
|
30
|
+
intensity: merged.intensity,
|
|
31
|
+
distance: merged.distance,
|
|
32
|
+
decay: merged.decay,
|
|
33
|
+
castShadow: merged.castShadow,
|
|
34
|
+
"shadow-mapSize-width": merged.shadowMapSize,
|
|
35
|
+
"shadow-mapSize-height": merged.shadowMapSize,
|
|
36
|
+
"shadow-bias": merged.shadowBias,
|
|
37
|
+
"shadow-normalBias": merged.shadowNormalBias,
|
|
38
|
+
"shadow-autoUpdate": merged.shadowAutoUpdate,
|
|
39
|
+
"shadow-camera-near": merged.shadowCameraNear,
|
|
40
|
+
"shadow-camera-far": merged.shadowCameraFar,
|
|
41
|
+
};
|
|
39
42
|
const lightRef = useRef(null);
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
var _a;
|
|
46
|
-
const shadow = (_a = lightRef.current) === null || _a === void 0 ? void 0 : _a.shadow;
|
|
47
|
-
if (!shadow)
|
|
48
|
-
return;
|
|
49
|
-
shadow.needsUpdate = true;
|
|
50
|
-
shadow.camera.updateProjectionMatrix();
|
|
51
|
-
});
|
|
52
|
-
return (_jsxs(_Fragment, { children: [_jsx("pointLight", { ref: lightRef, color: color, intensity: intensity, distance: distance, decay: decay, castShadow: castShadow, "shadow-mapSize-width": shadowMapSize, "shadow-mapSize-height": shadowMapSize, "shadow-bias": shadowBias, "shadow-normalBias": shadowNormalBias, "shadow-autoUpdate": shadowAutoUpdate, "shadow-camera-near": shadowCameraNear, "shadow-camera-far": shadowCameraFar }), editMode && isSelected ? (_jsxs("mesh", { children: [_jsx("sphereGeometry", { args: [0.2, 10, 8] }), _jsx("meshBasicMaterial", { color: color, wireframe: true })] })) : null, children] }));
|
|
43
|
+
const showHelper = editMode && isSelected && lightRef.current;
|
|
44
|
+
const helperTarget = showHelper && lightRef.current ? { current: lightRef.current } : null;
|
|
45
|
+
useHelper(helperTarget, PointLightHelper, 0.5);
|
|
46
|
+
return (_jsx("group", { children: _jsxs("pointLight", Object.assign({ ref: lightRef }, lightProps, { children: [children, editMode && isSelected && (_jsxs("mesh", { children: [_jsx("sphereGeometry", { args: [0.2, 10, 8] }), _jsx("meshBasicMaterial", { color: merged.color, wireframe: true })] }))] })) }));
|
|
53
47
|
}
|
|
54
48
|
const PointLightComponent = {
|
|
55
49
|
name: 'PointLight',
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { assetRef, assetRefs } from "./ComponentRegistry";
|
|
3
3
|
import { useHelper } from "@react-three/drei";
|
|
4
|
-
import { useRef
|
|
4
|
+
import { useRef } from "react";
|
|
5
5
|
import { BooleanField, ColorField, Label, NumberField, Vector3Input } from "./Input";
|
|
6
6
|
import { SpotLightHelper } from "three";
|
|
7
7
|
import { useAssetRuntime, useNode } from "../assetRuntime";
|
|
8
|
-
import { useFrame } from "@react-three/fiber";
|
|
9
8
|
import { TexturePicker } from "../../assetviewer/page";
|
|
10
9
|
import { LightSection, ShadowBiasField, mergeWithDefaults } from "./lightUtils";
|
|
11
10
|
const spotLightDefaults = {
|
|
@@ -30,51 +29,37 @@ function SpotLightComponentEditor({ component, onUpdate, basePath = "" }) {
|
|
|
30
29
|
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(NumberField, { name: "angle", label: "Angle", values: values, onChange: onUpdate, min: 0, max: Math.PI / 2, step: 0.05, fallback: Math.PI / 3 }), _jsx(NumberField, { name: "penumbra", label: "Penumbra", values: values, onChange: onUpdate, min: 0, max: 1, step: 0.05, fallback: 0 }), _jsx(NumberField, { name: "distance", label: "Distance", values: values, onChange: onUpdate, min: 0, step: 1, fallback: 0 }), _jsx(NumberField, { name: "decay", label: "Decay", values: values, onChange: onUpdate, min: 0, step: 0.1, fallback: 2 }), _jsx(Vector3Input, { label: "Target Offset", value: values.targetOffset, onChange: targetOffset => onUpdate({ targetOffset }), snap: 0.5 }), _jsxs("div", { children: [_jsx(Label, { children: "Texture Map" }), _jsx(TexturePicker, { value: values.map, onChange: (map) => onUpdate({ map }), basePath: basePath })] })] }), _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 })] })) : null] })] }));
|
|
31
30
|
}
|
|
32
31
|
function SpotLightView({ properties, children }) {
|
|
33
|
-
var _a;
|
|
32
|
+
var _a, _b;
|
|
34
33
|
const { getTexture } = useAssetRuntime();
|
|
35
34
|
const { editMode, isSelected } = useNode();
|
|
36
35
|
const merged = mergeWithDefaults(spotLightDefaults, properties);
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
36
|
+
const textureMap = merged.map
|
|
37
|
+
? (_a = getTexture(merged.map)) !== null && _a !== void 0 ? _a : undefined
|
|
38
|
+
: undefined;
|
|
39
|
+
const lightProps = {
|
|
40
|
+
color: merged.color,
|
|
41
|
+
intensity: merged.intensity,
|
|
42
|
+
angle: merged.angle,
|
|
43
|
+
penumbra: merged.penumbra,
|
|
44
|
+
distance: merged.distance,
|
|
45
|
+
decay: merged.decay,
|
|
46
|
+
castShadow: merged.castShadow,
|
|
47
|
+
map: textureMap,
|
|
48
|
+
// mapped props
|
|
49
|
+
"shadow-mapSize-width": merged.shadowMapSize,
|
|
50
|
+
"shadow-mapSize-height": merged.shadowMapSize,
|
|
51
|
+
"shadow-bias": merged.shadowBias,
|
|
52
|
+
"shadow-normalBias": merged.shadowNormalBias,
|
|
53
|
+
"shadow-autoUpdate": merged.shadowAutoUpdate,
|
|
54
|
+
"shadow-camera-near": merged.shadowCameraNear,
|
|
55
|
+
"shadow-camera-far": merged.shadowCameraFar,
|
|
56
|
+
};
|
|
52
57
|
const spotLightRef = useRef(null);
|
|
53
58
|
const targetRef = useRef(null);
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
if (spotLightRef.current && targetRef.current) {
|
|
60
|
-
spotLightRef.current.target = targetRef.current;
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
useEffect(() => {
|
|
64
|
-
var _a;
|
|
65
|
-
const shadow = (_a = spotLightRef.current) === null || _a === void 0 ? void 0 : _a.shadow;
|
|
66
|
-
if (!shadow)
|
|
67
|
-
return;
|
|
68
|
-
shadow.needsUpdate = true;
|
|
69
|
-
shadow.camera.updateProjectionMatrix();
|
|
70
|
-
});
|
|
71
|
-
useFrame(() => {
|
|
72
|
-
var _a;
|
|
73
|
-
if ((_a = spotLightRef.current) === null || _a === void 0 ? void 0 : _a.target) {
|
|
74
|
-
spotLightRef.current.target.updateMatrixWorld();
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
return (_jsxs(_Fragment, { children: [_jsx("spotLight", { ref: spotLightRef, color: color, intensity: intensity, angle: angle, penumbra: penumbra, distance: distance, decay: decay, map: textureMap, castShadow: castShadow, "shadow-mapSize-width": shadowMapSize, "shadow-mapSize-height": shadowMapSize, "shadow-bias": shadowBias, "shadow-normalBias": shadowNormalBias, "shadow-autoUpdate": shadowAutoUpdate, "shadow-camera-near": shadowCameraNear, "shadow-camera-far": shadowCameraFar }), _jsx("object3D", { ref: targetRef, position: targetOffset }), editMode && isSelected && (_jsxs(_Fragment, { children: [_jsxs("mesh", { children: [_jsx("sphereGeometry", { args: [0.2, 8, 6] }), _jsx("meshBasicMaterial", { color: color, wireframe: true })] }), _jsxs("mesh", { position: targetOffset, children: [_jsx("sphereGeometry", { args: [0.15, 8, 6] }), _jsx("meshBasicMaterial", { color: color, wireframe: true, opacity: 0.5, transparent: true })] })] })), children] }));
|
|
59
|
+
const showHelper = editMode && isSelected;
|
|
60
|
+
const helperTarget = showHelper && spotLightRef.current ? { current: spotLightRef.current } : null;
|
|
61
|
+
useHelper(helperTarget, SpotLightHelper);
|
|
62
|
+
return (_jsxs("group", { children: [_jsxs("spotLight", Object.assign({ ref: spotLightRef }, lightProps, { target: (_b = targetRef.current) !== null && _b !== void 0 ? _b : undefined, children: [showHelper && (_jsxs(_Fragment, { children: [_jsxs("mesh", { children: [_jsx("sphereGeometry", { args: [0.2, 8, 6] }), _jsx("meshBasicMaterial", { color: merged.color, wireframe: true })] }), _jsxs("mesh", { position: merged.targetOffset, children: [_jsx("sphereGeometry", { args: [0.15, 8, 6] }), _jsx("meshBasicMaterial", { color: merged.color, wireframe: true, opacity: 0.5, transparent: true })] })] })), children] })), _jsx("object3D", { ref: targetRef, position: merged.targetOffset })] }));
|
|
78
63
|
}
|
|
79
64
|
const SpotLightComponent = {
|
|
80
65
|
name: 'SpotLight',
|