blobt 3 years ago
parent
commit
48340539a7
  1. 22
      src/App.tsx
  2. 7
      src/examples/Test.ts
  3. 2
      src/render/core/Application.ts
  4. 2
      src/render/core/Timer.ts
  5. 415
      src/renderi/commons/Util.ts
  6. 57
      src/renderi/commons/types.ts
  7. 406
      src/renderi/core/Application.ts
  8. 88
      src/renderi/core/Event.ts
  9. 42
      src/renderi/core/Timer.ts
  10. 50
      src/renderi/lib/CameraApplication.ts
  11. 700
      src/renderi/math/Mat4.ts
  12. 470
      src/renderi/math/Quat.ts
  13. 42
      src/renderi/math/Vec2.ts
  14. 303
      src/renderi/math/Vec3.ts
  15. 136
      src/renderi/math/Vec4.ts
  16. 6
      src/renderi/math/index.ts
  17. 24
      src/renderi/webgl/GLApplication.ts

22
src/App.tsx

@ -1,18 +1,26 @@
import React from 'react';
import './App.css';
import { Demo1 } from "./examples/Demo1";
import { Application } from "./render/core/Application";
import { Test } from "./examples/Test";
import { Application } from "./renderi/core/Application";
function frameCallback(app: Application): void {
//console.log(app);
function fCallback(app: Application): void {
console.log(app.fps);
}
function App() {
function test() {
let canvas: HTMLCanvasElement | null = document.getElementById('render') as HTMLCanvasElement;
let instance = new Demo1(canvas);
instance.frameCallback = frameCallback;
instance.run();
let rect: ClientRect = canvas.getBoundingClientRect();
console.log(rect);
let instance = new Test(canvas);
//instance.frameCallback = fCallback;
instance.start();
}
function App() {
test();
return (
<div className="App">

7
src/examples/Test.ts

@ -0,0 +1,7 @@
import { Application } from "../renderi/core/Application";
export class Test extends Application {
public constructor(canvas: HTMLCanvasElement) {
super(canvas);
}
}

2
src/render/core/Application.ts

@ -389,7 +389,7 @@ export class Application implements EventListenerObject {
if (timer.countdown <= 0.0) {
timer.callback(timer.id, timer.callbackData);
if (timer.onlyOnce) {
if (timer.onlyOnce === true) {
this.removeTimer(timer.id);
} else {
timer.callbackData = timer.timeout;

2
src/render/core/Timer.ts

@ -36,7 +36,7 @@ export class Timer {
*/
public onlyOnce: boolean = false;
constructor(callback: TimerCallback){
constructor(callback: TimerCallback) {
this.callback = callback;
}
}

415
src/renderi/commons/Util.ts

@ -0,0 +1,415 @@
import { EPSILON, EPlaneLoc } from "./types";
import { vec2, vec3, vec4, mat4 } from "../math";
import { quat } from "../math/Quat";
export class Util {
/**
* x是否是2的n次方x是不是1248163264.....
* @param x
* @returns
*/
public static isPowerOfTwo(x: number) {
return (x & (x - 1)) === 0;
}
/**
* 2n次方数
* x为34
* x为44
* x为58
* @param x
* @returns
*/
public static getNextPowerOfTwo(x: number): number {
if (x <= 0) {
throw new Error("参数必须要大于0!")
}
--x;
for (var i = 1; i < 32; i <<= 1) {
let t:number = x >> i;
x = x | t;
}
return x + 1;
}
/**
* /
* @param degree
* @returns
*/
public static toRadian(degree: number): number {
return degree * Math.PI / 180;
}
/**
*
* @param left
* @param right
* @returns
*/
public static numberEuaqls(left: number, right: number): boolean {
if (Math.abs(left - right) > EPSILON) {
return false;
}
return true;
}
/**
*
* @param x
* @param min
* @param max
* @returns
*/
public static clamp(x: number, min: number, max: number): number {
return (x < min) ? min : (x > max) ? max : x;
}
/**
*
* @param localPt
* @param mvp
* @param viewport
* @param viewportPt
* @returns
*/
public static obj2GLViewportSpace(localPt: vec3, mvp: mat4, viewport: Int32Array | Float32Array, viewportPt: vec3): boolean {
let v: vec4 = new vec4([localPt.x, localPt.y, localPt.z, 1.0]);
//这里相当于 v = mvp * v, 将顶点从local坐标系变换到投影坐标系
mvp.multiplyVec4(v, v);
//如果变换后的w为0,则返回false
if (v.w === 0.0) {
return false;
}
// 将裁剪坐标系的点的x / y / z分量除以w,得到normalized坐标值[ -1 , 1 ]之间
v.x /= v.w;
v.y /= v.w;
v.z /= v.w;
// [-1 , 1]标示的点变换到视口坐标系
v.x = v.x * 0.5 + 0.5;
v.y = v.y * 0.5 + 0.5;
v.z = v.z * 0.5 + 0.5;
// 视口坐标系再变换到屏幕坐标系
viewportPt.x = v.x * viewport[2] + viewport[0];
viewportPt.y = v.y * viewport[3] + viewport[1];
viewportPt.z = v.z;
return true;
}
/**
* 3
* @param a
* @param b
* @param c
* @param result
* @returns
*/
public static computeNormal(a: vec3, b: vec3, c: vec3, result: vec3 | null): vec3 {
if (!result) {
result = new vec3();
}
let l0: vec3 = new vec3();
let l1: vec3 = new vec3();
vec3.difference(b, a, l0);
vec3.difference(c, a, l1);
vec3.cross(l0, l1, result);
result.normalize();
return result;
}
/**
* 3
* @param a
* @param b
* @param c
* @param result
* @returns
*/
public static planeFromPoints(a: vec3, b: vec3, c: vec3, result: vec4 | null = null): vec4 {
if (!result) {
result = new vec4();
}
let normal: vec3 = new vec3();
Util.computeNormal(a, b, c, normal);
let d: number = -vec3.dot(normal, a);
result.x = normal.x;
result.y = normal.y;
result.z = normal.z;
result.w = d;
return result;
}
/**
* 线
* @param p
* @param normal
* @param result
* @returns
*/
public static planeFromPointNormal(p: vec3, normal: vec3, result: vec4 | null = null): vec4 {
if (!result) {
result = new vec4();
}
let d: number = -vec3.dot(normal, p);
result.x = normal.x;
result.y = normal.y;
result.z = normal.z;
result.w = d;
return result;
}
/**
*
* @param polygon
* @returns
*/
public static planeFromPolygon(polygon: vec3[]): vec4 {
if (polygon.length < 3) {
throw new Error("The number of vertices of polygon must be greater than or equal to 3 ");
}
return Util.planeFromPoints(polygon[0], polygon[1], polygon[2]);
}
/**
*
* @param plane
* @param point
* @returns
*/
public static planeDistanceFromPoint(plane: vec4, point: vec3): number {
return (point.x * plane.x + point.y * plane.y + point.z * plane.z + plane.w);
}
/**
*
* @param plane
* @param point
* @returns
*/
public static planeTestPoint(plane: vec4, point: vec3): EPlaneLoc {
let num: number = Util.planeDistanceFromPoint(plane, point);
if (num > EPSILON) {
return EPlaneLoc.FRONT;
} else if (num < - EPSILON) {
return EPlaneLoc.BACK;
} else {
return EPlaneLoc.COPLANAR;
}
}
/**
*
* @param plane
* @returns
*/
public static planeNormalize(plane: vec4): number {
let length: number;
length = Math.sqrt(plane.x * plane.x + plane.y * plane.y + plane.z * plane.z);
if (length === 0) {
throw new Error("The plane area is 0");
}
plane.x /= length;
plane.y /= length;
plane.z /= length;
plane.w /= length;
return length;
}
/**
*
* @param v
* @param mins
* @param maxs
*/
public static boundBoxAddPoint(v: vec3, mins: vec3, maxs: vec3): void {
if (v.x < mins.x) {
mins.x = v.x;
}
if (v.x > maxs.x) {
maxs.x = v.x;
}
if (v.y < mins.y) {
mins.y = v.y;
}
if (v.y > maxs.y) {
maxs.y = v.y;
}
if (v.z < mins.z) {
mins.z = v.z;
}
if (v.z > maxs.z) {
maxs.z = v.z;
}
}
/**
*
* @param mins
* @param maxs
* @param value
*/
public static boundBoxClear(mins: vec3, maxs: vec3, value: number = Infinity): void {
mins.x = mins.y = mins.z = value; // 初始化时,让mins表示浮点数的最大范围
maxs.x = maxs.y = maxs.z = -value; // 初始化是,让maxs表示浮点数的最小范围
}
/**
*
* @param mins
* @param maxs
* @param out
* @returns
*/
public static boundBoxGetCenter(mins: vec3, maxs: vec3, out: vec3 | null = null): vec3 {
if (out === null) {
out = new vec3();
}
//(maxs + mins) * 0.5
vec3.sum(mins, maxs, out);
out.scale(0.5);
return out;
}
/**
* 8
* @param mins
* @param maxs
* @param pts8
* /3--------/7 |
* / | / |
* / | / |
* 1---------5 |
* | /2- - -|- -6
* | / | /
* |/ | /
* 0---------4/
*/
public static boundBoxGet8Points(mins: vec3, maxs: vec3, pts8: vec3[]): void {
//获取中心点
let center: vec3 = Util.boundBoxGetCenter(mins, maxs);
//获取最大点到中心点之间的距离向量
let maxs2center: vec3 = vec3.difference(center, maxs);
pts8.push(new vec3([center.x + maxs2center.x, center.y + maxs2center.y, center.z + maxs2center.z])); // 0
pts8.push(new vec3([center.x + maxs2center.x, center.y - maxs2center.y, center.z + maxs2center.z])); // 1
pts8.push(new vec3([center.x + maxs2center.x, center.y + maxs2center.y, center.z - maxs2center.z])); // 2
pts8.push(new vec3([center.x + maxs2center.x, center.y - maxs2center.y, center.z - maxs2center.z])); // 3
pts8.push(new vec3([center.x - maxs2center.x, center.y + maxs2center.y, center.z + maxs2center.z])); // 4
pts8.push(new vec3([center.x - maxs2center.x, center.y - maxs2center.y, center.z + maxs2center.z])); // 5
pts8.push(new vec3([center.x - maxs2center.x, center.y + maxs2center.y, center.z - maxs2center.z])); // 6
pts8.push(new vec3([center.x - maxs2center.x, center.y - maxs2center.y, center.z - maxs2center.z])); // 7
}
/**
*
* @param mat
* @param mins
* @param maxs
*/
public static boundBoxTransform(mat: mat4, mins: vec3, maxs: vec3): void {
// 获得局部坐标系表示的AABB的8个顶点坐标
let pts: vec3[] = [];
Util.boundBoxGet8Points(mins, maxs, pts);
//变换后的顶点
let out: vec3 = new vec3();
for (let i: number = 0; i < pts.length; i++) {
// 将局部坐标表示的顶点变换到mat坐标空间中去,变换后的结果放在out变量中
mat.multiplyVec3(pts[i], out);
Util.boundBoxAddPoint(out, mins, maxs);
}
}
/**
*
* @param point
* @param mins
* @param maxs
*/
public static boundBoxContainPoint(point: vec3, mins: vec3, maxs: vec3): boolean {
return (point.x >= mins.x && point.x <= maxs.x && point.y >= mins.y && point.y <= maxs.y && point.z >= mins.z && point.z <= maxs.z);
}
/**
*
* @param min1 1 2
* @param max1
* @param min2
* @param max2
* @returns
*/
public static boundBoxBoundBoxOverlap(min1: vec3, max1: vec3, min2: vec3, max2: vec3): boolean {
if (min1.x > max2.x) return false;
if (max1.x < min2.x) return false;
if (min1.y > max2.y) return false;
if (max1.y < min2.y) return false;
if (min1.z > max2.z) return false;
if (max1.z < min2.z) return false;
return true;
}
/**
* y轴 z轴
* @param v
* @param scale
*/
public static convertVec3IDCoord2GLCoord(v: vec3, scale: number = 10.0): void {
let f: number = v.y;
v.y = v.z;
v.z = -f;
if (!Util.numberEuaqls(scale, 0) && !Util.numberEuaqls(scale, 1.0)) {
v.x /= scale;
v.y /= scale;
v.z /= scale;
}
}
/**
*
* @param v
*/
public static convertVec2IDCoord2GLCoord(v: vec2): void {
v.y = 1.0 - v.y;
}
/**
*
* @param pos
* @param q
* @param dest
* @returns
*/
public static matrixFrom(pos: vec3, q: quat, dest: mat4 | null = null): mat4 {
if (dest === null) {
dest = new mat4();
}
q.toMat4(dest);
dest.values[12] = pos.x;
dest.values[13] = pos.y;
dest.values[14] = pos.z;
return dest;
}
}

57
src/renderi/commons/types.ts

@ -0,0 +1,57 @@
export let EPSILON: number = 0.0001;
export enum EShaderType {
VS_SHADER,
FS_SHADER
}
export enum EGLSLESDataType {
FLOAT_VEC2 = 0x8B50,
FLOAT_VEC3,
FLOAT_VEC4,
INT_VEC2,
INT_VEC3,
INT_VEC4,
BOOL,
BOOL_VEC2,
BOOL_VEC3,
BOOL_VEC4,
FLOAT_MAT2,
FLOAT_MAT3,
FLOAT_MAT4,
SAMPLER_2D,
SAMPLER_CUBE,
FLOAT = 0x1406,
INT = 0x1404
}
export enum EGLTexWrapType {
GL_REPEAT, //设置为gl对应的常量
GL_MIRRORED_REPEAT,
GL_CLAMP_TO_EDGE
}
export enum EPlaneLoc {
FRONT, // 在平面的正面
BACK, // 在平面的背面
COPLANAR // 与平面共面
}
export enum ECameraType {
FPSCAMERA,
FLYCAMERA
}
export enum EMatrixMode {
MODELVIEW,
PROJECTION,
TEXTURE
}
export enum EAxisType {
NONE = -1,
XAXIS,
YAXIS,
ZAXIS
}

406
src/renderi/core/Application.ts

@ -0,0 +1,406 @@
import { Timer, TimerCallback } from "./Timer";
import { vec2 } from "../math";
import { EInputEventType, CanvasMouseEvent, CanvasKeyBoardEvent } from "./Event";
export class Application implements EventListenerObject {
/**
* @var
*/
public timers: Timer[] = [];
/**
* @var id
*/
private _timerId: number = -1;
/**
* @var
*/
private _fps: number = 0;
/**
* @var y轴
*/
public isFlipYCoord: boolean = false;
/**
* @var canvas
*/
public canvas: HTMLCanvasElement;
/**
* @var mouse事件
*/
public isSupportMouseMove: boolean;
/**
* @var
*/
protected _isMouseDown: boolean;
/**
* @var drag事件
*/
protected _isRightMouseDown: boolean = false;
/**
* @var
*/
protected _start: boolean = false;
/**
* @var Window对象的requestAnimationFrame返回的大于0的id号,
* 使cancelAnimationFrame ( this ._requestId ).
*/
protected _requestId: number = -1;
/**
* @var
*/
protected _lastTime !: number;
protected _startTime !: number;
/**
* @function
*/
public frameCallback: ((app: Application) => void) | null;
public constructor(canvas: HTMLCanvasElement) {
this.canvas = canvas;
// canvas元素能够监听鼠标事件
this.canvas.addEventListener("mousedown", this, false);
this.canvas.addEventListener("mouseup", this, false);
this.canvas.addEventListener("mousemove", this, false);
// 很重要一点,键盘事件不能在canvas中触发,但是能在全局的window对象中触发
// 因此我们能在window对象中监听键盘事件
window.addEventListener("keydown", this, false);
window.addEventListener("keyup", this, false);
window.addEventListener("keypress", this, false);
//初始化时候mousedown 和 mousemvoe不开启
this._isMouseDown = false;
this.isSupportMouseMove = false;
this.frameCallback = null;
//禁止右键菜单
document.oncontextmenu = function () { return false };
}
/**
*
*/
public start(): void {
if (this._start === false) {
this._start = true;
this._startTime = -1;
this._lastTime = -1;
this._requestId = requestAnimationFrame((msec: number): void => {
this.step(msec);
});
}
}
/**
* Application是否一直在调用requestAnimationFrame
* @returns boolean
*/
public isRunning(): boolean {
return this._start;
}
/**
*
*/
public stop(): void {
if (this._start) {
cancelAnimationFrame(this._requestId);
this._startTime = -1;
this._lastTime = -1;
this._start = false;
}
}
/**
*
* @param timeStamp
*/
protected step(timeStamp: number): void {
if (this._startTime === -1) {
this._startTime = timeStamp;
}
if (this._lastTime === -1) {
this._lastTime = timeStamp;
}
//计算当前时间和第一次调用step时候的时间差
let elapsedMsec = timeStamp - this._startTime;
//计算当前时间和上一次调用step时候的时间差
let intervalMSec = timeStamp - this._lastTime;
let intervalSec = intervalMSec / 1000.0;
this._lastTime = timeStamp;
//计算帧率
if (intervalMSec !== 0) {
this._fps = 1000 / intervalMSec;
}
//处理timer
this._handleTimers(intervalSec);
//更新
this.update(elapsedMsec, intervalSec);
//渲染
this.render();
//触发帧回调函数
if (this.frameCallback !== null) {
this.frameCallback(this);
}
//递归调用
requestAnimationFrame((elapsedMsec: number): void => {
this.step(elapsedMsec);
});
}
/**
*
* @param elapsedMsec
* @param intervalSec
*/
public update(elapsedMsec: number, intervalSec: number): void { }
/**
*
*/
public render(): void { }
/**
*
* @param intervalSec
*/
private _handleTimers(intervalSec: number): void {
//遍历整个timer
for (let i = 0; i < this.timers.length; i++) {
let timer: Timer = this.timers[i];
// 如果当前timer enabled为false,那么继续循环
if (timer.enabled === false) {
continue;
}
//减少秒数,倒计时
timer.countdown -= intervalSec;
if (timer.countdown < 0) {
// 调用回调函数
timer.callback(timer.id, timer.callbackData);
if (timer.onlyOnce === false) {
timer.countdown = timer.timeout;
} else {
this.removeTimer(timer.id);
}
}
}
}
/**
*
* @param callback
* @param timeout
* @param onlyOnce
* @param data
* @returns
*/
public addTimer(callback: TimerCallback, timeout: number = 1.0, onlyOnce: boolean = false, data: any = undefined): number {
let timer: Timer;
for (let i = 0; i < this.timers.length; i++) {
timer = this.timers[i];
if (timer.enabled === false) {
timer.callback = callback;
timer.callbackData = data;
timer.timeout = timeout;
timer.enabled = true;
timer.onlyOnce = onlyOnce;
return timer.id;
}
}
timer = new Timer(callback);
timer.callback = callback;
timer.callbackData = data;
timer.timeout = timeout;
timer.enabled = true;
timer.onlyOnce = onlyOnce;
this.timers.push(timer);
timer.id = ++this._timerId;
return timer.id;
}
/**
*
* @param id
* @returns
*/
public removeTimer(id: number): boolean {
let ret: boolean = false;
for (let i = 0; i < this.timers.length; i++) {
if (this.timers[i].id === id) {
let timer: Timer = this.timers[i];
timer.enabled = false;
ret = true;
break;
}
}
return ret;
}
/**
*
* @param evt
*/
public handleEvent(evt: Event): void {
switch (evt.type) {
case "mousedown":
this._isMouseDown = true;
this.onMouseDown(this._toCanvasMouseEvent(evt, EInputEventType.MOUSEDOWN));
break;
case "mouseup":
this._isMouseDown = false;
this.onMouseDown(this._toCanvasMouseEvent(evt, EInputEventType.MOUSEUP));
break;
case "mousemove":
if (this.isSupportMouseMove) {
this.onMouseMove(this._toCanvasMouseEvent(evt, EInputEventType.MOUSEMOVE));
}
if (this._isMouseDown) {
this.onMouseDrag(this._toCanvasMouseEvent(evt, EInputEventType.MOUSEDRAG));
}
break;
case "keypress":
this.onKeyPress(this._toCanvasKeyBoardEvent(evt, EInputEventType.KEYPRESS));
break;
case "keydown":
this.onKeyDown(this._toCanvasKeyBoardEvent(evt, EInputEventType.MOUSEDOWN));
break;
case "keyup":
this.onKeyUp(this._toCanvasKeyBoardEvent(evt, EInputEventType.KEYUP));
break;
}
}
/**
* canvas的位置
* @param evt
*/
public viewportToCanvasCoordinate(evt: MouseEvent): vec2 {
let rect: ClientRect = this.getMouseCanvas().getBoundingClientRect();
//target是触发事件的元素,这里是canvas
if (evt.target) {
let x: number = evt.clientX - rect.left;
let y: number = evt.clientY - rect.top;
if (this.isFlipYCoord) {
y = this.getMouseCanvas().height - y;
}
let pos: vec2 = new vec2([x, y]);
return pos;
}
throw new Error("evt.target is null");
}
/**
* DOM
* @param evt
* @param type
*/
private _toCanvasMouseEvent(evt: Event, type: EInputEventType): CanvasMouseEvent {
let event: MouseEvent = evt as MouseEvent;//向下转型,将Event转换为MouseEvent
if (type === EInputEventType.MOUSEDOWN && event.button === 2) {
this._isRightMouseDown = true;
} else if (type === EInputEventType.MOUSEUP && event.button === 2) {
this._isRightMouseDown = false;
}
let buttonNum: number = event.button;
if (this._isRightMouseDown && type === EInputEventType.MOUSEDRAG) {
buttonNum = 2;
}
//将鼠标位置变换到canvas坐标系位置
let mousePosition: vec2 = this.viewportToCanvasCoordinate(event);
let ret: CanvasMouseEvent = new CanvasMouseEvent(type, mousePosition, buttonNum, event.altKey, event.ctrlKey, event.shiftKey);
return ret;
}
/**
* DOM
* @param evt
* @param type
*/
private _toCanvasKeyBoardEvent(evt: Event, type: EInputEventType): CanvasKeyBoardEvent {
let event: KeyboardEvent = evt as KeyboardEvent;
let ret: CanvasKeyBoardEvent = new CanvasKeyBoardEvent(type, event.key, event.keyCode, event.repeat, event.altKey, event.ctrlKey, event.shiftKey);
return ret;
}
protected onMouseDown(evt: CanvasMouseEvent): void {
return;
}
protected onMouseUp(evt: CanvasMouseEvent): void {
return;
}
protected onMouseMove(evt: CanvasMouseEvent): void {
return;
}
protected onMouseDrag(evt: CanvasMouseEvent): void {
return;
}
protected onKeyDown(evt: CanvasKeyBoardEvent): void {
return;
}
protected onKeyUp(evt: CanvasKeyBoardEvent): void {
return;
}
protected onKeyPress(evt: CanvasKeyBoardEvent): void {
return;
}
/**
*
* @returns
*/
protected getMouseCanvas(): HTMLCanvasElement {
return this.canvas;
}
/**
*
*/
public get fps(): number {
return this._fps;
}
}

88
src/renderi/core/Event.ts

@ -0,0 +1,88 @@
import { vec2 } from "../math";
/**
* appliaction所有事件
*/
export enum EInputEventType {
MOUSEEVENT, //总类。表示鼠标事件
MOUSEDOWN,
MOUSEUP,
MOUSEMOVE,
MOUSEDRAG,
KEYBOARDEVENT, //总类,表示键盘事件
KEYUP,
KEYDOWN,
KEYPRESS
}
export class CanvasInputEvent {
/**
* @var alt键是否被按下
*/
public altKey: boolean;
/**
* @var ctrl键是否被按下
*/
public ctrlKey: boolean;
/**
* @var shift键是否被按下
*/
public shiftKey: boolean;
/**
* @var
*/
public type: EInputEventType;
public constructor(type: EInputEventType, altKey: boolean = false, ctrlKey: boolean = false, shiftKey: boolean = false) {
this.type = type;
this.altKey = altKey;
this.ctrlKey = ctrlKey;
this.shiftKey = shiftKey;
}
}
export class CanvasMouseEvent extends CanvasInputEvent {
/**
* @var 0 : 鼠标左键 1 2
*/
public button: number;
/**
* @var canvas
*/
public canvasPosition: vec2;
public constructor(type: EInputEventType, canvasPos: vec2, button: number, altKey: boolean = false, ctrlKey: boolean = false, shiftKey: boolean = false) {
super(type, altKey, ctrlKey, shiftKey);
this.canvasPosition = canvasPos;
this.button = button;
}
}
export class CanvasKeyBoardEvent extends CanvasInputEvent {
/**
* @var
*/
public key: string;
/**
* @var ascii码
*/
public keyCode: number;
/**
* @var
*/
public repeat: boolean;
public constructor(type: EInputEventType, key: string, keyCode: number, repeat: boolean, altKey: boolean = false, ctrlKey: boolean = false, shiftKey: boolean = false) {
super(type, altKey, ctrlKey, shiftKey);
this.key = key;
this.keyCode = keyCode;
this.repeat = repeat;
}
}

42
src/renderi/core/Timer.ts

@ -0,0 +1,42 @@
export type TimerCallback = (id: number, data: any) => void;
export class Timer {
/**
* @var id
*/
public id: number = -1;
/**
* @var
*/
public enabled: boolean = false;
/**
* @function
*/
public callback: TimerCallback;
/**
* @var
*/
public callbackData: any = undefined;
/**
* @var update次数
*/
public countdown: number = 0;
/**
* @var
*/
public timeout: number = 0;
/**
* @var
*/
public onlyOnce: boolean = false;
constructor(callback: TimerCallback) {
this.callback = callback;
}
}

50
src/renderi/lib/CameraApplication.ts

@ -0,0 +1,50 @@
import { GLApplication } from "../webgl/GLApplication";
export class CameraApplication extends GLApplication {
/**
* @var
*/
public camera: Camera;
public constructor(canvas: HTMLCanvasElement, contextAttributes: WebGLContextAttributes = { premultipliedAlpha: false }, need2d: boolean = false) {
super(canvas, contextAttributes, need2d);
this.camera = new Camera(this.gl, canvas.width, canvas.height, 45, 1, 200);
this.camera.z = 4;
}
/**
* camera的updatecamera的投影和视图矩阵
* CameraApplication的子类复写本函数 super.update(elapsedMsec, intervalSec)
* @param elapsedMsec
* @param intervalSec
*/
public update(elapsedMsec: number, intervalSec: number) {
this.camera.update(intervalSec);
}
/**
* onKeyPress
* @param evt
*/
public onKeyPress(evt: CanvasKeyBoardEvent): void {
if (evt.key === "w") {
this.camera.moveForward(-1); // 摄像机向前运行
} else if (evt.key === "s") {
this.camera.moveForward(1); // 摄像机向后运行
} else if (evt.key === "a") {
this.camera.moveRightward(1); // 摄像机向右运行
} else if (evt.key === "d") {
this.camera.moveRightward(-1); // 摄像机向左运行
} else if (evt.key === "z") {
this.camera.moveUpward(1); // 摄像机向上运行
} else if (evt.key === "x") {
this.camera.moveUpward(-1); // 摄像机向下运行
} else if (evt.key === "y") {
this.camera.yaw(1); // 摄像机绕本身的Y轴旋转
} else if (evt.key === "r") {
this.camera.roll(1); // 摄像机绕本身的Z轴旋转
} else if (evt.key == "p") {
this.camera.pitch(1); // 摄像机绕本身的X轴旋转
}
}
}

700
src/renderi/math/Mat4.ts

@ -0,0 +1,700 @@
import { EPSILON } from "../commons/types";
import { vec3, vec4 } from ".";
export class mat4 {
public values = new Float32Array(16);
public static identity = new mat4().setIdentity();
public static m0 = new mat4();
public static m1 = new mat4();
public constructor(values: number[] | null = null) {
if (values) {
this.set(values);
}
else {
this.setIdentity();
}
}
public set(values: number[]): mat4 {
for (let i = 0; i < 16; i++) {
this.values[i] = values[i];
}
return this;
}
public at(index: number): number {
return this.values[index];
}
/**
*
* @param dest
* @returns
*/
public copy(dest: mat4 | null = null): mat4 {
if (!dest) dest = new mat4();
for (let i = 0; i < 16; i++) {
dest.values[i] = this.values[i];
}
return dest;
}
/**
*
* @param matrix
* @param threshold
* @returns
*/
public equals(matrix: mat4, threshold = EPSILON): boolean {
for (let i = 0; i < 16; i++) {
if (Math.abs(this.values[i] - matrix.at(i)) > threshold)
return false;
}
return true;
}
/**
*
* @param index
* @param dest
* @returns
*/
public getRow(index: number, dest: vec4 | null = null): vec4 {
if (dest === null) {
dest = new vec4();
}
dest.x = this.values[index * 4 + 0];
dest.y = this.values[index * 4 + 1];
dest.z = this.values[index * 4 + 2];
dest.w = this.values[index * 4 + 3];
return dest;
}
/**
*
* @param index
* @param dest
* @returns
*/
public getColumn(index: number, dest: vec4 | null = null): vec4 {
if (dest === null) {
dest = new vec4();
}
dest.x = this.values[index];
dest.y = this.values[index + 4];
dest.z = this.values[index + 8];
dest.w = this.values[index + 12];
return dest;
}
/**
*
* @param dest
* @returns
*/
public getPosition(dest: vec3 | null = null): vec3 {
if (dest === null) {
dest = new vec3();
}
dest.x = this.values[12];
dest.y = this.values[13];
dest.z = this.values[14];
return dest;
}
/**
* x轴
* @param dest
* @returns
*/
public getXAxis(dest: vec3 | null = null): vec3 {
if (dest === null) {
dest = new vec3();
}
dest.x = this.values[0];
dest.y = this.values[1];
dest.z = this.values[2];
return dest;
}
/**
* y轴
* @param dest
* @returns
*/
public getYAxis(dest: vec3 | null = null): vec3 {
if (dest === null) {
dest = new vec3();
}
dest.x = this.values[4];
dest.y = this.values[5];
dest.z = this.values[6];
return dest;
}
/**
* z轴
* @param dest
* @returns
*/
public getZAxis(dest: vec3 | null = null): vec3 {
if (dest === null) {
dest = new vec3();
}
dest.x = this.values[8];
dest.y = this.values[9];
dest.z = this.values[10];
return dest;
}
/**
*
* @param idx
* @param dest
* @returns
*/
public getAxis(idx: number, dest: vec3 | null = null): vec3 {
if (idx === 0) {
return this.getXAxis(dest);
} else if (idx === 1) {
return this.getYAxis(dest);
} else {
return this.getZAxis(dest);
}
}
/**
*
* @returns
*/
public setIdentity(): mat4 {
this.values[0] = 1;
this.values[1] = 0;
this.values[2] = 0;
this.values[3] = 0;
this.values[4] = 0;
this.values[5] = 1;
this.values[6] = 0;
this.values[7] = 0;
this.values[8] = 0;
this.values[9] = 0;
this.values[10] = 1;
this.values[11] = 0;
this.values[12] = 0;
this.values[13] = 0;
this.values[14] = 0;
this.values[15] = 1;
return this;
}
/**
*
* @returns
*/
public transpose(): mat4 {
let temp01 = this.values[1], temp02 = this.values[2],
temp03 = this.values[3], temp12 = this.values[6],
temp13 = this.values[7], temp23 = this.values[11];
this.values[1] = this.values[4];
this.values[2] = this.values[8];
this.values[3] = this.values[12];
this.values[4] = temp01;
this.values[6] = this.values[9];
this.values[7] = this.values[13];
this.values[8] = temp02;
this.values[9] = temp12;
this.values[11] = this.values[14];
this.values[12] = temp03;
this.values[13] = temp13;
this.values[14] = temp23;
return this;
}
/**
*
* @returns
*/
public determinant(): number {
let a00 = this.values[0], a01 = this.values[1], a02 = this.values[2], a03 = this.values[3],
a10 = this.values[4], a11 = this.values[5], a12 = this.values[6], a13 = this.values[7],
a20 = this.values[8], a21 = this.values[9], a22 = this.values[10], a23 = this.values[11],
a30 = this.values[12], a31 = this.values[13], a32 = this.values[14], a33 = this.values[15];
let det00 = a00 * a11 - a01 * a10,
det01 = a00 * a12 - a02 * a10,
det02 = a00 * a13 - a03 * a10,
det03 = a01 * a12 - a02 * a11,
det04 = a01 * a13 - a03 * a11,
det05 = a02 * a13 - a03 * a12,
det06 = a20 * a31 - a21 * a30,
det07 = a20 * a32 - a22 * a30,
det08 = a20 * a33 - a23 * a30,
det09 = a21 * a32 - a22 * a31,
det10 = a21 * a33 - a23 * a31,
det11 = a22 * a33 - a23 * a32;
return (det00 * det11 - det01 * det10 + det02 * det09 + det03 * det08 - det04 * det07 + det05 * det06);
}
public det(): number {
return this.determinant();
}
/**
*
* @param out
* @returns
*/
public inverse(out: mat4): boolean {
this.copy(out);
let a00 = out.values[0], a01 = out.values[1], a02 = out.values[2], a03 = out.values[3],
a10 = out.values[4], a11 = out.values[5], a12 = out.values[6], a13 = out.values[7],
a20 = out.values[8], a21 = out.values[9], a22 = out.values[10], a23 = out.values[11],
a30 = out.values[12], a31 = out.values[13], a32 = out.values[14], a33 = out.values[15];
let det00 = a00 * a11 - a01 * a10,
det01 = a00 * a12 - a02 * a10,
det02 = a00 * a13 - a03 * a10,
det03 = a01 * a12 - a02 * a11,
det04 = a01 * a13 - a03 * a11,
det05 = a02 * a13 - a03 * a12,
det06 = a20 * a31 - a21 * a30,
det07 = a20 * a32 - a22 * a30,
det08 = a20 * a33 - a23 * a30,
det09 = a21 * a32 - a22 * a31,
det10 = a21 * a33 - a23 * a31,
det11 = a22 * a33 - a23 * a32;
let det = (det00 * det11 - det01 * det10 + det02 * det09 + det03 * det08 - det04 * det07 + det05 * det06);
if (!det)
return false;
det = 1.0 / det;
out.values[0] = (a11 * det11 - a12 * det10 + a13 * det09) * det;
out.values[1] = (-a01 * det11 + a02 * det10 - a03 * det09) * det;
out.values[2] = (a31 * det05 - a32 * det04 + a33 * det03) * det;
out.values[3] = (-a21 * det05 + a22 * det04 - a23 * det03) * det;
out.values[4] = (-a10 * det11 + a12 * det08 - a13 * det07) * det;
out.values[5] = (a00 * det11 - a02 * det08 + a03 * det07) * det;
out.values[6] = (-a30 * det05 + a32 * det02 - a33 * det01) * det;
out.values[7] = (a20 * det05 - a22 * det02 + a23 * det01) * det;
out.values[8] = (a10 * det10 - a11 * det08 + a13 * det06) * det;
out.values[9] = (-a00 * det10 + a01 * det08 - a03 * det06) * det;
out.values[10] = (a30 * det04 - a31 * det02 + a33 * det00) * det;
out.values[11] = (-a20 * det04 + a21 * det02 - a23 * det00) * det;
out.values[12] = (-a10 * det09 + a11 * det07 - a12 * det06) * det;
out.values[13] = (a00 * det09 - a01 * det07 + a02 * det06) * det;
out.values[14] = (-a30 * det03 + a31 * det01 - a32 * det00) * det;
out.values[15] = (a20 * det03 - a21 * det01 + a22 * det00) * det;
return true;
}
/**
*
* @param matrix
* @returns
*/
public multiply(matrix: mat4): mat4 {
let a00 = this.values[0], a01 = this.values[1], a02 = this.values[2], a03 = this.values[3];
let a10 = this.values[4], a11 = this.values[5], a12 = this.values[6], a13 = this.values[7];
let a20 = this.values[8], a21 = this.values[9], a22 = this.values[10], a23 = this.values[11];
let a30 = this.values[12], a31 = this.values[13], a32 = this.values[14], a33 = this.values[15];
let b0 = matrix.at(0),
b1 = matrix.at(1),
b2 = matrix.at(2),
b3 = matrix.at(3);
this.values[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
this.values[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
this.values[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
this.values[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
b0 = matrix.at(4);
b1 = matrix.at(5);
b2 = matrix.at(6);
b3 = matrix.at(7);
this.values[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
this.values[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
this.values[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
this.values[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
b0 = matrix.at(8);
b1 = matrix.at(9);
b2 = matrix.at(10);
b3 = matrix.at(11);
this.values[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
this.values[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
this.values[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
this.values[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
b0 = matrix.at(12);
b1 = matrix.at(13);
b2 = matrix.at(14);
b3 = matrix.at(15);
this.values[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
this.values[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
this.values[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
this.values[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
return this;
}
/**
* 3
* @param vector
* @param dest
* @returns
*/
public multiplyVec3(vector: vec3, dest: vec3 | null = null): vec3 {
if (!dest) dest = new vec3();
let x = vector.x,
y = vector.y,
z = vector.z;
dest.x = this.values[0] * x + this.values[4] * y + this.values[8] * z + this.values[12];
dest.y = this.values[1] * x + this.values[5] * y + this.values[9] * z + this.values[13];
dest.z = this.values[2] * x + this.values[6] * y + this.values[10] * z + this.values[14];
return dest;
}
/**
* 4
* @param vector
* @param dest
* @returns
*/
public multiplyVec4(vector: vec4, dest: vec4 | null = null): vec4 {
if (!dest) dest = new vec4();
let x = vector.x,
y = vector.y,
z = vector.z,
w = vector.w;
dest.x = this.values[0] * x + this.values[4] * y + this.values[8] * z + this.values[12] * w;
dest.y = this.values[1] * x + this.values[5] * y + this.values[9] * z + this.values[13] * w;
dest.z = this.values[2] * x + this.values[6] * y + this.values[10] * z + this.values[14] * w;
dest.w = this.values[3] * x + this.values[7] * y + this.values[11] * z + this.values[15] * w;
return dest;
}
/**
*
* @param vector
* @returns
*/
public translate(vector: vec3): mat4 {
let x = vector.x,
y = vector.y,
z = vector.z;
this.values[12] += this.values[0] * x + this.values[4] * y + this.values[8] * z;
this.values[13] += this.values[1] * x + this.values[5] * y + this.values[9] * z;
this.values[14] += this.values[2] * x + this.values[6] * y + this.values[10] * z;
this.values[15] += this.values[3] * x + this.values[7] * y + this.values[11] * z;
return this;
}
/**
*
* @param vector
* @returns
*/
public scale(vector: vec3): mat4 {
let x = vector.x,
y = vector.y,
z = vector.z;
this.values[0] *= x;
this.values[1] *= x;
this.values[2] *= x;
this.values[3] *= x;
this.values[4] *= y;
this.values[5] *= y;
this.values[6] *= y;
this.values[7] *= y;
this.values[8] *= z;
this.values[9] *= z;
this.values[10] *= z;
this.values[11] *= z;
return this;
}
/**
*
* @param angle
* @param axis
* @returns
*/
public rotate(angle: number, axis: vec3): mat4 | null {
let x = axis.x,
y = axis.y,
z = axis.z;
let length = Math.sqrt(x * x + y * y + z * z);
if (!length)
return null;
if (length !== 1) {
length = 1 / length;
x *= length;
y *= length;
z *= length;
}
let s = Math.sin(angle);
let c = Math.cos(angle);
let t = 1.0 - c;
let a00 = this.values[0], a01 = this.values[1], a02 = this.values[2], a03 = this.values[3],
a10 = this.values[4], a11 = this.values[5], a12 = this.values[6], a13 = this.values[7],
a20 = this.values[8], a21 = this.values[9], a22 = this.values[10], a23 = this.values[11];
let b00 = x * x * t + c, b01 = y * x * t + z * s, b02 = z * x * t - y * s,
b10 = x * y * t - z * s, b11 = y * y * t + c, b12 = z * y * t + x * s,
b20 = x * z * t + y * s, b21 = y * z * t - x * s, b22 = z * z * t + c;
this.values[0] = a00 * b00 + a10 * b01 + a20 * b02;
this.values[1] = a01 * b00 + a11 * b01 + a21 * b02;
this.values[2] = a02 * b00 + a12 * b01 + a22 * b02;
this.values[3] = a03 * b00 + a13 * b01 + a23 * b02;
this.values[4] = a00 * b10 + a10 * b11 + a20 * b12;
this.values[5] = a01 * b10 + a11 * b11 + a21 * b12;
this.values[6] = a02 * b10 + a12 * b11 + a22 * b12;
this.values[7] = a03 * b10 + a13 * b11 + a23 * b12;
this.values[8] = a00 * b20 + a10 * b21 + a20 * b22;
this.values[9] = a01 * b20 + a11 * b21 + a21 * b22;
this.values[10] = a02 * b20 + a12 * b21 + a22 * b22;
this.values[11] = a03 * b20 + a13 * b21 + a23 * b22;
return this;
}
/**
*
* @param left
* @param right
* @param bottom
* @param top
* @param near
* @param far
* @returns
*/
public static frustum(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4 {
let rl = (right - left),
tb = (top - bottom),
fn = (far - near);
return new mat4([
(near * 2) / rl,
0,
0,
0,
0,
(near * 2) / tb,
0,
0,
(right + left) / rl,
(top + bottom) / tb,
-(far + near) / fn,
-1,
0,
0,
-(far * near * 2) / fn,
0
]);
}
/**
*
* @param fov
* @param aspect
* @param near
* @param far
* @returns
*/
public static perspective(fov: number, aspect: number, near: number, far: number): mat4 {
let top = near * Math.tan(fov * 0.5),
right = top * aspect;
return mat4.frustum(-right, right, -top, top, near, far);
}
/**
*
* @param left
* @param right
* @param bottom
* @param top
* @param near
* @param far
* @returns
*/
public static orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4 {
let rl = (right - left),
tb = (top - bottom),
fn = (far - near);
return new mat4([
2 / rl,
0,
0,
0,
0,
2 / tb,
0,
0,
0,
0,
-2 / fn,
0,
-(left + right) / rl,
-(top + bottom) / tb,
-(far + near) / fn,
1
]);
}
/**
*
* @param position
* @param target
* @param up
* @returns
*/
public static lookAt(position: vec3, target: vec3, up: vec3 = vec3.up): mat4 {
if (position.equals(target)) {
return this.identity;
}
let z = vec3.difference(position, target).normalize();
let x = vec3.cross(up, z).normalize();
let y = vec3.cross(z, x).normalize();
return new mat4([
x.x,
y.x,
z.x,
0,
x.y,
y.y,
z.y,
0,
x.z,
y.z,
z.z,
0,
-vec3.dot(x, position),
-vec3.dot(y, position),
-vec3.dot(z, position),
1
]);
}
/**
* mvp矩阵的
* @param m1
* @param m2
* @param result
* @returns
*/
public static product(m1: mat4, m2: mat4, result: mat4 | null = null): mat4 {
let a00 = m1.at(0), a01 = m1.at(1), a02 = m1.at(2), a03 = m1.at(3),
a10 = m1.at(4), a11 = m1.at(5), a12 = m1.at(6), a13 = m1.at(7),
a20 = m1.at(8), a21 = m1.at(9), a22 = m1.at(10), a23 = m1.at(11),
a30 = m1.at(12), a31 = m1.at(13), a32 = m1.at(14), a33 = m1.at(15);
let b00 = m2.at(0), b01 = m2.at(1), b02 = m2.at(2), b03 = m2.at(3),
b10 = m2.at(4), b11 = m2.at(5), b12 = m2.at(6), b13 = m2.at(7),
b20 = m2.at(8), b21 = m2.at(9), b22 = m2.at(10), b23 = m2.at(11),
b30 = m2.at(12), b31 = m2.at(13), b32 = m2.at(14), b33 = m2.at(15);
if (result) {
result.set([
b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33
]);
return result;
}
else {
return new mat4([
b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33
]);
}
}
}

470
src/renderi/math/Quat.ts

@ -0,0 +1,470 @@
import { EPSILON } from "../commons/types";
import { vec3, vec4, mat4 } from ".";
export class quat {
public values = new Float32Array(4);
static identity = new quat().setIdentity();
static q0 = new quat();
static q1 = new quat();
static q2 = new quat();
public get x(): number {
return this.values[0];
}
public get y(): number {
return this.values[1];
}
public get z(): number {
return this.values[2];
}
public get w(): number {
return this.values[3];
}
public set x(value: number) {
this.values[0] = value;
}
public set y(value: number) {
this.values[1] = value;
}
public set z(value: number) {
this.values[2] = value;
}
public set w(value: number) {
this.values[3] = value;
}
public constructor() {
this.setIdentity();
}
/**
*
* @returns
*/
public setIdentity(): quat {
this.x = 0;
this.y = 0;
this.z = 0;
this.w = 1;
return this;
}
public at(index: number): number {
return this.values[index];
}
/**
*
*/
public reset(): void {
for (let i = 0; i < 4; i++) {
this.values[i] = 0;
}
}
public copy(dest: quat | null = null): quat {
if (!dest) dest = new quat();
for (let i = 0; i < 4; i++) {
dest.values[i] = this.values[i];
}
return dest;
}
public roll(): number {
let x = this.x,
y = this.y,
z = this.z,
w = this.w;
return Math.atan2(2.0 * (x * y + w * z), w * w + x * x - y * y - z * z);
}
public pitch(): number {
let x = this.x,
y = this.y,
z = this.z,
w = this.w;
return Math.atan2(2.0 * (y * z + w * x), w * w - x * x - y * y + z * z);
}
public yaw(): number {
return Math.asin(2.0 * (this.x * this.z - this.w * this.y));
}
/**
*
* @param vector
* @param threshold
* @returns
*/
public equals(vector: quat, threshold = EPSILON): boolean {
for (let i = 0; i < 4; i++) {
if (Math.abs(this.values[i] - vector.at(i)) > threshold)
return false;
}
return true;
}
/**
* W
* @returns
*/
public calculateW(): quat {
let x = this.x,
y = this.y,
z = this.z;
this.w = -(Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)));
return this;
}
/**
*
* @param q1
* @param q2
* @returns
*/
public static dot(q1: quat, q2: quat): number {
return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
}
/**
*
* @returns
*/
public inverse(): quat {
let dot = quat.dot(this, this);
if (!dot) {
this.setIdentity();
return this;
}
let invDot = dot ? 1.0 / dot : 0;
this.x *= -invDot;
this.y *= -invDot;
this.z *= -invDot;
this.w *= invDot;
return this;
}
public conjugate(): quat {
this.values[0] *= -1;
this.values[1] *= -1;
this.values[2] *= -1;
return this;
}
/**
*
* @returns
*/
public length(): number {
let x = this.x,
y = this.y,
z = this.z,
w = this.w;
return Math.sqrt(x * x + y * y + z * z + w * w);
}
public normalize(dest: quat | null = null): quat {
if (!dest) dest = this;
let x = this.x,
y = this.y,
z = this.z,
w = this.w;
let length = Math.sqrt(x * x + y * y + z * z + w * w);
if (!length) {
dest.x = 0;
dest.y = 0;
dest.z = 0;
dest.w = 0;
return dest;
}
length = 1 / length;
dest.x = x * length;
dest.y = y * length;
dest.z = z * length;
dest.w = w * length;
return dest;
}
public add(other: quat): quat {
for (let i = 0; i < 4; i++) {
this.values[i] += other.at(i);
}
return this;
}
// 这个是左到右结合 this.cross.other
public multiply(other: quat): quat {
let q1x = this.values[0],
q1y = this.values[1],
q1z = this.values[2],
q1w = this.values[3];
let q2x = other.x,
q2y = other.y,
q2z = other.z,
q2w = other.w;
this.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y;
this.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z;
this.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x;
this.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z;
return this;
}
/**
*
* @param vector
* @param dest
* @returns
*/
public multiplyVec3(vector: vec3, dest: vec3 | null = null): vec3 {
if (!dest) dest = new vec3();
let x = vector.x,
y = vector.y,
z = vector.z;
let qx = this.x,
qy = this.y,
qz = this.z,
qw = this.w;
//
let ix = qw * x + qy * z - qz * y,
iy = qw * y + qz * x - qx * z,
iz = qw * z + qx * y - qy * x,
iw = -qx * x - qy * y - qz * z;
dest.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
dest.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
dest.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
return dest;
}
public toMat4(dest: mat4 | null = null): mat4 {
if (!dest) dest = new mat4();
let x = this.x,
y = this.y,
z = this.z,
w = this.w,
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
xy = x * y2,
xz = x * z2,
yy = y * y2,
yz = y * z2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2;
dest.set([
1 - (yy + zz),
xy + wz,
xz - wy,
0,
(xy - wz),
(1 - (xx + zz)),
(yz + wx),
0,
xz + wy,
yz - wx,
1 - (xx + yy),
0,
0,
0,
0,
1
]);
return dest;
}
public static sum(q1: quat, q2: quat, dest: quat | null = null): quat {
if (!dest) dest = new quat();
dest.x = q1.x + q2.x;
dest.y = q1.y + q2.y;
dest.z = q1.z + q2.z;
dest.w = q1.w + q2.w;
return dest;
}
public static product(q1: quat, q2: quat, dest: quat | null = null): quat {
if (!dest) dest = new quat();
let q1x = q1.x,
q1y = q1.y,
q1z = q1.z,
q1w = q1.w,
q2x = q2.x,
q2y = q2.y,
q2z = q2.z,
q2w = q2.w;
dest.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y;
dest.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z;
dest.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x;
dest.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z;
return dest;
}
public static cross(q1: quat, q2: quat, dest: quat | null = null): quat {
if (!dest) dest = new quat();
let q1x = q1.x,
q1y = q1.y,
q1z = q1.z,
q1w = q1.w,
q2x = q2.x,
q2y = q2.y,
q2z = q2.z,
q2w = q2.w;
dest.x = q1w * q2z + q1z * q2w + q1x * q2y - q1y * q2x;
dest.y = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z;
dest.z = q1w * q2x + q1x * q2w + q1y * q2z - q1z * q2y;
dest.w = q1w * q2y + q1y * q2w + q1z * q2x - q1x * q2z;
return dest;
}
public static shortMix(q1: quat, q2: quat, time: number, dest: quat | null = null): quat {
if (!dest) dest = new quat();
if (time <= 0.0) {
q1.copy(q1);
return dest;
} else if (time >= 1.0) {
q2.copy(dest);
return dest;
}
let cos = quat.dot(q1, q2),
q2a = q2.copy();
if (cos < 0.0) {
q2a.inverse();
cos = -cos;
}
let k0: number,
k1: number;
if (cos > 0.9999) {
k0 = 1 - time;
k1 = 0 + time;
}
else {
let sin: number = Math.sqrt(1 - cos * cos);
let angle: number = Math.atan2(sin, cos);
let oneOverSin: number = 1 / sin;
k0 = Math.sin((1 - time) * angle) * oneOverSin;
k1 = Math.sin((0 + time) * angle) * oneOverSin;
}
dest.x = k0 * q1.x + k1 * q2a.x;
dest.y = k0 * q1.y + k1 * q2a.y;
dest.z = k0 * q1.z + k1 * q2a.z;
dest.w = k0 * q1.w + k1 * q2a.w;
return dest;
}
public static mix(q1: quat, q2: quat, time: number, dest: quat | null = null): quat {
if (!dest) dest = new quat();
let cosHalfTheta = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
if (Math.abs(cosHalfTheta) >= 1.0) {
q1.copy(dest);
return dest;
}
let halfTheta = Math.acos(cosHalfTheta),
sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta);
if (Math.abs(sinHalfTheta) < 0.001) {
dest.x = q1.x * 0.5 + q2.x * 0.5;
dest.y = q1.y * 0.5 + q2.y * 0.5;
dest.z = q1.z * 0.5 + q2.z * 0.5;
dest.w = q1.w * 0.5 + q2.w * 0.5;
return dest;
}
let ratioA = Math.sin((1 - time) * halfTheta) / sinHalfTheta,
ratioB = Math.sin(time * halfTheta) / sinHalfTheta;
dest.x = q1.x * ratioA + q2.x * ratioB;
dest.y = q1.y * ratioA + q2.y * ratioB;
dest.z = q1.z * ratioA + q2.z * ratioB;
dest.w = q1.w * ratioA + q2.w * ratioB;
return dest;
}
static fromAxis(axis: vec3, angle: number, dest: quat | null = null): quat {
if (!dest) dest = new quat();
angle *= 0.5;
let sin = Math.sin(angle);
dest.x = axis.x * sin;
dest.y = axis.y * sin;
dest.z = axis.z * sin;
dest.w = Math.cos(angle);
return dest;
}
}

42
src/renderi/math/Vec2.ts

@ -0,0 +1,42 @@
/**
*
*/
export class vec2 {
/**
* @var
*/
public values = new Float32Array(2);
public get x(): number {
return this.values[0];
}
public get y(): number {
return this.values[1];
}
public set x(value: number) {
this.values[0] = value;
}
public set y(value: number) {
this.values[1] = value;
}
public constructor(values: number[] | null = null) {
if (values) {
this.x = values[0];
this.y = values[1];
} else {
this.x = this.y = 0;
}
}
copy(dest: vec2 | null = null): vec2 {
if (!dest) dest = new vec2();
dest.x = this.x;
dest.y = this.y;
return dest;
}
}

303
src/renderi/math/Vec3.ts

@ -0,0 +1,303 @@
import { EPSILON } from "../commons/types";
export class vec3 {
/**
* @var
*/
public values = new Float32Array(3);
public get x(): number {
return this.values[0];
}
public get y(): number {
return this.values[1];
}
public get z(): number {
return this.values[2];
}
public set x(value: number) {
this.values[0] = value;
}
public set y(value: number) {
this.values[1] = value;
}
public set z(value: number) {
this.values[2] = value;
}
public constructor(values: number[] | null = null) {
if (values !== null) {
this.x = values[0];
this.y = values[1];
this.z = values[2];
} else {
this.x = this.y = this.z = 0;
}
}
public at(index: number): number {
return this.values[index];
}
public reset(x: number = 0, y: number = 0, z: number = 0): void {
this.x = x;
this.y = y;
this.z = z;
}
public copy(dest: vec3 | null = null): vec3 {
if (!dest) dest = new vec3();
dest.x = this.x;
dest.y = this.y;
dest.z = this.z;
return dest;
}
/**
*
* @param dest
* @returns
*/
public negate(dest: vec3 | null = null): vec3 {
if (!dest) dest = this;
dest.x = -this.x;
dest.y = -this.y;
dest.z = -this.z;
return dest;
}
/**
*
* @param vector
* @param threshold
* @returns
*/
public equals(vector: vec3, threshold = EPSILON): boolean {
if (Math.abs(this.x - vector.x) > threshold)
return false;
if (Math.abs(this.y - vector.y) > threshold)
return false;
if (Math.abs(this.z - vector.z) > threshold)
return false;
return true;
}
/**
*
*/
public get length(): number {
return Math.sqrt(this.length2);
}
/**
*
*/
public get length2(): number {
let x = this.x,
y = this.y,
z = this.z;
return (x * x + y * y + z * z);
}
/**
*
* @param vector
* @returns
*/
add(vector: vec3): vec3 {
this.x += vector.x;
this.y += vector.y;
this.z += vector.z;
return this;
}
/**
*
* @param vector
* @returns
*/
subtract(vector: vec3): vec3 {
this.x -= vector.x;
this.y -= vector.y;
this.z -= vector.z;
return this;
}
/**
*
* @param value
* @param dest
* @returns
*/
public scale(value: number, dest: vec3 | null = null): vec3 {
if (!dest) {
dest = this;
} else {
this.copy(dest);
}
dest.x *= value;
dest.y *= value;
dest.z *= value;
return dest;
}
/**
*
* @param dest
* @returns
*/
public normalize(dest: vec3 | null = null): vec3 {
if (!dest) {
dest = this;
}
let length = this.length;
if (length === 1) {
return this;
}
if (length === 0) {
dest.x = 0
dest.y = 0;
dest.z = 0;
return dest;
}
dest.x /= length;
dest.y /= length;
dest.z /= length;
return dest;
}
/**
*
* @returns
*/
public normalize2(): number {
let length = this.length;
this.x /= length;
this.y /= length;
this.z /= length;
return length;
}
public print(): void {
console.log("[ " +
this.x + " " +
this.y + " " +
this.z
+" ]");
}
/**
*
* @param vector
* @param value
* @param dest
* @returns
*/
public static multiplyScalar(vector: vec3, value: number, dest: vec3 | null = null): vec3 {
if (!dest) dest = new vec3();
dest.x *= value;
dest.y *= value;
dest.z *= value;
return dest;
}
/**
*
* @param vector
* @param vector2
* @param dest
* @returns
*/
public static cross(vector: vec3, vector2: vec3, dest: vec3 | null = null): vec3 {
if (!dest) dest = new vec3();
let x = vector.x,
y = vector.y,
z = vector.z;
let x2 = vector2.x,
y2 = vector2.y,
z2 = vector2.z;
dest.x = y * z2 - z * y2;
dest.y = z * x2 - x * z2;
dest.z = x * y2 - y * x2;
return dest;
}
/**
*
* @param vector
* @param vector2
* @returns
*/
public static dot(vector: vec3, vector2: vec3): number {
let x = vector.x,
y = vector.y,
z = vector.z;
let x2 = vector2.x,
y2 = vector2.y,
z2 = vector2.z;
return (x * x2 + y * y2 + z * z2);
}
public static sum(vector: vec3, vector2: vec3, dest: vec3 | null = null): vec3 {
if (!dest) dest = new vec3();
dest.x = vector.x + vector2.x;
dest.y = vector.y + vector2.y;
dest.z = vector.z + vector2.z;
return dest;
}
public static difference(vector: vec3, vector2: vec3, dest: vec3 | null = null): vec3 {
if (!dest) dest = new vec3();
dest.x = vector.x - vector2.x;
dest.y = vector.y - vector2.y;
dest.z = vector.z - vector2.z;
return dest;
}
static readonly up = new vec3([0, 1, 0]);
static readonly down = new vec3([0, -1, 0]);
static readonly right = new vec3([1, 0, 0]);
static readonly left = new vec3([-1, 0, 0]);
static readonly forward = new vec3([0, 0, 1]);
static readonly backward = new vec3([0, 0, -1]);
static readonly zero = new vec3([0, 0, 0]);
static v0 = new vec3([0, 0, 0]);
static v1 = new vec3([0, 0, 0]);
static v2 = new vec3([0, 0, 0]);
}

136
src/renderi/math/Vec4.ts

@ -0,0 +1,136 @@
import { EPSILON } from "../commons/types";
import { vec3 } from "./Vec3";
export class vec4 {
public values = new Float32Array(4);
public get x(): number {
return this.values[0];
}
public get y(): number {
return this.values[1];
}
public get z(): number {
return this.values[2];
}
public get w(): number {
return this.values[3];
}
public set x(value: number) {
this.values[0] = value;
}
public set y(value: number) {
this.values[1] = value;
}
public set z(value: number) {
this.values[2] = value;
}
public set w(value: number) {
this.values[3] = value;
}
public get vec3(): vec3 {
return new vec3([this.x, this.y, this.z]);
}
/**
* RGBA
*/
public get r(): number {
return this.values[0];
}
public get g(): number {
return this.values[1];
}
public get b(): number {
return this.values[2];
}
public get a(): number {
return this.values[3];
}
public set r(value: number) {
this.values[0] = value;
}
public set g(value: number) {
this.values[1] = value;
}
public set b(value: number) {
this.values[2] = value;
}
public set a(value: number) {
this.values[3] = value;
}
public constructor(values: number[] | null = null) {
if (values) {
this.x = values[0];
this.y = values[1];
this.z = values[2];
this.w = values[3];
} else {
this.x = this.y = this.z = this.w = 0.0;
}
}
public at(index: number): number {
return this.values[index];
}
public reset(): void {
this.x = 0;
this.y = 0;
this.z = 0;
this.w = 0;
}
public copy(dest: vec4 | null = null): vec4 {
if (!dest) dest = new vec4();
dest.x = this.x;
dest.y = this.y;
dest.z = this.z;
dest.w = this.w;
return dest;
}
public equals(vector: vec4, threshold = EPSILON): boolean {
if (Math.abs(this.x - vector.x) > threshold)
return false;
if (Math.abs(this.y - vector.y) > threshold)
return false;
if (Math.abs(this.z - vector.z) > threshold)
return false;
if (Math.abs(this.w - vector.w) > threshold)
return false;
return true;
}
static red: vec4 = new vec4([1.0, 0.0, 0.0, 1.0]);
static green: vec4 = new vec4([0.0, 1.0, 0.0, 1.0]);
static blue: vec4 = new vec4([0.0, 0.0, 1.0, 1.0]);
static black: vec4 = new vec4([0, 0, 0, 0]);
static v0: vec4 = new vec4();
static v1: vec4 = new vec4();
static v2: vec4 = new vec4();
}

6
src/renderi/math/index.ts

@ -0,0 +1,6 @@
export * from './Vec2';
export * from './Vec3';
export * from './Vec4';
export * from './Mat4';
export * from './Quat';
export * from '../commons/Util';

24
src/renderi/webgl/GLApplication.ts

@ -0,0 +1,24 @@
import { Application } from "../core/Application";
export class GLApplication extends Application {
/**
* @var WebGL
*/
public gl: WebGLRenderingContext;
/**
* @var OpenGL1.1
*/
public matStack: GLWordMatrixStack;
/**
* @var OpenGL1.1
*/
public builder: GLMeshBuilder;
/**
* @var canvas
*/
protected canvas2D: HTMLCanvasElement | null = null;
protected ctx2D: CanvasRenderingContext2D | null = null;
}
Loading…
Cancel
Save