diff --git a/src/app.ts b/src/app.ts index c2911e3..15be461 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,71 +1,118 @@ +import { vec3 } from "gl-matrix"; import { Drawer2D } from "./drawer2D"; import { Drawer3D } from "./drawer3D"; import { TriangleDrawer } from "./triangle_drawer"; +class InputMap{ + private pressedKey:Set; + //private mouseLast : [number,number]; + private mouseDelta : [number,number]; + constructor(){ + this.pressedKey = new Set(); + this.mouseDelta = [0,0]; + } + registerHandler(){ + const self = this; + document.addEventListener("keydown",(ev)=>{ + if(self.pressedKey.has(ev.key)){ + console.log(ev.key,"pressed"); + } + self.pressedKey.add(ev.key); + }); + document.addEventListener("keyup",(ev)=>{ + const exist = self.pressedKey.delete(ev.key); + if(exist){ + console.log(ev.key,"released"); + } + }); + } + isPressed(keyname:string){ + return this.pressedKey.has(keyname); + } +} + +/** get timestamp counter in millisecond*/ +function getCurrentTime() : number{ + return performance.now(); +} +const MillisecondPerFrame = 1000/60; export class CanvasApp{ readonly gl: WebGL2RenderingContext; + private n : number; renderer: Drawer2D; trenderer : TriangleDrawer; r : Drawer3D; + inputMap: InputMap; constructor(gl: WebGL2RenderingContext){ this.gl = gl; this.renderer = new Drawer2D(gl); this.trenderer = new TriangleDrawer(gl); this.r = new Drawer3D(gl); + this.inputMap = new InputMap(); + this.inputMap.registerHandler(); } intialize():boolean{ this.renderer.prepare(); this.trenderer.prepare(this.gl); this.r.init(); - - document.addEventListener("keydown",(e)=>{ - if(e.key == "h"){ - this.r.camera.rotateRight(Math.PI * 5 / 180.0); - } - if(e.key == "f"){ - this.r.camera.rotateRight(-Math.PI * 5 / 180.0) - } - if(e.key == "t"){ - this.r.camera.rotateUp(Math.PI * 5 / 180.0) - } - if(e.key == "g"){ - this.r.camera.rotateUp(-Math.PI * 5 / 180.0) - } - if(e.key == "d"){ - this.r.camera.pos[0] += 0.5; - } - if(e.key == "a"){ - this.r.camera.pos[0] -= 0.5; - } - if(e.key == "w"){ - this.r.camera.pos[2] += 0.5; - } - if(e.key == "s"){ - this.r.camera.pos[2] -= 0.5; + let escPressed = false; + document.addEventListener("mousemove",(ev)=>{ + if(!escPressed){ + this.r.camera.rotateRight(Math.PI / 180.0 * ev.movementX); + this.r.camera.rotateUp(Math.PI / 180.0 * ev.movementY); + } + }); + document.addEventListener("keydown",(e)=>{ + if(e.key == "Escape"){ + escPressed = !escPressed; } }); - this.gl.clearColor(0,0,0,0); this.gl.clearDepth(1); this.gl.enable(this.gl.DEPTH_TEST); return true; } - startRun(){ - const current = new Date(); + handleInput(){ + const Speed = 0.5; + let forward = this.r.camera.forward; + let right = this.r.camera.right; + vec3.scale(forward,forward,Speed); + vec3.scale(right,right,Speed); + if(this.inputMap.isPressed("d")){ + vec3.add(this.r.camera.pos,this.r.camera.pos,right); + } + if(this.inputMap.isPressed("a")){ + const r = vec3.create(); + vec3.negate(r,right); + vec3.add(this.r.camera.pos,this.r.camera.pos,r); + } + if(this.inputMap.isPressed("w")){ + vec3.add(this.r.camera.pos,this.r.camera.pos,forward); + } + if(this.inputMap.isPressed("s")){ + const f = vec3.create(); + vec3.negate(f,forward); + vec3.add(this.r.camera.pos,this.r.camera.pos,f); + } + } + startRun(synctime = 0){ + const beforeLoop = getCurrentTime(); this.loop(); - const delta = (new Date().getMilliseconds()) - current.getMilliseconds(); - const delay = (delta < 16) ? (16 - delta) : 1; + const afterLoop = getCurrentTime(); + const delta = afterLoop - beforeLoop - synctime; + const delay = (delta < MillisecondPerFrame) ? (MillisecondPerFrame - delta) : 0; setTimeout((()=>{ - this.startRun(); + const afterWait = getCurrentTime(); + this.startRun(afterWait - afterLoop - delay); }).bind(this),delay); } loop(){ - + this.handleInput(); } startDraw(){ - this.drawScene(); + this.drawScene(0); } - drawScene(){ + drawScene(time:DOMHighResTimeStamp){ this.gl.viewport(0,0,this.gl.canvas.width,this.gl.canvas.height); this.gl.clear(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT); //this.renderer.draw(this.gl,{}); diff --git a/src/camera.ts b/src/camera.ts index 53a6143..91fa242 100644 --- a/src/camera.ts +++ b/src/camera.ts @@ -1,49 +1,82 @@ -import {mat4, vec3, quat, mat3} from "gl-matrix"; +import { mat4, vec3, quat, mat3 } from "gl-matrix"; -export class Camera{ - pos:vec3; - rot:quat; - #proj : mat4; - fovY : number; - aspect : number; - far : number; +export class Camera { + pos: vec3; + + yaw: number; + pitch: number; + roll: number; + + #proj: mat4; + + fovY: number; + aspect: number; + far: number; near: number; - constructor(pos:vec3,rot?:quat){ + constructor(pos: vec3) { this.pos = pos; this.#proj = mat4.create(); - if(rot == undefined){ - const lookAt = mat4.lookAt(mat4.create(),this.pos,[0,0,0],[0,1,0]); - const rotMat = mat3.fromMat4(mat3.create(),lookAt); - this.rot = quat.fromMat3(quat.create(), rotMat); - //quat.normalize(this.rot,this.rot); - //quat.conjugate(this.rot,this.rot); - } - else{ - this.rot = rot; + this.yaw = 0; + this.pitch = 0; + this.roll = 0; + console.log("forward" , this.forward); + console.log("up" , this.up); + } + rotateRight(rad: number) { + this.yaw += rad; + if(this.yaw >= Math.PI * 2 ){ + this.yaw -= Math.PI * 2; } } - rotateRight(rad:number){ - quat.rotateY(this.rot,this.rot,rad); + rotateUp(rad: number) { + this.pitch += rad; + this.pitch = Math.min(this.pitch, Math.PI * 89/ 180); + this.pitch = Math.max(this.pitch, - Math.PI * 89 / 180); } - rotateUp(rad:number){ - quat.rotateZ(this.rot,this.rot,rad); + rotateClockwise(rad: number) { + this.roll += rad; } - rotateClockwise(rad:number){ - quat.rotateX(this.rot,this.rot,rad); - } - get viewMatrix():mat4{ - const p = vec3.negate(vec3.create() ,this.pos); - const t = mat4.fromTranslation(mat4.create(),p); - const r = mat4.fromQuat(mat4.create(),this.rot); - return mat4.mul(mat4.create(),r,t); + get viewMatrix(): mat4 { + const eye = vec3.create(); + const lookAt = mat4.create(); + vec3.add(eye, this.pos, this.forward); + return mat4.lookAt(lookAt, this.pos, eye, this.up); } /** * update projection matrix */ - UpdateProjectionMat(){ - mat4.perspective(this.#proj,this.fovY,this.aspect,this.near,this.far); + UpdateProjectionMat() { + mat4.perspective(this.#proj, this.fovY, this.aspect, this.near, this.far); } - get projectionMatrix():mat4{ + get projectionMatrix(): mat4 { return this.#proj; } + get forward(): vec3 { + const sinYaw = -Math.sin(this.yaw); + const cosYaw = Math.cos(this.yaw); + const ret = vec3.fromValues(sinYaw * Math.cos(this.pitch), -Math.sin(this.pitch), cosYaw * Math.cos(this.pitch)); + vec3.normalize(ret,ret); + return ret; + } + get up(): vec3 { + const right = vec3.cross(vec3.create(),this.forward,[0,1,0]); + vec3.normalize(right,right); + const ret = vec3.cross(vec3.create(),right,this.forward); + vec3.normalize(ret,ret); + /*const a = Math.sin(this.yaw); + const b = Math.cos(this.yaw); + const u = vec3.fromValues(b * Math.sin(this.pitch), Math.cos(this.pitch), a * Math.sin(this.pitch)); + const v = vec3.create(); + vec3.cross(v, u, this.forward); + const ret = vec3.create(); + const tmp1 = vec3.create(); + const tmp2 = vec3.create(); + vec3.add(ret, vec3.scale(tmp1, u, Math.cos(this.roll)), vec3.scale(tmp2, v, -Math.sin(this.roll)));*/ + return ret; + } + get right(): vec3 { + const ret = vec3.create(); + vec3.cross(ret, this.up, this.forward) + return vec3.cross(vec3.create(),this.forward,[0,1,0]);; + } }; \ No newline at end of file diff --git a/src/drawer3D.ts b/src/drawer3D.ts index ea0a487..321477b 100644 --- a/src/drawer3D.ts +++ b/src/drawer3D.ts @@ -9,7 +9,7 @@ import { Camera } from "./camera"; import * as G from "./glWrapper"; import { Drawable, RenderState } from "./drawable"; import { Model } from "./model"; -import { mat4 } from "gl-matrix"; +import { mat4, vec3 } from "gl-matrix"; export class Drawer3D implements Drawable{ @@ -52,9 +52,11 @@ export class Drawer3D implements Drawable{ this.program.setUniformMat4f(gl,"viewMat",this.camera.viewMatrix); this.program.setUniformMat4f(gl,"projectionMat",this.camera.projectionMatrix); - this.program.setUniformMat4f(gl,"modelMat",mat4.fromTranslation(mat4.create(),[0,0,0])); - - this.model.draw(gl); + for(const pos of [[0,0,0],[0,0,25],[40,0,25]]){ + this.program.setUniformMat4f(gl,"modelMat",mat4.fromTranslation(mat4.create(), vec3.fromValues(pos[0],pos[1],pos[2]) )); + + this.model.draw(gl); + } } } } \ No newline at end of file diff --git a/src/model.ts b/src/model.ts index c94a8e8..11f0fca 100644 --- a/src/model.ts +++ b/src/model.ts @@ -43,7 +43,9 @@ export class Model{ for(const [name,buf] of Object.entries(this.vertexes)){ const loc = p.getAttribLocation(gl,name); assertBoolean(loc >= 0,"there is no",name,"attribute"); - this.vao.addBuffer(gl,buf,loc,VertexLayouts[name]); + if(loc >= 0){ + this.vao.addBuffer(gl,buf,loc,VertexLayouts[name]); + } } this.ibo.bind(gl); this.vao.unbind(gl);