add 3d drawer
This commit is contained in:
parent
5092540715
commit
1e6314fcdd
@ -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…
Reference in New Issue
Block a user