diff --git a/declarations/mapillary.js.flow b/declarations/mapillary.js.flow index f3b5130c1..27e9735c4 100644 --- a/declarations/mapillary.js.flow +++ b/declarations/mapillary.js.flow @@ -3113,6 +3113,7 @@ export type ViewerEventType = declare var RenderPass: {| +Opaque: 0, // 0 + +Transparent: 1, // 1 |}; /** diff --git a/src/render/GLRenderer.ts b/src/render/GLRenderer.ts index 4aec218d5..2575751d1 100644 --- a/src/render/GLRenderer.ts +++ b/src/render/GLRenderer.ts @@ -106,6 +106,7 @@ export class GLRenderer { private _subscriptions: SubscriptionHolder = new SubscriptionHolder(); private _opaqueRender$: Subject = new Subject(); + private _transparentRender$: Subject = new Subject(); constructor( canvas: HTMLCanvasElement, @@ -245,6 +246,7 @@ export class GLRenderer { renderer.resetState(); this._opaqueRender$.next(); + this._transparentRender$.next(); }); subs.push(renderSubscription); @@ -398,6 +400,10 @@ export class GLRenderer { return this._opaqueRender$; } + public get transparentRender$(): Observable { + return this._transparentRender$; + } + public get webGLRenderer$(): Observable { return this._webGLRenderer$; } diff --git a/src/viewer/CustomRenderer.ts b/src/viewer/CustomRenderer.ts index d39d40690..679510782 100644 --- a/src/viewer/CustomRenderer.ts +++ b/src/viewer/CustomRenderer.ts @@ -13,6 +13,7 @@ import { LngLatAlt } from "../api/interfaces/LngLatAlt"; import { WebGLRenderer } from "three"; import { RenderCamera } from "../render/RenderCamera"; import { IViewer } from "./interfaces/IViewer"; +import { RenderPass } from "./enums/RenderPass"; export class CustomRenderer { private _renderers: { @@ -44,7 +45,11 @@ export class CustomRenderer { renderer.onAdd(viewer, reference, gl.getContext()); })); - subs.push(this._container.glRenderer.opaqueRender$ + const render$ = renderer.renderPass === RenderPass.Opaque ? + this._container.glRenderer.opaqueRender$ : + this._container.glRenderer.transparentRender$; + + subs.push(render$ .pipe( withLatestFrom( this._container.renderService.renderCamera$, diff --git a/src/viewer/enums/RenderPass.ts b/src/viewer/enums/RenderPass.ts index a4f4533b6..88913b05a 100644 --- a/src/viewer/enums/RenderPass.ts +++ b/src/viewer/enums/RenderPass.ts @@ -3,4 +3,9 @@ export enum RenderPass { * Occurs after the background render pass. */ Opaque, + + /** + * Occurs last in the render sequence, after the opaque render pass. + */ + Transparent, } diff --git a/test/helper/GLRendererMockCreator.ts b/test/helper/GLRendererMockCreator.ts index 88f6ddba6..1ec0785ac 100644 --- a/test/helper/GLRendererMockCreator.ts +++ b/test/helper/GLRendererMockCreator.ts @@ -12,6 +12,7 @@ export class GLRendererMockCreator extends MockCreatorBase { this._mockProperty(mock, "webGLRenderer$", new Subject()); this._mockProperty(mock, "render$", new Subject()); this._mockProperty(mock, "opaqueRender$", new Subject()); + this._mockProperty(mock, "transparentRender$", new Subject()); return mock; } diff --git a/test/viewer/CustomRenderer.test.ts b/test/viewer/CustomRenderer.test.ts index 421d054cc..346f76df0 100644 --- a/test/viewer/CustomRenderer.test.ts +++ b/test/viewer/CustomRenderer.test.ts @@ -185,7 +185,7 @@ describe("CustomRenderer.add", () => { expect(invokeCount).toBe(1); }); - it("should invoke render on postrender emit", done => { + it("should invoke render on postrender opaque emit", done => { const navigator = new NavigatorMockCreator().create(); const container = new ContainerMockCreator().create(); spyOn(Navigator, "Navigator").and.returnValue(navigator); @@ -246,6 +246,68 @@ describe("CustomRenderer.add", () => { (>container.glRenderer.opaqueRender$).next(); }); + + it("should invoke render on postrender transparent emit", done => { + const navigator = new NavigatorMockCreator().create(); + const container = new ContainerMockCreator().create(); + spyOn(Navigator, "Navigator").and.returnValue(navigator); + spyOn(Container, "Container").and.returnValue(container); + + const customRenderer = new CustomRenderer( + container, + navigator); + + const viewer = {}; + const referenceMock: LngLatAlt = { alt: 1, lat: 2, lng: 2 }; + const rendererId = "id"; + + customRenderer.add( + { + id: rendererId, + renderPass: RenderPass.Transparent, + onAdd: () => { /* noop */ }, + onReference: () => { /* noop */ }, + onRemove: () => { /* noop */ }, + render: (context, viewMatrix, projectionMatrix) => { + expect(context).toBe(contextMock); + expect(viewMatrix).toEqual(viewMatrixMock); + expect(projectionMatrix).toEqual(projectionMatrixMock); + done(); + }, + }, + viewer); + + const rendererMock = new RendererMock(); + const contextMock = new MockCreator() + .create(WebGL2RenderingContext, "WebGL2RenderingContext"); + spyOn(rendererMock, "getContext").and.returnValue(contextMock); + (>container.glRenderer.webGLRenderer$) + .next(rendererMock); + (>navigator.stateService.reference$) + .next(referenceMock); + + const renderCameraMock = new RenderCamera(1, 1, RenderMode.Fill); + const viewMatrixMock = [ + 2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 2, 0, + 0, 0, 0, 2, + ]; + renderCameraMock.perspective.matrixWorldInverse + .fromArray(viewMatrixMock); + const projectionMatrixMock = [ + 3, 0, 0, 0, + 0, 3, 0, 0, + 0, 0, 3, 0, + 0, 0, 0, 3, + ]; + renderCameraMock.perspective.projectionMatrix + .fromArray(projectionMatrixMock); + (>container.renderService.renderCamera$) + .next(renderCameraMock); + + (>container.glRenderer.transparentRender$).next(); + }); }); describe("CustomRenderer.remove", () => {