Skip to content

Commit

Permalink
feat: add transparent renderpass
Browse files Browse the repository at this point in the history
Render transparently after opaque pass.
  • Loading branch information
oscarlorentzon committed Feb 2, 2024
1 parent 602bc9c commit 97f867d
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 2 deletions.
1 change: 1 addition & 0 deletions declarations/mapillary.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -3113,6 +3113,7 @@ export type ViewerEventType =

declare var RenderPass: {|
+Opaque: 0, // 0
+Transparent: 1, // 1
|};

/**
Expand Down
6 changes: 6 additions & 0 deletions src/render/GLRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export class GLRenderer {
private _subscriptions: SubscriptionHolder = new SubscriptionHolder();

private _opaqueRender$: Subject<void> = new Subject<void>();
private _transparentRender$: Subject<void> = new Subject<void>();

constructor(
canvas: HTMLCanvasElement,
Expand Down Expand Up @@ -245,6 +246,7 @@ export class GLRenderer {
renderer.resetState();

this._opaqueRender$.next();
this._transparentRender$.next();
});

subs.push(renderSubscription);
Expand Down Expand Up @@ -398,6 +400,10 @@ export class GLRenderer {
return this._opaqueRender$;
}

public get transparentRender$(): Observable<void> {
return this._transparentRender$;
}

public get webGLRenderer$(): Observable<THREE.WebGLRenderer> {
return this._webGLRenderer$;
}
Expand Down
7 changes: 6 additions & 1 deletion src/viewer/CustomRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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$,
Expand Down
5 changes: 5 additions & 0 deletions src/viewer/enums/RenderPass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
1 change: 1 addition & 0 deletions test/helper/GLRendererMockCreator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export class GLRendererMockCreator extends MockCreatorBase<GLRenderer> {
this._mockProperty(mock, "webGLRenderer$", new Subject<THREE.WebGLRenderer>());
this._mockProperty(mock, "render$", new Subject<GLRenderHash>());
this._mockProperty(mock, "opaqueRender$", new Subject<void>());
this._mockProperty(mock, "transparentRender$", new Subject<void>());

return mock;
}
Expand Down
64 changes: 63 additions & 1 deletion test/viewer/CustomRenderer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -246,6 +246,68 @@ describe("CustomRenderer.add", () => {

(<Subject<void>>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 = <any>{};
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 = <WebGLRenderer><unknown>new RendererMock();
const contextMock = new MockCreator()
.create(WebGL2RenderingContext, "WebGL2RenderingContext");
spyOn(rendererMock, "getContext").and.returnValue(contextMock);
(<Subject<WebGLRenderer>>container.glRenderer.webGLRenderer$)
.next(rendererMock);
(<Subject<LngLatAlt>>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);
(<Subject<RenderCamera>>container.renderService.renderCamera$)
.next(renderCameraMock);

(<Subject<void>>container.glRenderer.transparentRender$).next();
});
});

describe("CustomRenderer.remove", () => {
Expand Down

0 comments on commit 97f867d

Please sign in to comment.