|
@@ -352,7 +352,7 @@
|
|
|
|
|
|
/**
|
|
/**
|
|
* If you set your own WorldSpaceNode to display the Canvas2D you have to provide your own implementation of this method which computes the local position in the Canvas based on the given 3D World one.
|
|
* If you set your own WorldSpaceNode to display the Canvas2D you have to provide your own implementation of this method which computes the local position in the Canvas based on the given 3D World one.
|
|
- * Beware that you have to take under consideration the origin in your calculations! Good luck!
|
|
|
|
|
|
+ * Beware that you have to take under consideration the origin and unitScaleFactor in your calculations! Good luck!
|
|
*/
|
|
*/
|
|
public worldSpaceToNodeLocal = (worldPos: Vector3): Vector2 => {
|
|
public worldSpaceToNodeLocal = (worldPos: Vector3): Vector2 => {
|
|
let node = this._worldSpaceNode;
|
|
let node = this._worldSpaceNode;
|
|
@@ -362,11 +362,14 @@
|
|
|
|
|
|
let mtx = node.getWorldMatrix().clone();
|
|
let mtx = node.getWorldMatrix().clone();
|
|
mtx.invert();
|
|
mtx.invert();
|
|
|
|
+ let usf = this.unitScaleFactor;
|
|
let v = Vector3.TransformCoordinates(worldPos, mtx);
|
|
let v = Vector3.TransformCoordinates(worldPos, mtx);
|
|
let res = new Vector2(v.x, v.y);
|
|
let res = new Vector2(v.x, v.y);
|
|
let size = this.actualSize;
|
|
let size = this.actualSize;
|
|
- res.x += size.width * 0.5; // res is centered, make it relative to bottom/left
|
|
|
|
- res.y += size.height * 0.5;
|
|
|
|
|
|
+ res.x += (size.width/usf) * 0.5; // res is centered, make it relative to bottom/left
|
|
|
|
+ res.y += (size.height/usf) * 0.5;
|
|
|
|
+ res.x *= usf; // multiply by the unitScaleFactor, which defines if the canvas is nth time bigger than the original world plane
|
|
|
|
+ res.y *= usf;
|
|
return res;
|
|
return res;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -583,6 +586,9 @@
|
|
} else {
|
|
} else {
|
|
// The pointer is inside the Canvas, do an intersection test
|
|
// The pointer is inside the Canvas, do an intersection test
|
|
this.intersect(ii);
|
|
this.intersect(ii);
|
|
|
|
+
|
|
|
|
+ // Sort primitives to get them from top to bottom
|
|
|
|
+ ii.intersectedPrimitives = ii.intersectedPrimitives.sort((a, b) => a.prim.actualZOffset - b.prim.actualZOffset);
|
|
}
|
|
}
|
|
|
|
|
|
{
|
|
{
|
|
@@ -604,10 +610,14 @@
|
|
|
|
|
|
// Based on the previousIntersectionList and the actualInstersectionList we can determined which primitives are being hover state or loosing it
|
|
// Based on the previousIntersectionList and the actualInstersectionList we can determined which primitives are being hover state or loosing it
|
|
private _updateOverStatus(force: boolean) {
|
|
private _updateOverStatus(force: boolean) {
|
|
- if ((!force && (this.scene.getRenderId() === this._hoverStatusRenderId)) || !this._previousIntersectionList || !this._actualIntersectionList) {
|
|
|
|
|
|
+ if ((!force && (this.scene.getRenderId() === this._hoverStatusRenderId)) || !this._actualIntersectionList) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (this._previousIntersectionList == null) {
|
|
|
|
+ this._previousIntersectionList = [];
|
|
|
|
+ }
|
|
|
|
+
|
|
// Detect a change of over
|
|
// Detect a change of over
|
|
let prevPrim = this._previousOverPrimitive ? this._previousOverPrimitive.prim : null;
|
|
let prevPrim = this._previousOverPrimitive ? this._previousOverPrimitive.prim : null;
|
|
let actualPrim = this._actualOverPrimitive ? this._actualOverPrimitive.prim : null;
|
|
let actualPrim = this._actualOverPrimitive ? this._actualOverPrimitive.prim : null;
|
|
@@ -616,16 +626,31 @@
|
|
// Detect if the current pointer is captured, only fire event if they belong to the capture primitive
|
|
// Detect if the current pointer is captured, only fire event if they belong to the capture primitive
|
|
let capturedPrim = this.getCapturedPrimitive(this._primPointerInfo.pointerId);
|
|
let capturedPrim = this.getCapturedPrimitive(this._primPointerInfo.pointerId);
|
|
|
|
|
|
- // Notify the previous "over" prim that the pointer is no longer over it
|
|
|
|
- if ((capturedPrim && capturedPrim === prevPrim) || (!capturedPrim && prevPrim && !prevPrim.isDisposed)) {
|
|
|
|
- this._primPointerInfo.updateRelatedTarget(prevPrim, this._previousOverPrimitive.intersectionLocation);
|
|
|
|
- this._bubbleNotifyPrimPointerObserver(prevPrim, PrimitivePointerInfo.PointerOut, null);
|
|
|
|
- }
|
|
|
|
|
|
+ // See the NOTE section of: https://www.w3.org/TR/pointerevents/#setting-pointer-capture
|
|
|
|
+ if (capturedPrim) {
|
|
|
|
+ if (capturedPrim === prevPrim) {
|
|
|
|
+ this._primPointerInfo.updateRelatedTarget(prevPrim, this._previousOverPrimitive.intersectionLocation);
|
|
|
|
+ this._bubbleNotifyPrimPointerObserver(prevPrim, PrimitivePointerInfo.PointerOut, null);
|
|
|
|
+ } else if (capturedPrim === actualPrim) {
|
|
|
|
+ this._primPointerInfo.updateRelatedTarget(actualPrim, this._actualOverPrimitive.intersectionLocation);
|
|
|
|
+ this._bubbleNotifyPrimPointerObserver(actualPrim, PrimitivePointerInfo.PointerOver, null);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // Check for Out & Leave
|
|
|
|
+ for (let prev of this._previousIntersectionList) {
|
|
|
|
+ if (!Tools.first(this._actualIntersectionList, (pii) => pii.prim === prev.prim)) {
|
|
|
|
+ this._primPointerInfo.updateRelatedTarget(prev.prim, prev.intersectionLocation);
|
|
|
|
+ this._bubbleNotifyPrimPointerObserver(prev.prim, PrimitivePointerInfo.PointerOut, null);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- // Notify the new "over" prim that the pointer is over it
|
|
|
|
- if ((capturedPrim && capturedPrim === actualPrim) || (!capturedPrim && actualPrim)) {
|
|
|
|
- this._primPointerInfo.updateRelatedTarget(actualPrim, this._actualOverPrimitive.intersectionLocation);
|
|
|
|
- this._bubbleNotifyPrimPointerObserver(actualPrim, PrimitivePointerInfo.PointerOver, null);
|
|
|
|
|
|
+ // Check for Over & Enter
|
|
|
|
+ for (let actual of this._actualIntersectionList) {
|
|
|
|
+ if (!Tools.first(this._previousIntersectionList, (pii) => pii.prim === actual.prim)) {
|
|
|
|
+ this._primPointerInfo.updateRelatedTarget(actual.prim, actual.intersectionLocation);
|
|
|
|
+ this._bubbleNotifyPrimPointerObserver(actual.prim, PrimitivePointerInfo.PointerOver, null);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -657,7 +682,7 @@
|
|
}
|
|
}
|
|
|
|
|
|
let pii = this._primPointerInfo;
|
|
let pii = this._primPointerInfo;
|
|
- debug += `[RID:${this.scene.getRenderId()}] [${prim.hierarchyDepth}] event:${PrimitivePointerInfo.getEventTypeName(mask)}, id: ${prim.id} (${Tools.getClassName(prim)}), primPos: ${pii.primitivePointerPos.toString()}, canvasPos: ${pii.canvasPointerPos.toString()}`;
|
|
|
|
|
|
+ debug += `[RID:${this.scene.getRenderId()}] [${prim.hierarchyDepth}] event:${PrimitivePointerInfo.getEventTypeName(mask)}, id: ${prim.id} (${Tools.getClassName(prim)}), primPos: ${pii.primitivePointerPos.toString()}, canvasPos: ${pii.canvasPointerPos.toString()}, relatedTarget: ${pii.relatedTarget.id}`;
|
|
console.log(debug);
|
|
console.log(debug);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -665,56 +690,40 @@
|
|
let ppi = this._primPointerInfo;
|
|
let ppi = this._primPointerInfo;
|
|
let event = eventData ? eventData.event : null;
|
|
let event = eventData ? eventData.event : null;
|
|
|
|
|
|
- // In case of PointerOver/Out we will first notify the parent with PointerEnter/Leave
|
|
|
|
- if ((mask & (PrimitivePointerInfo.PointerOver | PrimitivePointerInfo.PointerOut)) !== 0) {
|
|
|
|
- this._notifParents(prim, mask);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let bubbleCancelled = false;
|
|
|
|
let cur = prim;
|
|
let cur = prim;
|
|
while (cur && !cur.isDisposed) {
|
|
while (cur && !cur.isDisposed) {
|
|
- // Only trigger the observers if the primitive is intersected (except for out)
|
|
|
|
- if (!bubbleCancelled) {
|
|
|
|
- this._updatePrimPointerPos(cur);
|
|
|
|
-
|
|
|
|
- // Exec the observers
|
|
|
|
- this._debugExecObserver(cur, mask);
|
|
|
|
- if (!cur._pointerEventObservable.notifyObservers(ppi, mask) && eventData instanceof PointerInfoPre) {
|
|
|
|
- eventData.skipOnPointerObservable = true;
|
|
|
|
- return false;
|
|
|
|
|
|
+ this._updatePrimPointerPos(cur);
|
|
|
|
+
|
|
|
|
+ // For the first level we have to fire Enter or Leave for corresponding Over or Out
|
|
|
|
+ if (cur === prim) {
|
|
|
|
+ // Fire the proper notification
|
|
|
|
+ if (mask === PrimitivePointerInfo.PointerOver) {
|
|
|
|
+ this._debugExecObserver(prim, PrimitivePointerInfo.PointerEnter);
|
|
|
|
+ prim._pointerEventObservable.notifyObservers(ppi, PrimitivePointerInfo.PointerEnter);
|
|
}
|
|
}
|
|
|
|
|
|
- this._triggerActionManager(cur, ppi, mask, event);
|
|
|
|
-
|
|
|
|
- // Bubble canceled? If we're not executing PointerOver or PointerOut, quit immediately
|
|
|
|
- // If it's PointerOver/Out we have to trigger PointerEnter/Leave no matter what
|
|
|
|
- if (ppi.cancelBubble) {
|
|
|
|
- if ((mask & (PrimitivePointerInfo.PointerOver | PrimitivePointerInfo.PointerOut)) === 0) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // We're dealing with PointerOver/Out, let's keep looping to fire PointerEnter/Leave, but not Over/Out anymore
|
|
|
|
- bubbleCancelled = true;
|
|
|
|
|
|
+ // Trigger a PointerLeave corresponding to the PointerOut
|
|
|
|
+ else if (mask === PrimitivePointerInfo.PointerOut) {
|
|
|
|
+ this._debugExecObserver(prim, PrimitivePointerInfo.PointerLeave);
|
|
|
|
+ prim._pointerEventObservable.notifyObservers(ppi, PrimitivePointerInfo.PointerLeave);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- // If bubble is cancel we didn't update the Primitive Pointer Pos yet, let's do it
|
|
|
|
- if (bubbleCancelled) {
|
|
|
|
- this._updatePrimPointerPos(cur);
|
|
|
|
|
|
+ // Exec the observers
|
|
|
|
+ this._debugExecObserver(cur, mask);
|
|
|
|
+ if (!cur._pointerEventObservable.notifyObservers(ppi, mask) && eventData instanceof PointerInfoPre) {
|
|
|
|
+ eventData.skipOnPointerObservable = true;
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
|
|
|
|
- // NOTE TO MYSELF, this is commented right now because it doesn't seemed needed but I can't figure out why I put this code in the first place
|
|
|
|
- //// Trigger a PointerEnter corresponding to the PointerOver
|
|
|
|
- //if (mask === PrimitivePointerInfo.PointerOver) {
|
|
|
|
- // this._debugExecObserver(cur, PrimitivePointerInfo.PointerEnter);
|
|
|
|
- // cur._pointerEventObservable.notifyObservers(ppi, PrimitivePointerInfo.PointerEnter);
|
|
|
|
- //}
|
|
|
|
|
|
+ this._triggerActionManager(cur, ppi, mask, event);
|
|
|
|
|
|
- //// Trigger a PointerLeave corresponding to the PointerOut
|
|
|
|
- //else if (mask === PrimitivePointerInfo.PointerOut) {
|
|
|
|
- // this._debugExecObserver(cur, PrimitivePointerInfo.PointerLeave);
|
|
|
|
- // cur._pointerEventObservable.notifyObservers(ppi, PrimitivePointerInfo.PointerLeave);
|
|
|
|
- //}
|
|
|
|
|
|
+ // Bubble canceled? If we're not executing PointerOver or PointerOut, quit immediately
|
|
|
|
+ // If it's PointerOver/Out we have to trigger PointerEnter/Leave no matter what
|
|
|
|
+ if (ppi.cancelBubble) {
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
|
|
// Loop to the parent
|
|
// Loop to the parent
|
|
cur = cur.parent;
|
|
cur = cur.parent;
|
|
@@ -816,29 +825,6 @@
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- _notifParents(prim: Prim2DBase, mask: number) {
|
|
|
|
- let pii = this._primPointerInfo;
|
|
|
|
-
|
|
|
|
- let curPrim: Prim2DBase = this;
|
|
|
|
-
|
|
|
|
- while (curPrim) {
|
|
|
|
- this._updatePrimPointerPos(curPrim);
|
|
|
|
-
|
|
|
|
- // Fire the proper notification
|
|
|
|
- if (mask === PrimitivePointerInfo.PointerOver) {
|
|
|
|
- this._debugExecObserver(curPrim, PrimitivePointerInfo.PointerEnter);
|
|
|
|
- curPrim._pointerEventObservable.notifyObservers(pii, PrimitivePointerInfo.PointerEnter);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Trigger a PointerLeave corresponding to the PointerOut
|
|
|
|
- else if (mask === PrimitivePointerInfo.PointerOut) {
|
|
|
|
- this._debugExecObserver(curPrim, PrimitivePointerInfo.PointerLeave);
|
|
|
|
- curPrim._pointerEventObservable.notifyObservers(pii, PrimitivePointerInfo.PointerLeave);
|
|
|
|
- }
|
|
|
|
- curPrim = curPrim.parent;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* Don't forget to call the dispose method when you're done with the Canvas instance.
|
|
* Don't forget to call the dispose method when you're done with the Canvas instance.
|
|
* But don't worry, if you dispose its scene, the canvas will be automatically disposed too.
|
|
* But don't worry, if you dispose its scene, the canvas will be automatically disposed too.
|
|
@@ -1066,7 +1052,10 @@
|
|
* Return
|
|
* Return
|
|
*/
|
|
*/
|
|
public get overPrim(): Prim2DBase {
|
|
public get overPrim(): Prim2DBase {
|
|
- return this._actualOverPrimitive ? this._actualOverPrimitive.prim : null;
|
|
|
|
|
|
+ if (this._actualIntersectionList && this._actualIntersectionList.length>0) {
|
|
|
|
+ return this._actualIntersectionList[0].prim;
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1077,6 +1066,10 @@
|
|
return this.__engineData;
|
|
return this.__engineData;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ public get unitScaleFactor(): number {
|
|
|
|
+ return this._unitScaleFactor;
|
|
|
|
+ }
|
|
|
|
+
|
|
public createCanvasProfileInfoCanvas(): Canvas2D {
|
|
public createCanvasProfileInfoCanvas(): Canvas2D {
|
|
if (this._profilingCanvas) {
|
|
if (this._profilingCanvas) {
|
|
return this._profilingCanvas;
|
|
return this._profilingCanvas;
|
|
@@ -1242,7 +1235,11 @@
|
|
private _beforeRenderObserver: Observer<Scene>;
|
|
private _beforeRenderObserver: Observer<Scene>;
|
|
private _afterRenderObserver: Observer<Scene>;
|
|
private _afterRenderObserver: Observer<Scene>;
|
|
private _supprtInstancedArray: boolean;
|
|
private _supprtInstancedArray: boolean;
|
|
|
|
+ protected _unitScaleFactor: number;
|
|
private _trackedGroups: Array<Group2D>;
|
|
private _trackedGroups: Array<Group2D>;
|
|
|
|
+ protected _trackNode: Node;
|
|
|
|
+ protected _trackNodeOffset :Vector3;
|
|
|
|
+ protected _trackNodeBillboard : boolean;
|
|
protected _maxAdaptiveWorldSpaceCanvasSize: number;
|
|
protected _maxAdaptiveWorldSpaceCanvasSize: number;
|
|
private _designSize: Size;
|
|
private _designSize: Size;
|
|
private _designUseHorizAxis: boolean;
|
|
private _designUseHorizAxis: boolean;
|
|
@@ -1269,14 +1266,20 @@
|
|
private static _v = Vector3.Zero(); // Must stay zero
|
|
private static _v = Vector3.Zero(); // Must stay zero
|
|
private static _m = Matrix.Identity();
|
|
private static _m = Matrix.Identity();
|
|
private static _mI = Matrix.Identity(); // Must stay identity
|
|
private static _mI = Matrix.Identity(); // Must stay identity
|
|
|
|
+ private static tS = Vector3.Zero();
|
|
|
|
+ private static tT = Vector3.Zero();
|
|
|
|
+ private static tR = Quaternion.Identity();
|
|
|
|
|
|
private _updateTrackedNodes() {
|
|
private _updateTrackedNodes() {
|
|
|
|
+ // Get the used camera
|
|
let cam = this.scene.cameraToUseForPointers || this.scene.activeCamera;
|
|
let cam = this.scene.cameraToUseForPointers || this.scene.activeCamera;
|
|
|
|
|
|
|
|
+ // Compute some matrix stuff
|
|
cam.getViewMatrix().multiplyToRef(cam.getProjectionMatrix(), Canvas2D._m);
|
|
cam.getViewMatrix().multiplyToRef(cam.getProjectionMatrix(), Canvas2D._m);
|
|
let rh = this.engine.getRenderHeight();
|
|
let rh = this.engine.getRenderHeight();
|
|
let v = cam.viewport.toGlobal(this.engine.getRenderWidth(), rh);
|
|
let v = cam.viewport.toGlobal(this.engine.getRenderWidth(), rh);
|
|
|
|
|
|
|
|
+ // Compute the screen position of each group that track a given scene node
|
|
for (let group of this._trackedGroups) {
|
|
for (let group of this._trackedGroups) {
|
|
if (group.isDisposed) {
|
|
if (group.isDisposed) {
|
|
continue;
|
|
continue;
|
|
@@ -1294,6 +1297,43 @@
|
|
group.x = Math.round(proj.x/s);
|
|
group.x = Math.round(proj.x/s);
|
|
group.y = Math.round((rh - proj.y)/s);
|
|
group.y = Math.round((rh - proj.y)/s);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ // If it's a WorldSpaceCanvas and it's tracking a node, let's update the WSC transformation data
|
|
|
|
+ if (this._trackNode) {
|
|
|
|
+ let rot: Quaternion = null;
|
|
|
|
+ let scale: Vector3 = null;
|
|
|
|
+
|
|
|
|
+ let worldmtx = this._trackNode.getWorldMatrix();
|
|
|
|
+ let pos = worldmtx.getTranslation().add(this._trackNodeOffset);
|
|
|
|
+ let wsc = <WorldSpaceCanvas2D><any>this;
|
|
|
|
+ let wsn = wsc.worldSpaceCanvasNode;
|
|
|
|
+
|
|
|
|
+ if (this._trackNodeBillboard) {
|
|
|
|
+ let viewMtx = cam.getViewMatrix().clone().invert();
|
|
|
|
+ viewMtx.decompose(Canvas2D.tS, Canvas2D.tR, Canvas2D.tT);
|
|
|
|
+ rot = Canvas2D.tR.clone();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ worldmtx.decompose(Canvas2D.tS, Canvas2D.tR, Canvas2D.tT);
|
|
|
|
+ let mtx = Matrix.Compose(Canvas2D.tS, Canvas2D.tR, Vector3.Zero());
|
|
|
|
+ pos = worldmtx.getTranslation().add(Vector3.TransformCoordinates(this._trackNodeOffset, mtx));
|
|
|
|
+
|
|
|
|
+ if (Canvas2D.tS.lengthSquared() !== 1) {
|
|
|
|
+ scale = Canvas2D.tS.clone();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!this._trackNodeBillboard) {
|
|
|
|
+ rot = Canvas2D.tR.clone();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (wsn instanceof AbstractMesh) {
|
|
|
|
+ wsn.position = pos;
|
|
|
|
+ wsn.rotationQuaternion = rot;
|
|
|
|
+ if (scale) {
|
|
|
|
+ wsn.scaling = scale;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1717,10 +1757,14 @@
|
|
* @param scene the Scene that owns the Canvas
|
|
* @param scene the Scene that owns the Canvas
|
|
* @param size the dimension of the Canvas in World Space
|
|
* @param size the dimension of the Canvas in World Space
|
|
* @param settings a combination of settings, possible ones are
|
|
* @param settings a combination of settings, possible ones are
|
|
- * - children: an array of direct children primitives
|
|
|
|
- * - id: a text identifier, for information purpose only, default is null.
|
|
|
|
- * - worldPosition the position of the Canvas in World Space, default is [0,0,0]
|
|
|
|
- * - worldRotation the rotation of the Canvas in World Space, default is Quaternion.Identity()
|
|
|
|
|
|
+ * - children: an array of direct children primitives
|
|
|
|
+ * - id: a text identifier, for information purpose only, default is null.
|
|
|
|
+ * - unitScaleFactor: if specified the created canvas will be with a width of size.width*unitScaleFactor and a height of size.height.unitScaleFactor. If not specified, the unit of 1 is used. You can use this setting when you're dealing with a 3D world with small coordinates and you need a Canvas having bigger coordinates (typically to display text with better quality).
|
|
|
|
+ * - worldPosition the position of the Canvas in World Space, default is [0,0,0]
|
|
|
|
+ * - worldRotation the rotation of the Canvas in World Space, default is Quaternion.Identity()
|
|
|
|
+ * - trackNode: if you want the WorldSpaceCanvas to track the position/rotation/scale of a given Scene Node, use this setting to specify the Node to track
|
|
|
|
+ * - trackNodeOffset: if you use trackNode you may want to specify a 3D Offset to apply to shift the Canvas
|
|
|
|
+ * - trackNodeBillboard: if true the WorldSpaceCanvas will always face the screen
|
|
* - sideOrientation: Unexpected behavior occur if the value is different from Mesh.DEFAULTSIDE right now, so please use this one, which is the default.
|
|
* - sideOrientation: Unexpected behavior occur if the value is different from Mesh.DEFAULTSIDE right now, so please use this one, which is the default.
|
|
* - cachingStrategy Must be CACHESTRATEGY_CANVAS for now, which is the default.
|
|
* - cachingStrategy Must be CACHESTRATEGY_CANVAS for now, which is the default.
|
|
* - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property. Default is false (the opposite of ScreenSpace).
|
|
* - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property. Default is false (the opposite of ScreenSpace).
|
|
@@ -1741,8 +1785,12 @@
|
|
|
|
|
|
children ?: Array<Prim2DBase>,
|
|
children ?: Array<Prim2DBase>,
|
|
id ?: string,
|
|
id ?: string,
|
|
|
|
+ unitScaleFactor ?: number,
|
|
worldPosition ?: Vector3,
|
|
worldPosition ?: Vector3,
|
|
worldRotation ?: Quaternion,
|
|
worldRotation ?: Quaternion,
|
|
|
|
+ trackNode ?: Node,
|
|
|
|
+ trackNodeOffset ?: Vector3,
|
|
|
|
+ trackNodeBillboard ?: boolean,
|
|
sideOrientation ?: number,
|
|
sideOrientation ?: number,
|
|
cachingStrategy ?: number,
|
|
cachingStrategy ?: number,
|
|
enableInteraction ?: boolean,
|
|
enableInteraction ?: boolean,
|
|
@@ -1763,7 +1811,11 @@
|
|
Prim2DBase._isCanvasInit = true;
|
|
Prim2DBase._isCanvasInit = true;
|
|
let s = <any>settings;
|
|
let s = <any>settings;
|
|
s.isScreenSpace = false;
|
|
s.isScreenSpace = false;
|
|
- s.size = size.clone();
|
|
|
|
|
|
+ if (settings.unitScaleFactor != null) {
|
|
|
|
+ s.size = size.multiplyByFloats(settings.unitScaleFactor, settings.unitScaleFactor);
|
|
|
|
+ } else {
|
|
|
|
+ s.size = size.clone();
|
|
|
|
+ }
|
|
settings.cachingStrategy = (settings.cachingStrategy == null) ? Canvas2D.CACHESTRATEGY_CANVAS : settings.cachingStrategy;
|
|
settings.cachingStrategy = (settings.cachingStrategy == null) ? Canvas2D.CACHESTRATEGY_CANVAS : settings.cachingStrategy;
|
|
|
|
|
|
if (settings.cachingStrategy !== Canvas2D.CACHESTRATEGY_CANVAS) {
|
|
if (settings.cachingStrategy !== Canvas2D.CACHESTRATEGY_CANVAS) {
|
|
@@ -1773,6 +1825,8 @@
|
|
super(scene, settings);
|
|
super(scene, settings);
|
|
Prim2DBase._isCanvasInit = false;
|
|
Prim2DBase._isCanvasInit = false;
|
|
|
|
|
|
|
|
+ this._unitScaleFactor = (settings.unitScaleFactor != null) ? settings.unitScaleFactor : 1;
|
|
|
|
+
|
|
this._renderableData._useMipMap = true;
|
|
this._renderableData._useMipMap = true;
|
|
this._renderableData._anisotropicLevel = 8;
|
|
this._renderableData._anisotropicLevel = 8;
|
|
|
|
|
|
@@ -1780,13 +1834,23 @@
|
|
// throw new Error("CACHESTRATEGY_DONTCACHE cache Strategy can't be used for WorldSpace Canvas");
|
|
// throw new Error("CACHESTRATEGY_DONTCACHE cache Strategy can't be used for WorldSpace Canvas");
|
|
//}
|
|
//}
|
|
|
|
|
|
|
|
+ if (settings.trackNode != null) {
|
|
|
|
+ this._trackNode = settings.trackNode;
|
|
|
|
+ this._trackNodeOffset = (settings.trackNodeOffset != null) ? settings.trackNodeOffset : Vector3.Zero();
|
|
|
|
+ this._trackNodeBillboard = (settings.trackNodeBillboard != null) ? settings.trackNodeBillboard : false;
|
|
|
|
+ } else {
|
|
|
|
+ this._trackNode = null;
|
|
|
|
+ this._trackNodeOffset = null;
|
|
|
|
+ this._trackNodeBillboard = false;
|
|
|
|
+ }
|
|
|
|
+
|
|
let createWorldSpaceNode = !settings || (settings.customWorldSpaceNode == null);
|
|
let createWorldSpaceNode = !settings || (settings.customWorldSpaceNode == null);
|
|
this._customWorldSpaceNode = !createWorldSpaceNode;
|
|
this._customWorldSpaceNode = !createWorldSpaceNode;
|
|
let id = settings ? settings.id || null : null;
|
|
let id = settings ? settings.id || null : null;
|
|
|
|
|
|
// Set the max size of texture allowed for the adaptive render of the world space canvas cached bitmap
|
|
// Set the max size of texture allowed for the adaptive render of the world space canvas cached bitmap
|
|
let capMaxTextSize = this.engine.getCaps().maxRenderTextureSize;
|
|
let capMaxTextSize = this.engine.getCaps().maxRenderTextureSize;
|
|
- let defaultTextSize = (Math.min(capMaxTextSize, 1024)); // Default is 4K if allowed otherwise the max allowed
|
|
|
|
|
|
+ let defaultTextSize = (Math.min(capMaxTextSize, 1024)); // Default is 1K if allowed otherwise the max allowed
|
|
if (settings.maxAdaptiveCanvasSize == null) {
|
|
if (settings.maxAdaptiveCanvasSize == null) {
|
|
this._maxAdaptiveWorldSpaceCanvasSize = defaultTextSize;
|
|
this._maxAdaptiveWorldSpaceCanvasSize = defaultTextSize;
|
|
} else {
|
|
} else {
|
|
@@ -1809,6 +1873,9 @@
|
|
mtl.specularColor = new Color3(0, 0, 0);
|
|
mtl.specularColor = new Color3(0, 0, 0);
|
|
mtl.disableLighting = true;
|
|
mtl.disableLighting = true;
|
|
mtl.useAlphaFromDiffuseTexture = true;
|
|
mtl.useAlphaFromDiffuseTexture = true;
|
|
|
|
+ if (settings && settings.sideOrientation) {
|
|
|
|
+ mtl.backFaceCulling = (settings.sideOrientation === Mesh.DEFAULTSIDE || settings.sideOrientation === Mesh.FRONTSIDE);
|
|
|
|
+ }
|
|
plane.position = settings && settings.worldPosition || Vector3.Zero();
|
|
plane.position = settings && settings.worldPosition || Vector3.Zero();
|
|
plane.rotationQuaternion = settings && settings.worldRotation || Quaternion.Identity();
|
|
plane.rotationQuaternion = settings && settings.worldRotation || Quaternion.Identity();
|
|
plane.material = mtl;
|
|
plane.material = mtl;
|