add 3d drawer
This commit is contained in:
		
							parent
							
								
									5092540715
								
							
						
					
					
						commit
						1e6314fcdd
					
				
					 7 changed files with 212 additions and 18 deletions
				
			
		| 
						 | 
				
			
			@ -17,6 +17,7 @@
 | 
			
		|||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@parcel/transformer-glsl": "^2.0.0-rc.0",
 | 
			
		||||
    "@types/react": "^17.0.27",
 | 
			
		||||
    "parcel": "^2.0.0-rc.0",
 | 
			
		||||
    "webgl-strict-types": "^1.0.5"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										44
									
								
								src/app.ts
									
										
									
									
									
								
							
							
						
						
									
										44
									
								
								src/app.ts
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,18 +1,53 @@
 | 
			
		|||
import { Drawer2D } from "./drawer2D";
 | 
			
		||||
import { Drawer3D } from "./drawer3D";
 | 
			
		||||
import { TriangleDrawer } from "./triangle_drawer";
 | 
			
		||||
 | 
			
		||||
export class CanvasApp{
 | 
			
		||||
    readonly gl: WebGL2RenderingContext;
 | 
			
		||||
    renderer: Drawer2D;
 | 
			
		||||
    trenderer : TriangleDrawer;
 | 
			
		||||
    r : Drawer3D;
 | 
			
		||||
    constructor(gl: WebGL2RenderingContext){
 | 
			
		||||
        this.gl = gl;
 | 
			
		||||
        this.renderer = new Drawer2D(gl);
 | 
			
		||||
        this.trenderer = new TriangleDrawer(gl);
 | 
			
		||||
        this.r = new Drawer3D(gl);
 | 
			
		||||
    }
 | 
			
		||||
    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;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.gl.clearColor(0,0,0,0);
 | 
			
		||||
        this.gl.clearDepth(1);
 | 
			
		||||
        this.gl.enable(this.gl.DEPTH_TEST);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    startRun(){
 | 
			
		||||
| 
						 | 
				
			
			@ -32,11 +67,10 @@ export class CanvasApp{
 | 
			
		|||
    }
 | 
			
		||||
    drawScene(){
 | 
			
		||||
        this.gl.viewport(0,0,this.gl.canvas.width,this.gl.canvas.height);
 | 
			
		||||
        
 | 
			
		||||
        this.gl.clearColor(0,0,0,0);
 | 
			
		||||
        this.gl.clear(this.gl.COLOR_BUFFER_BIT);
 | 
			
		||||
        this.renderer.draw(this.gl,{});
 | 
			
		||||
        this.trenderer.draw(this.gl,{});
 | 
			
		||||
        this.gl.clear(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT);
 | 
			
		||||
        //this.renderer.draw(this.gl,{});
 | 
			
		||||
        //this.trenderer.draw(this.gl,{});
 | 
			
		||||
        this.r.draw(this.gl,{});
 | 
			
		||||
        requestAnimationFrame(this.drawScene.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -3,12 +3,20 @@ import {mat4, vec3, quat, mat3} from "gl-matrix";
 | 
			
		|||
export class Camera{
 | 
			
		||||
    pos:vec3;
 | 
			
		||||
    rot:quat;
 | 
			
		||||
    #proj : mat4;
 | 
			
		||||
    fovY : number;
 | 
			
		||||
    aspect : number;
 | 
			
		||||
    far : number;
 | 
			
		||||
    near: number;
 | 
			
		||||
    constructor(pos:vec3,rot?:quat){
 | 
			
		||||
        this.pos = pos;
 | 
			
		||||
        this.#proj = mat4.create();
 | 
			
		||||
        if(rot == undefined){
 | 
			
		||||
            const lookAt = mat4.lookAt(mat4.create(),this.pos,[0,0,0],[0,0,1])
 | 
			
		||||
            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;
 | 
			
		||||
| 
						 | 
				
			
			@ -18,14 +26,24 @@ export class Camera{
 | 
			
		|||
        quat.rotateY(this.rot,this.rot,rad);
 | 
			
		||||
    }
 | 
			
		||||
    rotateUp(rad:number){
 | 
			
		||||
        quat.rotateX(this.rot,this.rot,rad);
 | 
			
		||||
    }
 | 
			
		||||
    rotateClockwise(rad:number){
 | 
			
		||||
        quat.rotateZ(this.rot,this.rot,rad);
 | 
			
		||||
    }
 | 
			
		||||
    getViewMat(){
 | 
			
		||||
    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);
 | 
			
		||||
        mat4.translate(r,r,this.pos);
 | 
			
		||||
        return r;
 | 
			
		||||
        return mat4.mul(mat4.create(),r,t);
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * update projection matrix
 | 
			
		||||
     */
 | 
			
		||||
    UpdateProjectionMat(){
 | 
			
		||||
        mat4.perspective(this.#proj,this.fovY,this.aspect,this.near,this.far);
 | 
			
		||||
    }
 | 
			
		||||
    get projectionMatrix():mat4{
 | 
			
		||||
        return this.#proj;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										60
									
								
								src/drawer3D.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/drawer3D.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,60 @@
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
/// <reference path="./glsl.d.ts" />
 | 
			
		||||
import vert_src from "./vertex.vert";
 | 
			
		||||
import frag_src from "./fragment.frag";
 | 
			
		||||
 | 
			
		||||
import {createProgramFromSource, ProgramError, ShaderError} from "./gl_util";
 | 
			
		||||
import { Camera } from "./camera";
 | 
			
		||||
import * as G from "./glWrapper";
 | 
			
		||||
import { Drawable, RenderState } from "./drawable";
 | 
			
		||||
import { Model } from "./model";
 | 
			
		||||
import { mat4 } from "gl-matrix";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export class Drawer3D implements Drawable{
 | 
			
		||||
    gl : WebGL2RenderingContext;
 | 
			
		||||
    program: G.GLProgram;
 | 
			
		||||
    camera : Camera;
 | 
			
		||||
    model: Model | undefined;
 | 
			
		||||
    constructor(gl: WebGL2RenderingContext){
 | 
			
		||||
        this.gl = gl;
 | 
			
		||||
        this.camera = new Camera([-20,1,-10]);
 | 
			
		||||
        this.camera.far = 1000;
 | 
			
		||||
        this.camera.near = 0.1;
 | 
			
		||||
        this.camera.fovY = Math.PI * 90 / 180;
 | 
			
		||||
        this.camera.aspect = 1;
 | 
			
		||||
        this.model = undefined;
 | 
			
		||||
        try{
 | 
			
		||||
            this.program = new G.GLProgram(createProgramFromSource(gl,vert_src,frag_src));
 | 
			
		||||
            const attr = this.program.getActiveAttributes(gl);
 | 
			
		||||
            console.log(attr);
 | 
			
		||||
        }
 | 
			
		||||
        catch(e){
 | 
			
		||||
            if(e instanceof ShaderError){
 | 
			
		||||
                console.log(e.info);
 | 
			
		||||
            }
 | 
			
		||||
            throw e;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    async init(){
 | 
			
		||||
        const gl = this.gl;
 | 
			
		||||
        const url = new URL("../assets/models/teapot/teapot.obj",import.meta.url);
 | 
			
		||||
        this.model = await Model.loadFromOBJ(gl,url.href);
 | 
			
		||||
        console.log("loading model complete");
 | 
			
		||||
        this.model.ready(gl,this.program);
 | 
			
		||||
    }
 | 
			
		||||
    draw(gl: WebGL2RenderingContext,state:RenderState): void {
 | 
			
		||||
        if(this.model !== undefined){
 | 
			
		||||
            this.camera.aspect = gl.canvas.width/gl.canvas.height;
 | 
			
		||||
            this.camera.UpdateProjectionMat();
 | 
			
		||||
            this.program.use(gl);
 | 
			
		||||
 | 
			
		||||
            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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,10 +1,11 @@
 | 
			
		|||
#version 300 es
 | 
			
		||||
precision highp float;
 | 
			
		||||
layout(location=0) out vec4 outColor;
 | 
			
		||||
//in vec4 gl_FragCoord;
 | 
			
		||||
//in vec2 gl_PointCoord;
 | 
			
		||||
uniform vec4 u_color;
 | 
			
		||||
in vec3 fragNormal;
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
  outColor = u_color;
 | 
			
		||||
  vec3 c = normalize(vec3(20,20,1));
 | 
			
		||||
  float intense = dot(c,normalize(fragNormal));
 | 
			
		||||
  intense = (max(intense,-0.5)+1.0)/2.0;
 | 
			
		||||
  outColor = vec4(vec3(1,1,0) * intense,1);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								src/model.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/model.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
import { createIndexBuffer, createVertexArray, createVertexBuffer, GLProgram, IndexBuffer, VertexArray, VertexBuffer } from "./glWrapper";
 | 
			
		||||
import {OBJ} from "webgl-obj-loader";
 | 
			
		||||
import { assertBoolean } from "./util";
 | 
			
		||||
 | 
			
		||||
type VertexType = "position" | "normal" | "textureUV";
 | 
			
		||||
 | 
			
		||||
type Vertexes = {[key in VertexType]:VertexBuffer};
 | 
			
		||||
 | 
			
		||||
export class Model{
 | 
			
		||||
    vertexes : Vertexes;
 | 
			
		||||
    ibo :IndexBuffer;
 | 
			
		||||
    vao :VertexArray;
 | 
			
		||||
    constructor(gl:WebGL2RenderingContext,vertex:Vertexes,index :IndexBuffer){
 | 
			
		||||
        this.vertexes = vertex;
 | 
			
		||||
        this.vao = createVertexArray(gl);
 | 
			
		||||
        this.ibo = index;
 | 
			
		||||
    }
 | 
			
		||||
    ready(gl:WebGL2RenderingContext,p : GLProgram){
 | 
			
		||||
        const VertexLayouts = {
 | 
			
		||||
            "position":{
 | 
			
		||||
                count:3,
 | 
			
		||||
                type:gl.FLOAT,
 | 
			
		||||
                normalize:false,
 | 
			
		||||
                stride:0,
 | 
			
		||||
                offset:0
 | 
			
		||||
            },
 | 
			
		||||
            "normal":{
 | 
			
		||||
                count:3,
 | 
			
		||||
                type:gl.FLOAT,
 | 
			
		||||
                normalize:false,
 | 
			
		||||
                stride:0,
 | 
			
		||||
                offset:0
 | 
			
		||||
            },
 | 
			
		||||
            "textureUV":{
 | 
			
		||||
                count:2,
 | 
			
		||||
                type:gl.FLOAT,
 | 
			
		||||
                normalize:false,
 | 
			
		||||
                stride:0,
 | 
			
		||||
                offset:0
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this.vao.bind(gl);
 | 
			
		||||
        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]);
 | 
			
		||||
        }
 | 
			
		||||
        this.ibo.bind(gl);
 | 
			
		||||
        this.vao.unbind(gl);
 | 
			
		||||
    }
 | 
			
		||||
    draw(gl:WebGL2RenderingContext){
 | 
			
		||||
        this.vao.bind(gl);
 | 
			
		||||
        gl.drawElements(gl.TRIANGLES,this.ibo.count,gl.UNSIGNED_SHORT,0);
 | 
			
		||||
        this.vao.unbind(gl);
 | 
			
		||||
    }
 | 
			
		||||
    static async loadFromOBJ(gl:WebGL2RenderingContext,src:RequestInfo,init?:RequestInit){
 | 
			
		||||
        const response = await fetch(src,init);
 | 
			
		||||
        const text = await response.text();
 | 
			
		||||
        const mesh = new OBJ.Mesh(text);
 | 
			
		||||
        const position = createVertexBuffer(gl,mesh.vertices);
 | 
			
		||||
        const normal = createVertexBuffer(gl,mesh.vertexNormals);
 | 
			
		||||
        const texture = createVertexBuffer(gl,mesh.textures);
 | 
			
		||||
        const index = createIndexBuffer(gl,mesh.indices);
 | 
			
		||||
        return new Model(gl,{
 | 
			
		||||
            position: position,
 | 
			
		||||
            normal: normal,
 | 
			
		||||
            textureUV: texture
 | 
			
		||||
        }, index);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,16 @@
 | 
			
		|||
#version 300 es
 | 
			
		||||
layout(location=0) in vec4 pos;
 | 
			
		||||
 | 
			
		||||
layout(location=0) in vec3 position;
 | 
			
		||||
layout(location=1) in vec2 textureUV;
 | 
			
		||||
layout(location=2) in vec3 normal;
 | 
			
		||||
 | 
			
		||||
uniform mat4 modelMat;
 | 
			
		||||
uniform mat4 viewMat;
 | 
			
		||||
uniform mat4 projectionMat;
 | 
			
		||||
 | 
			
		||||
out vec3 fragNormal;
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
  gl_Position = pos;
 | 
			
		||||
  gl_Position = projectionMat * viewMat * modelMat * vec4(position,1);
 | 
			
		||||
  fragNormal = mat3(transpose(inverse(modelMat))) * normal;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue