react-three-game 0.0.84 → 0.0.85
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/README.md +23 -1
- package/dist/tools/prefabeditor/PrefabRoot.js +5 -4
- package/dist/tools/prefabeditor/components/BufferGeometryComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/BufferGeometryComponent.js +96 -0
- package/dist/tools/prefabeditor/components/MaterialComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/MaterialComponent.js +48 -17
- package/dist/tools/prefabeditor/components/index.js +8 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -113,13 +113,35 @@ That means a saved scene is just a prefab, and the same prefab can be:
|
|
|
113
113
|
`PrefabRoot` keeps the rendering model narrow and compositional:
|
|
114
114
|
|
|
115
115
|
* `Transform` is the renderer-owned outer transform
|
|
116
|
-
* `Geometry` + `Material` become the primary mesh content
|
|
116
|
+
* `Geometry` or `BufferGeometry` + `Material` become the primary mesh content
|
|
117
117
|
* non-instanced `Model` becomes the node's primary content
|
|
118
118
|
* `Physics` is a renderer-owned outer wrapper
|
|
119
119
|
* every other component `View` wraps the current subtree
|
|
120
120
|
|
|
121
121
|
Custom component `View`s use normal React Three Fiber composition with `children`.
|
|
122
122
|
|
|
123
|
+
For agent-authored custom meshes, use `BufferGeometry` with flat numeric arrays:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"id": "triangle",
|
|
128
|
+
"components": {
|
|
129
|
+
"bufferGeometry": {
|
|
130
|
+
"type": "BufferGeometry",
|
|
131
|
+
"properties": {
|
|
132
|
+
"positions": [0, 0, 0, 1, 0, 0, 0, 1, 0],
|
|
133
|
+
"indices": [0, 1, 2],
|
|
134
|
+
"computeVertexNormals": true
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"material": {
|
|
138
|
+
"type": "Material",
|
|
139
|
+
"properties": { "color": "#ff8844" }
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
123
145
|
## Prefab Format
|
|
124
146
|
|
|
125
147
|
```ts
|
|
@@ -292,6 +292,7 @@ function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, load
|
|
|
292
292
|
}
|
|
293
293
|
function isRendererHandledComponent(componentType) {
|
|
294
294
|
return componentType === "Transform"
|
|
295
|
+
|| componentType === "BufferGeometry"
|
|
295
296
|
|| componentType === "Geometry"
|
|
296
297
|
|| componentType === "Material"
|
|
297
298
|
|| componentType === "Physics"
|
|
@@ -387,21 +388,21 @@ function renderCompositionNode(gameObject, ctx, childNodes) {
|
|
|
387
388
|
return applyNodeComposition(gameObject, _jsxs(_Fragment, { children: [primaryContent, childNodes] }));
|
|
388
389
|
}
|
|
389
390
|
function renderNodePrimaryContent(gameObject, ctx) {
|
|
390
|
-
var _a, _b;
|
|
391
|
-
const geometry = findComponent(gameObject, "Geometry");
|
|
391
|
+
var _a, _b, _c;
|
|
392
|
+
const geometry = (_a = findComponent(gameObject, "BufferGeometry")) !== null && _a !== void 0 ? _a : findComponent(gameObject, "Geometry");
|
|
392
393
|
const material = findComponent(gameObject, "Material");
|
|
393
394
|
const model = findComponent(gameObject, "Model");
|
|
394
395
|
const geometryDef = geometry && getComponentDef(geometry.type);
|
|
395
396
|
const materialDef = material && getComponentDef(material.type);
|
|
396
397
|
const modelDef = model && getComponentDef(model.type);
|
|
397
|
-
const geometryProperties = (
|
|
398
|
+
const geometryProperties = (_b = geometry === null || geometry === void 0 ? void 0 : geometry.properties) !== null && _b !== void 0 ? _b : {};
|
|
398
399
|
const meshVisible = geometryProperties.visible !== false;
|
|
399
400
|
const meshCastShadow = meshVisible && geometryProperties.castShadow !== false;
|
|
400
401
|
const meshReceiveShadow = meshVisible && geometryProperties.receiveShadow !== false;
|
|
401
402
|
if ((geometry === null || geometry === void 0 ? void 0 : geometry.type) && (geometryDef === null || geometryDef === void 0 ? void 0 : geometryDef.View)) {
|
|
402
403
|
return (_jsxs("mesh", { visible: meshVisible, castShadow: meshCastShadow, receiveShadow: meshReceiveShadow, children: [_jsx(geometryDef.View, { properties: geometry.properties }), material && (materialDef === null || materialDef === void 0 ? void 0 : materialDef.View) && (_jsx(materialDef.View, { properties: material.properties }, "material"))] }));
|
|
403
404
|
}
|
|
404
|
-
if ((model === null || model === void 0 ? void 0 : model.type) && (modelDef === null || modelDef === void 0 ? void 0 : modelDef.View) && !((
|
|
405
|
+
if ((model === null || model === void 0 ? void 0 : model.type) && (modelDef === null || modelDef === void 0 ? void 0 : modelDef.View) && !((_c = model.properties) === null || _c === void 0 ? void 0 : _c.instanced) && isNodeReady(gameObject, ctx.loadedModels)) {
|
|
405
406
|
return _jsx(modelDef.View, { properties: model.properties });
|
|
406
407
|
}
|
|
407
408
|
return null;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { BooleanField, FieldGroup } from "./Input";
|
|
3
|
+
const DEFAULT_TRIANGLE_POSITIONS = [
|
|
4
|
+
0, 0, 0,
|
|
5
|
+
1, 0, 0,
|
|
6
|
+
0, 1, 0,
|
|
7
|
+
];
|
|
8
|
+
const DEFAULT_TRIANGLE_INDICES = [0, 1, 2];
|
|
9
|
+
const DEFAULT_TRIANGLE_UVS = [
|
|
10
|
+
0, 0,
|
|
11
|
+
1, 0,
|
|
12
|
+
0, 1,
|
|
13
|
+
];
|
|
14
|
+
function isFiniteNumberArray(value) {
|
|
15
|
+
return Array.isArray(value) && value.every(entry => typeof entry === 'number' && Number.isFinite(entry));
|
|
16
|
+
}
|
|
17
|
+
function normalizeNumberArray(value, fallback) {
|
|
18
|
+
return isFiniteNumberArray(value) ? value : fallback;
|
|
19
|
+
}
|
|
20
|
+
function toAttributeText(value, fallback) {
|
|
21
|
+
return JSON.stringify(normalizeNumberArray(value, fallback));
|
|
22
|
+
}
|
|
23
|
+
function parseArrayInput(raw) {
|
|
24
|
+
const trimmed = raw.trim();
|
|
25
|
+
if (!trimmed)
|
|
26
|
+
return [];
|
|
27
|
+
const parsed = JSON.parse(trimmed);
|
|
28
|
+
if (!isFiniteNumberArray(parsed)) {
|
|
29
|
+
throw new Error('Expected a JSON array of numbers');
|
|
30
|
+
}
|
|
31
|
+
return parsed;
|
|
32
|
+
}
|
|
33
|
+
function getIndexArray(indices) {
|
|
34
|
+
if (indices.length === 0)
|
|
35
|
+
return null;
|
|
36
|
+
const maxIndex = Math.max(...indices);
|
|
37
|
+
return maxIndex > 65535 ? new Uint32Array(indices) : new Uint16Array(indices);
|
|
38
|
+
}
|
|
39
|
+
function BufferArrayField({ label, value, fallback, onChange, rows = 4, }) {
|
|
40
|
+
return (_jsxs("label", { style: { display: 'grid', gap: 4 }, children: [_jsx("span", { style: { fontSize: '10px', color: '#888', textTransform: 'uppercase', letterSpacing: '0.05em', fontWeight: 500 }, children: label }), _jsx("textarea", { rows: rows, spellCheck: false, defaultValue: toAttributeText(value, fallback), onBlur: (event) => {
|
|
41
|
+
try {
|
|
42
|
+
onChange(parseArrayInput(event.target.value));
|
|
43
|
+
event.target.setCustomValidity('');
|
|
44
|
+
}
|
|
45
|
+
catch (_a) {
|
|
46
|
+
event.target.setCustomValidity('Expected a JSON array of numbers');
|
|
47
|
+
event.target.reportValidity();
|
|
48
|
+
}
|
|
49
|
+
}, style: {
|
|
50
|
+
width: '100%',
|
|
51
|
+
backgroundColor: '#171717',
|
|
52
|
+
border: '1px solid #333',
|
|
53
|
+
padding: '6px 8px',
|
|
54
|
+
fontSize: '11px',
|
|
55
|
+
color: '#eee',
|
|
56
|
+
fontFamily: 'monospace',
|
|
57
|
+
outline: 'none',
|
|
58
|
+
borderRadius: 3,
|
|
59
|
+
resize: 'vertical',
|
|
60
|
+
boxSizing: 'border-box',
|
|
61
|
+
} })] }));
|
|
62
|
+
}
|
|
63
|
+
function BufferGeometryComponentEditor({ component, onUpdate, }) {
|
|
64
|
+
var _a;
|
|
65
|
+
const properties = (_a = component.properties) !== null && _a !== void 0 ? _a : {};
|
|
66
|
+
return (_jsxs(FieldGroup, { children: [_jsx(BufferArrayField, { label: "Positions", value: properties.positions, fallback: DEFAULT_TRIANGLE_POSITIONS, rows: 5, onChange: (positions) => onUpdate({ positions }) }), _jsx(BufferArrayField, { label: "Indices", value: properties.indices, fallback: DEFAULT_TRIANGLE_INDICES, onChange: (indices) => onUpdate({ indices }) }), _jsx(BufferArrayField, { label: "Normals", value: properties.normals, fallback: [], onChange: (normals) => onUpdate({ normals }) }), _jsx(BufferArrayField, { label: "UVs", value: properties.uvs, fallback: DEFAULT_TRIANGLE_UVS, onChange: (uvs) => onUpdate({ uvs }) }), _jsx(BooleanField, { name: "computeVertexNormals", label: "Compute Normals", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "visible", label: "Visible", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "castShadow", label: "Cast Shadow", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "receiveShadow", label: "Receive Shadow", values: properties, onChange: onUpdate, fallback: true })] }));
|
|
67
|
+
}
|
|
68
|
+
function BufferGeometryComponentView({ properties }) {
|
|
69
|
+
const positions = normalizeNumberArray(properties.positions, DEFAULT_TRIANGLE_POSITIONS);
|
|
70
|
+
const indices = normalizeNumberArray(properties.indices, DEFAULT_TRIANGLE_INDICES);
|
|
71
|
+
const normals = normalizeNumberArray(properties.normals, []);
|
|
72
|
+
const uvs = normalizeNumberArray(properties.uvs, DEFAULT_TRIANGLE_UVS);
|
|
73
|
+
const indexArray = getIndexArray(indices);
|
|
74
|
+
const hasNormals = normals.length >= 3 && normals.length % 3 === 0;
|
|
75
|
+
const hasUvs = uvs.length >= 2 && uvs.length % 2 === 0;
|
|
76
|
+
return (_jsxs("bufferGeometry", { onUpdate: (geometry) => {
|
|
77
|
+
if (properties.computeVertexNormals !== false && !hasNormals) {
|
|
78
|
+
geometry.computeVertexNormals();
|
|
79
|
+
}
|
|
80
|
+
geometry.computeBoundingBox();
|
|
81
|
+
geometry.computeBoundingSphere();
|
|
82
|
+
}, children: [_jsx("bufferAttribute", { attach: "attributes-position", args: [new Float32Array(positions), 3] }), indexArray ? (_jsx("bufferAttribute", { attach: "index", args: [indexArray, 1] })) : null, hasNormals ? (_jsx("bufferAttribute", { attach: "attributes-normal", args: [new Float32Array(normals), 3] })) : null, hasUvs ? (_jsx("bufferAttribute", { attach: "attributes-uv", args: [new Float32Array(uvs), 2] })) : null] }));
|
|
83
|
+
}
|
|
84
|
+
const BufferGeometryComponent = {
|
|
85
|
+
name: 'BufferGeometry',
|
|
86
|
+
Editor: BufferGeometryComponentEditor,
|
|
87
|
+
View: BufferGeometryComponentView,
|
|
88
|
+
defaultProperties: {
|
|
89
|
+
positions: DEFAULT_TRIANGLE_POSITIONS,
|
|
90
|
+
indices: DEFAULT_TRIANGLE_INDICES,
|
|
91
|
+
normals: [],
|
|
92
|
+
uvs: DEFAULT_TRIANGLE_UVS,
|
|
93
|
+
computeVertexNormals: true,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
export default BufferGeometryComponent;
|
|
@@ -15,8 +15,11 @@ export interface MaterialProps extends Omit<MeshStandardMaterialProperties & Mes
|
|
|
15
15
|
thickness?: number;
|
|
16
16
|
ior?: number;
|
|
17
17
|
texture?: string;
|
|
18
|
+
offset?: [number, number];
|
|
18
19
|
repeat?: boolean;
|
|
19
20
|
repeatCount?: [number, number];
|
|
21
|
+
animateOffset?: boolean;
|
|
22
|
+
offsetSpeed?: [number, number];
|
|
20
23
|
generateMipmaps?: boolean;
|
|
21
24
|
minFilter?: string;
|
|
22
25
|
magFilter?: string;
|
|
@@ -9,14 +9,19 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import {
|
|
13
|
-
import { createContext, useContext, useMemo } from 'react';
|
|
12
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
import { createContext, useContext, useMemo, useRef } from 'react';
|
|
14
14
|
import { extend } from '@react-three/fiber';
|
|
15
|
+
import { useFrame } from '@react-three/fiber';
|
|
15
16
|
import { FieldRenderer, Label, NumberInput } from './Input';
|
|
16
17
|
import { useAssetRuntime } from '../runtime';
|
|
17
18
|
import { MeshBasicNodeMaterial, MeshStandardNodeMaterial } from 'three/webgpu';
|
|
18
19
|
import { TexturePicker } from '../../assetviewer/page';
|
|
19
20
|
import { RepeatWrapping, ClampToEdgeWrapping, SRGBColorSpace, LinearSRGBColorSpace, NearestFilter, LinearFilter, NearestMipmapNearestFilter, NearestMipmapLinearFilter, LinearMipmapNearestFilter, LinearMipmapLinearFilter, FrontSide, BackSide, DoubleSide, } from 'three';
|
|
21
|
+
function Vector2Editor({ label, value, onChange, min, max, step, }) {
|
|
22
|
+
var _a, _b;
|
|
23
|
+
return (_jsxs("div", { style: { display: 'flex', gap: 2 }, children: [_jsxs("div", { style: { flex: 1 }, children: [_jsxs(Label, { children: [label, " X"] }), _jsx(NumberInput, { value: (_a = value === null || value === void 0 ? void 0 : value[0]) !== null && _a !== void 0 ? _a : 0, onChange: x => { var _a; return onChange([x, (_a = value === null || value === void 0 ? void 0 : value[1]) !== null && _a !== void 0 ? _a : 0]); }, min: min, max: max, step: step, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] }), _jsxs("div", { style: { flex: 1 }, children: [_jsxs(Label, { children: [label, " Y"] }), _jsx(NumberInput, { value: (_b = value === null || value === void 0 ? void 0 : value[1]) !== null && _b !== void 0 ? _b : 0, onChange: y => { var _a; return onChange([(_a = value === null || value === void 0 ? void 0 : value[0]) !== null && _a !== void 0 ? _a : 0, y]); }, min: min, max: max, step: step, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] })] }));
|
|
24
|
+
}
|
|
20
25
|
const EMPTY_MATERIAL_OVERRIDES = Object.freeze({});
|
|
21
26
|
const MaterialOverridesContext = createContext(EMPTY_MATERIAL_OVERRIDES);
|
|
22
27
|
export function useMaterialOverrides() {
|
|
@@ -36,6 +41,7 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
|
|
|
36
41
|
const materialType = (_a = component.properties.materialType) !== null && _a !== void 0 ? _a : 'standard';
|
|
37
42
|
const hasTexture = !!component.properties.texture;
|
|
38
43
|
const hasRepeat = component.properties.repeat;
|
|
44
|
+
const animateOffset = component.properties.animateOffset;
|
|
39
45
|
const isStandardMaterial = materialType === 'standard';
|
|
40
46
|
const fields = [
|
|
41
47
|
{
|
|
@@ -82,10 +88,20 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
|
|
|
82
88
|
name: 'repeatCount',
|
|
83
89
|
type: 'custom',
|
|
84
90
|
label: 'Repeat (X, Y)',
|
|
85
|
-
render: ({ value, onChange }) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
render: ({ value, onChange }) => (_jsx(Vector2Editor, { label: "Repeat", value: value, onChange: onChange, min: 0.01, max: 100, step: 0.1 })),
|
|
92
|
+
}] : []),
|
|
93
|
+
{
|
|
94
|
+
name: 'offset',
|
|
95
|
+
type: 'custom',
|
|
96
|
+
label: 'Offset (X, Y)',
|
|
97
|
+
render: ({ value, onChange }) => (_jsx(Vector2Editor, { label: "Offset", value: value, onChange: onChange, step: 0.01 })),
|
|
98
|
+
},
|
|
99
|
+
{ name: 'animateOffset', type: 'boolean', label: 'Animate Offset' },
|
|
100
|
+
...(animateOffset ? [{
|
|
101
|
+
name: 'offsetSpeed',
|
|
102
|
+
type: 'custom',
|
|
103
|
+
label: 'Speed (X, Y)',
|
|
104
|
+
render: ({ value, onChange }) => (_jsx(Vector2Editor, { label: "Speed", value: value, onChange: onChange, step: 0.01 })),
|
|
89
105
|
}] : []),
|
|
90
106
|
{
|
|
91
107
|
name: 'normalMapTexture',
|
|
@@ -97,10 +113,7 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
|
|
|
97
113
|
name: 'normalScale',
|
|
98
114
|
type: 'custom',
|
|
99
115
|
label: 'Normal Scale (X, Y)',
|
|
100
|
-
render: ({ value, onChange }) => {
|
|
101
|
-
var _a, _b;
|
|
102
|
-
return (_jsxs("div", { style: { display: 'flex', gap: 2 }, children: [_jsxs("div", { style: { flex: 1 }, children: [_jsx(Label, { children: "X" }), _jsx(NumberInput, { value: (_a = value === null || value === void 0 ? void 0 : value[0]) !== null && _a !== void 0 ? _a : 1, onChange: v => { var _a; return onChange([v, (_a = value === null || value === void 0 ? void 0 : value[1]) !== null && _a !== void 0 ? _a : 1]); }, min: 0, max: 5, step: 0.01, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] }), _jsxs("div", { style: { flex: 1 }, children: [_jsx(Label, { children: "Y" }), _jsx(NumberInput, { value: (_b = value === null || value === void 0 ? void 0 : value[1]) !== null && _b !== void 0 ? _b : 1, onChange: v => { var _a; return onChange([(_a = value === null || value === void 0 ? void 0 : value[0]) !== null && _a !== void 0 ? _a : 1, v]); }, min: 0, max: 5, step: 0.01, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] })] }));
|
|
103
|
-
},
|
|
116
|
+
render: ({ value, onChange }) => (_jsx(Vector2Editor, { label: "Normal", value: value, onChange: onChange, min: 0, max: 5, step: 0.01 })),
|
|
104
117
|
}] : []),
|
|
105
118
|
{ name: 'generateMipmaps', type: 'boolean', label: 'Generate Mipmaps' },
|
|
106
119
|
{
|
|
@@ -131,13 +144,16 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
|
|
|
131
144
|
}
|
|
132
145
|
// View for Material component
|
|
133
146
|
function MaterialComponentView({ properties: rawProps }) {
|
|
134
|
-
var _a, _b, _c, _d, _e, _f;
|
|
147
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
135
148
|
const { getTexture } = useAssetRuntime();
|
|
136
149
|
const properties = rawProps;
|
|
137
150
|
const materialType = (_a = properties === null || properties === void 0 ? void 0 : properties.materialType) !== null && _a !== void 0 ? _a : 'standard';
|
|
138
151
|
const textureName = properties === null || properties === void 0 ? void 0 : properties.texture;
|
|
152
|
+
const offset = properties === null || properties === void 0 ? void 0 : properties.offset;
|
|
139
153
|
const repeat = properties === null || properties === void 0 ? void 0 : properties.repeat;
|
|
140
154
|
const repeatCount = properties === null || properties === void 0 ? void 0 : properties.repeatCount;
|
|
155
|
+
const animateOffset = properties === null || properties === void 0 ? void 0 : properties.animateOffset;
|
|
156
|
+
const offsetSpeed = properties === null || properties === void 0 ? void 0 : properties.offsetSpeed;
|
|
141
157
|
const generateMipmaps = (properties === null || properties === void 0 ? void 0 : properties.generateMipmaps) !== false;
|
|
142
158
|
const minFilter = (properties === null || properties === void 0 ? void 0 : properties.minFilter) || 'LinearMipmapLinearFilter';
|
|
143
159
|
const magFilter = (properties === null || properties === void 0 ? void 0 : properties.magFilter) || 'LinearFilter';
|
|
@@ -147,7 +163,7 @@ function MaterialComponentView({ properties: rawProps }) {
|
|
|
147
163
|
const normalMapTexture = normalMapTextureName ? (_c = getTexture(normalMapTextureName)) !== null && _c !== void 0 ? _c : undefined : undefined;
|
|
148
164
|
const materialSource = properties !== null && properties !== void 0 ? properties : {};
|
|
149
165
|
// Destructure all material props and separate custom texture handling props
|
|
150
|
-
const { texture: _texture, repeat: _repeat, repeatCount: _repeatCount, generateMipmaps: _generateMipmaps, minFilter: _minFilter, magFilter: _magFilter, map: _map, materialType: _materialType, normalMapTexture: _normalMapTexture, normalScale: _normalScale, normalMap: _normalMap, side: sideProp } = materialSource, materialProps = __rest(materialSource, ["texture", "repeat", "repeatCount", "generateMipmaps", "minFilter", "magFilter", "map", "materialType", "normalMapTexture", "normalScale", "normalMap", "side"]);
|
|
166
|
+
const { texture: _texture, offset: _offset, repeat: _repeat, repeatCount: _repeatCount, animateOffset: _animateOffset, offsetSpeed: _offsetSpeed, generateMipmaps: _generateMipmaps, minFilter: _minFilter, magFilter: _magFilter, map: _map, materialType: _materialType, normalMapTexture: _normalMapTexture, normalScale: _normalScale, normalMap: _normalMap, side: sideProp } = materialSource, materialProps = __rest(materialSource, ["texture", "offset", "repeat", "repeatCount", "animateOffset", "offsetSpeed", "generateMipmaps", "minFilter", "magFilter", "map", "materialType", "normalMapTexture", "normalScale", "normalMap", "side"]);
|
|
151
167
|
const sideMap = { FrontSide, BackSide, DoubleSide };
|
|
152
168
|
const resolvedSide = sideProp ? ((_d = sideMap[sideProp]) !== null && _d !== void 0 ? _d : FrontSide) : FrontSide;
|
|
153
169
|
const minFilterMap = {
|
|
@@ -162,8 +178,9 @@ function MaterialComponentView({ properties: rawProps }) {
|
|
|
162
178
|
NearestFilter,
|
|
163
179
|
LinearFilter
|
|
164
180
|
};
|
|
181
|
+
const animatedOffsetRef = useRef([(_e = offset === null || offset === void 0 ? void 0 : offset[0]) !== null && _e !== void 0 ? _e : 0, (_f = offset === null || offset === void 0 ? void 0 : offset[1]) !== null && _f !== void 0 ? _f : 0]);
|
|
165
182
|
const finalTexture = useMemo(() => {
|
|
166
|
-
var _a, _b;
|
|
183
|
+
var _a, _b, _c, _d;
|
|
167
184
|
if (!texture)
|
|
168
185
|
return undefined;
|
|
169
186
|
const t = texture.clone();
|
|
@@ -176,13 +193,24 @@ function MaterialComponentView({ properties: rawProps }) {
|
|
|
176
193
|
t.wrapS = t.wrapT = ClampToEdgeWrapping;
|
|
177
194
|
t.repeat.set(1, 1);
|
|
178
195
|
}
|
|
196
|
+
t.offset.set((_a = offset === null || offset === void 0 ? void 0 : offset[0]) !== null && _a !== void 0 ? _a : 0, (_b = offset === null || offset === void 0 ? void 0 : offset[1]) !== null && _b !== void 0 ? _b : 0);
|
|
179
197
|
t.colorSpace = SRGBColorSpace;
|
|
180
198
|
t.generateMipmaps = generateMipmaps;
|
|
181
|
-
t.minFilter = (
|
|
182
|
-
t.magFilter = (
|
|
199
|
+
t.minFilter = (_c = minFilterMap[minFilter]) !== null && _c !== void 0 ? _c : LinearMipmapLinearFilter;
|
|
200
|
+
t.magFilter = (_d = magFilterMap[magFilter]) !== null && _d !== void 0 ? _d : LinearFilter;
|
|
183
201
|
t.needsUpdate = true;
|
|
184
202
|
return t;
|
|
185
|
-
}, [texture, repeat, repeatCount === null || repeatCount === void 0 ? void 0 : repeatCount[0], repeatCount === null || repeatCount === void 0 ? void 0 : repeatCount[1], generateMipmaps, minFilter, magFilter]);
|
|
203
|
+
}, [texture, repeat, repeatCount === null || repeatCount === void 0 ? void 0 : repeatCount[0], repeatCount === null || repeatCount === void 0 ? void 0 : repeatCount[1], offset === null || offset === void 0 ? void 0 : offset[0], offset === null || offset === void 0 ? void 0 : offset[1], generateMipmaps, minFilter, magFilter]);
|
|
204
|
+
animatedOffsetRef.current = [(_g = offset === null || offset === void 0 ? void 0 : offset[0]) !== null && _g !== void 0 ? _g : 0, (_h = offset === null || offset === void 0 ? void 0 : offset[1]) !== null && _h !== void 0 ? _h : 0];
|
|
205
|
+
useFrame((_, delta) => {
|
|
206
|
+
var _a, _b;
|
|
207
|
+
if (!finalTexture || !animateOffset)
|
|
208
|
+
return;
|
|
209
|
+
const nextX = animatedOffsetRef.current[0] + ((_a = offsetSpeed === null || offsetSpeed === void 0 ? void 0 : offsetSpeed[0]) !== null && _a !== void 0 ? _a : 0) * delta;
|
|
210
|
+
const nextY = animatedOffsetRef.current[1] + ((_b = offsetSpeed === null || offsetSpeed === void 0 ? void 0 : offsetSpeed[1]) !== null && _b !== void 0 ? _b : 0) * delta;
|
|
211
|
+
animatedOffsetRef.current = [nextX, nextY];
|
|
212
|
+
finalTexture.offset.set(nextX, nextY);
|
|
213
|
+
});
|
|
186
214
|
const finalNormalMap = useMemo(() => {
|
|
187
215
|
if (!normalMapTexture)
|
|
188
216
|
return undefined;
|
|
@@ -199,7 +227,7 @@ function MaterialComponentView({ properties: rawProps }) {
|
|
|
199
227
|
if (materialType === 'basic') {
|
|
200
228
|
return _jsx("meshBasicNodeMaterial", Object.assign({}, sharedProps));
|
|
201
229
|
}
|
|
202
|
-
return (_jsx("meshStandardNodeMaterial", Object.assign({}, sharedProps, { normalMap: finalNormalMap, normalScale: finalNormalMap ? [(
|
|
230
|
+
return (_jsx("meshStandardNodeMaterial", Object.assign({}, sharedProps, { normalMap: finalNormalMap, normalScale: finalNormalMap ? [(_j = normalScaleProp === null || normalScaleProp === void 0 ? void 0 : normalScaleProp[0]) !== null && _j !== void 0 ? _j : 1, (_k = normalScaleProp === null || normalScaleProp === void 0 ? void 0 : normalScaleProp[1]) !== null && _k !== void 0 ? _k : 1] : undefined })));
|
|
203
231
|
}
|
|
204
232
|
const MaterialComponent = {
|
|
205
233
|
name: 'Material',
|
|
@@ -212,6 +240,9 @@ const MaterialComponent = {
|
|
|
212
240
|
wireframe: false,
|
|
213
241
|
transparent: false,
|
|
214
242
|
opacity: 1,
|
|
243
|
+
offset: [0, 0],
|
|
244
|
+
animateOffset: false,
|
|
245
|
+
offsetSpeed: [0, 0],
|
|
215
246
|
metalness: 0,
|
|
216
247
|
roughness: 1
|
|
217
248
|
},
|
|
@@ -1,28 +1,30 @@
|
|
|
1
|
-
import GeometryComponent from './GeometryComponent';
|
|
2
1
|
import TransformComponent from './TransformComponent';
|
|
2
|
+
import GeometryComponent from './GeometryComponent';
|
|
3
|
+
import BufferGeometryComponent from './BufferGeometryComponent';
|
|
4
|
+
import ModelComponent from './ModelComponent';
|
|
5
|
+
import TextComponent from './TextComponent';
|
|
3
6
|
import MaterialComponent from './MaterialComponent';
|
|
4
7
|
import PhysicsComponent from './PhysicsComponent';
|
|
5
8
|
import SpotLightComponent from './SpotLightComponent';
|
|
6
9
|
import PointLightComponent from './PointLightComponent';
|
|
7
10
|
import DirectionalLightComponent from './DirectionalLightComponent';
|
|
8
11
|
import AmbientLightComponent from './AmbientLightComponent';
|
|
9
|
-
import ModelComponent from './ModelComponent';
|
|
10
|
-
import TextComponent from './TextComponent';
|
|
11
12
|
import EnvironmentComponent from './EnvironmentComponent';
|
|
12
13
|
import CameraComponent from './CameraComponent';
|
|
13
14
|
import ClickComponent from './ClickComponent';
|
|
14
15
|
import SoundComponent from './SoundComponent';
|
|
15
16
|
export const builtinComponents = [
|
|
16
|
-
GeometryComponent,
|
|
17
17
|
TransformComponent,
|
|
18
|
+
GeometryComponent,
|
|
19
|
+
BufferGeometryComponent,
|
|
20
|
+
ModelComponent,
|
|
21
|
+
TextComponent,
|
|
18
22
|
MaterialComponent,
|
|
19
23
|
PhysicsComponent,
|
|
20
24
|
SpotLightComponent,
|
|
21
25
|
PointLightComponent,
|
|
22
26
|
DirectionalLightComponent,
|
|
23
27
|
AmbientLightComponent,
|
|
24
|
-
ModelComponent,
|
|
25
|
-
TextComponent,
|
|
26
28
|
EnvironmentComponent,
|
|
27
29
|
CameraComponent,
|
|
28
30
|
ClickComponent,
|