camera and moving
This commit is contained in:
parent
1e6314fcdd
commit
652e0d7c96
115
src/app.ts
115
src/app.ts
@ -1,71 +1,118 @@
|
|||||||
|
import { vec3 } from "gl-matrix";
|
||||||
import { Drawer2D } from "./drawer2D";
|
import { Drawer2D } from "./drawer2D";
|
||||||
import { Drawer3D } from "./drawer3D";
|
import { Drawer3D } from "./drawer3D";
|
||||||
import { TriangleDrawer } from "./triangle_drawer";
|
import { TriangleDrawer } from "./triangle_drawer";
|
||||||
|
|
||||||
|
class InputMap{
|
||||||
|
private pressedKey:Set<string>;
|
||||||
|
//private mouseLast : [number,number];
|
||||||
|
private mouseDelta : [number,number];
|
||||||
|
constructor(){
|
||||||
|
this.pressedKey = new Set<string>();
|
||||||
|
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{
|
export class CanvasApp{
|
||||||
readonly gl: WebGL2RenderingContext;
|
readonly gl: WebGL2RenderingContext;
|
||||||
|
private n : number;
|
||||||
renderer: Drawer2D;
|
renderer: Drawer2D;
|
||||||
trenderer : TriangleDrawer;
|
trenderer : TriangleDrawer;
|
||||||
r : Drawer3D;
|
r : Drawer3D;
|
||||||
|
inputMap: InputMap;
|
||||||
constructor(gl: WebGL2RenderingContext){
|
constructor(gl: WebGL2RenderingContext){
|
||||||
this.gl = gl;
|
this.gl = gl;
|
||||||
this.renderer = new Drawer2D(gl);
|
this.renderer = new Drawer2D(gl);
|
||||||
this.trenderer = new TriangleDrawer(gl);
|
this.trenderer = new TriangleDrawer(gl);
|
||||||
this.r = new Drawer3D(gl);
|
this.r = new Drawer3D(gl);
|
||||||
|
this.inputMap = new InputMap();
|
||||||
|
this.inputMap.registerHandler();
|
||||||
}
|
}
|
||||||
intialize():boolean{
|
intialize():boolean{
|
||||||
this.renderer.prepare();
|
this.renderer.prepare();
|
||||||
this.trenderer.prepare(this.gl);
|
this.trenderer.prepare(this.gl);
|
||||||
this.r.init();
|
this.r.init();
|
||||||
|
let escPressed = false;
|
||||||
document.addEventListener("keydown",(e)=>{
|
document.addEventListener("mousemove",(ev)=>{
|
||||||
if(e.key == "h"){
|
if(!escPressed){
|
||||||
this.r.camera.rotateRight(Math.PI * 5 / 180.0);
|
this.r.camera.rotateRight(Math.PI / 180.0 * ev.movementX);
|
||||||
}
|
this.r.camera.rotateUp(Math.PI / 180.0 * ev.movementY);
|
||||||
if(e.key == "f"){
|
}
|
||||||
this.r.camera.rotateRight(-Math.PI * 5 / 180.0)
|
});
|
||||||
}
|
document.addEventListener("keydown",(e)=>{
|
||||||
if(e.key == "t"){
|
if(e.key == "Escape"){
|
||||||
this.r.camera.rotateUp(Math.PI * 5 / 180.0)
|
escPressed = !escPressed;
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.gl.clearColor(0,0,0,0);
|
this.gl.clearColor(0,0,0,0);
|
||||||
this.gl.clearDepth(1);
|
this.gl.clearDepth(1);
|
||||||
this.gl.enable(this.gl.DEPTH_TEST);
|
this.gl.enable(this.gl.DEPTH_TEST);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
startRun(){
|
handleInput(){
|
||||||
const current = new Date();
|
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();
|
this.loop();
|
||||||
const delta = (new Date().getMilliseconds()) - current.getMilliseconds();
|
const afterLoop = getCurrentTime();
|
||||||
const delay = (delta < 16) ? (16 - delta) : 1;
|
const delta = afterLoop - beforeLoop - synctime;
|
||||||
|
const delay = (delta < MillisecondPerFrame) ? (MillisecondPerFrame - delta) : 0;
|
||||||
setTimeout((()=>{
|
setTimeout((()=>{
|
||||||
this.startRun();
|
const afterWait = getCurrentTime();
|
||||||
|
this.startRun(afterWait - afterLoop - delay);
|
||||||
}).bind(this),delay);
|
}).bind(this),delay);
|
||||||
}
|
}
|
||||||
loop(){
|
loop(){
|
||||||
|
this.handleInput();
|
||||||
}
|
}
|
||||||
startDraw(){
|
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.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.gl.clear(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT);
|
||||||
//this.renderer.draw(this.gl,{});
|
//this.renderer.draw(this.gl,{});
|
||||||
|
@ -2,40 +2,45 @@ import {mat4, vec3, quat, mat3} from "gl-matrix";
|
|||||||
|
|
||||||
export class Camera {
|
export class Camera {
|
||||||
pos: vec3;
|
pos: vec3;
|
||||||
rot:quat;
|
|
||||||
|
yaw: number;
|
||||||
|
pitch: number;
|
||||||
|
roll: number;
|
||||||
|
|
||||||
#proj: mat4;
|
#proj: mat4;
|
||||||
|
|
||||||
fovY: number;
|
fovY: number;
|
||||||
aspect: number;
|
aspect: number;
|
||||||
far: number;
|
far: number;
|
||||||
near: number;
|
near: number;
|
||||||
constructor(pos:vec3,rot?:quat){
|
constructor(pos: vec3) {
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
this.#proj = mat4.create();
|
this.#proj = mat4.create();
|
||||||
if(rot == undefined){
|
this.yaw = 0;
|
||||||
const lookAt = mat4.lookAt(mat4.create(),this.pos,[0,0,0],[0,1,0]);
|
this.pitch = 0;
|
||||||
const rotMat = mat3.fromMat4(mat3.create(),lookAt);
|
this.roll = 0;
|
||||||
this.rot = quat.fromMat3(quat.create(), rotMat);
|
console.log("forward" , this.forward);
|
||||||
//quat.normalize(this.rot,this.rot);
|
console.log("up" , this.up);
|
||||||
//quat.conjugate(this.rot,this.rot);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
this.rot = rot;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rotateRight(rad: number) {
|
rotateRight(rad: number) {
|
||||||
quat.rotateY(this.rot,this.rot,rad);
|
this.yaw += rad;
|
||||||
|
if(this.yaw >= Math.PI * 2 ){
|
||||||
|
this.yaw -= Math.PI * 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rotateUp(rad: number) {
|
rotateUp(rad: number) {
|
||||||
quat.rotateZ(this.rot,this.rot,rad);
|
this.pitch += rad;
|
||||||
|
this.pitch = Math.min(this.pitch, Math.PI * 89/ 180);
|
||||||
|
this.pitch = Math.max(this.pitch, - Math.PI * 89 / 180);
|
||||||
}
|
}
|
||||||
rotateClockwise(rad: number) {
|
rotateClockwise(rad: number) {
|
||||||
quat.rotateX(this.rot,this.rot,rad);
|
this.roll += rad;
|
||||||
}
|
}
|
||||||
get viewMatrix(): mat4 {
|
get viewMatrix(): mat4 {
|
||||||
const p = vec3.negate(vec3.create() ,this.pos);
|
const eye = vec3.create();
|
||||||
const t = mat4.fromTranslation(mat4.create(),p);
|
const lookAt = mat4.create();
|
||||||
const r = mat4.fromQuat(mat4.create(),this.rot);
|
vec3.add(eye, this.pos, this.forward);
|
||||||
return mat4.mul(mat4.create(),r,t);
|
return mat4.lookAt(lookAt, this.pos, eye, this.up);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* update projection matrix
|
* update projection matrix
|
||||||
@ -46,4 +51,32 @@ export class Camera{
|
|||||||
get projectionMatrix(): mat4 {
|
get projectionMatrix(): mat4 {
|
||||||
return this.#proj;
|
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]);;
|
||||||
|
}
|
||||||
};
|
};
|
@ -9,7 +9,7 @@ import { Camera } from "./camera";
|
|||||||
import * as G from "./glWrapper";
|
import * as G from "./glWrapper";
|
||||||
import { Drawable, RenderState } from "./drawable";
|
import { Drawable, RenderState } from "./drawable";
|
||||||
import { Model } from "./model";
|
import { Model } from "./model";
|
||||||
import { mat4 } from "gl-matrix";
|
import { mat4, vec3 } from "gl-matrix";
|
||||||
|
|
||||||
|
|
||||||
export class Drawer3D implements Drawable{
|
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,"viewMat",this.camera.viewMatrix);
|
||||||
this.program.setUniformMat4f(gl,"projectionMat",this.camera.projectionMatrix);
|
this.program.setUniformMat4f(gl,"projectionMat",this.camera.projectionMatrix);
|
||||||
this.program.setUniformMat4f(gl,"modelMat",mat4.fromTranslation(mat4.create(),[0,0,0]));
|
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);
|
this.model.draw(gl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
@ -43,8 +43,10 @@ export class Model{
|
|||||||
for(const [name,buf] of Object.entries(this.vertexes)){
|
for(const [name,buf] of Object.entries(this.vertexes)){
|
||||||
const loc = p.getAttribLocation(gl,name);
|
const loc = p.getAttribLocation(gl,name);
|
||||||
assertBoolean(loc >= 0,"there is no",name,"attribute");
|
assertBoolean(loc >= 0,"there is no",name,"attribute");
|
||||||
|
if(loc >= 0){
|
||||||
this.vao.addBuffer(gl,buf,loc,VertexLayouts[name]);
|
this.vao.addBuffer(gl,buf,loc,VertexLayouts[name]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this.ibo.bind(gl);
|
this.ibo.bind(gl);
|
||||||
this.vao.unbind(gl);
|
this.vao.unbind(gl);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user