@woosh/meep-engine 2.165.5 → 2.165.6
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/package.json +1 -1
- package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.d.ts.map +1 -1
- package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.js +65 -12
- package/src/engine/ecs/gui/hud/testHudEdgeStick.d.ts +2 -0
- package/src/engine/ecs/gui/hud/testHudEdgeStick.d.ts.map +1 -0
- package/src/engine/ecs/gui/hud/testHudEdgeStick.js +134 -0
- package/src/engine/ecs/gui/position/ViewportPositionSystem.d.ts.map +1 -1
- package/src/engine/ecs/gui/position/ViewportPositionSystem.js +44 -23
- package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts +24 -1
- package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts.map +1 -1
- package/src/engine/graphics/ecs/trail3d/Trail3D.js +43 -0
- package/src/engine/graphics/ecs/trail3d/Trail3DFlags.d.ts +1 -0
- package/src/engine/graphics/ecs/trail3d/Trail3DFlags.js +9 -1
- package/src/engine/graphics/ecs/trail3d/Trail3DSystem.d.ts.map +1 -1
- package/src/engine/graphics/ecs/trail3d/Trail3DSystem.js +4 -0
- package/src/engine/graphics/ecs/trail3d/prototypeTrail3D.js +22 -1
- package/src/engine/graphics/render/forward_plus/LightManager.d.ts +5 -0
- package/src/engine/graphics/render/forward_plus/LightManager.d.ts.map +1 -1
- package/src/engine/graphics/render/forward_plus/LightManager.js +11 -0
- package/src/engine/graphics/render/forward_plus/model/AbstractLight.d.ts +16 -1
- package/src/engine/graphics/render/forward_plus/model/AbstractLight.d.ts.map +1 -1
- package/src/engine/graphics/render/forward_plus/model/AbstractLight.js +22 -1
- package/src/engine/graphics/render/forward_plus/model/Decal.d.ts +7 -0
- package/src/engine/graphics/render/forward_plus/model/Decal.d.ts.map +1 -1
- package/src/engine/graphics/render/forward_plus/model/Decal.js +11 -0
- package/src/engine/graphics/render/forward_plus/model/PointLight.d.ts +2 -0
- package/src/engine/graphics/render/forward_plus/model/PointLight.d.ts.map +1 -1
- package/src/engine/graphics/render/forward_plus/model/PointLight.js +10 -0
- package/src/engine/graphics/render/forward_plus/model/SpotLight.d.ts +2 -0
- package/src/engine/graphics/render/forward_plus/model/SpotLight.d.ts.map +1 -1
- package/src/engine/graphics/render/forward_plus/model/SpotLight.js +12 -0
- package/src/engine/graphics/trail/tube/TubeMaterialX.d.ts +8 -1
- package/src/engine/graphics/trail/tube/TubeMaterialX.d.ts.map +1 -1
- package/src/engine/graphics/trail/tube/TubeMaterialX.js +111 -15
- package/src/engine/graphics/trail/tube/TubeXMaterialSpec.d.ts +9 -2
- package/src/engine/graphics/trail/tube/TubeXMaterialSpec.d.ts.map +1 -1
- package/src/engine/graphics/trail/tube/TubeXMaterialSpec.js +15 -4
- package/src/engine/graphics/trail/tube/TubeXPlugin.d.ts.map +1 -1
- package/src/engine/graphics/trail/tube/TubeXPlugin.js +7 -1
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"description": "Pure JavaScript game engine. Fully featured and production ready.",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"author": "Alexander Goldring",
|
|
9
|
-
"version": "2.165.
|
|
9
|
+
"version": "2.165.6",
|
|
10
10
|
"main": "build/meep.module.js",
|
|
11
11
|
"module": "build/meep.module.js",
|
|
12
12
|
"exports": {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeadsUpDisplaySystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/ecs/gui/hud/HeadsUpDisplaySystem.js"],"names":[],"mappings":";AAeA;;;;;GAKG;AACH;IASI;;;OAGG;IACH,4BAFW,cAAc,EAqBxB;IA/BD,wCAAgC;IAGhC,2HAGE;IAaE,yBAA8B;IAM9B;;;;OAIG;IACH,+BAAiD;IAGrD,iCAGC;IAED,gCAIC;IAED;;;;;;;OAOG;IACH,
|
|
1
|
+
{"version":3,"file":"HeadsUpDisplaySystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/ecs/gui/hud/HeadsUpDisplaySystem.js"],"names":[],"mappings":";AAeA;;;;;GAKG;AACH;IASI;;;OAGG;IACH,4BAFW,cAAc,EAqBxB;IA/BD,wCAAgC;IAGhC,2HAGE;IAaE,yBAA8B;IAM9B;;;;OAIG;IACH,+BAAiD;IAGrD,iCAGC;IAED,gCAIC;IAED;;;;;;;OAOG;IACH,sCA6JC;IAED,6BAsBC;CACJ;uBA3PsB,iBAAiB;2BAIb,qBAAqB;uBAFzB,kBAAkB;4CALG,uDAAuD;6BAMtE,iCAAiC;+BAL/B,qCAAqC"}
|
|
@@ -118,26 +118,79 @@ class HeadsUpDisplaySystem extends System {
|
|
|
118
118
|
const worldPositionY = y;
|
|
119
119
|
const worldPositionZ = z;
|
|
120
120
|
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
// apply projection matrix
|
|
121
|
+
// project world position into clip space
|
|
124
122
|
const _x = projection[0] * x + projection[4] * y + projection[8] * z + projection[12];
|
|
125
123
|
const _y = projection[1] * x + projection[5] * y + projection[9] * z + projection[13];
|
|
126
124
|
const _z = projection[2] * x + projection[6] * y + projection[10] * z + projection[14];
|
|
127
125
|
const _w = projection[3] * x + projection[7] * y + projection[11] * z + projection[15];
|
|
128
126
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
y = _y * d;
|
|
133
|
-
z = _z * d;
|
|
127
|
+
let ndcX;
|
|
128
|
+
let ndcY;
|
|
129
|
+
let trackedPositionOutOfBounds;
|
|
134
130
|
|
|
135
|
-
|
|
136
|
-
|
|
131
|
+
if (_w > 0) {
|
|
132
|
+
// point is in front of the camera plane, apply perspective transform
|
|
133
|
+
const d = 1 / _w;
|
|
137
134
|
|
|
138
|
-
|
|
135
|
+
x = _x * d;
|
|
136
|
+
y = _y * d;
|
|
137
|
+
z = _z * d;
|
|
138
|
+
|
|
139
|
+
trackedPositionOutOfBounds = z > 1 || z < -1;
|
|
140
|
+
|
|
141
|
+
let dx = x * 0.5;
|
|
142
|
+
let dy = y * -0.5;
|
|
143
|
+
|
|
144
|
+
/*
|
|
145
|
+
Near the camera plane the projected position grows without bound while carrying no more
|
|
146
|
+
information than its direction from the viewport center. Cap it to the boundary of a doubled
|
|
147
|
+
viewport rect: edge-stick placement depends only on that direction, and unbounded coordinates
|
|
148
|
+
wreck float precision downstream (element extents cancel to zero next to values around 1e15).
|
|
149
|
+
*/
|
|
150
|
+
const m = Math.max(Math.abs(dx), Math.abs(dy));
|
|
151
|
+
|
|
152
|
+
if (m > 1) {
|
|
153
|
+
const s = 1 / m;
|
|
154
|
+
|
|
155
|
+
dx *= s;
|
|
156
|
+
dy *= s;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
ndcX = 0.5 + dx;
|
|
160
|
+
ndcY = 0.5 + dy;
|
|
161
|
+
} else {
|
|
162
|
+
/*
|
|
163
|
+
Point is on or behind the camera plane. Perspective division inverts through the projection
|
|
164
|
+
center, which would place the point on the opposite side of the screen from where it actually is.
|
|
165
|
+
Only the direction from the viewport center remains meaningful: clip-space (_x, -_y), the limit of
|
|
166
|
+
the in-front projection as a point approaches the camera plane.
|
|
139
167
|
|
|
140
|
-
|
|
168
|
+
Push the position out along that direction to the boundary of a doubled viewport rect. That is
|
|
169
|
+
guaranteed to be off-screen, letting stick-to-edge placement resolve it to the correct point on
|
|
170
|
+
the screen edge; without stick-to-edge the element is hidden anyway.
|
|
171
|
+
*/
|
|
172
|
+
trackedPositionOutOfBounds = true;
|
|
173
|
+
|
|
174
|
+
let dx = _x;
|
|
175
|
+
let dy = -_y;
|
|
176
|
+
|
|
177
|
+
const m = Math.max(Math.abs(dx), Math.abs(dy));
|
|
178
|
+
|
|
179
|
+
if (m > 0) {
|
|
180
|
+
const s = 1 / m;
|
|
181
|
+
|
|
182
|
+
dx *= s;
|
|
183
|
+
dy *= s;
|
|
184
|
+
} else {
|
|
185
|
+
// point lies exactly on the camera's view axis, direction is undefined; push down
|
|
186
|
+
dy = 1;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
ndcX = 0.5 + dx;
|
|
190
|
+
ndcY = 0.5 + dy;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
vp.position.set(ndcX, ndcY);
|
|
141
194
|
|
|
142
195
|
const visible = (!trackedPositionOutOfBounds || vp.stickToScreenEdge) && this.__visibility_predicate.test(worldPositionX, worldPositionY, worldPositionZ);
|
|
143
196
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testHudEdgeStick.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/ecs/gui/hud/testHudEdgeStick.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { EngineHarness } from "../../../EngineHarness.js";
|
|
2
|
+
import Entity from "../../Entity.js";
|
|
3
|
+
import { Transform } from "../../transform/Transform.js";
|
|
4
|
+
import EmptyView from "../../../../view/elements/EmptyView.js";
|
|
5
|
+
import GUIElement from "../GUIElement.js";
|
|
6
|
+
import GUIElementSystem from "../GUIElementSystem.js";
|
|
7
|
+
import ViewportPosition from "../position/ViewportPosition.js";
|
|
8
|
+
import ViewportPositionSystem from "../position/ViewportPositionSystem.js";
|
|
9
|
+
import HeadsUpDisplay from "./HeadsUpDisplay.js";
|
|
10
|
+
import HeadsUpDisplaySystem from "./HeadsUpDisplaySystem.js";
|
|
11
|
+
import { EngineConfiguration } from "../../../EngineConfiguration.js";
|
|
12
|
+
import { AttachmentSystem } from "../../attachment/AttachmentSystem.js";
|
|
13
|
+
import { CameraSystem } from "../../../graphics/ecs/camera/CameraSystem.js";
|
|
14
|
+
import TopDownCameraController from "../../../graphics/ecs/camera/topdown/TopDownCameraController.js";
|
|
15
|
+
|
|
16
|
+
const eh = new EngineHarness();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
* @param {Engine} engine
|
|
21
|
+
* @return {EngineConfiguration}
|
|
22
|
+
*/
|
|
23
|
+
function makeConfig(engine) {
|
|
24
|
+
const r = new EngineConfiguration();
|
|
25
|
+
|
|
26
|
+
r.addSystem(new AttachmentSystem());
|
|
27
|
+
r.addSystem(new HeadsUpDisplaySystem(engine.graphics));
|
|
28
|
+
r.addSystem(new ViewportPositionSystem(engine.gameView.size));
|
|
29
|
+
r.addSystem(new GUIElementSystem(engine.gui.view, engine));
|
|
30
|
+
|
|
31
|
+
return r;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const RING_RADIUS = 25;
|
|
35
|
+
const BADGE_COUNT = 12;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
* @param {Engine} engine
|
|
40
|
+
*/
|
|
41
|
+
async function main(engine) {
|
|
42
|
+
|
|
43
|
+
await EngineHarness.buildBasics({
|
|
44
|
+
engine,
|
|
45
|
+
enableWater: false,
|
|
46
|
+
enableShadows: false,
|
|
47
|
+
pitch: 0.7,
|
|
48
|
+
distance: 10
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// highlight stuck badges
|
|
52
|
+
const style = document.createElement('style');
|
|
53
|
+
style.textContent = `
|
|
54
|
+
.hud-edge-stick-badge {
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
font: bold 12px sans-serif;
|
|
59
|
+
color: white;
|
|
60
|
+
border-radius: 50%;
|
|
61
|
+
border: 2px solid white;
|
|
62
|
+
box-sizing: border-box;
|
|
63
|
+
}
|
|
64
|
+
.hud-edge-stick-badge.hud-system-sticky-flag {
|
|
65
|
+
border-color: black;
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
document.head.appendChild(style);
|
|
69
|
+
|
|
70
|
+
const ecd = engine.entityManager.dataset;
|
|
71
|
+
|
|
72
|
+
const tracked = [];
|
|
73
|
+
|
|
74
|
+
for (let i = 0; i < BADGE_COUNT; i++) {
|
|
75
|
+
const angle = (i / BADGE_COUNT) * Math.PI * 2;
|
|
76
|
+
|
|
77
|
+
const x = 5 + Math.cos(angle) * RING_RADIUS;
|
|
78
|
+
const z = 5 + Math.sin(angle) * RING_RADIUS;
|
|
79
|
+
|
|
80
|
+
const view = new EmptyView({
|
|
81
|
+
classList: ['hud-edge-stick-badge'],
|
|
82
|
+
css: {
|
|
83
|
+
background: `hsl(${(i / BADGE_COUNT) * 360}, 80%, 45%)`
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
view.size.set(28, 28);
|
|
88
|
+
view.el.textContent = String(i);
|
|
89
|
+
|
|
90
|
+
const transform = new Transform();
|
|
91
|
+
transform.position.set(x, 0.5, z);
|
|
92
|
+
|
|
93
|
+
const vp = new ViewportPosition();
|
|
94
|
+
vp.anchor.set(0.5, 0.5);
|
|
95
|
+
vp.stickToScreenEdge = true;
|
|
96
|
+
vp.screenEdgeWidth = 8;
|
|
97
|
+
|
|
98
|
+
const entity = new Entity()
|
|
99
|
+
.add(transform)
|
|
100
|
+
.add(new HeadsUpDisplay())
|
|
101
|
+
.add(vp)
|
|
102
|
+
.add(GUIElement.fromView(view))
|
|
103
|
+
.build(ecd);
|
|
104
|
+
|
|
105
|
+
tracked.push({ entity, transform, vp, view, index: i });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const active_camera = CameraSystem.getFirstActiveCamera(ecd);
|
|
109
|
+
const controller = ecd.getComponent(active_camera.entity, TopDownCameraController);
|
|
110
|
+
|
|
111
|
+
window.__hud_edge_stick_test = {
|
|
112
|
+
engine,
|
|
113
|
+
ecd,
|
|
114
|
+
tracked,
|
|
115
|
+
camera: active_camera.component,
|
|
116
|
+
controller
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
*
|
|
122
|
+
* @param {EngineHarness} harness
|
|
123
|
+
*/
|
|
124
|
+
async function init(harness) {
|
|
125
|
+
const engine = eh.engine;
|
|
126
|
+
|
|
127
|
+
await makeConfig(engine).apply(engine);
|
|
128
|
+
|
|
129
|
+
await eh.initialize();
|
|
130
|
+
|
|
131
|
+
main(engine);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
init(eh);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ViewportPositionSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/ecs/gui/position/ViewportPositionSystem.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"ViewportPositionSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/ecs/gui/position/ViewportPositionSystem.js"],"names":[],"mappings":";AAwBA;IACI,+BAoBC;IAjBG,8DAAkD;IAElD,kEAEC;IAED,kBAAgC;IAEhC,yCAME;IAEF,SAAc;IAGlB,2CAEC;IAED,4CAEC;IAED;;;OAGG;IACH,sBAHW,UAAU,MACV,gBAAgB,QAkE1B;IAED;;;;;OAKG;IACH,SAJW,gBAAgB,MAChB,UAAU,qBA8BpB;IAED;;;;;OAKG;IACH,WAJW,gBAAgB,MAChB,UAAU,qBAmBpB;IAgGL;;;OAGG;IACH,mCAFU,OAAO,CAEwC;CAjGxD;uBAlLsB,iBAAiB;uBACjB,kBAAkB;6BAEZ,uBAAuB;4CAJR,uDAAuD;8BALrE,iDAAiD"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { assert } from "../../../../core/assert.js";
|
|
2
2
|
import { SignalBinding } from "../../../../core/events/signal/SignalBinding.js";
|
|
3
3
|
import AABB2 from "../../../../core/geom/2d/aabb/AABB2.js";
|
|
4
|
+
import { clamp } from "../../../../core/math/clamp.js";
|
|
4
5
|
import { EPSILON } from "../../../../core/math/EPSILON.js";
|
|
5
6
|
import { ResourceAccessKind } from "../../../../core/model/ResourceAccessKind.js";
|
|
6
7
|
import { ResourceAccessSpecification } from "../../../../core/model/ResourceAccessSpecification.js";
|
|
@@ -186,9 +187,6 @@ class ViewportPositionSystem extends System {
|
|
|
186
187
|
|
|
187
188
|
const STICKY_FLAG_CLASS_NAME = 'hud-system-sticky-flag';
|
|
188
189
|
|
|
189
|
-
|
|
190
|
-
const stickyBounds = new AABB2();
|
|
191
|
-
|
|
192
190
|
/**
|
|
193
191
|
*
|
|
194
192
|
* @param {View} view
|
|
@@ -202,37 +200,60 @@ function setElementPosition(view, bounds, viewportSize, vp) {
|
|
|
202
200
|
|
|
203
201
|
if (vp.stickToScreenEdge) {
|
|
204
202
|
|
|
205
|
-
|
|
206
203
|
const screenEdgeWidth = vp.screenEdgeWidth;
|
|
207
204
|
const clipEdgeX = screenEdgeWidth / viewportSize.x;
|
|
208
205
|
const clipEdgeY = screenEdgeWidth / viewportSize.y;
|
|
209
206
|
|
|
207
|
+
const width = bounds.width;
|
|
208
|
+
const height = bounds.height;
|
|
210
209
|
|
|
211
|
-
|
|
210
|
+
const anchorX = vp.anchor.x;
|
|
211
|
+
const anchorY = vp.anchor.y;
|
|
212
212
|
|
|
213
|
-
|
|
213
|
+
// tracked point that the element hangs off, in normalized viewport coordinates
|
|
214
|
+
const px = bounds.x0 + width * anchorX;
|
|
215
|
+
const py = bounds.y0 + height * anchorY;
|
|
216
|
+
|
|
217
|
+
// rect of anchor positions for which the element stays fully on screen, inset by the edge margin
|
|
218
|
+
const ax0 = clipEdgeX + width * anchorX;
|
|
219
|
+
const ay0 = clipEdgeY + height * anchorY;
|
|
220
|
+
const ax1 = 1 - clipEdgeX - width * (1 - anchorX);
|
|
221
|
+
const ay1 = 1 - clipEdgeY - height * (1 - anchorY);
|
|
222
|
+
|
|
223
|
+
const stickFlag = px < ax0 || px > ax1 || py < ay0 || py > ay1;
|
|
224
|
+
|
|
225
|
+
if (stickFlag) {
|
|
226
|
+
/*
|
|
227
|
+
Tracked point is off-screen. Place the element on the line from the viewport center towards the
|
|
228
|
+
tracked point, at the point where that line leaves the valid rect. This keeps the element on the
|
|
229
|
+
invisible line leading to the tracked position, instead of clamping each axis independently,
|
|
230
|
+
which piles far-away directions into the corners.
|
|
231
|
+
*/
|
|
232
|
+
const dx = px - 0.5;
|
|
233
|
+
const dy = py - 0.5;
|
|
234
|
+
|
|
235
|
+
let t = 1;
|
|
236
|
+
|
|
237
|
+
if (dx > 0) {
|
|
238
|
+
t = Math.min(t, (ax1 - 0.5) / dx);
|
|
239
|
+
} else if (dx < 0) {
|
|
240
|
+
t = Math.min(t, (ax0 - 0.5) / dx);
|
|
241
|
+
}
|
|
214
242
|
|
|
215
|
-
|
|
216
|
-
|
|
243
|
+
if (dy > 0) {
|
|
244
|
+
t = Math.min(t, (ay1 - 0.5) / dy);
|
|
245
|
+
} else if (dy < 0) {
|
|
246
|
+
t = Math.min(t, (ay0 - 0.5) / dy);
|
|
247
|
+
}
|
|
217
248
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
249
|
+
// clamp covers rects that do not contain the viewport center, such as for oversized elements
|
|
250
|
+
const sx = clamp(0.5 + dx * t, ax0, ax1);
|
|
251
|
+
const sy = clamp(0.5 + dy * t, ay0, ay1);
|
|
221
252
|
|
|
222
|
-
|
|
253
|
+
x = sx - width * anchorX;
|
|
254
|
+
y = sy - height * anchorY;
|
|
223
255
|
} else {
|
|
224
256
|
x = bounds.x0;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (bounds.y0 < stickyBounds.y0) {
|
|
228
|
-
y = stickyBounds.y0;
|
|
229
|
-
|
|
230
|
-
stickFlag = true;
|
|
231
|
-
} else if (bounds.y1 > stickyBounds.y1) {
|
|
232
|
-
y = stickyBounds.y1 - bounds.height;
|
|
233
|
-
|
|
234
|
-
stickFlag = true;
|
|
235
|
-
} else {
|
|
236
257
|
y = bounds.y0;
|
|
237
258
|
}
|
|
238
259
|
|
|
@@ -96,6 +96,27 @@ declare class Trail3D {
|
|
|
96
96
|
get textureURL(): string;
|
|
97
97
|
set depthWrite(arg: boolean);
|
|
98
98
|
get depthWrite(): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* @param {boolean} v
|
|
101
|
+
*/
|
|
102
|
+
set lightingEnabled(arg: boolean);
|
|
103
|
+
/**
|
|
104
|
+
* Whether the trail's tube processes standard scene lighting. When enabled the
|
|
105
|
+
* tube shades as a matte (Lambert) surface under the scene's ambient /
|
|
106
|
+
* hemisphere / light-probe / directional / point / spot lights and receives
|
|
107
|
+
* shadows; it never casts them. Under the Forward+ pipeline the material is
|
|
108
|
+
* additionally rewritten by the renderer's material manager, so clustered
|
|
109
|
+
* point lights and decals apply as well. When disabled (default) the tube
|
|
110
|
+
* renders unlit.
|
|
111
|
+
*
|
|
112
|
+
* Stored in {@link Trail3DFlags.Lit}. This is a build-time option — it selects
|
|
113
|
+
* the compiled material and the mesh's shadow settings — so it must be set
|
|
114
|
+
* before the trail is built / registered with the system, and cannot change
|
|
115
|
+
* afterwards.
|
|
116
|
+
*
|
|
117
|
+
* @returns {boolean}
|
|
118
|
+
*/
|
|
119
|
+
get lightingEnabled(): boolean;
|
|
99
120
|
/**
|
|
100
121
|
* @param {number|Trail3DFlags} flag
|
|
101
122
|
* @returns {void}
|
|
@@ -124,7 +145,7 @@ declare class Trail3D {
|
|
|
124
145
|
* Clear the trail's geometry and reset its state.
|
|
125
146
|
*/
|
|
126
147
|
clear(): void;
|
|
127
|
-
fromJSON({ maxAge, width, radialSegments, spawnMode, spawnDistance, textureURL, depthWrite, offset, color }: {
|
|
148
|
+
fromJSON({ maxAge, width, radialSegments, spawnMode, spawnDistance, textureURL, depthWrite, lightingEnabled, offset, color }: {
|
|
128
149
|
maxAge?: number;
|
|
129
150
|
width?: number;
|
|
130
151
|
radialSegments?: number;
|
|
@@ -132,6 +153,7 @@ declare class Trail3D {
|
|
|
132
153
|
spawnDistance?: number;
|
|
133
154
|
textureURL: any;
|
|
134
155
|
depthWrite?: boolean;
|
|
156
|
+
lightingEnabled?: boolean;
|
|
135
157
|
offset?: Vector3;
|
|
136
158
|
color?: {
|
|
137
159
|
r: number;
|
|
@@ -154,6 +176,7 @@ declare class Trail3D {
|
|
|
154
176
|
};
|
|
155
177
|
textureURL: string;
|
|
156
178
|
depthWrite: boolean;
|
|
179
|
+
lightingEnabled: boolean;
|
|
157
180
|
offset: {
|
|
158
181
|
x: number;
|
|
159
182
|
y: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Trail3D.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/trail3d/Trail3D.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"Trail3D.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/trail3d/Trail3D.js"],"names":[],"mappings":";AAiCA;;;;;GAKG;AACH;IAoPI,oCAMC;IAxPD;;;OAGG;IACH,QAFU,MAAM,CAES;IAEzB;;;OAGG;IACH,OAFU,MAAM,CAEM;IAEtB;;;;OAIG;IACH,gBAFU,MAAM,CAEyB;IAEzC;;;OAGG;IACH,WAFU,cAAc,GAAC,MAAM,CAEC;IAEhC;;;;OAIG;IACH,eAFU,MAAM,CAEuB;IAEvC;;;OAGG;IACH,MAFU,MAAM,CAEP;IAET;;OAEG;IACH,eAFU,MAAM,CAEE;IAElB;;;OAGG;IACH,qBAFU,MAAM,CAEQ;IAExB;;;OAGG;IACH,yBAFU,MAAM,CAEY;IAE5B;;;;;OAKG;IACH,gBAFU,KAAK,CAEe;IAE9B;;;;OAIG;IACH,iBAFU,OAAO,CAEM;IAEvB;;;OAGG;IACH,MAFU,KAAK,GAAC,IAAI,CAER;IAEZ;;;OAGG;IACH,MAFU,OAAK,IAAI,CAEP;IAEZ;;;OAGG;IACH,UAFU,iBAAiB,CAEQ;IAEnC;;;OAGG;IACH,cAFU,SAAS,CAEG;IAEtB;;;OAGG;IACH,cAAsB;IAEtB,gBAQC;IAMD,4BAEC;IAND,yBAEC;IAUD,6BAEC;IAND,0BAEC;IA0BD;;OAEG;IACH,kCAQC;IA/BD;;;;;;;;;;;;;;;OAeG;IACH,+BAEC;IAeD;;;OAGG;IACH,cAHW,MAAM,GAAC,YAAY,GACjB,IAAI,CAIhB;IAED;;;OAGG;IACH,gBAHW,MAAM,GAAC,YAAY,GACjB,IAAI,CAIhB;IAED;;;OAGG;IACH,gBAHW,MAAM,GAAC,YAAY,SACnB,OAAO,QAQjB;IAED;;;OAGG;IACH,cAHW,MAAM,GAAC,YAAY,GACjB,OAAO,CAInB;IAED;;OAEG;IACH,qBAFW,MAAM,QAoBhB;IAED;;OAEG;IACH,cAmBC;IAUD;;;;;;;;;;;;;;;;aAwBC;IAED;;;;;;;;;;;;;;;;;;;;MAaC;IAED;;OAEG;IACH,cAFW,OAAO,WAcjB;IAkDD;;;;;;OAMG;IACH,cANW,MAAM,KACN,MAAM,KACN,MAAM,YACN,MAAM,GACJ,OAAO,CAiEnB;;CAEJ;;;;;+BA3c8B,+BAA+B;sBAPxC,iCAAiC;oBACnC,kCAAkC;sBAShC,2BAA2B;kCACf,uCAAuC;0BAZ/C,yCAAyC;6BAatC,mBAAmB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
1
2
|
import { FLOAT32_MAX } from "../../../../core/binary/FLOAT32_MAX.js";
|
|
2
3
|
import { BvhClient } from "../../../../core/bvh2/bvh3/BvhClient.js";
|
|
3
4
|
import { Color } from "../../../../core/color/Color.js";
|
|
@@ -164,6 +165,39 @@ class Trail3D {
|
|
|
164
165
|
this.material.depthWrite = v;
|
|
165
166
|
}
|
|
166
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Whether the trail's tube processes standard scene lighting. When enabled the
|
|
170
|
+
* tube shades as a matte (Lambert) surface under the scene's ambient /
|
|
171
|
+
* hemisphere / light-probe / directional / point / spot lights and receives
|
|
172
|
+
* shadows; it never casts them. Under the Forward+ pipeline the material is
|
|
173
|
+
* additionally rewritten by the renderer's material manager, so clustered
|
|
174
|
+
* point lights and decals apply as well. When disabled (default) the tube
|
|
175
|
+
* renders unlit.
|
|
176
|
+
*
|
|
177
|
+
* Stored in {@link Trail3DFlags.Lit}. This is a build-time option — it selects
|
|
178
|
+
* the compiled material and the mesh's shadow settings — so it must be set
|
|
179
|
+
* before the trail is built / registered with the system, and cannot change
|
|
180
|
+
* afterwards.
|
|
181
|
+
*
|
|
182
|
+
* @returns {boolean}
|
|
183
|
+
*/
|
|
184
|
+
get lightingEnabled() {
|
|
185
|
+
return this.getFlag(Trail3DFlags.Lit);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* @param {boolean} v
|
|
190
|
+
*/
|
|
191
|
+
set lightingEnabled(v) {
|
|
192
|
+
if (v === this.lightingEnabled) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
assert.notOk(this.getFlag(Trail3DFlags.Built), "lightingEnabled cannot change after the trail is built");
|
|
197
|
+
|
|
198
|
+
this.writeFlag(Trail3DFlags.Lit, v);
|
|
199
|
+
}
|
|
200
|
+
|
|
167
201
|
/**
|
|
168
202
|
* @param {number|Trail3DFlags} flag
|
|
169
203
|
* @returns {void}
|
|
@@ -214,6 +248,11 @@ class Trail3D {
|
|
|
214
248
|
|
|
215
249
|
const mesh = ThreeFactory.createMesh(geometry, null);
|
|
216
250
|
|
|
251
|
+
// receive-only lighting: castShadow stays false. The geometry's `position`
|
|
252
|
+
// attribute holds ring CENTRES (the surface is extruded in the material's
|
|
253
|
+
// vertex stage), so a stock depth pass would render a degenerate line anyway.
|
|
254
|
+
mesh.receiveShadow = this.getFlag(Trail3DFlags.Lit);
|
|
255
|
+
|
|
217
256
|
this.tube = tube;
|
|
218
257
|
this.mesh = mesh;
|
|
219
258
|
}
|
|
@@ -258,6 +297,7 @@ class Trail3D {
|
|
|
258
297
|
spawnDistance = DEFAULT_SPAWN_DISTANCE,
|
|
259
298
|
textureURL,
|
|
260
299
|
depthWrite = false,
|
|
300
|
+
lightingEnabled = false,
|
|
261
301
|
offset = Vector3.zero,
|
|
262
302
|
color = { r: 1, g: 1, b: 1, a: 1 }
|
|
263
303
|
}) {
|
|
@@ -269,6 +309,7 @@ class Trail3D {
|
|
|
269
309
|
this.spawnDistance = spawnDistance;
|
|
270
310
|
this.textureURL = textureURL;
|
|
271
311
|
this.depthWrite = depthWrite;
|
|
312
|
+
this.lightingEnabled = lightingEnabled;
|
|
272
313
|
|
|
273
314
|
this.offset.fromJSON(offset);
|
|
274
315
|
this.color.fromJSON(color);
|
|
@@ -284,6 +325,7 @@ class Trail3D {
|
|
|
284
325
|
color: this.color.toJSON(),
|
|
285
326
|
textureURL: this.textureURL,
|
|
286
327
|
depthWrite: this.depthWrite,
|
|
328
|
+
lightingEnabled: this.lightingEnabled,
|
|
287
329
|
offset: this.offset.toJSON()
|
|
288
330
|
};
|
|
289
331
|
}
|
|
@@ -294,6 +336,7 @@ class Trail3D {
|
|
|
294
336
|
equals(other) {
|
|
295
337
|
return this.textureURL === other.textureURL
|
|
296
338
|
&& this.depthWrite === other.depthWrite
|
|
339
|
+
&& this.lightingEnabled === other.lightingEnabled
|
|
297
340
|
&& this.width === other.width
|
|
298
341
|
&& this.radialSegments === other.radialSegments
|
|
299
342
|
&& this.maxAge === other.maxAge
|
|
@@ -14,5 +14,13 @@ export const Trail3DFlags = {
|
|
|
14
14
|
* segment can bridge post-clear geometry to pre-clear history (e.g. a long
|
|
15
15
|
* streak after teleporting the entity).
|
|
16
16
|
*/
|
|
17
|
-
Reseed: 16
|
|
17
|
+
Reseed: 16,
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The tube processes standard scene lighting (receive-only — it never casts
|
|
21
|
+
* shadows). Build-time flag: it selects the compiled material and the mesh's
|
|
22
|
+
* shadow settings, so it must be set before the trail is built / registered
|
|
23
|
+
* with the system; changing it afterwards has no effect.
|
|
24
|
+
*/
|
|
25
|
+
Lit: 32
|
|
18
26
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Trail3DSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/trail3d/Trail3DSystem.js"],"names":[],"mappings":";AAyBA;IAiCI;;;OAGG;IACH,4BAkBC;IAtDD,oDAAoC;IAEpC,+DAEE;IAEF;;OAEG;IACH,WAFU,0BAA0B,CAES;IAiB7C;;;OAGG;IACH,YAAgB;IAeZ;;OAEG;IACH,UAFU,cAAc,CAEO;IAE/B;;OAEG;IACH,aAFU,cAAY,IAAI,CAEH;IAG3B,2CAmBC;IAED,4CAIC;IA2DD;;;;OAIG;IACH,YAJW,OAAO,aACP,SAAS,YACT,MAAM,
|
|
1
|
+
{"version":3,"file":"Trail3DSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/trail3d/Trail3DSystem.js"],"names":[],"mappings":";AAyBA;IAiCI;;;OAGG;IACH,4BAkBC;IAtDD,oDAAoC;IAEpC,+DAEE;IAEF;;OAEG;IACH,WAFU,0BAA0B,CAES;IAiB7C;;;OAGG;IACH,YAAgB;IAeZ;;OAEG;IACH,UAFU,cAAc,CAEO;IAE/B;;OAEG;IACH,aAFU,cAAY,IAAI,CAEH;IAG3B,2CAmBC;IAED,4CAIC;IA2DD;;;;OAIG;IACH,YAJW,OAAO,aACP,SAAS,YACT,MAAM,QAgBhB;IAED;;;;OAIG;IACH,kBAJW,OAAO,aACP,SAAS,UACT,MAAM,QAQhB;IAED;;;OAGG;IACH,yBAHW,OAAO,aACP,SAAS,QAkCnB;IAED,6BAWC;;CACJ;uBAlPsB,wBAAwB;0BACrB,qCAAqC;oBAW3C,cAAc;4CAbU,uDAAuD;2CAUxD,0DAA0D;+BANtE,yBAAyB"}
|
|
@@ -170,6 +170,10 @@ class Trail3DSystem extends System {
|
|
|
170
170
|
* @param {number} entityId
|
|
171
171
|
*/
|
|
172
172
|
link(trail, transform, entityId) {
|
|
173
|
+
// Trail3DFlags.Lit is final by link time — bake it into the material spec
|
|
174
|
+
// (the material cache key) so lit and unlit trails obtain distinct materials
|
|
175
|
+
trail.material.lit = trail.getFlag(Trail3DFlags.Lit);
|
|
176
|
+
|
|
173
177
|
if (!trail.getFlag(Trail3DFlags.Built)) {
|
|
174
178
|
this.#build_trail(trail, transform);
|
|
175
179
|
} else {
|
|
@@ -6,6 +6,8 @@ import { EngineHarness } from "../../../EngineHarness.js";
|
|
|
6
6
|
import { BehaviorComponent } from "../../../intelligence/behavior/ecs/BehaviorComponent.js";
|
|
7
7
|
import { BehaviorSystem } from "../../../intelligence/behavior/ecs/BehaviorSystem.js";
|
|
8
8
|
import { OrbitingBehavior } from "../../../intelligence/behavior/ecs/OrbitingBehavior.js";
|
|
9
|
+
import { Light } from "../light/Light.js";
|
|
10
|
+
import { LightType } from "../light/LightType.js";
|
|
9
11
|
import { TrailSpawnMode } from "../../trail/TrailSpawnMode.js";
|
|
10
12
|
import Trail3D from "./Trail3D.js";
|
|
11
13
|
import Trail3DSystem from "./Trail3DSystem.js";
|
|
@@ -44,6 +46,9 @@ async function main(engine) {
|
|
|
44
46
|
// exercise the distance-based spawning path too
|
|
45
47
|
spawnMode: TrailSpawnMode.Distance,
|
|
46
48
|
spawnDistance: 0.15,
|
|
49
|
+
// alternate unlit / lit around the ring: lit tubes shade under the
|
|
50
|
+
// harness sun + ambient fill and receive (never cast) shadows
|
|
51
|
+
lightingEnabled: i % 2 === 1,
|
|
47
52
|
color: { r: 1, g: 1, b: 1, a: 1 }
|
|
48
53
|
}));
|
|
49
54
|
|
|
@@ -59,7 +64,23 @@ async function main(engine) {
|
|
|
59
64
|
entity.build(ecd);
|
|
60
65
|
}
|
|
61
66
|
|
|
62
|
-
|
|
67
|
+
// a strong green point light in the middle of the ring. Non-shadow-casting
|
|
68
|
+
// POINT lights route through the Forward+ clustered path, so it only shows
|
|
69
|
+
// on materials that went through the FP material transformer — including
|
|
70
|
+
// the lit tubes.
|
|
71
|
+
new Entity()
|
|
72
|
+
.add(Light.fromJSON({
|
|
73
|
+
type: LightType.POINT,
|
|
74
|
+
color: { r: 0.1, g: 1, b: 0.1 },
|
|
75
|
+
intensity: 4,
|
|
76
|
+
distance: 8
|
|
77
|
+
}))
|
|
78
|
+
.add(Transform.fromJSON({
|
|
79
|
+
position: { x: 9, y: 2, z: 9 }
|
|
80
|
+
}))
|
|
81
|
+
.build(ecd);
|
|
82
|
+
|
|
83
|
+
console.log("Trail3D prototype: spawned", emitter_count, "orbiting tube emitters (odd indices lit) + clustered point light");
|
|
63
84
|
}
|
|
64
85
|
|
|
65
86
|
harness.initialize({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LightManager.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/render/forward_plus/LightManager.js"],"names":[],"mappings":"AAoIA;IAiBQ;;;;OAIG;IACH,2BAAgD;IAEhD,oCAAoC;IACpC,yCAA4C;IAE5C;;;;;;;;OAQG;IACH,0BAKC;IAaD;;;;;OAKG;IACH,+BAAoD;IAMpD;;;;;OAKG;IACH,8BAAmD;IAMnD;;;;OAIG;IACH,uCAAiF;IAWjF;;;;;OAKG;IACH,+BAEE;IAEF;;;;OAIG;IACH,iCAA8E;IAE9E;;;;OAIG;IACH,2BAAmC;IAEnC;;;;;OAKG;IACH,kCAAoE;IACpE;;;;;OAKG;IACH,kCAAoE;IAEpE;;;;OAIG;IACH,gCAAiC;IAEjC;;;;OAIG;IACH,6BAAiD;IACjD;;;;OAIG;IACH,6BAAiD;IAEjD;;;;OAIG;IACH,uBAAmC;IAEnC;;;;OAIG;IACH,8BAAiD;IAEjD;;;;OAIG;IACH,4BAA+C;IAG/C;;;;OAIG;IACH,yBAA2C;IAE3C;;;;OAIG;IACH,iCAAmD;IAUnD;;;;;OAKG;IACH,kCAAqC;IAErC;;;;OAIG;IACH,mCAAsC;IAK1C,0BAEC;IAED;;;;;;OAMG;IACH,0CAQC;IAED;;;OAGG;IACH,uCAEC;IAED,qCAQC;IAED;;;;;;OAMG;IACH,4CAgBC;IAED,iCAIC;IAED,gCA6BC;IAED;;;;;OAKG;IACH,6BAEC;IAED;;;OAGG;IACH,oBAFa,WAAW,CAIvB;IAED;;;OAGG;IACH,kBAFa,WAAW,CAIvB;IAED;;OAEG;IACH,sBAFa,aAAa,CAIzB;IAED;;OAEG;IACH,wBAFa,WAAW,CAIvB;IAED;;;OAGG;IACH,iBAFa,SAAS,OAAO,CAAC,CAI7B;IAED;;;OAGG;IACH,yCAKC;IAED;;;;OAIG;IACH,qCAyBC;IAED;;;;OAIG;IACH,uCA8BC;IAED;;;;OAIG;IACH,
|
|
1
|
+
{"version":3,"file":"LightManager.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/render/forward_plus/LightManager.js"],"names":[],"mappings":"AAoIA;IAiBQ;;;;OAIG;IACH,2BAAgD;IAEhD,oCAAoC;IACpC,yCAA4C;IAE5C;;;;;;;;OAQG;IACH,0BAKC;IAaD;;;;;OAKG;IACH,+BAAoD;IAMpD;;;;;OAKG;IACH,8BAAmD;IAMnD;;;;OAIG;IACH,uCAAiF;IAWjF;;;;;OAKG;IACH,+BAEE;IAEF;;;;OAIG;IACH,iCAA8E;IAE9E;;;;OAIG;IACH,2BAAmC;IAEnC;;;;;OAKG;IACH,kCAAoE;IACpE;;;;;OAKG;IACH,kCAAoE;IAEpE;;;;OAIG;IACH,gCAAiC;IAEjC;;;;OAIG;IACH,6BAAiD;IACjD;;;;OAIG;IACH,6BAAiD;IAEjD;;;;OAIG;IACH,uBAAmC;IAEnC;;;;OAIG;IACH,8BAAiD;IAEjD;;;;OAIG;IACH,4BAA+C;IAG/C;;;;OAIG;IACH,yBAA2C;IAE3C;;;;OAIG;IACH,iCAAmD;IAUnD;;;;;OAKG;IACH,kCAAqC;IAErC;;;;OAIG;IACH,mCAAsC;IAK1C,0BAEC;IAED;;;;;;OAMG;IACH,0CAQC;IAED;;;OAGG;IACH,uCAEC;IAED,qCAQC;IAED;;;;;;OAMG;IACH,4CAgBC;IAED,iCAIC;IAED,gCA6BC;IAED;;;;;OAKG;IACH,6BAEC;IAED;;;OAGG;IACH,oBAFa,WAAW,CAIvB;IAED;;;OAGG;IACH,kBAFa,WAAW,CAIvB;IAED;;OAEG;IACH,sBAFa,aAAa,CAIzB;IAED;;OAEG;IACH,wBAFa,WAAW,CAIvB;IAED;;;OAGG;IACH,iBAFa,SAAS,OAAO,CAAC,CAI7B;IAED;;;OAGG;IACH,yCAKC;IAED;;;OAGG;IACH,yCAGC;IAED;;;;OAIG;IACH,qCAyBC;IAED;;;;OAIG;IACH,uCA8BC;IAED;;;;OAIG;IACH,qCAOC;IAED;;;;OAIG;IACH,uCAMC;IAED;;;;;OAKG;IACH,4CAJW,mBAAmB,GACjB,MAAM,CAalB;IAED;;;;;;OAMG;IACH,+BAgCC;IAED;;;OAGG;IACH,6BAoBC;IAED,6BAYC;IAGD;;;;OAIG;IACH,6BAMC;IAED,mCA0EC;IAED,mCAgFC;IAED;;;OAGG;IACH,oCA+IC;IAED;;;OAGG;IACH,uCAUC;IAED;;;OAGG;IACH,oCAOC;IAED;;;OAGG;IACH,uCAWC;IAED;;;OAGG;IACH,mBAFW,SAAO,MAAM,iBAAiB,QAmDxC;IAED,gBAKC;IAED;;;;;OAKG;IACH,wBAJW,MAAM,KACN,MAAM,KACN,MAAM,QA2ChB;IAED;;;;OAIG;IACH,gCAFa,OAAO,CAInB;IAED;;;OAGG;IACH,qCAMC;IAED;;;;OAIG;IACH,mCAFa,OAAO,CAiBnB;;CACJ;4BAlsCM,OAAO;8BAAP,OAAO;oBAkBM,kCAAkC;oCAiBlB,0BAA0B"}
|
|
@@ -505,6 +505,15 @@ export class LightManager {
|
|
|
505
505
|
this.__light_data_needs_update = true;
|
|
506
506
|
}
|
|
507
507
|
|
|
508
|
+
/**
|
|
509
|
+
*
|
|
510
|
+
* @private
|
|
511
|
+
*/
|
|
512
|
+
__handle_light_appearance_change() {
|
|
513
|
+
// appearance changes (such as color or intensity) don't affect bounds, only the encoded data
|
|
514
|
+
this.__light_data_needs_update = true;
|
|
515
|
+
}
|
|
516
|
+
|
|
508
517
|
/**
|
|
509
518
|
*
|
|
510
519
|
* @param {LightRenderMetadata} data
|
|
@@ -585,6 +594,7 @@ export class LightManager {
|
|
|
585
594
|
const light = data.light;
|
|
586
595
|
|
|
587
596
|
light.onDimensionChanged(this.__handle_light_dimensions_change, this);
|
|
597
|
+
light.onAppearanceChanged(this.__handle_light_appearance_change, this);
|
|
588
598
|
}
|
|
589
599
|
|
|
590
600
|
/**
|
|
@@ -597,6 +607,7 @@ export class LightManager {
|
|
|
597
607
|
|
|
598
608
|
const light = data.light;
|
|
599
609
|
light.offDimensionChanged(this.__handle_light_dimensions_change, this);
|
|
610
|
+
light.offAppearanceChanged(this.__handle_light_appearance_change, this);
|
|
600
611
|
}
|
|
601
612
|
|
|
602
613
|
/**
|
|
@@ -2,7 +2,7 @@ export class AbstractLight {
|
|
|
2
2
|
id: number;
|
|
3
3
|
toString(): string;
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Dimension changes affect the light's bounds ({@link AbstractLight#getAABB}) as well as its encoded record
|
|
6
6
|
* @param {function} f
|
|
7
7
|
* @param {*} [thisArg]
|
|
8
8
|
* @returns {void}
|
|
@@ -15,6 +15,21 @@ export class AbstractLight {
|
|
|
15
15
|
* @returns {void}
|
|
16
16
|
*/
|
|
17
17
|
offDimensionChanged(f: Function, thisArg?: any): void;
|
|
18
|
+
/**
|
|
19
|
+
* Appearance changes affect the light's encoded record ({@link AbstractLight#toArray}) but not its bounds,
|
|
20
|
+
* such as color or intensity
|
|
21
|
+
* @param {function} f
|
|
22
|
+
* @param {*} [thisArg]
|
|
23
|
+
* @returns {void}
|
|
24
|
+
*/
|
|
25
|
+
onAppearanceChanged(f: Function, thisArg?: any): void;
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
* @param {function} f
|
|
29
|
+
* @param {*} [thisArg]
|
|
30
|
+
* @returns {void}
|
|
31
|
+
*/
|
|
32
|
+
offAppearanceChanged(f: Function, thisArg?: any): void;
|
|
18
33
|
/**
|
|
19
34
|
*
|
|
20
35
|
* @param {number[]} result
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AbstractLight.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/render/forward_plus/model/AbstractLight.js"],"names":[],"mappings":"AAEA;IAEI,WAAkB;IAGlB,mBAEC;IAED;;;;;OAKG;IACH,gDAFa,IAAI,CAIhB;IAED;;;;;OAKG;IACH,iDAFa,IAAI,CAIhB;IAED;;;;OAIG;IACH,kBAHW,MAAM,EAAE,GACN,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,EAAE,GAAC,UAAU,MAAM,CAAC,GAAC,YAAY,GACrC,IAAI,CAIhB;IAED;;;;;OAKG;IACH,qBAJW,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,WAClC,MAAM,GACJ,MAAM,CAIlB;IAED;;;;OAIG;IACH,eAHW,aAAa,GACX,MAAM,CAIlB;IAGL,aAA4B;CAF3B"}
|
|
1
|
+
{"version":3,"file":"AbstractLight.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/render/forward_plus/model/AbstractLight.js"],"names":[],"mappings":"AAEA;IAEI,WAAkB;IAGlB,mBAEC;IAED;;;;;OAKG;IACH,gDAFa,IAAI,CAIhB;IAED;;;;;OAKG;IACH,iDAFa,IAAI,CAIhB;IAED;;;;;;OAMG;IACH,iDAFa,IAAI,CAIhB;IAED;;;;;OAKG;IACH,kDAFa,IAAI,CAIhB;IAED;;;;OAIG;IACH,kBAHW,MAAM,EAAE,GACN,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,EAAE,GAAC,UAAU,MAAM,CAAC,GAAC,YAAY,GACrC,IAAI,CAIhB;IAED;;;;;OAKG;IACH,qBAJW,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,WAClC,MAAM,GACJ,MAAM,CAIlB;IAED;;;;OAIG;IACH,eAHW,aAAa,GACX,MAAM,CAIlB;IAGL,aAA4B;CAF3B"}
|
|
@@ -10,7 +10,7 @@ export class AbstractLight {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Dimension changes affect the light's bounds ({@link AbstractLight#getAABB}) as well as its encoded record
|
|
14
14
|
* @param {function} f
|
|
15
15
|
* @param {*} [thisArg]
|
|
16
16
|
* @returns {void}
|
|
@@ -29,6 +29,27 @@ export class AbstractLight {
|
|
|
29
29
|
throw new Error('Not Implemented');
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Appearance changes affect the light's encoded record ({@link AbstractLight#toArray}) but not its bounds,
|
|
34
|
+
* such as color or intensity
|
|
35
|
+
* @param {function} f
|
|
36
|
+
* @param {*} [thisArg]
|
|
37
|
+
* @returns {void}
|
|
38
|
+
*/
|
|
39
|
+
onAppearanceChanged(f, thisArg) {
|
|
40
|
+
throw new Error('Not Implemented');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
*
|
|
45
|
+
* @param {function} f
|
|
46
|
+
* @param {*} [thisArg]
|
|
47
|
+
* @returns {void}
|
|
48
|
+
*/
|
|
49
|
+
offAppearanceChanged(f, thisArg) {
|
|
50
|
+
throw new Error('Not Implemented');
|
|
51
|
+
}
|
|
52
|
+
|
|
32
53
|
/**
|
|
33
54
|
*
|
|
34
55
|
* @param {number[]} result
|
|
@@ -29,6 +29,13 @@ export class Decal extends AbstractLight {
|
|
|
29
29
|
compare(other: any): number;
|
|
30
30
|
onDimensionChanged(f: any, thisArg: any): void;
|
|
31
31
|
offDimensionChanged(f: any, thisArg: any): void;
|
|
32
|
+
/**
|
|
33
|
+
* Appearance data (color, uv) is stored in raw arrays without change signals; uv only shifts when the
|
|
34
|
+
* texture atlas re-packs, which happens alongside decal addition/removal where the encoded data is
|
|
35
|
+
* invalidated anyway
|
|
36
|
+
*/
|
|
37
|
+
onAppearanceChanged(f: any, thisArg: any): void;
|
|
38
|
+
offAppearanceChanged(f: any, thisArg: any): void;
|
|
32
39
|
getCenter(result: any): void;
|
|
33
40
|
getAABB(result: any): void;
|
|
34
41
|
toArray(destination: any, address: any): number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Decal.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/render/forward_plus/model/Decal.js"],"names":[],"mappings":"AASA;IAIQ;;;OAGG;IACH,WAFU,MAAM,EAAE,GAAC,YAAY,GAAC,MAAM,CAED;IACrC,gCAA6C;IAC7C,iBAA6B;IAE7B,oBAAgC;IAKhC;;;OAGG;IACH,2BAA2B;IAE3B;;;;OAIG;IACH,eAFU,MAAM,CAEM;IAEtB,0EAA6C;IAGjD;;;OAGG;IACH,gBAFW,MAAM,EAAE,GAAC,YAAY,GAAC,UAAU,MAAM,CAAC,QAOjD;IAED,6CAGC;IAED,yCAGC;IAED,4BAUC;IAED,+CAGC;IAED,gDAGC;IAED,6BAKC;IAED,2BAIC;IAED,gDAcC;IAGL;;;OAGG;IACH,kBAFU,OAAO,CAEM;IAEvB,2BAAkC;CARjC;
|
|
1
|
+
{"version":3,"file":"Decal.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/render/forward_plus/model/Decal.js"],"names":[],"mappings":"AASA;IAIQ;;;OAGG;IACH,WAFU,MAAM,EAAE,GAAC,YAAY,GAAC,MAAM,CAED;IACrC,gCAA6C;IAC7C,iBAA6B;IAE7B,oBAAgC;IAKhC;;;OAGG;IACH,2BAA2B;IAE3B;;;;OAIG;IACH,eAFU,MAAM,CAEM;IAEtB,0EAA6C;IAGjD;;;OAGG;IACH,gBAFW,MAAM,EAAE,GAAC,YAAY,GAAC,UAAU,MAAM,CAAC,QAOjD;IAED,6CAGC;IAED,yCAGC;IAED,4BAUC;IAED,+CAGC;IAED,gDAGC;IAED;;;;OAIG;IACH,gDACC;IAED,iDACC;IAED,6BAKC;IAED,2BAIC;IAED,gDAcC;IAGL;;;OAGG;IACH,kBAFU,OAAO,CAEM;IAEvB,2BAAkC;CARjC;8BA5H6B,oBAAoB;mBAK/B,6CAA6C"}
|
|
@@ -83,6 +83,17 @@ export class Decal extends AbstractLight {
|
|
|
83
83
|
this.__signal_transfom_changed.remove(f, thisArg);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Appearance data (color, uv) is stored in raw arrays without change signals; uv only shifts when the
|
|
88
|
+
* texture atlas re-packs, which happens alongside decal addition/removal where the encoded data is
|
|
89
|
+
* invalidated anyway
|
|
90
|
+
*/
|
|
91
|
+
onAppearanceChanged(f, thisArg) {
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
offAppearanceChanged(f, thisArg) {
|
|
95
|
+
}
|
|
96
|
+
|
|
86
97
|
getCenter(result) {
|
|
87
98
|
// extract translation portion of the matrix
|
|
88
99
|
result[0] = this.transform[12];
|
|
@@ -23,6 +23,8 @@ export class PointLight extends AbstractLight {
|
|
|
23
23
|
getAABB(result: any): void;
|
|
24
24
|
onDimensionChanged(listener: any, context: any): void;
|
|
25
25
|
offDimensionChanged(listener: any, context: any): void;
|
|
26
|
+
onAppearanceChanged(listener: any, context: any): void;
|
|
27
|
+
offAppearanceChanged(listener: any, context: any): void;
|
|
26
28
|
/**
|
|
27
29
|
* @readonly
|
|
28
30
|
* @type {boolean}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PointLight.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/render/forward_plus/model/PointLight.js"],"names":[],"mappings":"AAKA;IAEI;;;OAGG;IACH,mBAFU,OAAO,CAEQ;IAEzB;;;OAGG;IACH,iBAFU,OAAO,CAEO;IAExB;;;OAGG;IACH,gBAFU,KAAK,CAEY;IAE3B;;;OAGG;IACH,oBAFU,OAAO,CAEU;IAG3B,6BAEC;IAED,2BAeC;IAED,sDAGC;IAED,uDAGC;IA6BL;;;OAGG;IACH,uBAFU,OAAO,CAEgB;IAEjC,2BAAuC;CARtC;
|
|
1
|
+
{"version":3,"file":"PointLight.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/render/forward_plus/model/PointLight.js"],"names":[],"mappings":"AAKA;IAEI;;;OAGG;IACH,mBAFU,OAAO,CAEQ;IAEzB;;;OAGG;IACH,iBAFU,OAAO,CAEO;IAExB;;;OAGG;IACH,gBAFU,KAAK,CAEY;IAE3B;;;OAGG;IACH,oBAFU,OAAO,CAEU;IAG3B,6BAEC;IAED,2BAeC;IAED,sDAGC;IAED,uDAGC;IAED,uDAGC;IAED,wDAGC;IA6BL;;;OAGG;IACH,uBAFU,OAAO,CAEgB;IAEjC,2BAAuC;CARtC;8BA/F6B,oBAAoB;oBAD9B,qCAAqC;oBADrC,qCAAqC;sBADnC,oCAAoC"}
|
|
@@ -61,6 +61,16 @@ export class PointLight extends AbstractLight {
|
|
|
61
61
|
this.radius.onChanged.remove(listener, context);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
onAppearanceChanged(listener, context) {
|
|
65
|
+
this.color.onChanged.add(listener, context);
|
|
66
|
+
this.intensity.onChanged.add(listener, context);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
offAppearanceChanged(listener, context) {
|
|
70
|
+
this.color.onChanged.remove(listener, context);
|
|
71
|
+
this.intensity.onChanged.remove(listener, context);
|
|
72
|
+
}
|
|
73
|
+
|
|
64
74
|
/**
|
|
65
75
|
*
|
|
66
76
|
* @param {number[]|Float32Array|Float64Array} destination
|
|
@@ -38,6 +38,8 @@ export class SpotLight extends AbstractLight {
|
|
|
38
38
|
getAABB(result: any): void;
|
|
39
39
|
onDimensionChanged(listener: any, context: any): void;
|
|
40
40
|
offDimensionChanged(listener: any, context: any): void;
|
|
41
|
+
onAppearanceChanged(listener: any, context: any): void;
|
|
42
|
+
offAppearanceChanged(listener: any, context: any): void;
|
|
41
43
|
/**
|
|
42
44
|
* @readonly
|
|
43
45
|
* @type {boolean}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpotLight.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/render/forward_plus/model/SpotLight.js"],"names":[],"mappings":"AAMA;IAGI;;;OAGG;IACH,mBAFU,OAAO,CAEQ;IAEzB;;;OAGG;IACH,oBAFU,OAAO,CAES;IAE1B;;;OAGG;IACH,gBAFU,OAAO,CAEgB;IAEjC;;;OAGG;IACH,mBAFU,OAAO,CAES;IAE1B;;;OAGG;IACH,gBAFU,KAAK,CAEY;IAE3B;;;OAGG;IACH,oBAFU,OAAO,CAEU;IAE3B;;;OAGG;IACH,mBAFU,OAAO,CAEW;IAG5B,6BAYC;IAED,2BAcC;IAED,sDAKC;IAED,uDAKC;IAuCL;;;OAGG;IACH,sBAFU,OAAO,CAEc;CAN9B;
|
|
1
|
+
{"version":3,"file":"SpotLight.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/render/forward_plus/model/SpotLight.js"],"names":[],"mappings":"AAMA;IAGI;;;OAGG;IACH,mBAFU,OAAO,CAEQ;IAEzB;;;OAGG;IACH,oBAFU,OAAO,CAES;IAE1B;;;OAGG;IACH,gBAFU,OAAO,CAEgB;IAEjC;;;OAGG;IACH,mBAFU,OAAO,CAES;IAE1B;;;OAGG;IACH,gBAFU,KAAK,CAEY;IAE3B;;;OAGG;IACH,oBAFU,OAAO,CAEU;IAE3B;;;OAGG;IACH,mBAFU,OAAO,CAEW;IAG5B,6BAYC;IAED,2BAcC;IAED,sDAKC;IAED,uDAKC;IAED,uDAIC;IAED,wDAIC;IAuCL;;;OAGG;IACH,sBAFU,OAAO,CAEc;CAN9B;8BA3I6B,oBAAoB;oBAD9B,qCAAqC;oBADrC,qCAAqC;sBAFnC,oCAAoC"}
|
|
@@ -94,6 +94,18 @@ export class SpotLight extends AbstractLight {
|
|
|
94
94
|
this.direction.onChanged.remove(listener, context);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
onAppearanceChanged(listener, context) {
|
|
98
|
+
this.color.onChanged.add(listener, context);
|
|
99
|
+
this.intensity.onChanged.add(listener, context);
|
|
100
|
+
this.penumbra.onChanged.add(listener, context);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
offAppearanceChanged(listener, context) {
|
|
104
|
+
this.color.onChanged.remove(listener, context);
|
|
105
|
+
this.intensity.onChanged.remove(listener, context);
|
|
106
|
+
this.penumbra.onChanged.remove(listener, context);
|
|
107
|
+
}
|
|
108
|
+
|
|
97
109
|
/**
|
|
98
110
|
*
|
|
99
111
|
* @param {number[]|Float32Array|Float64Array} destination
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
export class TubeMaterialX extends ShaderMaterial {
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* @param {Object} params three.js material parameters, plus:
|
|
4
|
+
* @param {boolean} [params.lit=false] compile the lit variant — standard light
|
|
5
|
+
* chain, receive-only shadows — instead of the unlit one
|
|
6
|
+
*/
|
|
7
|
+
constructor({ lit, ...params }?: {
|
|
8
|
+
lit?: boolean;
|
|
9
|
+
});
|
|
3
10
|
}
|
|
4
11
|
import { ShaderMaterial } from "three";
|
|
5
12
|
//# sourceMappingURL=TubeMaterialX.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TubeMaterialX.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/trail/tube/TubeMaterialX.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TubeMaterialX.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/trail/tube/TubeMaterialX.js"],"names":[],"mappings":"AAuIA;IACI;;;;OAIG;IACH;QAH4B,GAAG,GAApB,OAAO;OAoCjB;CACJ;+BA/KsF,OAAO"}
|
|
@@ -1,12 +1,25 @@
|
|
|
1
|
-
import { DoubleSide, NormalBlending, ShaderMaterial } from "three";
|
|
1
|
+
import { DoubleSide, NormalBlending, ShaderMaterial, UniformsLib, UniformsUtils } from "three";
|
|
2
2
|
|
|
3
3
|
const TWO_PI = "6.283185307179586";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Tube material. Vertices arrive as ring CENTRES; the actual surface vertex
|
|
7
7
|
* is extruded here in WORLD space from the per-knot tangent frame (tn, tb) and the
|
|
8
8
|
* vertex's angular position `tubeUv.x`. The mesh transform is identity (centres are
|
|
9
9
|
* already world space, written CPU-side), so modelViewMatrix == viewMatrix.
|
|
10
|
+
*
|
|
11
|
+
* Unlit by default. The LIT define switches the fragment stage onto the standard
|
|
12
|
+
* three.js light chain instead — specular is forced to zero, so the tube shades as
|
|
13
|
+
* a matte (Lambert) surface under ambient / hemisphere / light-probe / directional /
|
|
14
|
+
* point / spot lights, and receives shadows (it never casts them). The surface
|
|
15
|
+
* normal is the ring's radial direction; the per-knot thickness taper's tilt is
|
|
16
|
+
* ignored.
|
|
17
|
+
*
|
|
18
|
+
* The lit variant deliberately follows the three.js chunk conventions —
|
|
19
|
+
* `void main() {`, `transformed`, `#include <worldpos_vertex>`,
|
|
20
|
+
* `#include <lights_pars_begin>`, `#include <lights_fragment_begin>` — because the
|
|
21
|
+
* Forward+ {@link MaterialTransformer} keys its textual injections on exactly these
|
|
22
|
+
* markers to add clustered point-light accumulation and decals.
|
|
10
23
|
*/
|
|
11
24
|
const vertexShader = `
|
|
12
25
|
varying vec2 vUv;
|
|
@@ -19,18 +32,44 @@ const vertexShader = `
|
|
|
19
32
|
attribute float thickness;
|
|
20
33
|
attribute vec3 color;
|
|
21
34
|
|
|
22
|
-
|
|
35
|
+
#ifdef LIT
|
|
36
|
+
|
|
37
|
+
varying vec3 vNormal;
|
|
38
|
+
varying vec3 vViewPosition;
|
|
39
|
+
|
|
40
|
+
#include <common>
|
|
41
|
+
#include <shadowmap_pars_vertex>
|
|
42
|
+
|
|
43
|
+
#endif
|
|
44
|
+
|
|
45
|
+
void main() {
|
|
23
46
|
float angle = tubeUv.x * ${TWO_PI};
|
|
24
47
|
|
|
25
48
|
// radial direction in the knot's frame; unit, perpendicular to the tangent
|
|
26
49
|
vec3 radial = cos(angle) * tn + sin(angle) * tb;
|
|
27
50
|
|
|
28
|
-
|
|
51
|
+
// extruded surface vertex, named per three.js chunk convention
|
|
52
|
+
vec3 transformed = position + radial * (thickness * 0.5);
|
|
29
53
|
|
|
30
54
|
vUv = tubeUv;
|
|
31
55
|
vColor = vec4(color / 255.0, alpha);
|
|
32
56
|
|
|
33
|
-
|
|
57
|
+
vec4 mvPosition = modelViewMatrix * vec4(transformed, 1.0);
|
|
58
|
+
|
|
59
|
+
#ifdef LIT
|
|
60
|
+
|
|
61
|
+
// the tube's surface normal is the radial direction itself
|
|
62
|
+
vec3 transformedNormal = normalMatrix * radial;
|
|
63
|
+
|
|
64
|
+
vNormal = transformedNormal;
|
|
65
|
+
vViewPosition = -mvPosition.xyz;
|
|
66
|
+
|
|
67
|
+
#include <worldpos_vertex>
|
|
68
|
+
#include <shadowmap_vertex>
|
|
69
|
+
|
|
70
|
+
#endif
|
|
71
|
+
|
|
72
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
34
73
|
}
|
|
35
74
|
`;
|
|
36
75
|
|
|
@@ -40,7 +79,21 @@ const fragmentShader = `
|
|
|
40
79
|
|
|
41
80
|
uniform sampler2D uDiffuse;
|
|
42
81
|
|
|
43
|
-
|
|
82
|
+
#ifdef LIT
|
|
83
|
+
|
|
84
|
+
// vViewPosition is declared by <lights_phong_pars_fragment>
|
|
85
|
+
varying vec3 vNormal;
|
|
86
|
+
|
|
87
|
+
#include <common>
|
|
88
|
+
#include <packing>
|
|
89
|
+
#include <bsdfs>
|
|
90
|
+
#include <lights_pars_begin>
|
|
91
|
+
#include <lights_phong_pars_fragment>
|
|
92
|
+
#include <shadowmap_pars_fragment>
|
|
93
|
+
|
|
94
|
+
#endif
|
|
95
|
+
|
|
96
|
+
void main() {
|
|
44
97
|
vec4 diffuseColor = vColor;
|
|
45
98
|
|
|
46
99
|
#ifdef USE_TEXTURE
|
|
@@ -48,24 +101,67 @@ const fragmentShader = `
|
|
|
48
101
|
diffuseColor *= texel;
|
|
49
102
|
#endif
|
|
50
103
|
|
|
51
|
-
|
|
104
|
+
#ifdef LIT
|
|
105
|
+
|
|
106
|
+
ReflectedLight reflectedLight = ReflectedLight(vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
|
|
107
|
+
|
|
108
|
+
#include <normal_fragment_begin>
|
|
109
|
+
|
|
110
|
+
// Blinn-Phong with specular forced to zero = pure Lambert; a trail is a
|
|
111
|
+
// matte surface, highlights on a fading tube read as artifacts
|
|
112
|
+
BlinnPhongMaterial material;
|
|
113
|
+
material.diffuseColor = diffuseColor.rgb;
|
|
114
|
+
material.specularColor = vec3(0.0);
|
|
115
|
+
material.specularShininess = 1.0;
|
|
116
|
+
material.specularStrength = 0.0;
|
|
117
|
+
|
|
118
|
+
#include <lights_fragment_begin>
|
|
119
|
+
#include <lights_fragment_end>
|
|
120
|
+
|
|
121
|
+
vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;
|
|
122
|
+
|
|
123
|
+
gl_FragColor = vec4(outgoingLight, diffuseColor.a);
|
|
124
|
+
|
|
125
|
+
#include <tonemapping_fragment>
|
|
126
|
+
#include <encodings_fragment>
|
|
127
|
+
|
|
128
|
+
#else
|
|
129
|
+
|
|
130
|
+
gl_FragColor = diffuseColor;
|
|
131
|
+
|
|
132
|
+
#endif
|
|
52
133
|
}
|
|
53
134
|
`;
|
|
54
135
|
|
|
55
136
|
export class TubeMaterialX extends ShaderMaterial {
|
|
56
|
-
|
|
137
|
+
/**
|
|
138
|
+
* @param {Object} params three.js material parameters, plus:
|
|
139
|
+
* @param {boolean} [params.lit=false] compile the lit variant — standard light
|
|
140
|
+
* chain, receive-only shadows — instead of the unlit one
|
|
141
|
+
*/
|
|
142
|
+
constructor({ lit = false, ...params } = {}) {
|
|
57
143
|
super({
|
|
58
144
|
fragmentShader,
|
|
59
145
|
vertexShader,
|
|
60
|
-
uniforms:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
value: null
|
|
64
|
-
|
|
65
|
-
|
|
146
|
+
uniforms: lit
|
|
147
|
+
? UniformsUtils.merge([
|
|
148
|
+
UniformsLib.lights,
|
|
149
|
+
{ uDiffuse: { value: null } }
|
|
150
|
+
])
|
|
151
|
+
: {
|
|
152
|
+
uDiffuse: {
|
|
153
|
+
type: 't',
|
|
154
|
+
value: null
|
|
155
|
+
}
|
|
156
|
+
},
|
|
66
157
|
defines: {
|
|
67
|
-
USE_TEXTURE: false
|
|
158
|
+
USE_TEXTURE: false,
|
|
159
|
+
// a `false` define is omitted from the compiled shader entirely,
|
|
160
|
+
// not emitted as "#define LIT false"
|
|
161
|
+
LIT: lit
|
|
68
162
|
},
|
|
163
|
+
// wires the renderer's light state into the merged uniforms
|
|
164
|
+
lights: lit,
|
|
69
165
|
blending: NormalBlending,
|
|
70
166
|
transparent: true,
|
|
71
167
|
// The primary use is transparent trails (depthWrite: false). Callers that
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Material configuration for a {@link TubeX}. Used as a cache key in
|
|
3
3
|
* {@link TubeXPlugin}, so any field that changes the compiled material (texture,
|
|
4
|
-
* depth-write mode) participates in {@link equals}/{@link hash}.
|
|
4
|
+
* depth-write mode, lighting) participates in {@link equals}/{@link hash}.
|
|
5
5
|
*/
|
|
6
6
|
export class TubeXMaterialSpec {
|
|
7
7
|
/**
|
|
@@ -16,11 +16,18 @@ export class TubeXMaterialSpec {
|
|
|
16
16
|
* @type {boolean}
|
|
17
17
|
*/
|
|
18
18
|
depthWrite: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* When true the tube shades as a matte surface under the standard scene
|
|
21
|
+
* lights and receives shadows; when false (default) it renders unlit.
|
|
22
|
+
* @type {boolean}
|
|
23
|
+
*/
|
|
24
|
+
lit: boolean;
|
|
19
25
|
equals(other: any): boolean;
|
|
20
26
|
hash(): number;
|
|
21
|
-
fromJSON({ diffuse, depthWrite }: {
|
|
27
|
+
fromJSON({ diffuse, depthWrite, lit }: {
|
|
22
28
|
diffuse: any;
|
|
23
29
|
depthWrite?: boolean;
|
|
30
|
+
lit?: boolean;
|
|
24
31
|
}): void;
|
|
25
32
|
}
|
|
26
33
|
//# sourceMappingURL=TubeXMaterialSpec.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TubeXMaterialSpec.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/trail/tube/TubeXMaterialSpec.js"],"names":[],"mappings":"AAGA;;;;GAIG;AACH;IAEI;;;OAGG;IACH,SAFU,SAAO,IAAI,CAEN;IAEf;;;;;OAKG;IACH,YAFU,OAAO,CAEE;IAEnB,
|
|
1
|
+
{"version":3,"file":"TubeXMaterialSpec.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/trail/tube/TubeXMaterialSpec.js"],"names":[],"mappings":"AAGA;;;;GAIG;AACH;IAEI;;;OAGG;IACH,SAFU,SAAO,IAAI,CAEN;IAEf;;;;;OAKG;IACH,YAFU,OAAO,CAEE;IAEnB;;;;OAIG;IACH,KAFU,OAAO,CAEL;IAEZ,4BAIC;IAED,eAEC;IAED;;;;aAeC;CACJ"}
|
|
@@ -4,7 +4,7 @@ import { computeStringHash } from "../../../../core/primitives/strings/computeSt
|
|
|
4
4
|
/**
|
|
5
5
|
* Material configuration for a {@link TubeX}. Used as a cache key in
|
|
6
6
|
* {@link TubeXPlugin}, so any field that changes the compiled material (texture,
|
|
7
|
-
* depth-write mode) participates in {@link equals}/{@link hash}.
|
|
7
|
+
* depth-write mode, lighting) participates in {@link equals}/{@link hash}.
|
|
8
8
|
*/
|
|
9
9
|
export class TubeXMaterialSpec {
|
|
10
10
|
|
|
@@ -22,16 +22,24 @@ export class TubeXMaterialSpec {
|
|
|
22
22
|
*/
|
|
23
23
|
depthWrite = false;
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* When true the tube shades as a matte surface under the standard scene
|
|
27
|
+
* lights and receives shadows; when false (default) it renders unlit.
|
|
28
|
+
* @type {boolean}
|
|
29
|
+
*/
|
|
30
|
+
lit = false;
|
|
31
|
+
|
|
25
32
|
equals(other) {
|
|
26
33
|
return this.diffuse === other.diffuse
|
|
27
|
-
&& this.depthWrite === other.depthWrite
|
|
34
|
+
&& this.depthWrite === other.depthWrite
|
|
35
|
+
&& this.lit === other.lit;
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
hash() {
|
|
31
|
-
return (computeStringHash(this.diffuse) * 2) + (this.depthWrite ? 1 : 0);
|
|
39
|
+
return (computeStringHash(this.diffuse) * 4) + (this.lit ? 2 : 0) + (this.depthWrite ? 1 : 0);
|
|
32
40
|
}
|
|
33
41
|
|
|
34
|
-
fromJSON({ diffuse, depthWrite = false }) {
|
|
42
|
+
fromJSON({ diffuse, depthWrite = false, lit = false }) {
|
|
35
43
|
|
|
36
44
|
if (diffuse !== undefined && diffuse !== null) {
|
|
37
45
|
assert.isString(diffuse, "diffuse");
|
|
@@ -43,5 +51,8 @@ export class TubeXMaterialSpec {
|
|
|
43
51
|
|
|
44
52
|
assert.isBoolean(depthWrite, "depthWrite");
|
|
45
53
|
this.depthWrite = depthWrite;
|
|
54
|
+
|
|
55
|
+
assert.isBoolean(lit, "lit");
|
|
56
|
+
this.lit = lit;
|
|
46
57
|
}
|
|
47
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TubeXPlugin.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/trail/tube/TubeXPlugin.js"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH;IAOI,8BAWC;IARG,WAAyB;IAU7B;;;OAGG;IACH,4CAFa,aAAa,CAIzB;;
|
|
1
|
+
{"version":3,"file":"TubeXPlugin.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/trail/tube/TubeXPlugin.js"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH;IAOI,8BAWC;IARG,WAAyB;IAU7B;;;OAGG;IACH,4CAFa,aAAa,CAIzB;;CA4CJ;6BAjF4B,iCAAiC;8BAChC,oBAAoB"}
|
|
@@ -48,6 +48,7 @@ export class TubeXPlugin extends EnginePlugin {
|
|
|
48
48
|
#build_material(spec) {
|
|
49
49
|
|
|
50
50
|
const material = new TubeMaterialX({
|
|
51
|
+
lit: spec.lit,
|
|
51
52
|
transparent: true,
|
|
52
53
|
depthWrite: spec.depthWrite,
|
|
53
54
|
wireframe: false
|
|
@@ -75,6 +76,11 @@ export class TubeXPlugin extends EnginePlugin {
|
|
|
75
76
|
material.needsUpdate = true;
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
// Hand the material to the material manager so renderer-wide compile steps
|
|
80
|
+
// apply — under Forward+ the lit variant is rewritten to also receive
|
|
81
|
+
// clustered point lights and decals. With no steps registered this is a
|
|
82
|
+
// pass-through. The async texture callback above still lands: the compiled
|
|
83
|
+
// material shares the source's uniform objects.
|
|
84
|
+
return this.engine.graphics.getMaterialManager().obtain(material).getValue();
|
|
79
85
|
}
|
|
80
86
|
}
|