Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebXRImageTracking and NativeEngine changes to support image tracking in BabylonNative #12097

Merged
merged 2 commits into from
Mar 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Engines/ICanvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ export interface IImage {
*/
onload: ((this: GlobalEventHandlers, ev: Event) => any) | null;

/**
* Error callback.
*/
onerror: ((this: GlobalEventHandlers, ev: Event) => any) | null;

/**
* Image source.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/Engines/Native/nativeInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface INativeEngine {
copyTexture(desination: Nullable<WebGLTexture>, source: Nullable<WebGLTexture>): void;
deleteTexture(texture: Nullable<WebGLTexture>): void;

createImageBitmap(data: ArrayBufferView): ImageBitmap;
createImageBitmap(data: ArrayBufferView | IImage): ImageBitmap;
resizeImageBitmap(image: ImageBitmap, bufferWidth: number, bufferHeight: number): Uint8Array;

createFrameBuffer(texture: WebGLTexture, width: number, height: number, format: number, generateStencilBuffer: boolean, generateDepthBuffer: boolean, generateMips: boolean): WebGLFramebuffer;
Expand Down
27 changes: 27 additions & 0 deletions src/Engines/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,33 @@ export class Engine extends ThinEngine {
return EngineStore.LastCreatedScene;
}

/** @hidden */
/**
* Engine abstraction for loading and creating an image bitmap from a given source string.
* @param imageSource source to load the image from.
* @param options An object that sets options for the image's extraction.
* @returns ImageBitmap.
*/
public createImageBitmapFromSource(imageSource: string, options?: ImageBitmapOptions): Promise<ImageBitmap> {
const promise = new Promise<ImageBitmap>((resolve, reject) => {
const image = new Image();
image.onload = () => {
image.decode().then(() => {
this.createImageBitmap(image, options).then((imageBitmap) => {
resolve(imageBitmap);
});
});
};
image.onerror = () => {
reject(`Error loading image ${image.src}`);
};

image.src = imageSource;
});

return promise;
}

/**
* Engine abstraction for createImageBitmap
* @param image source for image
Expand Down
29 changes: 29 additions & 0 deletions src/Engines/nativeEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2260,6 +2260,35 @@ export class NativeEngine extends Engine {
}
}

/** @hidden */
/**
* Engine abstraction for loading and creating an image bitmap from a given source string.
* @param imageSource source to load the image from.
* @param options An object that sets options for the image's extraction.
* @returns ImageBitmap
*/
public createImageBitmapFromSource(imageSource: string, options?: ImageBitmapOptions): Promise<ImageBitmap> {
const promise = new Promise<ImageBitmap>((resolve, reject) => {
const image = this.createCanvasImage();
image.onload = () => {
const imageBitmap = this._engine.createImageBitmap(image);
if (imageBitmap) {
resolve(imageBitmap);
return;
} else {
reject (`Error loading image ${image.src}`);
}
};
image.onerror = () => {
reject(`Error loading image ${image.src}`);
};

image.src = imageSource;
});

return promise;
}

/**
* Engine abstraction for createImageBitmap
* @param image source for image
Expand Down
78 changes: 35 additions & 43 deletions src/XR/features/WebXRImageTracking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { WebXRSessionManager } from "../webXRSessionManager";
import { Observable } from "../../Misc/observable";
import { WebXRAbstractFeature } from "./WebXRAbstractFeature";
import { Matrix } from "../../Maths/math.vector";
import { Tools } from "../../Misc/tools";
import { Nullable } from "../../types";
import { Tools } from "../../Misc/tools";

declare const XRImageTrackingResult: XRImageTrackingResult;

Expand Down Expand Up @@ -91,6 +91,7 @@ export class WebXRImageTracking extends WebXRAbstractFeature {
*/
public onTrackedImageUpdatedObservable: Observable<IWebXRTrackedImage> = new Observable();

private _trackableScoresReceived: boolean = false;
private _trackedImages: IWebXRTrackedImage[] = [];

private _originalTrackingRequest: XRTrackedImageInit[];
Expand All @@ -109,17 +110,6 @@ export class WebXRImageTracking extends WebXRAbstractFeature {
) {
super(_xrSessionManager);
this.xrNativeFeatureName = "image-tracking";
if (this.options.images.length === 0) {
// no images provided?... return.
return;
}
if (this._xrSessionManager.session) {
this._init();
} else {
this._xrSessionManager.onXRSessionInit.addOnce(() => {
this._init();
});
}
}

/**
Expand Down Expand Up @@ -184,47 +174,47 @@ export class WebXRImageTracking extends WebXRAbstractFeature {
}
const promises = this.options.images.map((image) => {
if (typeof image.src === "string") {
const p = new Promise<ImageBitmap>((resolve, reject) => {
if (typeof image.src === "string") {
const img = new Image();
img.src = image.src;
img.onload = () => {
img.decode().then(() => {
this._xrSessionManager.scene.getEngine().createImageBitmap(img).then((imageBitmap) => {
resolve(imageBitmap);
});
});
};
img.onerror = () => {
Tools.Error(`Error loading image ${image.src}`);
reject(`Error loading image ${image.src}`);
};
}
});
return p;
return this._xrSessionManager.scene.getEngine().createImageBitmapFromSource(image.src);
} else {
return Promise.resolve(image.src); // resolve is probably unneeded
}
});

const images = await Promise.all(promises);
try
{
const images = await Promise.all(promises);

this._originalTrackingRequest = images.map((image, idx) => {
return {
image,
widthInMeters: this.options.images[idx].estimatedRealWorldWidth,
};
});

this._originalTrackingRequest = images.map((image, idx) => {
return {
image,
widthInMeters: this.options.images[idx].estimatedRealWorldWidth,
trackedImages: this._originalTrackingRequest,
};
});

return {
trackedImages: this._originalTrackingRequest,
};
} catch (ex) {
Tools.Error("Error loading images for tracking, WebXRImageTracking disabled for this session.");
return {};
}
}

protected _onXRFrame(_xrFrame: XRFrame) {
if (!_xrFrame.getImageTrackingResults) {
return;
}

// Image tracking scores may be generated a few frames after the XR Session initializes.
// If we haven't received scores yet, then check scores first then bail out if necessary.
if (!this._trackableScoresReceived) {
this._checkScores();

if (!this._trackableScoresReceived) {
return;
}
}

const imageTrackedResults = _xrFrame.getImageTrackingResults();
for (const result of imageTrackedResults) {
let changed = false;
Expand Down Expand Up @@ -267,12 +257,12 @@ export class WebXRImageTracking extends WebXRAbstractFeature {
}
}

private async _init() {
if (!this._xrSessionManager.session.getTrackedImageScores) {
private _checkScores(): void {
if (!this._xrSessionManager.session.getTrackedImageScores || this._trackableScoresReceived) {
return;
}
//
const imageScores = await this._xrSessionManager.session.getTrackedImageScores();

const imageScores = this._xrSessionManager.session.getTrackedImageScores();
// check the scores for all
for (let idx = 0; idx < imageScores.length; ++idx) {
if (imageScores[idx] == "untrackable") {
Expand All @@ -289,6 +279,8 @@ export class WebXRImageTracking extends WebXRAbstractFeature {
this.onTrackableImageFoundObservable.notifyObservers(imageObject);
}
}

this._trackableScoresReceived ||= imageScores.length > 0;
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/XR/native/nativeXRFrame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ export class NativeXRFrame implements XRFrame {
public get featurePointCloud(): number[] | undefined {
return this._nativeImpl.featurePointCloud;
}

public readonly getImageTrackingResults = this._nativeImpl.getImageTrackingResults!.bind(this._nativeImpl);
}

RegisterNativeTypeAsync("NativeXRFrame", NativeXRFrame);