Big update
This commit is contained in:
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
45
.idea/workspace.xml
generated
45
.idea/workspace.xml
generated
@@ -1,7 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="dc704aa3-69bc-4c4e-bfa3-31f248741e3c" name="Default Changelist" comment="" />
|
||||
<list default="true" id="dc704aa3-69bc-4c4e-bfa3-31f248741e3c" name="Default Changelist" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/src/Camera.ts" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/Cone.ts" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/MatrixFour.ts" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/TransformableGeometry.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/build/bundle.js" beforeDir="false" afterPath="$PROJECT_DIR$/build/bundle.js" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/App.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/App.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/BasicColor.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/BasicColor.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Matrix4.ts" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Point2D.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/Point2D.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Point3D.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/Point3D.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/PointVec.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/PointVec.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Triangle2D.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/Triangle2D.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/TrsMatrix.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/TrsMatrix.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/fragmentShader.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/fragmentShader.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/types.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/types.d.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/utils.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/vertexShader.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/vertexShader.glsl" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
@@ -18,6 +37,9 @@
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectId" id="1dJrR6XMWeePLne62dJk97OPzOb" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
@@ -69,6 +91,8 @@
|
||||
<workItem from="1592157594053" duration="10162000" />
|
||||
<workItem from="1592213404810" duration="33877000" />
|
||||
<workItem from="1592384389528" duration="612000" />
|
||||
<workItem from="1593163095834" duration="18917000" />
|
||||
<workItem from="1593248452910" duration="13264000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
@@ -88,13 +112,20 @@
|
||||
<screen x="0" y="540" width="1080" height="1380" />
|
||||
</state>
|
||||
<state x="0" y="721" key="SettingsEditor/1080.513.1920.1080/0.540.1080.1380@0.540.1080.1380" timestamp="1592157574185" />
|
||||
<state x="204" y="456" width="672" height="677" key="run.anything.popup" timestamp="1592164107251">
|
||||
<screen x="0" y="540" width="1080" height="1380" />
|
||||
</state>
|
||||
<state x="204" y="456" width="672" height="677" key="run.anything.popup/1080.513.1920.1080/0.540.1080.1380@0.540.1080.1380" timestamp="1592164107251" />
|
||||
<state x="992" y="237" width="672" height="678" key="search.everywhere.popup" timestamp="1592225020545">
|
||||
<state x="608" y="250" width="704" height="578" key="find.popup" timestamp="1593260457178">
|
||||
<screen x="0" y="27" width="1920" height="1053" />
|
||||
</state>
|
||||
<state x="992" y="237" width="672" height="678" key="search.everywhere.popup/1920.0.1920.1080/0.27.1920.1053@0.27.1920.1053" timestamp="1592225020545" />
|
||||
<state x="608" y="250" width="704" height="578" key="find.popup/1920.0.1920.1080/0.27.1920.1053@0.27.1920.1053" timestamp="1593260457178" />
|
||||
<state x="363" y="-37" width="1195" height="517" key="run.anything.popup" timestamp="1593262773357">
|
||||
<screen x="0" y="27" width="1920" height="1053" />
|
||||
</state>
|
||||
<state x="204" y="456" width="672" height="677" key="run.anything.popup/1080.513.1920.1080/0.540.1080.1380@0.540.1080.1380" timestamp="1592164107251" />
|
||||
<state x="363" y="-37" width="1195" height="517" key="run.anything.popup/1920.0.1920.1080/0.27.1920.1053@0.27.1920.1053" timestamp="1593262773357" />
|
||||
<state x="2283" y="-66" width="1195" height="531" key="run.anything.popup/1920.0.1920.1080/0.27.1920.1053@1920.0.1920.1080" timestamp="1593189438638" />
|
||||
<state x="2912" y="215" width="672" height="696" key="search.everywhere.popup" timestamp="1593184656351">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="992" y="237" width="672" height="678" key="search.everywhere.popup/1920.0.1920.1080/0.27.1920.1053@0.27.1920.1053" timestamp="1593175537121" />
|
||||
<state x="2912" y="215" width="672" height="696" key="search.everywhere.popup/1920.0.1920.1080/0.27.1920.1053@1920.0.1920.1080" timestamp="1593184656351" />
|
||||
</component>
|
||||
</project>
|
||||
File diff suppressed because one or more lines are too long
144
src/App.ts
144
src/App.ts
@@ -1,12 +1,14 @@
|
||||
import vs_src from "./vertexShader.glsl";
|
||||
import fs_src from "./fragmentShader.glsl";
|
||||
import Matrix4 from "./Matrix4";
|
||||
import {perspMat} from "./utils";
|
||||
import {Color, Colored, Geometry, Transformable} from "./types";
|
||||
import MatrixFour from "./MatrixFour";
|
||||
import Triangle2D from "./Triangle2D";
|
||||
import TrsMatrix from "./TrsMatrix";
|
||||
import Point2D from "./Point2D";
|
||||
import BasicColor from "./BasicColor";
|
||||
import {ProgramLinkingError, ShaderCompilationError} from "./Errors";
|
||||
import Cone from "./Cone";
|
||||
import TrsMatrix from "./TrsMatrix";
|
||||
import Camera from "./Camera";
|
||||
import Point3D from "./Point3D";
|
||||
|
||||
export enum ExitCode {
|
||||
ERROR,
|
||||
@@ -15,29 +17,37 @@ export enum ExitCode {
|
||||
WEBGL_ERROR
|
||||
}
|
||||
|
||||
export interface Updatable {
|
||||
update(delta: number): void;
|
||||
}
|
||||
type Object = Transformable & Geometry & Colored & Updatable;
|
||||
|
||||
class WebGlApp {
|
||||
private gl: WebGLRenderingContext;
|
||||
private stage: HTMLCanvasElement;
|
||||
private perspMat: Matrix4;
|
||||
private normalBuffer?: WebGLBuffer;
|
||||
private pointBuffer?: WebGLBuffer;
|
||||
private elementBuffer?: WebGLBuffer;
|
||||
private currentProgram: WebGLProgram | null;
|
||||
private positionAttributeLocation: number = 0;
|
||||
private a_position: number = 0;
|
||||
private a_normal: number = 0;
|
||||
private u_colorLoc: number = 0;
|
||||
private u_trsMatrixLoc: number = 0;
|
||||
private maxTris: number = 1000;
|
||||
private tris: Triangle2D[] = [];
|
||||
private sinceLastTri: number = 0;
|
||||
private objects: Object[] = [];
|
||||
private camera: Camera = new Camera();
|
||||
private running: boolean = true;
|
||||
private onShutdownCallback: (exitCode: ExitCode) => any = () => {};
|
||||
constructor(gl: WebGLRenderingContext, canvas: HTMLCanvasElement) {
|
||||
this.gl = gl;
|
||||
this.stage = canvas;
|
||||
this.currentProgram = this.createDefaultProgram();
|
||||
this.perspMat = perspMat(90, this.stage.width / this.stage.height, 1.0, 2000.0);
|
||||
this.setupGl();
|
||||
}
|
||||
|
||||
private setupGl(): void {
|
||||
this.gl.enable(this.gl.DEPTH_TEST);
|
||||
this.gl.enable(this.gl.CULL_FACE);
|
||||
//this.gl.enable(this.gl.CULL_FACE);
|
||||
//this.gl.frontFace(this.gl.CCW);
|
||||
}
|
||||
|
||||
onShutdown(callback: (exitCode: ExitCode) => any): void {
|
||||
@@ -45,6 +55,7 @@ class WebGlApp {
|
||||
}
|
||||
|
||||
private shutdown(exitCode: ExitCode) {
|
||||
this.running = false;
|
||||
this.onShutdownCallback(exitCode);
|
||||
}
|
||||
|
||||
@@ -52,13 +63,14 @@ class WebGlApp {
|
||||
const program = this.createProgram(
|
||||
this.createShaderFromString(this.gl.VERTEX_SHADER, vs_src),
|
||||
this.createShaderFromString(this.gl.FRAGMENT_SHADER, fs_src));
|
||||
this.positionAttributeLocation = this.gl.getAttribLocation(program, "a_position");
|
||||
this.a_position = this.gl.getAttribLocation(program, "a_position");
|
||||
this.a_normal = this.gl.getAttribLocation(program, "a_normal");
|
||||
this.u_colorLoc = this.gl.getUniformLocation(program, "u_color") as number;
|
||||
this.u_trsMatrixLoc = this.gl.getUniformLocation(program, "u_trsMatrix") as number;
|
||||
return program;
|
||||
}
|
||||
|
||||
private createProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader) {
|
||||
private createProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader): WebGLProgram {
|
||||
const program: WebGLProgram = this.gl.createProgram() as WebGLProgram;
|
||||
this.gl.attachShader(program, vertexShader);
|
||||
this.gl.attachShader(program, fragmentShader);
|
||||
@@ -89,12 +101,27 @@ class WebGlApp {
|
||||
}
|
||||
}
|
||||
|
||||
private renderTriangle(triangle: Triangle2D) {
|
||||
this.gl.bufferData(this.gl.ARRAY_BUFFER, triangle.pointBuffer(), this.gl.STATIC_DRAW);
|
||||
this.gl.uniform4fv(this.u_colorLoc, triangle.colorVec());
|
||||
private renderObject(object: Object) {
|
||||
this.gl.enableVertexAttribArray(this.a_position);
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.pointBuffer!);
|
||||
this.gl.bufferData(this.gl.ARRAY_BUFFER, object.pointBuffer(), this.gl.STATIC_DRAW);
|
||||
this.gl.vertexAttribPointer(
|
||||
this.a_position, 3, this.gl.FLOAT, false, 0, 0);
|
||||
|
||||
this.gl.enableVertexAttribArray(this.a_normal);
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.normalBuffer!);
|
||||
this.gl.bufferData(this.gl.ARRAY_BUFFER, object.normalBuffer(), this.gl.STATIC_DRAW);
|
||||
this.gl.vertexAttribPointer(
|
||||
this.a_normal, 3, this.gl.FLOAT, false, 0, 0);
|
||||
|
||||
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.elementBuffer!);
|
||||
this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, object.elementBuffer(), this.gl.STATIC_DRAW);
|
||||
|
||||
this.gl.uniform4fv(this.u_colorLoc, object.getColor().vec());
|
||||
this.gl.uniformMatrix4fv(this.u_trsMatrixLoc, false,
|
||||
triangle.getTrsMatrix().buffer());
|
||||
this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
|
||||
this.useCamera(object.getTrsMatrix()).buffer());
|
||||
|
||||
this.gl.drawElements(this.gl.TRIANGLES, object.elementBuffer().length, this.gl.UNSIGNED_SHORT, 0);
|
||||
}
|
||||
|
||||
private initViewport(): void {
|
||||
@@ -105,70 +132,53 @@ class WebGlApp {
|
||||
|
||||
private useDefaultProgram(): void {
|
||||
this.gl.useProgram(this.currentProgram);
|
||||
const positionBuffer = this.gl.createBuffer();
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer);
|
||||
this.gl.enableVertexAttribArray(this.positionAttributeLocation);
|
||||
this.gl.vertexAttribPointer(
|
||||
this.positionAttributeLocation, 3, this.gl.FLOAT, false, 0, 0);
|
||||
this.pointBuffer = this.gl.createBuffer()!;
|
||||
this.elementBuffer = this.gl.createBuffer()!;
|
||||
this.normalBuffer = this.gl.createBuffer()!;
|
||||
}
|
||||
|
||||
private createRandomTriangle(): Triangle2D {
|
||||
return new Triangle2D(
|
||||
this.rand2DClipspacePoint(),
|
||||
this.rand2DClipspacePoint(),
|
||||
this.rand2DClipspacePoint(),
|
||||
this.randTrsMat(),
|
||||
this.randBasicColor()
|
||||
)
|
||||
private useCamera(inputTrs: TrsMatrix): MatrixFour {
|
||||
const projectionMatrix = MatrixFour.Perspective(
|
||||
Math.PI,
|
||||
this.stage.clientWidth / this.stage.clientHeight,
|
||||
1,
|
||||
2000);
|
||||
const viewProjectionMatrix = projectionMatrix.times(this.camera.viewMat());
|
||||
return viewProjectionMatrix.times(inputTrs);
|
||||
}
|
||||
|
||||
private randTrsMat(): TrsMatrix {
|
||||
return new TrsMatrix()
|
||||
.translateBy(this.randClipspaceInt() / 2, this.randClipspaceInt() / 2, this.randClipspaceInt() / 2)
|
||||
.rotateBy(this.randAngle(), this.randAngle(), this.randAngle())
|
||||
}
|
||||
|
||||
private rand2DClipspacePoint(): Point2D {
|
||||
return new Point2D(this.randClipspaceInt() / 2, this.randClipspaceInt() / 2);
|
||||
}
|
||||
|
||||
private randBasicColor(): BasicColor {
|
||||
return new BasicColor(Math.random(), Math.random(), Math.random());
|
||||
}
|
||||
|
||||
private randAngle(): number {
|
||||
return Math.random() * Math.PI / 10;
|
||||
}
|
||||
|
||||
private randClipspaceInt(): number {
|
||||
return Math.random() * 2 - 1;
|
||||
}
|
||||
|
||||
private animateRandomTrisPopin(delta: number): void {
|
||||
if (this.maxTris >= this.tris.length) {
|
||||
this.sinceLastTri += delta;
|
||||
if (this.sinceLastTri > 100) {
|
||||
this.tris.push(this.createRandomTriangle());
|
||||
this.sinceLastTri = 0;
|
||||
}
|
||||
private mainLoop(delta: number): void {
|
||||
for (const object of this.objects) {
|
||||
object.update(delta);
|
||||
}
|
||||
for (const tri of this.tris) {
|
||||
this.renderTriangle(tri);
|
||||
for (const object of this.objects) {
|
||||
this.renderObject(object);
|
||||
}
|
||||
}
|
||||
|
||||
private animate(then: number): void {
|
||||
private frame(then: number): void {
|
||||
const now = Date.now();
|
||||
const delta = now - then;
|
||||
this.animateRandomTrisPopin(delta);
|
||||
window.requestAnimationFrame(() => this.animate(now));
|
||||
this.mainLoop(delta);
|
||||
if (this.running) {
|
||||
window.requestAnimationFrame(() => this.frame(now));
|
||||
}
|
||||
}
|
||||
|
||||
private setupScene(): void {
|
||||
const cone = new Cone(4, 100);
|
||||
cone.setColor(new BasicColor(1.0, 0, 0, 1.0));
|
||||
cone.scaleBy(100);
|
||||
this.objects.push(cone);
|
||||
this.camera.translateBy(100, 100, 100);
|
||||
console.log(this.useCamera(cone.getTrsMatrix()));
|
||||
}
|
||||
|
||||
run() {
|
||||
this.initViewport();
|
||||
this.useDefaultProgram();
|
||||
window.requestAnimationFrame(() => this.animate(Date.now()));
|
||||
//this.shutdown(ExitCode.QUIT);
|
||||
this.setupScene();
|
||||
window.requestAnimationFrame(() => this.frame(Date.now()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import {VectorSizeError} from "./Errors";
|
||||
import {Color, Vector} from "./types";
|
||||
|
||||
class BasicColor implements Vector, Color {
|
||||
private rep: Float32Array;
|
||||
constructor(r: number, g: number, b: number, a?: number) {
|
||||
this.rep = new Float32Array([r, g, b, a ?? 1.0]);
|
||||
private readonly rep: Float32Array;
|
||||
constructor();
|
||||
constructor(r: number, g: number, b: number, a?: number);
|
||||
constructor(...args: any[]) {
|
||||
this.rep = new Float32Array([args[0] ?? 0.5, args[1] ?? 0.5, args[2] ?? 0.5, args[3] ?? 1.0]);
|
||||
}
|
||||
static fromVec(vec: Float32Array): Color {
|
||||
static fromVec(vec: ArrayLike<number>): Color {
|
||||
if (vec.length === 4) {
|
||||
return new BasicColor(vec[0], vec[1], vec[2], vec[3]);
|
||||
}
|
||||
|
||||
66
src/Camera.ts
Normal file
66
src/Camera.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import TrsMatrix from "./TrsMatrix";
|
||||
import Point3D from "./Point3D";
|
||||
import {Transformable} from "./types";
|
||||
import MatrixFour from "./MatrixFour";
|
||||
|
||||
class Camera implements Transformable {
|
||||
private trs: TrsMatrix;
|
||||
constructor();
|
||||
constructor(position: Point3D, lookAt: Point3D, up: Point3D);
|
||||
constructor(radius: number, rotX: number, rotY: number, rotZ: number);
|
||||
constructor(...args: any[]) {
|
||||
this.trs = new TrsMatrix();
|
||||
if (args[0] !== undefined) {
|
||||
if (args[0] instanceof Point3D) {
|
||||
this.trs.setPosition(args[0]);
|
||||
this.lookAt(args[1], args[2]);
|
||||
}
|
||||
else {
|
||||
this.rotateBy(args[1], args[2], args[3]);
|
||||
this.translateBy(0, 0, args[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
translateBy(tX: number, tY: number, tZ: number): Camera {
|
||||
this.trs.translateBy(tX, tY, tZ);
|
||||
return this;
|
||||
}
|
||||
|
||||
rotateBy(degX: number, degY: number, degZ: number): Camera {
|
||||
this.trs.rotateBy(degX, degY, degZ);
|
||||
return this;
|
||||
}
|
||||
|
||||
scaleBy(sX: number, sY: number, sZ: number): Camera {
|
||||
this.trs.scaleBy(sX, sY, sZ);
|
||||
return this;
|
||||
}
|
||||
|
||||
getTrsMatrix(): TrsMatrix {
|
||||
return this.trs;
|
||||
}
|
||||
|
||||
position(): Point3D {
|
||||
return this.trs.position();
|
||||
};
|
||||
|
||||
lookAt(other: Point3D, up: Point3D) {
|
||||
const selfPosition = this.position();
|
||||
const zAxis = selfPosition.minus(other).normalised();
|
||||
const xAxis = up.cross(zAxis).normalised();
|
||||
const yAxis = zAxis.cross(xAxis).normalised();
|
||||
this.trs.setSlice([
|
||||
xAxis.x(), xAxis.y(), xAxis.z(), 0,
|
||||
yAxis.x(), yAxis.y(), yAxis.z(), 0,
|
||||
zAxis.x(), zAxis.y(), zAxis.z(), 0,
|
||||
selfPosition.x(), selfPosition.y(), selfPosition.z(), 1,
|
||||
], 0);
|
||||
}
|
||||
|
||||
viewMat(): MatrixFour {
|
||||
return this.trs.inverse();
|
||||
}
|
||||
}
|
||||
|
||||
export default Camera;
|
||||
106
src/Cone.ts
Normal file
106
src/Cone.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import TrsMatrix from "./TrsMatrix";
|
||||
import BasicColor from "./BasicColor";
|
||||
import TransformableGeometry from "./TransformableGeometry";
|
||||
import {triNormal} from "./utils";
|
||||
import Point3D from "./Point3D";
|
||||
import {Color, Colored, GeometryParams, Transformable} from "./types";
|
||||
import {Updatable} from "./App";
|
||||
|
||||
class Cone extends TransformableGeometry implements Transformable, Colored, Updatable {
|
||||
private color: Color;
|
||||
private height?: number;
|
||||
private basePoints?: number;
|
||||
private static DEFAULT_BASE_POINTS: number = 10;
|
||||
private static DEFAULT_HEIGHT: number = 1;
|
||||
constructor(geometry: GeometryParams, trsMatrix?: TrsMatrix, color?: Color);
|
||||
constructor(height?: number, basePoints?: number, trsMatrix?: TrsMatrix, color?: Color | ArrayLike<number>);
|
||||
constructor(...args: any[]) {
|
||||
let color;
|
||||
if (typeof args[0] !== "number") {
|
||||
super(args[0], args[1]);
|
||||
color = args[2];
|
||||
}
|
||||
else {
|
||||
super(Cone.generateGeometry(args[0], args[1]), args[2]);
|
||||
this.height = args[0] ?? Cone.DEFAULT_HEIGHT;
|
||||
this.basePoints = args[1] ?? Cone.DEFAULT_BASE_POINTS;
|
||||
color = args[4] ?? new BasicColor();
|
||||
}
|
||||
if (color.hasOwnProperty("length")) {
|
||||
this.color = BasicColor.fromVec(color as ArrayLike<number>);
|
||||
}
|
||||
else {
|
||||
this.color = color as Color;
|
||||
}
|
||||
}
|
||||
|
||||
private static generateGeometry(height: number, basePoints: number): GeometryParams {
|
||||
basePoints = Math.abs(Math.ceil(basePoints));
|
||||
const basePointsAngle = 2 * Math.PI / basePoints;
|
||||
const pointBuffer = [
|
||||
0.0, 0.0, 0.0,
|
||||
0.0, 0.0, height,
|
||||
0.0, 1.0, 0.0
|
||||
];
|
||||
const normalBuffer = [];
|
||||
const elementBuffer = [];
|
||||
for (let i = 1; i < basePoints; i++) {
|
||||
pointBuffer.push(
|
||||
Math.sin(basePointsAngle * i),
|
||||
Math.cos(basePointsAngle * i),
|
||||
0.0
|
||||
);
|
||||
elementBuffer.push(0, 2 + i, 1 + i);
|
||||
normalBuffer.push(
|
||||
0.0, 0.0, -1.0,
|
||||
0.0, 0.0, -1.0,
|
||||
0.0, 0.0, -1.0,
|
||||
);
|
||||
elementBuffer.push(1, 1 + i, 2 + i);
|
||||
normalBuffer.push(
|
||||
...triNormal(
|
||||
new Point3D(pointBuffer.slice(1, 4)),
|
||||
new Point3D(pointBuffer.slice(1 + i, 4 + i)),
|
||||
new Point3D(pointBuffer.slice(2 + i, 5 + i)),
|
||||
).vec()
|
||||
);
|
||||
}
|
||||
elementBuffer.push(0, 2, 1 + basePoints);
|
||||
elementBuffer.push(1, 1 + basePoints, 2);
|
||||
return {
|
||||
pointBuffer: new Float32Array(pointBuffer),
|
||||
normalBuffer: new Float32Array(normalBuffer),
|
||||
elementBuffer: new Uint16Array(elementBuffer)
|
||||
};
|
||||
}
|
||||
|
||||
update(delta: number): void {
|
||||
const secs = delta / 1000.0;
|
||||
this.rotateBy(0, 0.05 * secs, 0);
|
||||
}
|
||||
|
||||
setHeight(height: number) {
|
||||
this.changeHeight(height - (this.height ?? 0));
|
||||
}
|
||||
|
||||
changeHeight(deltaHeight: number) {
|
||||
this.height = this.height ?? Cone.DEFAULT_HEIGHT + deltaHeight;
|
||||
this.geometry = Cone.generateGeometry(this.height, this.basePoints ?? Cone.DEFAULT_BASE_POINTS);
|
||||
}
|
||||
|
||||
setBasePoints(basePoints: number) {
|
||||
this.height = basePoints;
|
||||
this.geometry = Cone.generateGeometry(this.height, this.basePoints ?? Cone.DEFAULT_BASE_POINTS);
|
||||
}
|
||||
|
||||
setColor(color: Color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
getColor(): Color {
|
||||
return this.color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default Cone;
|
||||
@@ -1,54 +0,0 @@
|
||||
import {identityMatrix} from "./utils";
|
||||
|
||||
class Matrix4 {
|
||||
protected readonly matrix: Float32Array;
|
||||
constructor(matrix: Float32Array | ArrayLike<number>);
|
||||
constructor(...args: any[]) {
|
||||
if (args[0].length === 16) {
|
||||
if (!(args[0] instanceof Float32Array)) {
|
||||
args[0] = new Float32Array(args[0]);
|
||||
}
|
||||
this.matrix = args[0];
|
||||
}
|
||||
else {
|
||||
throw new VectorSizeError(16, args[0].length);
|
||||
}
|
||||
}
|
||||
times(other: Matrix4) {
|
||||
const result = new Matrix4(Array<number>(16));
|
||||
const a = this.matrix;
|
||||
const b = other.matrix;
|
||||
const c = result.matrix;
|
||||
c[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12];
|
||||
c[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13];
|
||||
c[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14];
|
||||
c[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15];
|
||||
c[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12];
|
||||
c[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13];
|
||||
c[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14];
|
||||
c[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15];
|
||||
c[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12];
|
||||
c[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13];
|
||||
c[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14];
|
||||
c[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15];
|
||||
c[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12];
|
||||
c[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13];
|
||||
c[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14];
|
||||
c[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15];
|
||||
return result;
|
||||
}
|
||||
buffer(): Float32Array {
|
||||
return this.matrix.slice();
|
||||
}
|
||||
set(m: number, n: number, val: number): void {
|
||||
this.matrix[m * 4 + n] = val;
|
||||
}
|
||||
setRel(m: number, n: number, val: number): void {
|
||||
this.matrix[m * 4 + n] += val;
|
||||
}
|
||||
static Identity(): Matrix4 {
|
||||
return new Matrix4(identityMatrix(4));
|
||||
}
|
||||
}
|
||||
|
||||
export default Matrix4;
|
||||
155
src/MatrixFour.ts
Normal file
155
src/MatrixFour.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
import {identityMatrix} from "./utils";
|
||||
import {VectorSizeError} from "./Errors";
|
||||
|
||||
class MatrixFour {
|
||||
protected matrix: Float32Array;
|
||||
constructor();
|
||||
constructor(matrix: Float32Array | ArrayLike<number>);
|
||||
constructor(...args: any[]) {
|
||||
if (args[0]) {
|
||||
if (args[0].length === 16) {
|
||||
if (!(args[0] instanceof Float32Array)) {
|
||||
args[0] = new Float32Array(args[0]);
|
||||
}
|
||||
this.matrix = args[0];
|
||||
}
|
||||
else {
|
||||
throw new VectorSizeError(16, args[0].length);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.matrix = identityMatrix(4);
|
||||
}
|
||||
}
|
||||
|
||||
times(other: MatrixFour) {
|
||||
const result = new MatrixFour(Array<number>(16));
|
||||
const a = this.matrix;
|
||||
const b = other.matrix;
|
||||
const c = result.matrix;
|
||||
c[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12];
|
||||
c[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13];
|
||||
c[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14];
|
||||
c[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15];
|
||||
c[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12];
|
||||
c[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13];
|
||||
c[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14];
|
||||
c[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15];
|
||||
c[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12];
|
||||
c[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13];
|
||||
c[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14];
|
||||
c[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15];
|
||||
c[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12];
|
||||
c[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13];
|
||||
c[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14];
|
||||
c[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15];
|
||||
return result;
|
||||
}
|
||||
|
||||
buffer(start?: number, stop?: number): Float32Array {
|
||||
return this.matrix.slice(start, stop);
|
||||
}
|
||||
|
||||
set(m: number, n: number, val: number): void {
|
||||
this.matrix[m * 4 + n] = val;
|
||||
}
|
||||
|
||||
setSlice(vals: number[], offset: number): void {
|
||||
this.matrix.set(vals, offset);
|
||||
}
|
||||
|
||||
setRel(m: number, n: number, val: number): void {
|
||||
this.matrix[m * 4 + n] += val;
|
||||
}
|
||||
|
||||
inverse(): MatrixFour {
|
||||
const m = this.matrix;
|
||||
const m00 = m[0];
|
||||
const m01 = m[1];
|
||||
const m02 = m[2];
|
||||
const m03 = m[3];
|
||||
const m10 = m[4];
|
||||
const m11 = m[5];
|
||||
const m12 = m[6];
|
||||
const m13 = m[7];
|
||||
const m20 = m[8];
|
||||
const m21 = m[9];
|
||||
const m22 = m[10];
|
||||
const m23 = m[11];
|
||||
const m30 = m[12];
|
||||
const m31 = m[13];
|
||||
const m32 = m[14];
|
||||
const m33 = m[15];
|
||||
const tmp_0 = m22 * m33;
|
||||
const tmp_1 = m32 * m23;
|
||||
const tmp_2 = m12 * m33;
|
||||
const tmp_3 = m32 * m13;
|
||||
const tmp_4 = m12 * m23;
|
||||
const tmp_5 = m22 * m13;
|
||||
const tmp_6 = m02 * m33;
|
||||
const tmp_7 = m32 * m03;
|
||||
const tmp_8 = m02 * m23;
|
||||
const tmp_9 = m22 * m03;
|
||||
const tmp_10 = m02 * m13;
|
||||
const tmp_11 = m12 * m03;
|
||||
const tmp_12 = m20 * m31;
|
||||
const tmp_13 = m30 * m21;
|
||||
const tmp_14 = m10 * m31;
|
||||
const tmp_15 = m30 * m11;
|
||||
const tmp_16 = m10 * m21;
|
||||
const tmp_17 = m20 * m11;
|
||||
const tmp_18 = m00 * m31;
|
||||
const tmp_19 = m30 * m01;
|
||||
const tmp_20 = m00 * m21;
|
||||
const tmp_21 = m20 * m01;
|
||||
const tmp_22 = m00 * m11;
|
||||
const tmp_23 = m10 * m01;
|
||||
|
||||
const t0 = (tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31) - (tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31);
|
||||
const t1 = (tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31) - (tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31);
|
||||
const t2 = (tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31) - (tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31);
|
||||
const t3 = (tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21) - (tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21);
|
||||
|
||||
const d = 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3);
|
||||
|
||||
const result = new MatrixFour([
|
||||
d * t0,
|
||||
d * t1,
|
||||
d * t2,
|
||||
d * t3,
|
||||
|
||||
d * ((tmp_1 * m10 + tmp_2 * m20 + tmp_5 * m30) - (tmp_0 * m10 + tmp_3 * m20 + tmp_4 * m30)),
|
||||
d * ((tmp_0 * m00 + tmp_7 * m20 + tmp_8 * m30) - (tmp_1 * m00 + tmp_6 * m20 + tmp_9 * m30)),
|
||||
d * ((tmp_3 * m00 + tmp_6 * m10 + tmp_11 * m30) - (tmp_2 * m00 + tmp_7 * m10 + tmp_10 * m30)),
|
||||
d * ((tmp_4 * m00 + tmp_9 * m10 + tmp_10 * m20) - (tmp_5 * m00 + tmp_8 * m10 + tmp_11 * m20)),
|
||||
|
||||
d * ((tmp_12 * m13 + tmp_15 * m23 + tmp_16 * m33) - (tmp_13 * m13 + tmp_14 * m23 + tmp_17 * m33)),
|
||||
d * ((tmp_13 * m03 + tmp_18 * m23 + tmp_21 * m33) - (tmp_12 * m03 + tmp_19 * m23 + tmp_20 * m33)),
|
||||
d * ((tmp_14 * m03 + tmp_19 * m13 + tmp_22 * m33) - (tmp_15 * m03 + tmp_18 * m13 + tmp_23 * m33)),
|
||||
d * ((tmp_17 * m03 + tmp_20 * m13 + tmp_23 * m23) - (tmp_16 * m03 + tmp_21 * m13 + tmp_22 * m23)),
|
||||
|
||||
d * ((tmp_14 * m22 + tmp_17 * m32 + tmp_13 * m12) - (tmp_16 * m32 + tmp_12 * m12 + tmp_15 * m22)),
|
||||
d * ((tmp_20 * m32 + tmp_12 * m02 + tmp_19 * m22) - (tmp_18 * m22 + tmp_21 * m32 + tmp_13 * m02)),
|
||||
d * ((tmp_18 * m12 + tmp_23 * m32 + tmp_15 * m02) - (tmp_22 * m32 + tmp_14 * m02 + tmp_19 * m12)),
|
||||
d * ((tmp_22 * m22 + tmp_16 * m02 + tmp_21 * m12) - (tmp_20 * m12 + tmp_23 * m22 + tmp_17 * m02))
|
||||
]);
|
||||
return result;
|
||||
}
|
||||
|
||||
static Perspective(fov: number, aspect: number, near: number, far: number): MatrixFour {
|
||||
const f = Math.tan(Math.PI / 2 - fov / 2);
|
||||
const rangeInv = 1.0 / (near - far);
|
||||
return new MatrixFour(new Float32Array([
|
||||
f / aspect, 0, 0, 0,
|
||||
0, f, 0, 0,
|
||||
0, 0, (near + far) * rangeInv, -1,
|
||||
0, 0, near * far * rangeInv * 2, 0
|
||||
]));
|
||||
}
|
||||
|
||||
static Identity(): MatrixFour {
|
||||
return new MatrixFour(identityMatrix(4));
|
||||
}
|
||||
}
|
||||
|
||||
export default MatrixFour;
|
||||
@@ -1,4 +1,5 @@
|
||||
import PointVec from "./PointVec";
|
||||
import {VectorSizeError} from "./Errors";
|
||||
|
||||
class Point2D extends PointVec {
|
||||
constructor(vec: Float32Array | ArrayLike<number>);
|
||||
|
||||
@@ -1,32 +1,102 @@
|
||||
import PointVec from "./PointVec";
|
||||
import {VectorSizeError} from "./Errors";
|
||||
|
||||
class Point3D extends PointVec {
|
||||
private len: number;
|
||||
private lengthCacheDirty: boolean;
|
||||
constructor(vec: Float32Array | ArrayLike<number>);
|
||||
constructor(x: number, y: number, z: number);
|
||||
constructor(first: any, second?: any, third?: any) {
|
||||
super(first, second, third);
|
||||
constructor(...args: any[]) {
|
||||
if (typeof args[0] === "number") {
|
||||
super(args[0], args[1], args[2]);
|
||||
}
|
||||
else {
|
||||
if (args[0].length !== 3) {
|
||||
throw new VectorSizeError(3, args[0].length);
|
||||
}
|
||||
else {
|
||||
super(args[0][0], args[0][1], args[0][2]);
|
||||
}
|
||||
}
|
||||
this.len = 0;
|
||||
this.lengthCacheDirty = true;
|
||||
}
|
||||
xOrd(): number {
|
||||
x(): number {
|
||||
return this.rep[0];
|
||||
}
|
||||
yOrd(): number {
|
||||
y(): number {
|
||||
return this.rep[1];
|
||||
}
|
||||
zOrd(): number {
|
||||
z(): number {
|
||||
return this.rep[2];
|
||||
}
|
||||
setX(x: number): void {
|
||||
this.rep[0] = x;
|
||||
this.lengthCacheDirty = false;
|
||||
}
|
||||
setY(y: number): void {
|
||||
this.rep[1] = y;
|
||||
this.lengthCacheDirty = false;
|
||||
}
|
||||
setZ(z: number): void {
|
||||
this.rep[2] = z;
|
||||
this.lengthCacheDirty = false;
|
||||
}
|
||||
set(point: Point3D): void {
|
||||
this.setX(point.x());
|
||||
this.setY(point.y());
|
||||
this.setZ(point.z());
|
||||
}
|
||||
vec(): Float32Array {
|
||||
return this.rep.slice();
|
||||
}
|
||||
cross(other: Point3D): Point3D {
|
||||
return new Point3D(
|
||||
this.y() * other.z() - this.z() * other.y(),
|
||||
this.z() * other.x() - this.x() * other.z(),
|
||||
this.x() * other.y() - this.y() * other.x(),
|
||||
);
|
||||
}
|
||||
dot(other: Point3D): number {
|
||||
return this.x() * other.x() + this.y() * other.y() + this.z() * other.z();
|
||||
}
|
||||
minus(other: Point3D): Point3D {
|
||||
return new Point3D(
|
||||
this.x() - other.x(),
|
||||
this.y() - other.y(),
|
||||
this.z() - other.z(),
|
||||
)
|
||||
}
|
||||
plus(other: Point3D): Point3D {
|
||||
return new Point3D(
|
||||
this.x() + other.x(),
|
||||
this.y() + other.y(),
|
||||
this.z() + other.z(),
|
||||
);
|
||||
}
|
||||
normalised(): Point3D {
|
||||
const len = this.length();
|
||||
if (len > 0.00001) {
|
||||
return this.scaled(1 / len);
|
||||
}
|
||||
else {
|
||||
return Point3D.Zeros();
|
||||
}
|
||||
}
|
||||
scaled(scalar: number) {
|
||||
return new Point3D(
|
||||
this.x() * scalar,
|
||||
this.y() * scalar,
|
||||
this.z() * scalar,
|
||||
);
|
||||
}
|
||||
length(): number {
|
||||
if (this.lengthCacheDirty) {
|
||||
this.len = Math.sqrt(this.dot(this));
|
||||
this.lengthCacheDirty = false;
|
||||
}
|
||||
return this.len;
|
||||
}
|
||||
static Zeros(): Point3D {
|
||||
return new Point3D(0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
@@ -1,22 +1,12 @@
|
||||
import {Vector} from "./types";
|
||||
|
||||
abstract class PointVec implements Vector {
|
||||
protected rep: Float32Array;
|
||||
protected constructor(vec: Float32Array | ArrayLike<number>);
|
||||
protected constructor(x: number, y: number, z: number);
|
||||
protected constructor(first: number | Float32Array | ArrayLike<number>, second?: number, third?: number) {
|
||||
if (typeof first === "number") {
|
||||
if (typeof second !== "number" || typeof third !== "number"){
|
||||
throw new TypeError("Incorrect constructor call for Point3D");
|
||||
}
|
||||
else {
|
||||
this.rep = new Float32Array(3);
|
||||
this.rep[0] = first;
|
||||
this.rep[1] = <number>second;
|
||||
this.rep[2] = <number>third;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.rep = new Float32Array(first[2]);
|
||||
}
|
||||
protected constructor(first: number, second: number, third: number) {
|
||||
this.rep = new Float32Array(3);
|
||||
this.rep[0] = first;
|
||||
this.rep[1] = second;
|
||||
this.rep[2] = third;
|
||||
}
|
||||
abstract vec(): Float32Array;
|
||||
}
|
||||
|
||||
76
src/TransformableGeometry.ts
Normal file
76
src/TransformableGeometry.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import TrsMatrix from "./TrsMatrix";
|
||||
import {VectorSizeError} from "./Errors";
|
||||
import {Geometry, GeometryParams, Transformable} from "./types";
|
||||
import Point3D from "./Point3D";
|
||||
|
||||
class TransformableGeometry implements Transformable, Geometry {
|
||||
protected geometry: GeometryParams;
|
||||
protected readonly trsMatrix: TrsMatrix;
|
||||
constructor(geometry: {
|
||||
pointBuffer: Float32Array,
|
||||
normalBuffer: Float32Array,
|
||||
elementBuffer?: ArrayLike<number>,
|
||||
}, trsMatrix?: TrsMatrix) {
|
||||
let elBuffer;
|
||||
if (geometry.elementBuffer) {
|
||||
elBuffer = new Uint16Array(geometry.elementBuffer);
|
||||
}
|
||||
else {
|
||||
if (geometry.pointBuffer.length % 3 !== 0) {
|
||||
throw new VectorSizeError("Multiple of 3 (no vertexOrder supplied)",
|
||||
geometry.pointBuffer.length);
|
||||
}
|
||||
else {
|
||||
elBuffer = new Uint16Array(Array(geometry.pointBuffer.length / 3).keys());
|
||||
}
|
||||
}
|
||||
this.geometry = {
|
||||
pointBuffer: geometry.pointBuffer,
|
||||
normalBuffer: geometry.normalBuffer,
|
||||
elementBuffer: elBuffer,
|
||||
};
|
||||
this.trsMatrix = trsMatrix ?? new TrsMatrix();
|
||||
}
|
||||
|
||||
getTrsMatrix(): TrsMatrix {
|
||||
return this.trsMatrix;
|
||||
}
|
||||
|
||||
pointBuffer(): Float32Array {
|
||||
return this.geometry.pointBuffer;
|
||||
}
|
||||
|
||||
normalBuffer(): Float32Array {
|
||||
return this.geometry.normalBuffer;
|
||||
}
|
||||
|
||||
elementBuffer(): Uint16Array {
|
||||
return this.geometry.elementBuffer;
|
||||
}
|
||||
|
||||
position(): Point3D {
|
||||
return this.trsMatrix.position();
|
||||
}
|
||||
|
||||
translateBy(tX: number, tY: number, tZ: number): this {
|
||||
this.trsMatrix.translateBy(tX, tY, tZ);
|
||||
return this;
|
||||
}
|
||||
|
||||
rotateBy(degX: number, degY: number, degZ: number): this {
|
||||
this.trsMatrix.rotateBy(degX, degY, degZ);
|
||||
return this;
|
||||
}
|
||||
|
||||
scaleBy(xOrAll: number, sY?: number, sZ?: number): this {
|
||||
if (sY && sZ) {
|
||||
this.trsMatrix.scaleBy(xOrAll, sY, sZ);
|
||||
}
|
||||
else {
|
||||
this.trsMatrix.scaleBy(xOrAll);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export default TransformableGeometry;
|
||||
@@ -1,39 +1,56 @@
|
||||
import TrsMatrix from "./TrsMatrix";
|
||||
import Point2D from "./Point2D";
|
||||
import BasicColor from "./BasicColor";
|
||||
import {VectorSizeError} from "./Errors";
|
||||
import TransformableGeometry from "./TransformableGeometry";
|
||||
import {triNormal} from "./utils";
|
||||
import Point3D from "./Point3D";
|
||||
import {Color, Colored, Transformable} from "./types";
|
||||
|
||||
class Triangle2D implements Transformable{
|
||||
private geometryRep: Float32Array;
|
||||
class Triangle2D extends TransformableGeometry implements Transformable, Colored {
|
||||
private color: Color;
|
||||
private readonly trsMatrix: TrsMatrix;
|
||||
constructor(vec: Float32Array, trsMatrix?: TrsMatrix, color?: Color);
|
||||
constructor(p1: Point2D, p2: Point2D, p3: Point2D, trsMatrix?: TrsMatrix, color?: Color);
|
||||
constructor(pointBuffer: Float32Array, trsMatrix?: TrsMatrix, color?: Color);
|
||||
constructor(p1: Point2D, p2: Point2D, p3: Point2D, trsMatrix?: TrsMatrix, color?: Color | ArrayLike<any>);
|
||||
constructor(...args: any[]) {
|
||||
let trsMatrix: TrsMatrix, pointBuff: Float32Array, color: Color | ArrayLike<number>;
|
||||
if (args[0] instanceof Float32Array) {
|
||||
if (args[0].length !== 6 && args[0].length !== 8) {
|
||||
throw new VectorSizeError("6 or 9", args[0].length)
|
||||
}
|
||||
else if (args[0].length === 6) {
|
||||
this.geometryRep = new Float32Array([
|
||||
pointBuff = new Float32Array([
|
||||
...args[0].slice(0, 2), 0.0,
|
||||
...args[0].slice(2, 4), 0.0,
|
||||
...args[0].slice(4, 6), 0.0
|
||||
]);
|
||||
}
|
||||
else {
|
||||
this.geometryRep = args[0];
|
||||
pointBuff = args[0];
|
||||
}
|
||||
this.trsMatrix = args[1] ?? new TrsMatrix();
|
||||
this.color = args[2] ?? new BasicColor(0, 0, 0, 1.0);
|
||||
trsMatrix = args[1] ?? new TrsMatrix();
|
||||
color = args[2] ?? new BasicColor();
|
||||
}
|
||||
else {
|
||||
this.geometryRep = new Float32Array([...args[0].vec(), ...args[1].vec(), ...args[2].vec()]);
|
||||
this.trsMatrix = args[3] ?? new TrsMatrix();
|
||||
this.color = args[4] ?? new BasicColor(0, 0, 0, 1.0);
|
||||
pointBuff = new Float32Array([...args[0].vec(), ...args[1].vec(), ...args[2].vec()]);
|
||||
trsMatrix = args[3] ?? new TrsMatrix();
|
||||
color = args[4] ?? new BasicColor();
|
||||
}
|
||||
super({
|
||||
pointBuffer: pointBuff,
|
||||
normalBuffer: new Float32Array(
|
||||
triNormal(
|
||||
new Point3D(pointBuff.slice(0, 3)),
|
||||
new Point3D(pointBuff.slice(3, 6)),
|
||||
new Point3D(pointBuff.slice(6, 9))
|
||||
).vec()
|
||||
),
|
||||
}, trsMatrix);
|
||||
if (color.hasOwnProperty("length")) {
|
||||
this.color = BasicColor.fromVec(color as ArrayLike<number>);
|
||||
}
|
||||
else {
|
||||
this.color = color as Color;
|
||||
}
|
||||
}
|
||||
|
||||
colorVec(): Float32Array {
|
||||
return this.color.vec();
|
||||
}
|
||||
|
||||
setColor(color: Color) {
|
||||
@@ -44,18 +61,14 @@ class Triangle2D implements Transformable{
|
||||
return this.color;
|
||||
}
|
||||
|
||||
getTrsMatrix(): TrsMatrix {
|
||||
return this.trsMatrix;
|
||||
}
|
||||
|
||||
private mapPointTo(point: Point2D | ArrayLike<number>, x: number) {
|
||||
if (point instanceof Point2D) {
|
||||
this.geometryRep[x] = point.xOrd();
|
||||
this.geometryRep[x + 1] = point.yOrd();
|
||||
this.geometry.pointBuffer[x] = point.xOrd();
|
||||
this.geometry.pointBuffer[x + 1] = point.yOrd();
|
||||
}
|
||||
else {
|
||||
this.geometryRep[x] = point[0];
|
||||
this.geometryRep[x + 1] = point[1];
|
||||
this.geometry.pointBuffer[x] = point[0];
|
||||
this.geometry.pointBuffer[x + 1] = point[1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,34 +85,6 @@ class Triangle2D implements Transformable{
|
||||
this.mapPointTo(p3, 6);
|
||||
}
|
||||
}
|
||||
|
||||
updatePointsFromVec(vec: Float32Array) {
|
||||
if (vec.length === 6) {
|
||||
this.geometryRep = vec;
|
||||
}
|
||||
else {
|
||||
throw new VectorSizeError(6, vec.length);
|
||||
}
|
||||
}
|
||||
|
||||
pointBuffer(): Float32Array {
|
||||
return this.geometryRep;
|
||||
}
|
||||
|
||||
translateBy(tX: number, tY: number, tZ: number): Triangle2D {
|
||||
this.trsMatrix.translateBy(tX, tY, tZ);
|
||||
return this;
|
||||
}
|
||||
|
||||
rotateBy(degX: number, degY: number, degZ: number): Triangle2D {
|
||||
this.trsMatrix.rotateBy(degX, degY, degZ);
|
||||
return this;
|
||||
}
|
||||
|
||||
scaleBy(sX: number, sY: number, sZ: number): Triangle2D {
|
||||
this.trsMatrix.scaleBy(sX, sY, sZ);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export default Triangle2D;
|
||||
@@ -1,34 +1,44 @@
|
||||
import Matrix4 from "./Matrix4";
|
||||
import MatrixFour from "./MatrixFour";
|
||||
import Point3D from "./Point3D";
|
||||
|
||||
class TrsMatrix implements Transformable {
|
||||
protected trs: Matrix4 = Matrix4.Identity();
|
||||
class TrsMatrix extends MatrixFour {
|
||||
constructor();
|
||||
constructor(translation: Matrix4, rotX: Matrix4, rotY: Matrix4, rotZ: Matrix4, scale: Matrix4);
|
||||
constructor(translation: MatrixFour, rotX: MatrixFour, rotY: MatrixFour, rotZ: MatrixFour, scale: MatrixFour);
|
||||
constructor(mat: TrsMatrix);
|
||||
constructor(...args: any[]) {
|
||||
super();
|
||||
if (args[0]) {
|
||||
if (args[0] instanceof TrsMatrix) {
|
||||
this.trs = new Matrix4(args[0].buffer());
|
||||
this.matrix = args[0].buffer();
|
||||
} else {
|
||||
this.trs = args[0].times(args[1]).times(args[2]).times(args[3]).times(args[4])
|
||||
this.matrix = args[0].times(args[1]).times(args[2]).times(args[3]).times(args[4])
|
||||
}
|
||||
}
|
||||
}
|
||||
toMatrix4(): Matrix4 {
|
||||
return this.trs;
|
||||
|
||||
position(): Point3D {
|
||||
return new Point3D(this.buffer(12, 15));
|
||||
}
|
||||
buffer(): Float32Array {
|
||||
return this.trs.buffer();
|
||||
|
||||
setPosition(xOrPoint: number | Point3D, y?: number, z?: number): void {
|
||||
if (xOrPoint instanceof Point3D) {
|
||||
this.setSlice([xOrPoint.x(), xOrPoint.y(), xOrPoint.z()], 12);
|
||||
}
|
||||
else {
|
||||
this.setSlice([xOrPoint, y ?? 0, z ?? 0], 12);
|
||||
}
|
||||
}
|
||||
|
||||
translateBy(tX: number, tY: number, tZ: number): TrsMatrix {
|
||||
this.trs = this.trs.times(new Matrix4([
|
||||
this.matrix = this.times(new MatrixFour([
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
tX, tY, tZ, 1,
|
||||
]));
|
||||
])).buffer();
|
||||
return this;
|
||||
}
|
||||
|
||||
rotateBy(degX: number, degY: number, degZ: number): TrsMatrix {
|
||||
const sx = Math.sin(degX);
|
||||
const cx = Math.cos(degX);
|
||||
@@ -36,34 +46,39 @@ class TrsMatrix implements Transformable {
|
||||
const cy = Math.cos(degY);
|
||||
const sz = Math.sin(degZ);
|
||||
const cz = Math.cos(degZ);
|
||||
this.trs = this.trs
|
||||
.times(new Matrix4([
|
||||
this.matrix = this
|
||||
.times(new MatrixFour([
|
||||
1, 0, 0, 0,
|
||||
0, cx, sx, 0,
|
||||
0, -sx, cx, 0,
|
||||
0, 0, 0, 1,
|
||||
]))
|
||||
.times(new Matrix4([
|
||||
.times(new MatrixFour([
|
||||
cy, 0, -sy, 0,
|
||||
0, 1, 0, 0,
|
||||
sy, 0, cy, 0,
|
||||
0, 0, 0, 1,
|
||||
]))
|
||||
.times(new Matrix4([
|
||||
.times(new MatrixFour([
|
||||
cz, sz, 0, 0,
|
||||
-sz, cz, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
]));
|
||||
])).buffer();
|
||||
return this;
|
||||
}
|
||||
scaleBy(sX: number, sY: number, sZ: number): TrsMatrix {
|
||||
this.trs = this.trs.times(new Matrix4([
|
||||
sX, 0, 0, 0,
|
||||
0, sY, 0, 0,
|
||||
0, 0, sZ, 0,
|
||||
0, 0, 0, 1,
|
||||
]));
|
||||
|
||||
scaleBy(xOrAll: number, sY?: number, sZ?: number): TrsMatrix {
|
||||
if (sY === undefined || sZ === undefined) {
|
||||
sY = xOrAll;
|
||||
sZ = xOrAll;
|
||||
}
|
||||
this.matrix = this.times(new MatrixFour([
|
||||
xOrAll, 0, 0, 0,
|
||||
0, sY, 0, 0,
|
||||
0, 0, sZ, 0,
|
||||
0, 0, 0, 1,
|
||||
])).buffer();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
precision mediump float;
|
||||
|
||||
uniform vec4 u_color;
|
||||
|
||||
varying float v_depth;
|
||||
varying vec3 v_light;
|
||||
varying vec3 v_normal;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vec4(exp(v_depth), exp(v_depth), exp(v_depth), 1.0);
|
||||
vec3 normal = normalize(v_normal);
|
||||
float light = dot(normal, v_light);
|
||||
gl_FragColor = u_color * (1.0 + light - light);
|
||||
}
|
||||
28
src/types.d.ts
vendored
28
src/types.d.ts
vendored
@@ -1,3 +1,6 @@
|
||||
import TrsMatrix from "./TrsMatrix";
|
||||
import Point3D from "./Point3D";
|
||||
|
||||
declare module '*.glsl' {
|
||||
const value: string;
|
||||
export = value;
|
||||
@@ -8,9 +11,16 @@ declare interface Vector {
|
||||
}
|
||||
|
||||
declare interface Transformable {
|
||||
translateBy(tX: number, tY: number, tZ: number): any;
|
||||
rotateBy(degX: number, degY: number, degZ: number): any;
|
||||
scaleBy(sX: number, sY: number, sZ: number): any;
|
||||
translateBy(tX: number, tY: number, tZ: number): Transformable;
|
||||
rotateBy(degX: number, degY: number, degZ: number): Transformable;
|
||||
scaleBy(sX: number, sY: number, sZ: number): Transformable;
|
||||
getTrsMatrix(): TrsMatrix;
|
||||
position(): Point3D;
|
||||
}
|
||||
|
||||
declare interface Colored {
|
||||
setColor(color: Color);
|
||||
getColor(): Color;
|
||||
}
|
||||
|
||||
declare interface Color extends Vector {
|
||||
@@ -19,3 +29,15 @@ declare interface Color extends Vector {
|
||||
blue(): number;
|
||||
alpha(): number;
|
||||
}
|
||||
|
||||
declare interface GeometryParams {
|
||||
pointBuffer: Float32Array;
|
||||
normalBuffer: Float32Array;
|
||||
elementBuffer: Uint16Array;
|
||||
}
|
||||
|
||||
declare interface Geometry {
|
||||
pointBuffer(): Float32Array;
|
||||
normalBuffer(): Float32Array;
|
||||
elementBuffer(): Uint16Array;
|
||||
}
|
||||
19
src/utils.ts
19
src/utils.ts
@@ -1,4 +1,9 @@
|
||||
import Matrix4 from "./Matrix4";
|
||||
import MatrixFour from "./MatrixFour";
|
||||
import Triangle2D from "./Triangle2D";
|
||||
import TrsMatrix from "./TrsMatrix";
|
||||
import Point2D from "./Point2D";
|
||||
import BasicColor from "./BasicColor";
|
||||
import Point3D from "./Point3D";
|
||||
|
||||
export function identityMatrix(size: number): Float32Array {
|
||||
const mat = Array<number>(size*size).fill(0);
|
||||
@@ -8,14 +13,6 @@ export function identityMatrix(size: number): Float32Array {
|
||||
));
|
||||
}
|
||||
|
||||
export function perspMat(fovDeg: number, aspect: number, near: number, far: number): Matrix4 {
|
||||
const f = Math.tan(Math.PI * 0.5 - 0.5 * fovDeg);
|
||||
const rangeInv = 1.0 / (near - far);
|
||||
|
||||
return new Matrix4([
|
||||
f / aspect, 0, 0, 0,
|
||||
0, f, 0, 0,
|
||||
0, 0, (near + far) * rangeInv, -1,
|
||||
0, 0, near * far * rangeInv * 2, 0
|
||||
]);
|
||||
export function triNormal(p1: Point3D, p2: Point3D, p3: Point3D): Point3D {
|
||||
return p2.minus(p1).cross(p3.minus(p1));
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
attribute vec4 a_position;
|
||||
|
||||
attribute vec4 a_normal;
|
||||
uniform mat4 u_trsMatrix;
|
||||
|
||||
varying vec3 v_light;
|
||||
varying float v_depth;
|
||||
|
||||
varying vec3 v_normal;
|
||||
|
||||
void main() {
|
||||
v_light = vec3(0.0, 0.0, 1.0);
|
||||
v_normal = (u_trsMatrix * a_normal).xyz;
|
||||
vec4 pos = u_trsMatrix * a_position;
|
||||
v_depth = pos.z;
|
||||
gl_Position = pos;
|
||||
|
||||
Reference in New Issue
Block a user