All texture viewer features are now supported by the TextureWebglRenderer.

This commit is contained in:
Daan Vanden Bosch 2020-01-19 22:38:45 +01:00
parent 85ccdbb0a6
commit 9960d745c2
7 changed files with 179 additions and 46 deletions

View File

@ -25,14 +25,26 @@ export function floor_mod(dividend: number, divisor: number): number {
return ((dividend % divisor) + divisor) % divisor;
}
export class Matrix4 {
static of(...values: readonly number[]): Matrix4 {
return new Matrix4(new Float32Array(values));
export class Vec2 {
constructor(public x: number, public y: number) {}
}
export function vec2_diff(v: Vec2, w: Vec2): Vec2 {
return new Vec2(v.x - w.x, v.y - w.y);
}
export class Vec3 {
constructor(public x: number, public y: number, public z: number) {}
}
export class Mat4 {
static of(...values: readonly number[]): Mat4 {
return new Mat4(new Float32Array(values));
}
static identity(): Matrix4 {
static identity(): Mat4 {
// prettier-ignore
return Matrix4.of(
return Mat4.of(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
@ -45,9 +57,19 @@ export class Matrix4 {
}
}
export function matrix4_product(a: Matrix4, b: Matrix4): Matrix4 {
const array = new Float32Array(16);
export function mat4_product(a: Mat4, b: Mat4): Mat4 {
const c = new Mat4(new Float32Array(16));
mat4_product_into_array(c.data, a, b);
return c;
}
export function mat4_multiply(a: Mat4, b: Mat4): void {
const array = new Float32Array(16);
mat4_product_into_array(array, a, b);
a.data.set(array);
}
function mat4_product_into_array(array: Float32Array, a: Mat4, b: Mat4): void {
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
for (let k = 0; k < 4; k++) {
@ -55,6 +77,8 @@ export function matrix4_product(a: Matrix4, b: Matrix4): Matrix4 {
}
}
}
return new Matrix4(array);
}
export class Quat {
constructor(public x: number, public y: number, public z: number, public w: number) {}
}

View File

@ -0,0 +1,56 @@
import { Mat4, Vec3 } from "../math";
import { Mat4Transform, Transform } from "./Transform";
export class Camera {
private readonly look_at: Vec3 = new Vec3(0, 0, 0);
private x_rot: number = 0;
private y_rot: number = 0;
private z_rot: number = 0;
private _zoom: number = 1;
private readonly _transform = new Mat4Transform(Mat4.identity());
get transform(): Transform {
return this._transform;
}
pan(x: number, y: number, z: number): this {
this.look_at.x += x;
this.look_at.y += y;
this.look_at.z += z;
this.update_transform();
return this;
}
/**
* Increase (or decrease) zoom by a factor.
*/
zoom(factor: number): this {
this._zoom *= factor;
this.look_at.x *= factor;
this.look_at.y *= factor;
this.look_at.z *= factor;
this.update_transform();
return this;
}
reset(): this {
this.look_at.x = 0;
this.look_at.y = 0;
this.look_at.z = 0;
this.x_rot = 0;
this.y_rot = 0;
this.z_rot = 0;
this._zoom = 1;
this.update_transform();
return this;
}
private update_transform(): void {
this._transform.data[3] = -this.look_at.x;
this._transform.data[7] = -this.look_at.y;
this._transform.data[11] = -this.look_at.z;
this._transform.data[0] = this._zoom;
this._transform.data[5] = this._zoom;
this._transform.data[10] = this._zoom;
}
}

View File

@ -1,6 +1,5 @@
import { Matrix4 } from "../math";
import { Mat4 } from "../math";
import { GL, VERTEX_POS_LOC, VERTEX_TEX_LOC } from "./VertexFormat";
import { Texture } from "./Texture";
export class ShaderProgram {
private readonly gl: GL;
@ -51,13 +50,12 @@ export class ShaderProgram {
}
}
set_transform(matrix: Matrix4): void {
set_transform_uniform(matrix: Mat4): void {
this.gl.uniformMatrix4fv(this.transform_loc, true, matrix.data);
}
set_texture(texture: Texture): void {
const gl = this.gl;
gl.uniform1i(this.tex_sampler_loc, 0);
set_texture_uniform(unit: GLenum): void {
this.gl.uniform1i(this.tex_sampler_loc, unit - this.gl.TEXTURE0);
}
bind(): void {

View File

@ -1,15 +1,23 @@
import { Matrix4 } from "../math";
import { Mat4 } from "../math";
export interface Transform {
readonly matrix4: Matrix4;
readonly mat4: Mat4;
}
export class Mat4Transform implements Transform {
readonly data: Float32Array;
constructor(readonly mat4: Mat4) {
this.data = mat4.data;
}
}
export class TranslateTransform implements Transform {
readonly matrix4: Matrix4;
readonly mat4: Mat4;
constructor(x: number, y: number, z: number) {
// prettier-ignore
this.matrix4 = Matrix4.of(
this.mat4 = Mat4.of(
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
@ -19,11 +27,11 @@ export class TranslateTransform implements Transform {
}
export class IdentityTransform implements Transform {
readonly matrix4: Matrix4;
readonly mat4: Mat4;
constructor() {
// prettier-ignore
this.matrix4 = Matrix4.of(
this.mat4 = Mat4.of(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,

View File

@ -1,5 +1,5 @@
import { Renderer } from "./Renderer";
import { Matrix4, matrix4_product } from "../math";
import { Mat4, mat4_product, Vec2, vec2_diff } from "../math";
import { ShaderProgram } from "./ShaderProgram";
import { GL } from "./VertexFormat";
import { Scene } from "./Scene";
@ -9,17 +9,17 @@ import {
POS_TEX_VERTEX_SHADER_SOURCE,
POS_VERTEX_SHADER_SOURCE,
} from "./shader_sources";
import { LogManager } from "../Logger";
const logger = LogManager.get("core/rendering/WebglRenderer");
import { Camera } from "./Camera";
export class WebglRenderer extends Renderer {
private readonly gl: GL;
private readonly shader_programs: ShaderProgram[];
private render_scheduled = false;
private projection!: Matrix4;
private animation_frame?: number;
private projection!: Mat4;
private pointer_pos?: Vec2;
protected readonly scene: Scene;
protected readonly camera = new Camera();
readonly canvas_element: HTMLCanvasElement;
@ -38,6 +38,7 @@ export class WebglRenderer extends Renderer {
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.clearColor(0.1, 0.1, 0.1, 1);
this.shader_programs = [
new ShaderProgram(gl, POS_VERTEX_SHADER_SOURCE, POS_FRAG_SHADER_SOURCE),
@ -48,7 +49,8 @@ export class WebglRenderer extends Renderer {
this.set_size(800, 600);
requestAnimationFrame(this.render);
this.canvas_element.addEventListener("mousedown", this.mousedown);
this.canvas_element.addEventListener("wheel", this.wheel, { passive: true });
}
dispose(): void {
@ -60,15 +62,21 @@ export class WebglRenderer extends Renderer {
}
start_rendering(): void {
// TODO
this.schedule_render();
}
stop_rendering(): void {
// TODO
if (this.animation_frame != undefined) {
cancelAnimationFrame(this.animation_frame);
}
this.animation_frame = undefined;
}
schedule_render = (): void => {
this.render_scheduled = true;
if (this.animation_frame == undefined) {
this.animation_frame = requestAnimationFrame(this.render);
}
};
set_size(width: number, height: number): void {
@ -77,32 +85,37 @@ export class WebglRenderer extends Renderer {
this.gl.viewport(0, 0, width, height);
// prettier-ignore
this.projection = Matrix4.of(
this.projection = Mat4.of(
2/width, 0, 0, 0,
0, 2/height, 0, 0,
0, 0, 2/10, 0,
0, 0, 0, 1,
);
this.schedule_render();
}
private render = (): void => {
this.animation_frame = undefined;
const gl = this.gl;
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
this.scene.traverse((node, parent_transform) => {
const transform = matrix4_product(parent_transform, node.transform.matrix4);
const camera_project_mat = mat4_product(this.projection, this.camera.transform.mat4);
this.scene.traverse((node, parent_mat) => {
const mat = mat4_product(parent_mat, node.transform.mat4);
if (node.mesh) {
const program = this.shader_programs[node.mesh.format];
program.bind();
program.set_transform(transform);
program.set_transform_uniform(mat);
if (node.mesh.texture) {
gl.activeTexture(gl.TEXTURE0);
node.mesh.texture.bind(gl);
program.set_texture(node.mesh.texture);
program.set_texture_uniform(gl.TEXTURE0);
}
node.mesh.render(gl);
@ -111,9 +124,43 @@ export class WebglRenderer extends Renderer {
program.unbind();
}
return transform;
}, this.projection);
return mat;
}, camera_project_mat);
};
requestAnimationFrame(this.render);
private mousedown = (evt: MouseEvent): void => {
if (evt.buttons === 1) {
this.pointer_pos = new Vec2(evt.clientX, evt.clientY);
window.addEventListener("mousemove", this.mousemove);
window.addEventListener("mouseup", this.mouseup);
}
};
private mousemove = (evt: MouseEvent): void => {
if (evt.buttons === 1) {
const new_pos = new Vec2(evt.clientX, evt.clientY);
const diff = vec2_diff(new_pos, this.pointer_pos!);
this.camera.pan(-diff.x, diff.y, 0);
this.pointer_pos = new_pos;
this.schedule_render();
}
};
private mouseup = (): void => {
this.pointer_pos = undefined;
window.removeEventListener("mousemove", this.mousemove);
window.removeEventListener("mouseup", this.mouseup);
};
private wheel = (evt: WheelEvent): void => {
if (evt.deltaY < 0) {
this.camera.zoom(1.1);
} else {
this.camera.zoom(0.9);
}
this.schedule_render();
};
}

View File

@ -60,8 +60,8 @@ export function initialize_viewer(
let renderer: Renderer;
if (gui_store.feature_active("renderer")) {
const { WebglTextureRenderer } = await import("./rendering/WebglTextureRenderer");
renderer = new WebglTextureRenderer(controller);
const { TextureWebglRenderer } = await import("./rendering/TextureWebglRenderer");
renderer = new TextureWebglRenderer(controller);
} else {
const { TextureRenderer } = await import("./rendering/TextureRenderer");
renderer = new TextureRenderer(controller, create_three_renderer());

View File

@ -10,7 +10,7 @@ import { Texture, TextureFormat } from "../../core/rendering/Texture";
const logger = LogManager.get("viewer/rendering/WebglTextureRenderer");
export class WebglTextureRenderer extends WebglRenderer {
export class TextureWebglRenderer extends WebglRenderer {
private readonly disposer = new Disposer();
constructor(ctrl: TextureController) {
@ -18,7 +18,9 @@ export class WebglTextureRenderer extends WebglRenderer {
this.disposer.add_all(
ctrl.textures.observe(({ value: textures }) => {
this.render_textures(textures);
this.scene.delete();
this.camera.reset();
this.create_quads(textures);
this.schedule_render();
}),
);
@ -29,9 +31,7 @@ export class WebglTextureRenderer extends WebglRenderer {
this.disposer.dispose();
}
private render_textures(textures: readonly XvrTexture[]): void {
this.scene.delete();
private create_quads(textures: readonly XvrTexture[]): void {
let total_width = 10 * (textures.length - 1); // 10px spacing between textures.
let total_height = 0;