mirror of
https://github.com/DaanVandenBosch/phantasmal-world.git
synced 2025-04-05 07:18:29 +08:00
Improved panning with perspective camera.
This commit is contained in:
parent
64daaf8fd2
commit
ff31c1ad27
@ -19,6 +19,24 @@ export function vec2_diff(v: Vec2, w: Vec2): Vec2 {
|
|||||||
|
|
||||||
export class Vec3 {
|
export class Vec3 {
|
||||||
constructor(public x: number, public y: number, public z: number) {}
|
constructor(public x: number, public y: number, public z: number) {}
|
||||||
|
|
||||||
|
magnitude(): number {
|
||||||
|
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function vec3_diff(v: Vec3, w: Vec3): Vec3 {
|
||||||
|
return new Vec3(v.x - w.x, v.y - w.y, v.z - v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the distance between points p and q. Equivalent to `vec3_diff(p, q).magnitude()`.
|
||||||
|
*/
|
||||||
|
export function vec3_dist(p: Vec3, q: Vec3): number {
|
||||||
|
const x = p.x - q.x;
|
||||||
|
const y = p.y - q.y;
|
||||||
|
const z = p.z - q.z;
|
||||||
|
return Math.sqrt(x * x + y * y + z * z);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -275,6 +293,34 @@ export class Mat4 {
|
|||||||
this.data[i + j * 4] = value;
|
this.data[i + j * 4] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
set_all(
|
||||||
|
m00: number, m01: number, m02: number, m03: number,
|
||||||
|
m10: number, m11: number, m12: number, m13: number,
|
||||||
|
m20: number, m21: number, m22: number, m23: number,
|
||||||
|
m30: number, m31: number, m32: number, m33: number,
|
||||||
|
):void {
|
||||||
|
this.data[0] = m00;
|
||||||
|
this.data[1] = m10;
|
||||||
|
this.data[2] = m20;
|
||||||
|
this.data[3] = m30;
|
||||||
|
|
||||||
|
this.data[4] = m01;
|
||||||
|
this.data[5] = m11;
|
||||||
|
this.data[6] = m21;
|
||||||
|
this.data[7] = m31;
|
||||||
|
|
||||||
|
this.data[8] = m02;
|
||||||
|
this.data[9] = m12;
|
||||||
|
this.data[10] = m22;
|
||||||
|
this.data[11] = m32;
|
||||||
|
|
||||||
|
this.data[12] = m03;
|
||||||
|
this.data[13] = m13;
|
||||||
|
this.data[14] = m23;
|
||||||
|
this.data[15] = m33;
|
||||||
|
}
|
||||||
|
|
||||||
clone(): Mat4 {
|
clone(): Mat4 {
|
||||||
return new Mat4(new Float32Array(this.data));
|
return new Mat4(new Float32Array(this.data));
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,98 @@
|
|||||||
import { Mat4, Vec3 } from "../math/linear_algebra";
|
import { Mat4, Vec3, vec3_dist } from "../math/linear_algebra";
|
||||||
|
import { deg_to_rad } from "../math";
|
||||||
|
|
||||||
|
export enum Projection {
|
||||||
|
Orthographic,
|
||||||
|
Perspective,
|
||||||
|
}
|
||||||
|
|
||||||
export class Camera {
|
export class Camera {
|
||||||
|
// Only applicable in perspective mode.
|
||||||
|
private readonly fov = deg_to_rad(75);
|
||||||
|
private readonly position: Vec3 = new Vec3(0, 0, 0);
|
||||||
private readonly look_at: Vec3 = new Vec3(0, 0, 0);
|
private readonly look_at: Vec3 = new Vec3(0, 0, 0);
|
||||||
private x_rot: number = 0;
|
private x_rot: number = 0;
|
||||||
private y_rot: number = 0;
|
private y_rot: number = 0;
|
||||||
private z_rot: number = 0;
|
private z_rot: number = 0;
|
||||||
private _zoom: number = 1;
|
private _zoom: number = 1;
|
||||||
private readonly _mat4 = Mat4.identity();
|
|
||||||
|
|
||||||
get mat4(): Mat4 {
|
readonly view_mat4 = Mat4.identity();
|
||||||
return this._mat4;
|
readonly projection_mat4 = Mat4.identity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Effective field of view in radians. Only applicable in perspective mode.
|
||||||
|
*/
|
||||||
|
get effective_fov(): number {
|
||||||
|
return 2 * Math.atan(Math.tan(0.5 * this.fov) / this._zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private viewport_width: number,
|
||||||
|
private viewport_height: number,
|
||||||
|
readonly projection: Projection,
|
||||||
|
) {
|
||||||
|
this.set_viewport(viewport_width, viewport_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_viewport(width: number, height: number): void {
|
||||||
|
this.viewport_width = width;
|
||||||
|
this.viewport_height = height;
|
||||||
|
|
||||||
|
switch (this.projection) {
|
||||||
|
case Projection.Orthographic:
|
||||||
|
{
|
||||||
|
const w = width;
|
||||||
|
const h = height;
|
||||||
|
const n = -1000;
|
||||||
|
const f = 1000;
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
this.projection_mat4.set_all(
|
||||||
|
2/w, 0, 0, 0,
|
||||||
|
0, 2/h, 0, 0,
|
||||||
|
0, 0, 2/(n-f), 0,
|
||||||
|
0, 0, 0, 1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Projection.Perspective:
|
||||||
|
{
|
||||||
|
const aspect = width / height;
|
||||||
|
|
||||||
|
const n = 0.1;
|
||||||
|
const f = 2000;
|
||||||
|
const t = n * Math.tan(0.5 * this.fov);
|
||||||
|
const b = -t;
|
||||||
|
const r = aspect * t;
|
||||||
|
const l = -r;
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
this.projection_mat4.set_all(
|
||||||
|
2*n / (r-l), 0, (l+r) / (l-r), 0,
|
||||||
|
0, 2*n / (t-b), (b+t) / (b-t), 0,
|
||||||
|
0, 0, (f+n) / (n-f), (2*f*n) / (f-n),
|
||||||
|
0, 0, 1, 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pan(x: number, y: number, z: number): this {
|
pan(x: number, y: number, z: number): this {
|
||||||
|
const pan_factor =
|
||||||
|
(3 * vec3_dist(this.position, this.look_at) * Math.tan(0.5 * this.effective_fov)) /
|
||||||
|
this.viewport_width;
|
||||||
|
|
||||||
|
x *= pan_factor;
|
||||||
|
y *= pan_factor;
|
||||||
|
|
||||||
|
this.position.x += x;
|
||||||
|
this.position.y += y;
|
||||||
|
this.position.z += z;
|
||||||
this.look_at.x += x;
|
this.look_at.x += x;
|
||||||
this.look_at.y += y;
|
this.look_at.y += y;
|
||||||
this.look_at.z += z;
|
|
||||||
this.update_matrix();
|
this.update_matrix();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -25,6 +102,9 @@ export class Camera {
|
|||||||
*/
|
*/
|
||||||
zoom(factor: number): this {
|
zoom(factor: number): this {
|
||||||
this._zoom *= factor;
|
this._zoom *= factor;
|
||||||
|
this.position.x *= factor;
|
||||||
|
this.position.y *= factor;
|
||||||
|
this.position.z *= factor;
|
||||||
this.look_at.x *= factor;
|
this.look_at.x *= factor;
|
||||||
this.look_at.y *= factor;
|
this.look_at.y *= factor;
|
||||||
this.look_at.z *= factor;
|
this.look_at.z *= factor;
|
||||||
@ -33,6 +113,9 @@ export class Camera {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reset(): this {
|
reset(): this {
|
||||||
|
this.position.x = 0;
|
||||||
|
this.position.y = 0;
|
||||||
|
this.position.z = 0;
|
||||||
this.look_at.x = 0;
|
this.look_at.x = 0;
|
||||||
this.look_at.y = 0;
|
this.look_at.y = 0;
|
||||||
this.look_at.z = 0;
|
this.look_at.z = 0;
|
||||||
@ -45,11 +128,11 @@ export class Camera {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private update_matrix(): void {
|
private update_matrix(): void {
|
||||||
this._mat4.data[12] = -this.look_at.x;
|
this.view_mat4.data[12] = this._zoom * -this.position.x;
|
||||||
this._mat4.data[13] = -this.look_at.y;
|
this.view_mat4.data[13] = this._zoom * -this.position.y;
|
||||||
this._mat4.data[14] = -this.look_at.z;
|
this.view_mat4.data[14] = this._zoom * -this.position.z;
|
||||||
this._mat4.data[0] = this._zoom;
|
this.view_mat4.data[0] = this._zoom;
|
||||||
this._mat4.data[5] = this._zoom;
|
this.view_mat4.data[5] = this._zoom;
|
||||||
this._mat4.data[10] = this._zoom;
|
this.view_mat4.data[10] = this._zoom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { Renderer } from "./Renderer";
|
import { Renderer } from "./Renderer";
|
||||||
import { Scene } from "./Scene";
|
import { Scene } from "./Scene";
|
||||||
import { Camera } from "./Camera";
|
import { Camera, Projection } from "./Camera";
|
||||||
import { Gfx } from "./Gfx";
|
import { Gfx } from "./Gfx";
|
||||||
import { Mat4, Vec2, vec2_diff } from "../math/linear_algebra";
|
import { Mat4, Vec2, vec2_diff } from "../math/linear_algebra";
|
||||||
import { deg_to_rad } from "../math";
|
|
||||||
|
|
||||||
export abstract class GfxRenderer implements Renderer {
|
export abstract class GfxRenderer implements Renderer {
|
||||||
private pointer_pos?: Vec2;
|
private pointer_pos?: Vec2;
|
||||||
@ -12,18 +11,18 @@ export abstract class GfxRenderer implements Renderer {
|
|||||||
*/
|
*/
|
||||||
private animation_frame?: number;
|
private animation_frame?: number;
|
||||||
|
|
||||||
protected projection_mat: Mat4 = Mat4.identity();
|
|
||||||
|
|
||||||
abstract readonly gfx: Gfx;
|
abstract readonly gfx: Gfx;
|
||||||
readonly scene = new Scene();
|
readonly scene = new Scene();
|
||||||
readonly camera = new Camera();
|
readonly camera: Camera;
|
||||||
readonly canvas_element: HTMLCanvasElement = document.createElement("canvas");
|
readonly canvas_element: HTMLCanvasElement = document.createElement("canvas");
|
||||||
|
|
||||||
protected constructor(private readonly perspective_projection: boolean) {
|
protected constructor(projection: Projection) {
|
||||||
this.canvas_element.width = 800;
|
this.canvas_element.width = 800;
|
||||||
this.canvas_element.height = 600;
|
this.canvas_element.height = 600;
|
||||||
this.canvas_element.addEventListener("mousedown", this.mousedown);
|
this.canvas_element.addEventListener("mousedown", this.mousedown);
|
||||||
this.canvas_element.addEventListener("wheel", this.wheel, { passive: true });
|
this.canvas_element.addEventListener("wheel", this.wheel, { passive: true });
|
||||||
|
|
||||||
|
this.camera = new Camera(this.canvas_element.width, this.canvas_element.height, projection);
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
@ -31,39 +30,7 @@ export abstract class GfxRenderer implements Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_size(width: number, height: number): void {
|
set_size(width: number, height: number): void {
|
||||||
if (this.perspective_projection) {
|
this.camera.set_viewport(width, height);
|
||||||
const fov = 75;
|
|
||||||
const aspect = width / height;
|
|
||||||
|
|
||||||
const n = 0.1;
|
|
||||||
const f = 2000;
|
|
||||||
const t = n * Math.tan(deg_to_rad(0.5 * fov));
|
|
||||||
const b = -t;
|
|
||||||
const r = aspect * t;
|
|
||||||
const l = -r;
|
|
||||||
|
|
||||||
// prettier-ignore
|
|
||||||
this.projection_mat = Mat4.of(
|
|
||||||
2*n / (r-l), 0, (r+l) / (r-l), 0,
|
|
||||||
0, 2*n / (t-b), (t+b) / (t-b), 0,
|
|
||||||
0, 0, -(f+n) / (f-n), -(2*f*n) / (f-n),
|
|
||||||
0, 0, -1, 0,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const w = width;
|
|
||||||
const h = height;
|
|
||||||
const n = -1000;
|
|
||||||
const f = 1000;
|
|
||||||
|
|
||||||
// prettier-ignore
|
|
||||||
this.projection_mat = Mat4.of(
|
|
||||||
2/w, 0, 0, 0,
|
|
||||||
0, 2/h, 0, 0,
|
|
||||||
0, 0, 2/(n-f), 0,
|
|
||||||
0, 0, 0, 1,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.schedule_render();
|
this.schedule_render();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,18 +100,22 @@ export abstract class GfxRenderer implements Renderer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private wheel = (evt: WheelEvent): void => {
|
private wheel = (evt: WheelEvent): void => {
|
||||||
if (this.perspective_projection) {
|
switch (this.camera.projection) {
|
||||||
if (evt.deltaY < 0) {
|
case Projection.Orthographic:
|
||||||
this.camera.pan(0, 0, -5);
|
if (evt.deltaY < 0) {
|
||||||
} else {
|
this.camera.zoom(1.1);
|
||||||
this.camera.pan(0, 0, 5);
|
} else {
|
||||||
}
|
this.camera.zoom(0.9);
|
||||||
} else {
|
}
|
||||||
if (evt.deltaY < 0) {
|
break;
|
||||||
this.camera.zoom(1.1);
|
|
||||||
} else {
|
case Projection.Perspective:
|
||||||
this.camera.zoom(0.9);
|
if (evt.deltaY < 0) {
|
||||||
}
|
this.camera.pan(0, 0, 5);
|
||||||
|
} else {
|
||||||
|
this.camera.pan(0, 0, -5);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.schedule_render();
|
this.schedule_render();
|
||||||
|
@ -6,6 +6,7 @@ import pos_tex_vert_shader_source from "./pos_tex.vert";
|
|||||||
import pos_tex_frag_shader_source from "./pos_tex.frag";
|
import pos_tex_frag_shader_source from "./pos_tex.frag";
|
||||||
import { GfxRenderer } from "../GfxRenderer";
|
import { GfxRenderer } from "../GfxRenderer";
|
||||||
import { WebglGfx, WebglMesh } from "./WebglGfx";
|
import { WebglGfx, WebglMesh } from "./WebglGfx";
|
||||||
|
import { Projection } from "../Camera";
|
||||||
|
|
||||||
export class WebglRenderer extends GfxRenderer {
|
export class WebglRenderer extends GfxRenderer {
|
||||||
private readonly gl: WebGL2RenderingContext;
|
private readonly gl: WebGL2RenderingContext;
|
||||||
@ -13,8 +14,8 @@ export class WebglRenderer extends GfxRenderer {
|
|||||||
|
|
||||||
readonly gfx: WebglGfx;
|
readonly gfx: WebglGfx;
|
||||||
|
|
||||||
constructor(perspective_projection: boolean) {
|
constructor(projection: Projection) {
|
||||||
super(perspective_projection);
|
super(projection);
|
||||||
|
|
||||||
const gl = this.canvas_element.getContext("webgl2");
|
const gl = this.canvas_element.getContext("webgl2");
|
||||||
|
|
||||||
@ -65,7 +66,7 @@ export class WebglRenderer extends GfxRenderer {
|
|||||||
const program = this.shader_programs[node.mesh.format];
|
const program = this.shader_programs[node.mesh.format];
|
||||||
program.bind();
|
program.bind();
|
||||||
|
|
||||||
program.set_mat_projection_uniform(this.projection_mat);
|
program.set_mat_projection_uniform(this.camera.projection_mat4);
|
||||||
program.set_mat_camera_uniform(mat);
|
program.set_mat_camera_uniform(mat);
|
||||||
program.set_mat_normal_uniform(mat.normal_mat3());
|
program.set_mat_normal_uniform(mat.normal_mat3());
|
||||||
|
|
||||||
@ -86,6 +87,6 @@ export class WebglRenderer extends GfxRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return mat;
|
return mat;
|
||||||
}, this.camera.mat4);
|
}, this.camera.view_mat4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { mat4_product } from "../../math/linear_algebra";
|
|||||||
import { WebgpuGfx, WebgpuMesh } from "./WebgpuGfx";
|
import { WebgpuGfx, WebgpuMesh } from "./WebgpuGfx";
|
||||||
import { ShaderLoader } from "./ShaderLoader";
|
import { ShaderLoader } from "./ShaderLoader";
|
||||||
import { HttpClient } from "../../HttpClient";
|
import { HttpClient } from "../../HttpClient";
|
||||||
|
import { Projection } from "../Camera";
|
||||||
|
|
||||||
const logger = LogManager.get("core/rendering/webgpu/WebgpuRenderer");
|
const logger = LogManager.get("core/rendering/webgpu/WebgpuRenderer");
|
||||||
|
|
||||||
@ -30,8 +31,8 @@ export class WebgpuRenderer extends GfxRenderer {
|
|||||||
return this.gpu!.gfx;
|
return this.gpu!.gfx;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(perspective_projection: boolean, http_client: HttpClient) {
|
constructor(projection: Projection, http_client: HttpClient) {
|
||||||
super(perspective_projection);
|
super(projection);
|
||||||
|
|
||||||
this.shader_loader = new ShaderLoader(http_client);
|
this.shader_loader = new ShaderLoader(http_client);
|
||||||
|
|
||||||
@ -175,7 +176,7 @@ export class WebgpuRenderer extends GfxRenderer {
|
|||||||
|
|
||||||
pass_encoder.setPipeline(pipeline);
|
pass_encoder.setPipeline(pipeline);
|
||||||
|
|
||||||
const camera_project_mat = mat4_product(this.projection_mat, this.camera.mat4);
|
const camera_project_mat = mat4_product(this.camera.projection_mat4, this.camera.view_mat4);
|
||||||
|
|
||||||
this.scene.traverse((node, parent_mat) => {
|
this.scene.traverse((node, parent_mat) => {
|
||||||
const mat = mat4_product(parent_mat, node.transform);
|
const mat = mat4_product(parent_mat, node.transform);
|
||||||
|
@ -6,6 +6,7 @@ import { Disposer } from "../core/observable/Disposer";
|
|||||||
import { Random } from "../core/Random";
|
import { Random } from "../core/Random";
|
||||||
import { Renderer } from "../core/rendering/Renderer";
|
import { Renderer } from "../core/rendering/Renderer";
|
||||||
import { DisposableThreeRenderer } from "../core/rendering/ThreeRenderer";
|
import { DisposableThreeRenderer } from "../core/rendering/ThreeRenderer";
|
||||||
|
import { Projection } from "../core/rendering/Camera";
|
||||||
|
|
||||||
export function initialize_viewer(
|
export function initialize_viewer(
|
||||||
http_client: HttpClient,
|
http_client: HttpClient,
|
||||||
@ -48,12 +49,15 @@ export function initialize_viewer(
|
|||||||
const { WebgpuRenderer } = await import("../core/rendering/webgpu/WebgpuRenderer");
|
const { WebgpuRenderer } = await import("../core/rendering/webgpu/WebgpuRenderer");
|
||||||
const { ModelGfxRenderer } = await import("./rendering/ModelGfxRenderer");
|
const { ModelGfxRenderer } = await import("./rendering/ModelGfxRenderer");
|
||||||
|
|
||||||
renderer = new ModelGfxRenderer(store, new WebgpuRenderer(true, http_client));
|
renderer = new ModelGfxRenderer(
|
||||||
|
store,
|
||||||
|
new WebgpuRenderer(Projection.Perspective, http_client),
|
||||||
|
);
|
||||||
} else if (gui_store.feature_active("webgl")) {
|
} else if (gui_store.feature_active("webgl")) {
|
||||||
const { WebglRenderer } = await import("../core/rendering/webgl/WebglRenderer");
|
const { WebglRenderer } = await import("../core/rendering/webgl/WebglRenderer");
|
||||||
const { ModelGfxRenderer } = await import("./rendering/ModelGfxRenderer");
|
const { ModelGfxRenderer } = await import("./rendering/ModelGfxRenderer");
|
||||||
|
|
||||||
renderer = new ModelGfxRenderer(store, new WebglRenderer(true));
|
renderer = new ModelGfxRenderer(store, new WebglRenderer(Projection.Perspective));
|
||||||
} else {
|
} else {
|
||||||
const { ModelRenderer } = await import("./rendering/ModelRenderer");
|
const { ModelRenderer } = await import("./rendering/ModelRenderer");
|
||||||
|
|
||||||
@ -79,10 +83,16 @@ export function initialize_viewer(
|
|||||||
|
|
||||||
if (gui_store.feature_active("webgpu")) {
|
if (gui_store.feature_active("webgpu")) {
|
||||||
const { WebgpuRenderer } = await import("../core/rendering/webgpu/WebgpuRenderer");
|
const { WebgpuRenderer } = await import("../core/rendering/webgpu/WebgpuRenderer");
|
||||||
renderer = new TextureRenderer(controller, new WebgpuRenderer(false, http_client));
|
renderer = new TextureRenderer(
|
||||||
|
controller,
|
||||||
|
new WebgpuRenderer(Projection.Orthographic, http_client),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
const { WebglRenderer } = await import("../core/rendering/webgl/WebglRenderer");
|
const { WebglRenderer } = await import("../core/rendering/webgl/WebglRenderer");
|
||||||
renderer = new TextureRenderer(controller, new WebglRenderer(false));
|
renderer = new TextureRenderer(
|
||||||
|
controller,
|
||||||
|
new WebglRenderer(Projection.Orthographic),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TextureView(controller, renderer);
|
return new TextureView(controller, renderer);
|
||||||
|
@ -12,7 +12,7 @@ export class ModelGfxRenderer implements Renderer {
|
|||||||
constructor(private readonly store: ModelStore, private readonly renderer: GfxRenderer) {
|
constructor(private readonly store: ModelStore, private readonly renderer: GfxRenderer) {
|
||||||
this.canvas_element = renderer.canvas_element;
|
this.canvas_element = renderer.canvas_element;
|
||||||
|
|
||||||
renderer.camera.pan(0, 0, 50);
|
renderer.camera.pan(0, 0, -50);
|
||||||
|
|
||||||
this.disposer.add_all(store.current_nj_object.observe(this.nj_object_or_xvm_changed));
|
this.disposer.add_all(store.current_nj_object.observe(this.nj_object_or_xvm_changed));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { GfxRenderer } from "../../../../src/core/rendering/GfxRenderer";
|
import { GfxRenderer } from "../../../../src/core/rendering/GfxRenderer";
|
||||||
import { Gfx } from "../../../../src/core/rendering/Gfx";
|
import { Gfx } from "../../../../src/core/rendering/Gfx";
|
||||||
|
import { Projection } from "../../../../src/core/rendering/Camera";
|
||||||
|
|
||||||
export class StubGfxRenderer extends GfxRenderer {
|
export class StubGfxRenderer extends GfxRenderer {
|
||||||
get gfx(): Gfx {
|
get gfx(): Gfx {
|
||||||
@ -7,7 +8,7 @@ export class StubGfxRenderer extends GfxRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(false);
|
super(Projection.Orthographic);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): void {} // eslint-disable-line
|
protected render(): void {} // eslint-disable-line
|
||||||
|
Loading…
Reference in New Issue
Block a user