@babylonjs/addons 7.32.4 → 7.34.0
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/htmlMesh/fitStrategy.d.ts +10 -0
- package/htmlMesh/fitStrategy.js +84 -0
- package/htmlMesh/fitStrategy.js.map +1 -0
- package/htmlMesh/htmlMesh.d.ts +114 -0
- package/htmlMesh/htmlMesh.js +301 -0
- package/htmlMesh/htmlMesh.js.map +1 -0
- package/htmlMesh/htmlMeshRenderer.d.ts +72 -0
- package/htmlMesh/htmlMeshRenderer.js +464 -0
- package/htmlMesh/htmlMeshRenderer.js.map +1 -0
- package/htmlMesh/index.d.ts +5 -0
- package/htmlMesh/index.js +7 -0
- package/htmlMesh/index.js.map +1 -0
- package/htmlMesh/pointerEventsCapture.d.ts +37 -0
- package/htmlMesh/pointerEventsCapture.js +152 -0
- package/htmlMesh/pointerEventsCapture.js.map +1 -0
- package/htmlMesh/pointerEventsCaptureBehavior.d.ts +47 -0
- package/htmlMesh/pointerEventsCaptureBehavior.js +191 -0
- package/htmlMesh/pointerEventsCaptureBehavior.js.map +1 -0
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
import { Matrix, Quaternion, Vector3 } from "@babylonjs/core/Maths/math.js";
|
|
2
|
+
import { Camera } from "@babylonjs/core/Cameras/camera.js";
|
|
3
|
+
import { RenderingGroup } from "@babylonjs/core/Rendering/renderingGroup.js";
|
|
4
|
+
import { Logger } from "@babylonjs/core/Misc/logger.js";
|
|
5
|
+
const _positionUpdateFailMessage = "Failed to update html mesh renderer position due to failure to get canvas rect. HtmlMesh instances may not render correctly";
|
|
6
|
+
const babylonUnitsToPixels = 100;
|
|
7
|
+
// Returns a function that ensures that HtmlMeshes are rendered before all other meshes.
|
|
8
|
+
// Note this will only be applied to group 0.
|
|
9
|
+
// If neither mesh is an HtmlMesh, then the default render order is used
|
|
10
|
+
// This prevents HtmlMeshes from appearing in front of other meshes when they are behind them
|
|
11
|
+
const renderOrderFunc = (defaultRenderOrder) => {
|
|
12
|
+
return (subMeshA, subMeshB) => {
|
|
13
|
+
const meshA = subMeshA.getMesh();
|
|
14
|
+
const meshB = subMeshB.getMesh();
|
|
15
|
+
// Use property check instead of instanceof since it is less expensive and
|
|
16
|
+
// this will be called many times per frame
|
|
17
|
+
const meshAIsHtmlMesh = meshA["isHtmlMesh"];
|
|
18
|
+
const meshBIsHtmlMesh = meshB["isHtmlMesh"];
|
|
19
|
+
if (meshAIsHtmlMesh) {
|
|
20
|
+
return meshBIsHtmlMesh ? (meshA.absolutePosition.z <= meshB.absolutePosition.z ? 1 : -1) : -1;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
return meshBIsHtmlMesh ? 1 : defaultRenderOrder(subMeshA, subMeshB);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* An instance of this is required to render HtmlMeshes in the scene.
|
|
29
|
+
* if using HtmlMeshes, you must not set render order for group 0 using
|
|
30
|
+
* scene.setRenderingOrder. You must instead pass the compare functions
|
|
31
|
+
* to the HtmlMeshRenderer constructor. If you do not, then your render
|
|
32
|
+
* order will be overwritten if the HtmlMeshRenderer is created after and
|
|
33
|
+
* the HtmlMeshes will not render correctly (they will appear in front of
|
|
34
|
+
* meshes that are actually in front of them) if the HtmlMeshRenderer is
|
|
35
|
+
* created before.
|
|
36
|
+
*/
|
|
37
|
+
export class HtmlMeshRenderer {
|
|
38
|
+
/**
|
|
39
|
+
* Contruct an instance of HtmlMeshRenderer
|
|
40
|
+
* @param scene
|
|
41
|
+
* @param options object containing the following optional properties:
|
|
42
|
+
* @returns
|
|
43
|
+
*/
|
|
44
|
+
constructor(scene, { parentContainerId = null, _containerId = "css-container", enableOverlayRender = true, defaultOpaqueRenderOrder = RenderingGroup.PainterSortCompare, defaultAlphaTestRenderOrder = RenderingGroup.PainterSortCompare, defaultTransparentRenderOrder = RenderingGroup.defaultTransparentSortCompare, } = {}) {
|
|
45
|
+
this._cache = {
|
|
46
|
+
cameraData: { fov: 0, position: new Vector3(), style: "" },
|
|
47
|
+
htmlMeshData: new WeakMap(),
|
|
48
|
+
};
|
|
49
|
+
this._width = 0;
|
|
50
|
+
this._height = 0;
|
|
51
|
+
this._heightHalf = 0;
|
|
52
|
+
// Create some refs to avoid creating new objects every frame
|
|
53
|
+
this._temp = {
|
|
54
|
+
scaleTransform: new Vector3(),
|
|
55
|
+
rotationTransform: new Quaternion(),
|
|
56
|
+
positionTransform: new Vector3(),
|
|
57
|
+
objectMatrix: Matrix.Identity(),
|
|
58
|
+
cameraWorldMatrix: Matrix.Identity(),
|
|
59
|
+
cameraRotationMatrix: Matrix.Identity(),
|
|
60
|
+
cameraWorldMatrixAsArray: new Array(16),
|
|
61
|
+
};
|
|
62
|
+
// Keep track of DPR so we can resize if DPR changes
|
|
63
|
+
// Otherwise the DOM content will scale, but the mesh won't
|
|
64
|
+
this._lastDevicePixelRatio = window.devicePixelRatio;
|
|
65
|
+
// Keep track of camera matrix changes so we only update the
|
|
66
|
+
// DOM element styles when necessary
|
|
67
|
+
this._cameraMatrixUpdated = true;
|
|
68
|
+
// Keep track of position changes so we only update the DOM element
|
|
69
|
+
// styles when necessary
|
|
70
|
+
this._previousCanvasDocumentPosition = {
|
|
71
|
+
top: 0,
|
|
72
|
+
left: 0,
|
|
73
|
+
};
|
|
74
|
+
this._renderObserver = null;
|
|
75
|
+
this._onCameraMatrixChanged = (camera) => {
|
|
76
|
+
this._cameraWorldMatrix = camera.getWorldMatrix();
|
|
77
|
+
this._cameraMatrixUpdated = true;
|
|
78
|
+
};
|
|
79
|
+
// Requires a browser to work. Only init if we are in a browser
|
|
80
|
+
if (typeof document === "undefined") {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
this._containerId = _containerId;
|
|
84
|
+
this._init(scene, parentContainerId, enableOverlayRender, defaultOpaqueRenderOrder, defaultAlphaTestRenderOrder, defaultTransparentRenderOrder);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Dispose of the HtmlMeshRenderer
|
|
88
|
+
*/
|
|
89
|
+
dispose() {
|
|
90
|
+
if (this._renderObserver) {
|
|
91
|
+
this._renderObserver.remove();
|
|
92
|
+
this._renderObserver = null;
|
|
93
|
+
}
|
|
94
|
+
this._overlayElements?.container.remove();
|
|
95
|
+
this._overlayElements = null;
|
|
96
|
+
this._inSceneElements?.container.remove();
|
|
97
|
+
this._inSceneElements = null;
|
|
98
|
+
}
|
|
99
|
+
_init(scene, parentContainerId, enableOverlayRender, defaultOpaqueRenderOrder, defaultAlphaTestRenderOrder, defaultTransparentRenderOrder) {
|
|
100
|
+
// Requires a browser to work. Only init if we are in a browser
|
|
101
|
+
if (typeof document === "undefined") {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// Create the DOM containers
|
|
105
|
+
let parentContainer = parentContainerId ? document.getElementById(parentContainerId) : document.body;
|
|
106
|
+
if (!parentContainer) {
|
|
107
|
+
parentContainer = document.body;
|
|
108
|
+
}
|
|
109
|
+
// if the container already exists, then remove it
|
|
110
|
+
const inSceneContainerId = `${this._containerId}_in_scene`;
|
|
111
|
+
this._inSceneElements = this._createRenderLayerElements(inSceneContainerId);
|
|
112
|
+
parentContainer.insertBefore(this._inSceneElements.container, parentContainer.firstChild);
|
|
113
|
+
if (enableOverlayRender) {
|
|
114
|
+
const overlayContainerId = `${this._containerId}_overlay`;
|
|
115
|
+
this._overlayElements = this._createRenderLayerElements(overlayContainerId);
|
|
116
|
+
const zIndex = +(scene.getEngine().getRenderingCanvas().style.zIndex ?? "0") + 1;
|
|
117
|
+
this._overlayElements.container.style.zIndex = `${zIndex}`;
|
|
118
|
+
this._overlayElements.container.style.pointerEvents = "none";
|
|
119
|
+
parentContainer.insertBefore(this._overlayElements.container, parentContainer.firstChild);
|
|
120
|
+
}
|
|
121
|
+
this._engine = scene.getEngine();
|
|
122
|
+
const clientRect = this._engine.getRenderingCanvasClientRect();
|
|
123
|
+
if (!clientRect) {
|
|
124
|
+
throw new Error("Failed to get client rect for rendering canvas");
|
|
125
|
+
}
|
|
126
|
+
// Set the size and resize behavior
|
|
127
|
+
this._setSize(clientRect.width, clientRect.height);
|
|
128
|
+
this._engine.onResizeObservable.add(() => {
|
|
129
|
+
const clientRect = this._engine.getRenderingCanvasClientRect();
|
|
130
|
+
if (clientRect) {
|
|
131
|
+
this._setSize(clientRect.width, clientRect.height);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
let projectionObs;
|
|
135
|
+
let matrixObs;
|
|
136
|
+
const observeCamera = () => {
|
|
137
|
+
const camera = scene.activeCamera;
|
|
138
|
+
if (camera) {
|
|
139
|
+
projectionObs = camera.onProjectionMatrixChangedObservable.add(() => {
|
|
140
|
+
this._onCameraMatrixChanged(camera);
|
|
141
|
+
});
|
|
142
|
+
matrixObs = camera.onViewMatrixChangedObservable.add(() => {
|
|
143
|
+
this._onCameraMatrixChanged(camera);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
observeCamera();
|
|
148
|
+
scene.onActiveCameraChanged.add(() => {
|
|
149
|
+
if (projectionObs) {
|
|
150
|
+
scene.activeCamera?.onProjectionMatrixChangedObservable.remove(projectionObs);
|
|
151
|
+
}
|
|
152
|
+
if (matrixObs) {
|
|
153
|
+
scene.activeCamera?.onViewMatrixChangedObservable.remove(matrixObs);
|
|
154
|
+
}
|
|
155
|
+
observeCamera();
|
|
156
|
+
});
|
|
157
|
+
// We need to make sure that HtmlMeshes are rendered before all other meshes
|
|
158
|
+
// so that they don't appear in front of meshes that are actually in front of them
|
|
159
|
+
// Updating the render order isn't ideal, but it is the only way to acheive this
|
|
160
|
+
// The implication is that an app using the HtmlMeshRendered must set the scene render order
|
|
161
|
+
// via the HtmlMeshRendered constructor
|
|
162
|
+
const opaqueRenderOrder = renderOrderFunc(defaultOpaqueRenderOrder);
|
|
163
|
+
const alphaTestRenderOrder = renderOrderFunc(defaultAlphaTestRenderOrder);
|
|
164
|
+
const transparentRenderOrder = renderOrderFunc(defaultTransparentRenderOrder);
|
|
165
|
+
scene.setRenderingOrder(0, opaqueRenderOrder, alphaTestRenderOrder, transparentRenderOrder);
|
|
166
|
+
this._renderObserver = scene.onBeforeRenderObservable.add(() => {
|
|
167
|
+
this._render(scene, scene.activeCamera);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
_createRenderLayerElements(containerId) {
|
|
171
|
+
const existingContainer = document.getElementById(containerId);
|
|
172
|
+
if (existingContainer) {
|
|
173
|
+
existingContainer.remove();
|
|
174
|
+
}
|
|
175
|
+
const container = document.createElement("div");
|
|
176
|
+
container.id = containerId;
|
|
177
|
+
container.style.position = "absolute";
|
|
178
|
+
container.style.width = "100%";
|
|
179
|
+
container.style.height = "100%";
|
|
180
|
+
container.style.zIndex = "-1";
|
|
181
|
+
const domElement = document.createElement("div");
|
|
182
|
+
domElement.style.overflow = "hidden";
|
|
183
|
+
const cameraElement = document.createElement("div");
|
|
184
|
+
cameraElement.style.webkitTransformStyle = "preserve-3d";
|
|
185
|
+
cameraElement.style.transformStyle = "preserve-3d";
|
|
186
|
+
cameraElement.style.pointerEvents = "none";
|
|
187
|
+
domElement.appendChild(cameraElement);
|
|
188
|
+
container.appendChild(domElement);
|
|
189
|
+
return {
|
|
190
|
+
container,
|
|
191
|
+
domElement,
|
|
192
|
+
cameraElement,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
_getSize() {
|
|
196
|
+
return {
|
|
197
|
+
width: this._width,
|
|
198
|
+
height: this._height,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
_setSize(width, height) {
|
|
202
|
+
this._width = width;
|
|
203
|
+
this._height = height;
|
|
204
|
+
this._heightHalf = this._height / 2;
|
|
205
|
+
if (!this._inSceneElements || !this._overlayElements) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const domElements = [this._inSceneElements.domElement, this._overlayElements.domElement, this._inSceneElements.cameraElement, this._overlayElements.cameraElement];
|
|
209
|
+
domElements.forEach((dom) => {
|
|
210
|
+
if (dom) {
|
|
211
|
+
dom.style.width = `${width}px`;
|
|
212
|
+
dom.style.height = `${height}px`;
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
// prettier-ignore
|
|
217
|
+
_getCameraCSSMatrix(matrix) {
|
|
218
|
+
const elements = matrix.m;
|
|
219
|
+
return `matrix3d(${this._epsilon(elements[0])},${this._epsilon(-elements[1])},${this._epsilon(elements[2])},${this._epsilon(elements[3])},${this._epsilon(elements[4])},${this._epsilon(-elements[5])},${this._epsilon(elements[6])},${this._epsilon(elements[7])},${this._epsilon(elements[8])},${this._epsilon(-elements[9])},${this._epsilon(elements[10])},${this._epsilon(elements[11])},${this._epsilon(elements[12])},${this._epsilon(-elements[13])},${this._epsilon(elements[14])},${this._epsilon(elements[15])})`;
|
|
220
|
+
}
|
|
221
|
+
// Convert a Babylon world matrix to a CSS matrix
|
|
222
|
+
// This also handles conversion from BJS left handed coords
|
|
223
|
+
// to CSS right handed coords
|
|
224
|
+
// prettier-ignore
|
|
225
|
+
_getHtmlContentCSSMatrix(matrix, useRightHandedSystem) {
|
|
226
|
+
const elements = matrix.m;
|
|
227
|
+
// In a right handed coordinate system, the elements 11 to 14 have to change their direction
|
|
228
|
+
const direction = useRightHandedSystem ? -1 : 1;
|
|
229
|
+
const matrix3d = `matrix3d(${this._epsilon(elements[0])},${this._epsilon(elements[1])},${this._epsilon(elements[2] * -direction)},${this._epsilon(elements[3])},${this._epsilon(-elements[4])},${this._epsilon(-elements[5])},${this._epsilon(elements[6] * direction)},${this._epsilon(-elements[7])},${this._epsilon(elements[8] * -direction)},${this._epsilon(elements[9] * -direction)},${this._epsilon(elements[10])},${this._epsilon(elements[11] * direction)},${this._epsilon(elements[12] * direction)},${this._epsilon(elements[13] * direction)},${this._epsilon(elements[14] * direction)},${this._epsilon(elements[15])})`;
|
|
230
|
+
return matrix3d;
|
|
231
|
+
}
|
|
232
|
+
_getTransformationMatrix(htmlMesh, useRightHandedSystem) {
|
|
233
|
+
// Get the camera world matrix
|
|
234
|
+
// Make sure the camera world matrix is up to date
|
|
235
|
+
if (!this._cameraWorldMatrix) {
|
|
236
|
+
this._cameraWorldMatrix = htmlMesh.getScene().activeCamera?.getWorldMatrix();
|
|
237
|
+
}
|
|
238
|
+
if (!this._cameraWorldMatrix) {
|
|
239
|
+
return Matrix.Identity();
|
|
240
|
+
}
|
|
241
|
+
const objectWorldMatrix = htmlMesh.getWorldMatrix();
|
|
242
|
+
// Scale the object matrix by the base scale factor for the mesh
|
|
243
|
+
// which is the ratio of the mesh width/height to the renderer
|
|
244
|
+
// width/height divided by the babylon units to pixels ratio
|
|
245
|
+
let widthScaleFactor = 1;
|
|
246
|
+
let heightScaleFactor = 1;
|
|
247
|
+
if (htmlMesh.sourceWidth && htmlMesh.sourceHeight) {
|
|
248
|
+
widthScaleFactor = htmlMesh.width / (htmlMesh.sourceWidth / babylonUnitsToPixels);
|
|
249
|
+
heightScaleFactor = htmlMesh.height / (htmlMesh.sourceHeight / babylonUnitsToPixels);
|
|
250
|
+
}
|
|
251
|
+
// Apply the scale to the object's world matrix. Note we aren't scaling
|
|
252
|
+
// the object, just getting a matrix as though it were scaled, so we can
|
|
253
|
+
// scale the content
|
|
254
|
+
const scaleTransform = this._temp.scaleTransform;
|
|
255
|
+
const rotationTransform = this._temp.rotationTransform;
|
|
256
|
+
const positionTransform = this._temp.positionTransform;
|
|
257
|
+
const scaledAndTranslatedObjectMatrix = this._temp.objectMatrix;
|
|
258
|
+
objectWorldMatrix.decompose(scaleTransform, rotationTransform, positionTransform);
|
|
259
|
+
scaleTransform.x *= widthScaleFactor;
|
|
260
|
+
scaleTransform.y *= heightScaleFactor;
|
|
261
|
+
Matrix.ComposeToRef(scaleTransform, rotationTransform, positionTransform, scaledAndTranslatedObjectMatrix);
|
|
262
|
+
// Adjust direction of 12 and 13 of the transformation matrix based on the handedness of the system
|
|
263
|
+
const direction = useRightHandedSystem ? -1 : 1;
|
|
264
|
+
// Adjust translation values to be from camera vs world origin
|
|
265
|
+
// Note that we are also adjusting these values to be pixels vs Babylon units
|
|
266
|
+
const position = htmlMesh.getAbsolutePosition();
|
|
267
|
+
scaledAndTranslatedObjectMatrix.setRowFromFloats(3, (-this._cameraWorldMatrix.m[12] + position.x) * babylonUnitsToPixels * direction, (-this._cameraWorldMatrix.m[13] + position.y) * babylonUnitsToPixels * direction, (this._cameraWorldMatrix.m[14] - position.z) * babylonUnitsToPixels, this._cameraWorldMatrix.m[15] * 0.00001 * babylonUnitsToPixels);
|
|
268
|
+
// Adjust other values to be pixels vs Babylon units
|
|
269
|
+
scaledAndTranslatedObjectMatrix.multiplyAtIndex(3, babylonUnitsToPixels);
|
|
270
|
+
scaledAndTranslatedObjectMatrix.multiplyAtIndex(7, babylonUnitsToPixels);
|
|
271
|
+
scaledAndTranslatedObjectMatrix.multiplyAtIndex(11, babylonUnitsToPixels);
|
|
272
|
+
return scaledAndTranslatedObjectMatrix;
|
|
273
|
+
}
|
|
274
|
+
_renderHtmlMesh(htmlMesh, useRightHandedSystem) {
|
|
275
|
+
if (!htmlMesh.element || !htmlMesh.element.firstElementChild) {
|
|
276
|
+
// nothing to render, so bail
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
// We need to ensure html mesh data is initialized before
|
|
280
|
+
// computing the base scale factor
|
|
281
|
+
let htmlMeshData = this._cache.htmlMeshData.get(htmlMesh);
|
|
282
|
+
if (!htmlMeshData) {
|
|
283
|
+
htmlMeshData = { style: "" };
|
|
284
|
+
this._cache.htmlMeshData.set(htmlMesh, htmlMeshData);
|
|
285
|
+
}
|
|
286
|
+
const cameraElement = htmlMesh._isCanvasOverlay ? this._overlayElements?.cameraElement : this._inSceneElements?.cameraElement;
|
|
287
|
+
if (htmlMesh.element.parentNode !== cameraElement) {
|
|
288
|
+
cameraElement.appendChild(htmlMesh.element);
|
|
289
|
+
}
|
|
290
|
+
// If the htmlMesh content has changed, update the base scale factor
|
|
291
|
+
if (htmlMesh.requiresUpdate) {
|
|
292
|
+
this._updateBaseScaleFactor(htmlMesh);
|
|
293
|
+
}
|
|
294
|
+
// Get the transformation matrix for the html mesh
|
|
295
|
+
const scaledAndTranslatedObjectMatrix = this._getTransformationMatrix(htmlMesh, useRightHandedSystem);
|
|
296
|
+
let style = `translate(-50%, -50%) ${this._getHtmlContentCSSMatrix(scaledAndTranslatedObjectMatrix, useRightHandedSystem)}`;
|
|
297
|
+
// In a right handed system, screens are on the wrong side of the mesh, so we have to rotate by Math.PI which results in the matrix3d seen below
|
|
298
|
+
style += `${useRightHandedSystem ? "matrix3d(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1)" : ""}`;
|
|
299
|
+
if (htmlMeshData.style !== style) {
|
|
300
|
+
htmlMesh.element.style.webkitTransform = style;
|
|
301
|
+
htmlMesh.element.style.transform = style;
|
|
302
|
+
}
|
|
303
|
+
htmlMesh._markAsUpdated();
|
|
304
|
+
}
|
|
305
|
+
_render(scene, camera) {
|
|
306
|
+
let needsUpdate = false;
|
|
307
|
+
const useRightHandedSystem = scene.useRightHandedSystem;
|
|
308
|
+
// Update the container position and size if necessary
|
|
309
|
+
this._updateContainerPositionIfNeeded();
|
|
310
|
+
// Check for a camera change
|
|
311
|
+
if (this._cameraMatrixUpdated) {
|
|
312
|
+
this._cameraMatrixUpdated = false;
|
|
313
|
+
needsUpdate = true;
|
|
314
|
+
}
|
|
315
|
+
// If the camera position has changed, then we also need to update
|
|
316
|
+
if (camera.position.x !== this._cache.cameraData.position.x ||
|
|
317
|
+
camera.position.y !== this._cache.cameraData.position.y ||
|
|
318
|
+
camera.position.z !== this._cache.cameraData.position.z) {
|
|
319
|
+
this._cache.cameraData.position.copyFrom(camera.position);
|
|
320
|
+
needsUpdate = true;
|
|
321
|
+
}
|
|
322
|
+
// Check for a dpr change
|
|
323
|
+
if (window.devicePixelRatio !== this._lastDevicePixelRatio) {
|
|
324
|
+
this._lastDevicePixelRatio = window.devicePixelRatio;
|
|
325
|
+
Logger.Log("In render - dpr changed: ", this._lastDevicePixelRatio);
|
|
326
|
+
needsUpdate = true;
|
|
327
|
+
}
|
|
328
|
+
// Check if any meshes need to be updated
|
|
329
|
+
const meshesNeedingUpdate = scene.meshes.filter((mesh) => mesh["isHtmlMesh"] && (needsUpdate || mesh.requiresUpdate));
|
|
330
|
+
needsUpdate = needsUpdate || meshesNeedingUpdate.length > 0;
|
|
331
|
+
if (!needsUpdate) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
// Get a projection matrix for the camera
|
|
335
|
+
const projectionMatrix = camera.getProjectionMatrix();
|
|
336
|
+
const fov = projectionMatrix.m[5] * this._heightHalf;
|
|
337
|
+
if (this._cache.cameraData.fov !== fov) {
|
|
338
|
+
if (camera.mode == Camera.PERSPECTIVE_CAMERA) {
|
|
339
|
+
[this._overlayElements?.domElement, this._inSceneElements?.domElement].forEach((el) => {
|
|
340
|
+
if (el) {
|
|
341
|
+
el.style.webkitPerspective = fov + "px";
|
|
342
|
+
el.style.perspective = fov + "px";
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
[this._overlayElements?.domElement, this._inSceneElements?.domElement].forEach((el) => {
|
|
348
|
+
if (el) {
|
|
349
|
+
el.style.webkitPerspective = "";
|
|
350
|
+
el.style.perspective = "";
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
this._cache.cameraData.fov = fov;
|
|
355
|
+
}
|
|
356
|
+
// Get the CSS matrix for the camera (which will include any camera rotation)
|
|
357
|
+
if (camera.parent === null) {
|
|
358
|
+
camera.computeWorldMatrix();
|
|
359
|
+
}
|
|
360
|
+
const cameraMatrixWorld = this._temp.cameraWorldMatrix;
|
|
361
|
+
cameraMatrixWorld.copyFrom(camera.getWorldMatrix());
|
|
362
|
+
const cameraRotationMatrix = this._temp.cameraRotationMatrix;
|
|
363
|
+
cameraMatrixWorld.getRotationMatrix().transposeToRef(cameraRotationMatrix);
|
|
364
|
+
const cameraMatrixWorldAsArray = this._temp.cameraWorldMatrixAsArray;
|
|
365
|
+
cameraMatrixWorld.copyToArray(cameraMatrixWorldAsArray);
|
|
366
|
+
// For a few values, we have to adjust the direction based on the handedness of the system
|
|
367
|
+
const direction = useRightHandedSystem ? 1 : -1;
|
|
368
|
+
cameraMatrixWorldAsArray[1] = cameraRotationMatrix.m[1];
|
|
369
|
+
cameraMatrixWorldAsArray[2] = cameraRotationMatrix.m[2] * direction;
|
|
370
|
+
cameraMatrixWorldAsArray[4] = cameraRotationMatrix.m[4] * direction;
|
|
371
|
+
cameraMatrixWorldAsArray[6] = cameraRotationMatrix.m[6] * direction;
|
|
372
|
+
cameraMatrixWorldAsArray[8] = cameraRotationMatrix.m[8] * direction;
|
|
373
|
+
cameraMatrixWorldAsArray[9] = cameraRotationMatrix.m[9] * direction;
|
|
374
|
+
Matrix.FromArrayToRef(cameraMatrixWorldAsArray, 0, cameraMatrixWorld);
|
|
375
|
+
const cameraCSSMatrix = this._getCameraCSSMatrix(cameraMatrixWorld);
|
|
376
|
+
const style = cameraCSSMatrix;
|
|
377
|
+
if (this._cache.cameraData.style !== style) {
|
|
378
|
+
[this._inSceneElements?.cameraElement, this._overlayElements?.cameraElement].forEach((el) => {
|
|
379
|
+
if (el) {
|
|
380
|
+
el.style.webkitTransform = style;
|
|
381
|
+
el.style.transform = style;
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
this._cache.cameraData.style = style;
|
|
385
|
+
}
|
|
386
|
+
// _Render objects if necessary
|
|
387
|
+
meshesNeedingUpdate.forEach((mesh) => {
|
|
388
|
+
this._renderHtmlMesh(mesh, useRightHandedSystem);
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
_updateBaseScaleFactor(htmlMesh) {
|
|
392
|
+
// Get screen width and height
|
|
393
|
+
let screenWidth = this._width;
|
|
394
|
+
let screenHeight = this._height;
|
|
395
|
+
// Calculate aspect ratios
|
|
396
|
+
const htmlMeshAspectRatio = (htmlMesh.width || 1) / (htmlMesh.height || 1);
|
|
397
|
+
const screenAspectRatio = screenWidth / screenHeight;
|
|
398
|
+
// Adjust screen dimensions based on aspect ratios
|
|
399
|
+
if (htmlMeshAspectRatio > screenAspectRatio) {
|
|
400
|
+
// If the HTML mesh is wider relative to its height than the screen, adjust the screen width
|
|
401
|
+
screenWidth = screenHeight * htmlMeshAspectRatio;
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
// If the HTML mesh is taller relative to its width than the screen, adjust the screen height
|
|
405
|
+
screenHeight = screenWidth / htmlMeshAspectRatio;
|
|
406
|
+
}
|
|
407
|
+
// Set content to fill screen so we get max resolution when it is shrunk to fit the mesh
|
|
408
|
+
htmlMesh.setContentSizePx(screenWidth, screenHeight);
|
|
409
|
+
}
|
|
410
|
+
_updateContainerPositionIfNeeded() {
|
|
411
|
+
// Determine if the canvas has moved on the screen
|
|
412
|
+
const canvasRect = this._engine.getRenderingCanvasClientRect();
|
|
413
|
+
// canvas rect may be null if layout not complete
|
|
414
|
+
if (!canvasRect) {
|
|
415
|
+
Logger.Warn(_positionUpdateFailMessage);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
const scrollTop = window.scrollY;
|
|
419
|
+
const scrollLeft = window.scrollX;
|
|
420
|
+
const canvasDocumentTop = canvasRect.top + scrollTop;
|
|
421
|
+
const canvasDocumentLeft = canvasRect.left + scrollLeft;
|
|
422
|
+
if (this._previousCanvasDocumentPosition.top !== canvasDocumentTop || this._previousCanvasDocumentPosition.left !== canvasDocumentLeft) {
|
|
423
|
+
this._previousCanvasDocumentPosition.top = canvasDocumentTop;
|
|
424
|
+
this._previousCanvasDocumentPosition.left = canvasDocumentLeft;
|
|
425
|
+
[this._inSceneElements?.container, this._overlayElements?.container].forEach((container) => {
|
|
426
|
+
if (!container) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
// set the top and left of the css container to match the canvas
|
|
430
|
+
const containerParent = container.offsetParent;
|
|
431
|
+
const parentRect = containerParent.getBoundingClientRect();
|
|
432
|
+
const parentDocumentTop = parentRect.top + scrollTop;
|
|
433
|
+
const parentDocumentLeft = parentRect.left + scrollLeft;
|
|
434
|
+
const ancestorMarginsAndPadding = this._getAncestorMarginsAndPadding(containerParent);
|
|
435
|
+
// Add the body margin
|
|
436
|
+
const bodyStyle = window.getComputedStyle(document.body);
|
|
437
|
+
const bodyMarginTop = parseInt(bodyStyle.marginTop, 10);
|
|
438
|
+
const bodyMarginLeft = parseInt(bodyStyle.marginLeft, 10);
|
|
439
|
+
container.style.top = `${canvasDocumentTop - parentDocumentTop - ancestorMarginsAndPadding.marginTop + ancestorMarginsAndPadding.paddingTop + bodyMarginTop}px`;
|
|
440
|
+
container.style.left = `${canvasDocumentLeft - parentDocumentLeft - ancestorMarginsAndPadding.marginLeft + ancestorMarginsAndPadding.paddingLeft + bodyMarginLeft}px`;
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
_epsilon(value) {
|
|
445
|
+
return Math.abs(value) < 1e-10 ? 0 : value;
|
|
446
|
+
}
|
|
447
|
+
// Get total margins and padding for an element, excluding the body and document margins
|
|
448
|
+
_getAncestorMarginsAndPadding(element) {
|
|
449
|
+
let marginTop = 0;
|
|
450
|
+
let marginLeft = 0;
|
|
451
|
+
let paddingTop = 0;
|
|
452
|
+
let paddingLeft = 0;
|
|
453
|
+
while (element && element !== document.body && element !== document.documentElement) {
|
|
454
|
+
const style = window.getComputedStyle(element);
|
|
455
|
+
marginTop += parseInt(style.marginTop, 10);
|
|
456
|
+
marginLeft += parseInt(style.marginLeft, 10);
|
|
457
|
+
paddingTop += parseInt(style.paddingTop, 10);
|
|
458
|
+
paddingLeft += parseInt(style.paddingLeft, 10);
|
|
459
|
+
element = element.offsetParent;
|
|
460
|
+
}
|
|
461
|
+
return { marginTop, marginLeft, paddingTop, paddingLeft };
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
//# sourceMappingURL=htmlMeshRenderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"htmlMeshRenderer.js","sourceRoot":"","sources":["../../../../dev/addons/src/htmlMesh/htmlMeshRenderer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Scene } from \"core/scene\";\r\nimport { Matrix, Quaternion, Vector3 } from \"core/Maths/math\";\r\n\r\nimport type { HtmlMesh } from \"./htmlMesh\";\r\nimport { Camera } from \"core/Cameras/camera\";\r\nimport type { SubMesh } from \"core/Meshes/subMesh\";\r\nimport { RenderingGroup } from \"core/Rendering/renderingGroup\";\r\n\r\nimport type { Observer } from \"core/Misc/observable\";\r\nimport { Logger } from \"core/Misc/logger\";\r\nimport type { AbstractEngine } from \"core/Engines\";\r\n\r\nconst _positionUpdateFailMessage = \"Failed to update html mesh renderer position due to failure to get canvas rect. HtmlMesh instances may not render correctly\";\r\nconst babylonUnitsToPixels = 100;\r\n\r\n/**\r\n * A function that compares two submeshes and returns a number indicating which\r\n * should be rendered first.\r\n */\r\ntype RenderOrderFunction = (subMeshA: SubMesh, subMeshB: SubMesh) => number;\r\n\r\ntype RenderLayerElements = {\r\n container: HTMLElement;\r\n domElement: HTMLElement;\r\n cameraElement: HTMLElement;\r\n};\r\n\r\n// Returns a function that ensures that HtmlMeshes are rendered before all other meshes.\r\n// Note this will only be applied to group 0.\r\n// If neither mesh is an HtmlMesh, then the default render order is used\r\n// This prevents HtmlMeshes from appearing in front of other meshes when they are behind them\r\nconst renderOrderFunc = (defaultRenderOrder: RenderOrderFunction): RenderOrderFunction => {\r\n return (subMeshA: SubMesh, subMeshB: SubMesh) => {\r\n const meshA = subMeshA.getMesh();\r\n const meshB = subMeshB.getMesh();\r\n\r\n // Use property check instead of instanceof since it is less expensive and\r\n // this will be called many times per frame\r\n const meshAIsHtmlMesh = (meshA as any)[\"isHtmlMesh\"];\r\n const meshBIsHtmlMesh = (meshB as any)[\"isHtmlMesh\"];\r\n if (meshAIsHtmlMesh) {\r\n return meshBIsHtmlMesh ? (meshA.absolutePosition.z <= meshB.absolutePosition.z ? 1 : -1) : -1;\r\n } else {\r\n return meshBIsHtmlMesh ? 1 : defaultRenderOrder(subMeshA, subMeshB);\r\n }\r\n };\r\n};\r\n\r\n/**\r\n * An instance of this is required to render HtmlMeshes in the scene.\r\n * if using HtmlMeshes, you must not set render order for group 0 using\r\n * scene.setRenderingOrder. You must instead pass the compare functions\r\n * to the HtmlMeshRenderer constructor. If you do not, then your render\r\n * order will be overwritten if the HtmlMeshRenderer is created after and\r\n * the HtmlMeshes will not render correctly (they will appear in front of\r\n * meshes that are actually in front of them) if the HtmlMeshRenderer is\r\n * created before.\r\n */\r\nexport class HtmlMeshRenderer {\r\n private _containerId?: string;\r\n private _inSceneElements?: RenderLayerElements | null;\r\n private _overlayElements?: RenderLayerElements | null;\r\n private _engine: AbstractEngine;\r\n\r\n private _cache = {\r\n cameraData: { fov: 0, position: new Vector3(), style: \"\" },\r\n htmlMeshData: new WeakMap<object, { style: string }>(),\r\n };\r\n private _width = 0;\r\n private _height = 0;\r\n private _heightHalf = 0;\r\n\r\n private _cameraWorldMatrix?: Matrix;\r\n\r\n // Create some refs to avoid creating new objects every frame\r\n private _temp = {\r\n scaleTransform: new Vector3(),\r\n rotationTransform: new Quaternion(),\r\n positionTransform: new Vector3(),\r\n objectMatrix: Matrix.Identity(),\r\n cameraWorldMatrix: Matrix.Identity(),\r\n cameraRotationMatrix: Matrix.Identity(),\r\n cameraWorldMatrixAsArray: new Array(16),\r\n };\r\n\r\n // Keep track of DPR so we can resize if DPR changes\r\n // Otherwise the DOM content will scale, but the mesh won't\r\n private _lastDevicePixelRatio = window.devicePixelRatio;\r\n\r\n // Keep track of camera matrix changes so we only update the\r\n // DOM element styles when necessary\r\n private _cameraMatrixUpdated = true;\r\n\r\n // Keep track of position changes so we only update the DOM element\r\n // styles when necessary\r\n private _previousCanvasDocumentPosition = {\r\n top: 0,\r\n left: 0,\r\n };\r\n\r\n private _renderObserver: Observer<Scene> | null = null;\r\n\r\n /**\r\n * Contruct an instance of HtmlMeshRenderer\r\n * @param scene\r\n * @param options object containing the following optional properties:\r\n * @returns\r\n */\r\n constructor(\r\n scene: Scene,\r\n {\r\n parentContainerId = null,\r\n _containerId = \"css-container\",\r\n enableOverlayRender = true,\r\n defaultOpaqueRenderOrder = RenderingGroup.PainterSortCompare,\r\n defaultAlphaTestRenderOrder = RenderingGroup.PainterSortCompare,\r\n defaultTransparentRenderOrder = RenderingGroup.defaultTransparentSortCompare,\r\n }: {\r\n parentContainerId?: string | null;\r\n _containerId?: string;\r\n defaultOpaqueRenderOrder?: RenderOrderFunction;\r\n defaultAlphaTestRenderOrder?: RenderOrderFunction;\r\n defaultTransparentRenderOrder?: RenderOrderFunction;\r\n enableOverlayRender?: boolean;\r\n } = {}\r\n ) {\r\n // Requires a browser to work. Only init if we are in a browser\r\n if (typeof document === \"undefined\") {\r\n return;\r\n }\r\n this._containerId = _containerId;\r\n this._init(scene, parentContainerId, enableOverlayRender, defaultOpaqueRenderOrder, defaultAlphaTestRenderOrder, defaultTransparentRenderOrder);\r\n }\r\n\r\n /**\r\n * Dispose of the HtmlMeshRenderer\r\n */\r\n public dispose() {\r\n if (this._renderObserver) {\r\n this._renderObserver.remove();\r\n this._renderObserver = null;\r\n }\r\n\r\n this._overlayElements?.container.remove();\r\n this._overlayElements = null;\r\n\r\n this._inSceneElements?.container.remove();\r\n this._inSceneElements = null;\r\n }\r\n\r\n protected _init(\r\n scene: Scene,\r\n parentContainerId: string | null,\r\n enableOverlayRender: boolean,\r\n defaultOpaqueRenderOrder: RenderOrderFunction,\r\n defaultAlphaTestRenderOrder: RenderOrderFunction,\r\n defaultTransparentRenderOrder: RenderOrderFunction\r\n ): void {\r\n // Requires a browser to work. Only init if we are in a browser\r\n if (typeof document === \"undefined\") {\r\n return;\r\n }\r\n\r\n // Create the DOM containers\r\n let parentContainer = parentContainerId ? document.getElementById(parentContainerId) : document.body;\r\n\r\n if (!parentContainer) {\r\n parentContainer = document.body;\r\n }\r\n\r\n // if the container already exists, then remove it\r\n const inSceneContainerId = `${this._containerId}_in_scene`;\r\n this._inSceneElements = this._createRenderLayerElements(inSceneContainerId);\r\n\r\n parentContainer.insertBefore(this._inSceneElements.container, parentContainer.firstChild);\r\n\r\n if (enableOverlayRender) {\r\n const overlayContainerId = `${this._containerId}_overlay`;\r\n this._overlayElements = this._createRenderLayerElements(overlayContainerId);\r\n const zIndex = +(scene.getEngine().getRenderingCanvas()!.style.zIndex ?? \"0\") + 1;\r\n this._overlayElements.container.style.zIndex = `${zIndex}`;\r\n this._overlayElements.container.style.pointerEvents = \"none\";\r\n parentContainer.insertBefore(this._overlayElements.container, parentContainer.firstChild);\r\n }\r\n this._engine = scene.getEngine();\r\n const clientRect = this._engine.getRenderingCanvasClientRect();\r\n if (!clientRect) {\r\n throw new Error(\"Failed to get client rect for rendering canvas\");\r\n }\r\n\r\n // Set the size and resize behavior\r\n this._setSize(clientRect.width, clientRect.height);\r\n\r\n this._engine.onResizeObservable.add(() => {\r\n const clientRect = this._engine.getRenderingCanvasClientRect();\r\n if (clientRect) {\r\n this._setSize(clientRect.width, clientRect.height);\r\n }\r\n });\r\n\r\n let projectionObs: Observer<Camera>;\r\n let matrixObs: Observer<Camera>;\r\n\r\n const observeCamera = () => {\r\n const camera = scene.activeCamera;\r\n if (camera) {\r\n projectionObs = camera.onProjectionMatrixChangedObservable.add(() => {\r\n this._onCameraMatrixChanged(camera);\r\n });\r\n matrixObs = camera.onViewMatrixChangedObservable.add(() => {\r\n this._onCameraMatrixChanged(camera);\r\n });\r\n }\r\n };\r\n\r\n observeCamera();\r\n\r\n scene.onActiveCameraChanged.add(() => {\r\n if (projectionObs) {\r\n scene.activeCamera?.onProjectionMatrixChangedObservable.remove(projectionObs);\r\n }\r\n if (matrixObs) {\r\n scene.activeCamera?.onViewMatrixChangedObservable.remove(matrixObs);\r\n }\r\n observeCamera();\r\n });\r\n\r\n // We need to make sure that HtmlMeshes are rendered before all other meshes\r\n // so that they don't appear in front of meshes that are actually in front of them\r\n // Updating the render order isn't ideal, but it is the only way to acheive this\r\n // The implication is that an app using the HtmlMeshRendered must set the scene render order\r\n // via the HtmlMeshRendered constructor\r\n const opaqueRenderOrder = renderOrderFunc(defaultOpaqueRenderOrder);\r\n const alphaTestRenderOrder = renderOrderFunc(defaultAlphaTestRenderOrder);\r\n const transparentRenderOrder = renderOrderFunc(defaultTransparentRenderOrder);\r\n scene.setRenderingOrder(0, opaqueRenderOrder, alphaTestRenderOrder, transparentRenderOrder);\r\n\r\n this._renderObserver = scene.onBeforeRenderObservable.add(() => {\r\n this._render(scene, scene.activeCamera as Camera);\r\n });\r\n }\r\n\r\n private _createRenderLayerElements(containerId: string): RenderLayerElements {\r\n const existingContainer = document.getElementById(containerId);\r\n if (existingContainer) {\r\n existingContainer.remove();\r\n }\r\n const container = document.createElement(\"div\");\r\n container.id = containerId;\r\n container.style.position = \"absolute\";\r\n container.style.width = \"100%\";\r\n container.style.height = \"100%\";\r\n container.style.zIndex = \"-1\";\r\n\r\n const domElement = document.createElement(\"div\");\r\n domElement.style.overflow = \"hidden\";\r\n\r\n const cameraElement = document.createElement(\"div\");\r\n\r\n cameraElement.style.webkitTransformStyle = \"preserve-3d\";\r\n cameraElement.style.transformStyle = \"preserve-3d\";\r\n\r\n cameraElement.style.pointerEvents = \"none\";\r\n\r\n domElement.appendChild(cameraElement);\r\n container.appendChild(domElement);\r\n return {\r\n container,\r\n domElement,\r\n cameraElement,\r\n };\r\n }\r\n\r\n protected _getSize(): { width: number; height: number } {\r\n return {\r\n width: this._width,\r\n height: this._height,\r\n };\r\n }\r\n\r\n protected _setSize(width: number, height: number): void {\r\n this._width = width;\r\n this._height = height;\r\n this._heightHalf = this._height / 2;\r\n\r\n if (!this._inSceneElements || !this._overlayElements) {\r\n return;\r\n }\r\n\r\n const domElements = [this._inSceneElements!.domElement, this._overlayElements!.domElement, this._inSceneElements!.cameraElement, this._overlayElements!.cameraElement];\r\n domElements.forEach((dom) => {\r\n if (dom) {\r\n dom.style.width = `${width}px`;\r\n dom.style.height = `${height}px`;\r\n }\r\n });\r\n }\r\n\r\n // prettier-ignore\r\n protected _getCameraCSSMatrix(matrix: Matrix): string {\r\n const elements = matrix.m;\r\n return `matrix3d(${\r\n this._epsilon( elements[0] )\r\n },${\r\n this._epsilon( - elements[1] )\r\n },${\r\n this._epsilon( elements[2] )\r\n },${\r\n this._epsilon( elements[3] )\r\n },${\r\n this._epsilon( elements[4] )\r\n },${\r\n this._epsilon( - elements[5] )\r\n },${\r\n this._epsilon( elements[6] )\r\n },${\r\n this._epsilon( elements[7] )\r\n },${\r\n this._epsilon( elements[8] )\r\n },${\r\n this._epsilon( - elements[9] )\r\n },${\r\n this._epsilon( elements[10] )\r\n },${\r\n this._epsilon( elements[11] )\r\n },${\r\n this._epsilon( elements[12] )\r\n },${\r\n this._epsilon( - elements[13] )\r\n },${\r\n this._epsilon( elements[14] )\r\n },${\r\n this._epsilon( elements[15] )\r\n })`;\r\n }\r\n\r\n // Convert a Babylon world matrix to a CSS matrix\r\n // This also handles conversion from BJS left handed coords\r\n // to CSS right handed coords\r\n // prettier-ignore\r\n protected _getHtmlContentCSSMatrix(matrix: Matrix, useRightHandedSystem: boolean): string {\r\n const elements = matrix.m;\r\n // In a right handed coordinate system, the elements 11 to 14 have to change their direction\r\n const direction = useRightHandedSystem ? -1 : 1;\r\n const matrix3d = `matrix3d(${\r\n this._epsilon( elements[0] )\r\n },${\r\n this._epsilon( elements[1] )\r\n },${\r\n this._epsilon( elements[2] * -direction )\r\n },${\r\n this._epsilon( elements[3] )\r\n },${\r\n this._epsilon( - elements[4] )\r\n },${\r\n this._epsilon( - elements[5] )\r\n },${\r\n this._epsilon( elements[6] * direction )\r\n },${\r\n this._epsilon( - elements[7] )\r\n },${\r\n this._epsilon( elements[8] * -direction )\r\n },${\r\n this._epsilon( elements[9] * -direction )\r\n },${\r\n this._epsilon( elements[10] )\r\n },${\r\n this._epsilon( elements[11] * direction )\r\n },${\r\n this._epsilon( elements[12] * direction )\r\n },${\r\n this._epsilon( elements[13] * direction )\r\n },${\r\n this._epsilon( elements[14] * direction )\r\n },${\r\n this._epsilon( elements[15] )\r\n })`;\r\n return matrix3d;\r\n }\r\n\r\n protected _getTransformationMatrix(htmlMesh: HtmlMesh, useRightHandedSystem: boolean): Matrix {\r\n // Get the camera world matrix\r\n // Make sure the camera world matrix is up to date\r\n if (!this._cameraWorldMatrix) {\r\n this._cameraWorldMatrix = htmlMesh.getScene().activeCamera?.getWorldMatrix();\r\n }\r\n if (!this._cameraWorldMatrix) {\r\n return Matrix.Identity();\r\n }\r\n\r\n const objectWorldMatrix = htmlMesh.getWorldMatrix();\r\n\r\n // Scale the object matrix by the base scale factor for the mesh\r\n // which is the ratio of the mesh width/height to the renderer\r\n // width/height divided by the babylon units to pixels ratio\r\n let widthScaleFactor = 1;\r\n let heightScaleFactor = 1;\r\n if (htmlMesh.sourceWidth && htmlMesh.sourceHeight) {\r\n widthScaleFactor = htmlMesh.width! / (htmlMesh.sourceWidth / babylonUnitsToPixels);\r\n heightScaleFactor = htmlMesh.height! / (htmlMesh.sourceHeight / babylonUnitsToPixels);\r\n }\r\n\r\n // Apply the scale to the object's world matrix. Note we aren't scaling\r\n // the object, just getting a matrix as though it were scaled, so we can\r\n // scale the content\r\n const scaleTransform = this._temp.scaleTransform;\r\n const rotationTransform = this._temp.rotationTransform;\r\n const positionTransform = this._temp.positionTransform;\r\n const scaledAndTranslatedObjectMatrix = this._temp.objectMatrix;\r\n\r\n objectWorldMatrix.decompose(scaleTransform, rotationTransform, positionTransform);\r\n scaleTransform.x *= widthScaleFactor;\r\n scaleTransform.y *= heightScaleFactor;\r\n\r\n Matrix.ComposeToRef(scaleTransform, rotationTransform, positionTransform, scaledAndTranslatedObjectMatrix);\r\n\r\n // Adjust direction of 12 and 13 of the transformation matrix based on the handedness of the system\r\n const direction = useRightHandedSystem ? -1 : 1;\r\n // Adjust translation values to be from camera vs world origin\r\n // Note that we are also adjusting these values to be pixels vs Babylon units\r\n const position = htmlMesh.getAbsolutePosition();\r\n scaledAndTranslatedObjectMatrix.setRowFromFloats(\r\n 3,\r\n (-this._cameraWorldMatrix.m[12] + position.x) * babylonUnitsToPixels * direction,\r\n (-this._cameraWorldMatrix.m[13] + position.y) * babylonUnitsToPixels * direction,\r\n (this._cameraWorldMatrix.m[14] - position.z) * babylonUnitsToPixels,\r\n this._cameraWorldMatrix.m[15] * 0.00001 * babylonUnitsToPixels\r\n );\r\n\r\n // Adjust other values to be pixels vs Babylon units\r\n scaledAndTranslatedObjectMatrix.multiplyAtIndex(3, babylonUnitsToPixels);\r\n scaledAndTranslatedObjectMatrix.multiplyAtIndex(7, babylonUnitsToPixels);\r\n scaledAndTranslatedObjectMatrix.multiplyAtIndex(11, babylonUnitsToPixels);\r\n\r\n return scaledAndTranslatedObjectMatrix;\r\n }\r\n\r\n protected _renderHtmlMesh(htmlMesh: HtmlMesh, useRightHandedSystem: boolean) {\r\n if (!htmlMesh.element || !htmlMesh.element.firstElementChild) {\r\n // nothing to render, so bail\r\n return;\r\n }\r\n\r\n // We need to ensure html mesh data is initialized before\r\n // computing the base scale factor\r\n let htmlMeshData = this._cache.htmlMeshData.get(htmlMesh);\r\n if (!htmlMeshData) {\r\n htmlMeshData = { style: \"\" };\r\n this._cache.htmlMeshData.set(htmlMesh, htmlMeshData);\r\n }\r\n\r\n const cameraElement = htmlMesh._isCanvasOverlay ? this._overlayElements?.cameraElement : this._inSceneElements?.cameraElement;\r\n\r\n if (htmlMesh.element.parentNode !== cameraElement) {\r\n cameraElement!.appendChild(htmlMesh.element);\r\n }\r\n\r\n // If the htmlMesh content has changed, update the base scale factor\r\n if (htmlMesh.requiresUpdate) {\r\n this._updateBaseScaleFactor(htmlMesh);\r\n }\r\n\r\n // Get the transformation matrix for the html mesh\r\n const scaledAndTranslatedObjectMatrix = this._getTransformationMatrix(htmlMesh, useRightHandedSystem);\r\n\r\n let style = `translate(-50%, -50%) ${this._getHtmlContentCSSMatrix(scaledAndTranslatedObjectMatrix, useRightHandedSystem)}`;\r\n // In a right handed system, screens are on the wrong side of the mesh, so we have to rotate by Math.PI which results in the matrix3d seen below\r\n style += `${useRightHandedSystem ? \"matrix3d(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1)\" : \"\"}`;\r\n\r\n if (htmlMeshData.style !== style) {\r\n htmlMesh.element.style.webkitTransform = style;\r\n htmlMesh.element.style.transform = style;\r\n }\r\n\r\n htmlMesh._markAsUpdated();\r\n }\r\n\r\n protected _render(scene: Scene, camera: Camera) {\r\n let needsUpdate = false;\r\n\r\n const useRightHandedSystem = scene.useRightHandedSystem;\r\n\r\n // Update the container position and size if necessary\r\n this._updateContainerPositionIfNeeded();\r\n\r\n // Check for a camera change\r\n if (this._cameraMatrixUpdated) {\r\n this._cameraMatrixUpdated = false;\r\n needsUpdate = true;\r\n }\r\n\r\n // If the camera position has changed, then we also need to update\r\n if (\r\n camera.position.x !== this._cache.cameraData.position.x ||\r\n camera.position.y !== this._cache.cameraData.position.y ||\r\n camera.position.z !== this._cache.cameraData.position.z\r\n ) {\r\n this._cache.cameraData.position.copyFrom(camera.position);\r\n needsUpdate = true;\r\n }\r\n\r\n // Check for a dpr change\r\n if (window.devicePixelRatio !== this._lastDevicePixelRatio) {\r\n this._lastDevicePixelRatio = window.devicePixelRatio;\r\n Logger.Log(\"In render - dpr changed: \", this._lastDevicePixelRatio);\r\n needsUpdate = true;\r\n }\r\n\r\n // Check if any meshes need to be updated\r\n const meshesNeedingUpdate = scene.meshes.filter((mesh) => (mesh as any)[\"isHtmlMesh\"] && (needsUpdate || (mesh as HtmlMesh).requiresUpdate));\r\n needsUpdate = needsUpdate || meshesNeedingUpdate.length > 0;\r\n\r\n if (!needsUpdate) {\r\n return;\r\n }\r\n\r\n // Get a projection matrix for the camera\r\n const projectionMatrix = camera.getProjectionMatrix();\r\n const fov = projectionMatrix.m[5] * this._heightHalf;\r\n\r\n if (this._cache.cameraData.fov !== fov) {\r\n if (camera.mode == Camera.PERSPECTIVE_CAMERA) {\r\n [this._overlayElements?.domElement, this._inSceneElements?.domElement].forEach((el) => {\r\n if (el) {\r\n el.style.webkitPerspective = fov + \"px\";\r\n el.style.perspective = fov + \"px\";\r\n }\r\n });\r\n } else {\r\n [this._overlayElements?.domElement, this._inSceneElements?.domElement].forEach((el) => {\r\n if (el) {\r\n el.style.webkitPerspective = \"\";\r\n el.style.perspective = \"\";\r\n }\r\n });\r\n }\r\n this._cache.cameraData.fov = fov;\r\n }\r\n\r\n // Get the CSS matrix for the camera (which will include any camera rotation)\r\n if (camera.parent === null) {\r\n camera.computeWorldMatrix();\r\n }\r\n\r\n const cameraMatrixWorld = this._temp.cameraWorldMatrix;\r\n cameraMatrixWorld.copyFrom(camera.getWorldMatrix());\r\n const cameraRotationMatrix = this._temp.cameraRotationMatrix;\r\n cameraMatrixWorld.getRotationMatrix().transposeToRef(cameraRotationMatrix);\r\n\r\n const cameraMatrixWorldAsArray = this._temp.cameraWorldMatrixAsArray;\r\n cameraMatrixWorld.copyToArray(cameraMatrixWorldAsArray);\r\n\r\n // For a few values, we have to adjust the direction based on the handedness of the system\r\n const direction = useRightHandedSystem ? 1 : -1;\r\n\r\n cameraMatrixWorldAsArray[1] = cameraRotationMatrix.m[1];\r\n cameraMatrixWorldAsArray[2] = cameraRotationMatrix.m[2] * direction;\r\n cameraMatrixWorldAsArray[4] = cameraRotationMatrix.m[4] * direction;\r\n cameraMatrixWorldAsArray[6] = cameraRotationMatrix.m[6] * direction;\r\n cameraMatrixWorldAsArray[8] = cameraRotationMatrix.m[8] * direction;\r\n cameraMatrixWorldAsArray[9] = cameraRotationMatrix.m[9] * direction;\r\n\r\n Matrix.FromArrayToRef(cameraMatrixWorldAsArray, 0, cameraMatrixWorld);\r\n\r\n const cameraCSSMatrix = this._getCameraCSSMatrix(cameraMatrixWorld);\r\n const style = cameraCSSMatrix;\r\n\r\n if (this._cache.cameraData.style !== style) {\r\n [this._inSceneElements?.cameraElement, this._overlayElements?.cameraElement].forEach((el) => {\r\n if (el) {\r\n el.style.webkitTransform = style;\r\n el.style.transform = style;\r\n }\r\n });\r\n this._cache.cameraData.style = style;\r\n }\r\n\r\n // _Render objects if necessary\r\n meshesNeedingUpdate.forEach((mesh) => {\r\n this._renderHtmlMesh(mesh as HtmlMesh, useRightHandedSystem);\r\n });\r\n }\r\n\r\n protected _updateBaseScaleFactor(htmlMesh: HtmlMesh) {\r\n // Get screen width and height\r\n let screenWidth = this._width;\r\n let screenHeight = this._height;\r\n\r\n // Calculate aspect ratios\r\n const htmlMeshAspectRatio = (htmlMesh.width || 1) / (htmlMesh.height || 1);\r\n const screenAspectRatio = screenWidth / screenHeight;\r\n\r\n // Adjust screen dimensions based on aspect ratios\r\n if (htmlMeshAspectRatio > screenAspectRatio) {\r\n // If the HTML mesh is wider relative to its height than the screen, adjust the screen width\r\n screenWidth = screenHeight * htmlMeshAspectRatio;\r\n } else {\r\n // If the HTML mesh is taller relative to its width than the screen, adjust the screen height\r\n screenHeight = screenWidth / htmlMeshAspectRatio;\r\n }\r\n\r\n // Set content to fill screen so we get max resolution when it is shrunk to fit the mesh\r\n htmlMesh.setContentSizePx(screenWidth, screenHeight);\r\n }\r\n\r\n protected _updateContainerPositionIfNeeded() {\r\n // Determine if the canvas has moved on the screen\r\n const canvasRect = this._engine.getRenderingCanvasClientRect();\r\n\r\n // canvas rect may be null if layout not complete\r\n if (!canvasRect) {\r\n Logger.Warn(_positionUpdateFailMessage);\r\n return;\r\n }\r\n const scrollTop = window.scrollY;\r\n const scrollLeft = window.scrollX;\r\n const canvasDocumentTop = canvasRect.top + scrollTop;\r\n const canvasDocumentLeft = canvasRect.left + scrollLeft;\r\n\r\n if (this._previousCanvasDocumentPosition.top !== canvasDocumentTop || this._previousCanvasDocumentPosition.left !== canvasDocumentLeft) {\r\n this._previousCanvasDocumentPosition.top = canvasDocumentTop;\r\n this._previousCanvasDocumentPosition.left = canvasDocumentLeft;\r\n\r\n [this._inSceneElements?.container, this._overlayElements?.container].forEach((container) => {\r\n if (!container) {\r\n return;\r\n }\r\n // set the top and left of the css container to match the canvas\r\n const containerParent = container.offsetParent as HTMLElement;\r\n const parentRect = containerParent.getBoundingClientRect();\r\n const parentDocumentTop = parentRect.top + scrollTop;\r\n const parentDocumentLeft = parentRect.left + scrollLeft;\r\n\r\n const ancestorMarginsAndPadding = this._getAncestorMarginsAndPadding(containerParent);\r\n\r\n // Add the body margin\r\n const bodyStyle = window.getComputedStyle(document.body);\r\n const bodyMarginTop = parseInt(bodyStyle.marginTop, 10);\r\n const bodyMarginLeft = parseInt(bodyStyle.marginLeft, 10);\r\n\r\n container.style.top = `${canvasDocumentTop - parentDocumentTop - ancestorMarginsAndPadding.marginTop + ancestorMarginsAndPadding.paddingTop + bodyMarginTop}px`;\r\n container.style.left = `${\r\n canvasDocumentLeft - parentDocumentLeft - ancestorMarginsAndPadding.marginLeft + ancestorMarginsAndPadding.paddingLeft + bodyMarginLeft\r\n }px`;\r\n });\r\n }\r\n }\r\n\r\n protected _onCameraMatrixChanged = (camera: Camera) => {\r\n this._cameraWorldMatrix = camera.getWorldMatrix();\r\n this._cameraMatrixUpdated = true;\r\n };\r\n\r\n private _epsilon(value: number) {\r\n return Math.abs(value) < 1e-10 ? 0 : value;\r\n }\r\n\r\n // Get total margins and padding for an element, excluding the body and document margins\r\n private _getAncestorMarginsAndPadding(element: HTMLElement) {\r\n let marginTop = 0;\r\n let marginLeft = 0;\r\n let paddingTop = 0;\r\n let paddingLeft = 0;\r\n\r\n while (element && element !== document.body && element !== document.documentElement) {\r\n const style = window.getComputedStyle(element);\r\n marginTop += parseInt(style.marginTop, 10);\r\n marginLeft += parseInt(style.marginLeft, 10);\r\n paddingTop += parseInt(style.paddingTop, 10);\r\n paddingLeft += parseInt(style.paddingLeft, 10);\r\n element = element.offsetParent as HTMLElement;\r\n }\r\n\r\n return { marginTop, marginLeft, paddingTop, paddingLeft };\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { HtmlMeshRenderer } from "./htmlMeshRenderer";
|
|
2
|
+
import { HtmlMesh } from "./htmlMesh";
|
|
3
|
+
import { PointerEventsCaptureBehavior } from "./pointerEventsCaptureBehavior";
|
|
4
|
+
import { FitStrategy } from "./fitStrategy";
|
|
5
|
+
export { HtmlMeshRenderer, HtmlMesh, PointerEventsCaptureBehavior, FitStrategy };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { HtmlMeshRenderer } from "./htmlMeshRenderer.js";
|
|
2
|
+
import { HtmlMesh } from "./htmlMesh.js";
|
|
3
|
+
import { PointerEventsCaptureBehavior } from "./pointerEventsCaptureBehavior.js";
|
|
4
|
+
import { FitStrategy } from "./fitStrategy.js";
|
|
5
|
+
// Export public classes and functions
|
|
6
|
+
export { HtmlMeshRenderer, HtmlMesh, PointerEventsCaptureBehavior, FitStrategy };
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../dev/addons/src/htmlMesh/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,sCAAsC;AACtC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,4BAA4B,EAAE,WAAW,EAAE,CAAC","sourcesContent":["import { HtmlMeshRenderer } from \"./htmlMeshRenderer\";\r\nimport { HtmlMesh } from \"./htmlMesh\";\r\nimport { PointerEventsCaptureBehavior } from \"./pointerEventsCaptureBehavior\";\r\nimport { FitStrategy } from \"./fitStrategy\";\r\n\r\n// Export public classes and functions\r\nexport { HtmlMeshRenderer, HtmlMesh, PointerEventsCaptureBehavior, FitStrategy };\r\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
type CaptureReleaseCallback = () => void;
|
|
2
|
+
/**
|
|
3
|
+
* Get the id of the object currently capturing pointer events
|
|
4
|
+
* @returns The id of the object currently capturing pointer events
|
|
5
|
+
* or null if no object is capturing pointer events
|
|
6
|
+
*/
|
|
7
|
+
export declare const getCapturingId: () => string | null;
|
|
8
|
+
/**
|
|
9
|
+
* Request that the object with the given id capture pointer events. If there is no current
|
|
10
|
+
* owner, then the request is granted immediately. If there is a current owner, then the request
|
|
11
|
+
* is queued until the current owner releases pointer events.
|
|
12
|
+
* @param requestId An id to identify the request. This id will be used to match the capture
|
|
13
|
+
* request with the release request.
|
|
14
|
+
* @param captureCallback The callback to call when the request is granted and the object is capturing
|
|
15
|
+
* @param releaseCallback The callback to call when the object is no longer capturing pointer events
|
|
16
|
+
*/
|
|
17
|
+
export declare const requestCapture: (requestId: string, captureCallback: CaptureReleaseCallback, releaseCallback: CaptureReleaseCallback) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Release pointer events from the object with the given id. If the object is the current owner
|
|
20
|
+
* then pointer events are released immediately. If the object is not the current owner, then the
|
|
21
|
+
* associated capture request is removed from the queue. If there is no matching capture request
|
|
22
|
+
* in the queue, then the release request is added to a list of unmatched release requests and will
|
|
23
|
+
* negate the next capture request with the same id. This is to guard against the possibility that
|
|
24
|
+
* the release request arrived before the capture request.
|
|
25
|
+
* @param requestId The id which should match the id of the capture request
|
|
26
|
+
*/
|
|
27
|
+
export declare const requestRelease: (requestId: string | null) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Relase pointer events from the current owner
|
|
30
|
+
*/
|
|
31
|
+
export declare const releaseCurrent: () => void;
|
|
32
|
+
declare global {
|
|
33
|
+
interface Window {
|
|
34
|
+
"pointer-events-capture-debug": boolean | null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export {};
|