add 3d drawer
This commit is contained in:
parent
5092540715
commit
1e6314fcdd
@ -17,6 +17,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@parcel/transformer-glsl": "^2.0.0-rc.0",
|
||||||
"@types/react": "^17.0.27",
|
"@types/react": "^17.0.27",
|
||||||
"parcel": "^2.0.0-rc.0",
|
"parcel": "^2.0.0-rc.0",
|
||||||
"webgl-strict-types": "^1.0.5"
|
"webgl-strict-types": "^1.0.5"
|
||||||
|
44
src/app.ts
44
src/app.ts
@ -1,18 +1,53 @@
|
|||||||
import { Drawer2D } from "./drawer2D";
|
import { Drawer2D } from "./drawer2D";
|
||||||
|
import { Drawer3D } from "./drawer3D";
|
||||||
import { TriangleDrawer } from "./triangle_drawer";
|
import { TriangleDrawer } from "./triangle_drawer";
|
||||||
|
|
||||||
export class CanvasApp{
|
export class CanvasApp{
|
||||||
readonly gl: WebGL2RenderingContext;
|
readonly gl: WebGL2RenderingContext;
|
||||||
renderer: Drawer2D;
|
renderer: Drawer2D;
|
||||||
trenderer : TriangleDrawer;
|
trenderer : TriangleDrawer;
|
||||||
|
r : Drawer3D;
|
||||||
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);
|
||||||
}
|
}
|
||||||
intialize():boolean{
|
intialize():boolean{
|
||||||
this.renderer.prepare();
|
this.renderer.prepare();
|
||||||
this.trenderer.prepare(this.gl);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
startRun(){
|
startRun(){
|
||||||
@ -32,11 +67,10 @@ export class CanvasApp{
|
|||||||
}
|
}
|
||||||
drawScene(){
|
drawScene(){
|
||||||
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.clearColor(0,0,0,0);
|
//this.renderer.draw(this.gl,{});
|
||||||
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
//this.trenderer.draw(this.gl,{});
|
||||||
this.renderer.draw(this.gl,{});
|
this.r.draw(this.gl,{});
|
||||||
this.trenderer.draw(this.gl,{});
|
|
||||||
requestAnimationFrame(this.drawScene.bind(this));
|
requestAnimationFrame(this.drawScene.bind(this));
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -3,12 +3,20 @@ import {mat4, vec3, quat, mat3} from "gl-matrix";
|
|||||||
export class Camera{
|
export class Camera{
|
||||||
pos:vec3;
|
pos:vec3;
|
||||||
rot:quat;
|
rot:quat;
|
||||||
|
#proj : mat4;
|
||||||
|
fovY : number;
|
||||||
|
aspect : number;
|
||||||
|
far : number;
|
||||||
|
near: number;
|
||||||
constructor(pos:vec3,rot?:quat){
|
constructor(pos:vec3,rot?:quat){
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
|
this.#proj = mat4.create();
|
||||||
if(rot == undefined){
|
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);
|
const rotMat = mat3.fromMat4(mat3.create(),lookAt);
|
||||||
this.rot = quat.fromMat3(quat.create(), rotMat);
|
this.rot = quat.fromMat3(quat.create(), rotMat);
|
||||||
|
//quat.normalize(this.rot,this.rot);
|
||||||
|
//quat.conjugate(this.rot,this.rot);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
this.rot = rot;
|
this.rot = rot;
|
||||||
@ -18,14 +26,24 @@ export class Camera{
|
|||||||
quat.rotateY(this.rot,this.rot,rad);
|
quat.rotateY(this.rot,this.rot,rad);
|
||||||
}
|
}
|
||||||
rotateUp(rad:number){
|
rotateUp(rad:number){
|
||||||
quat.rotateX(this.rot,this.rot,rad);
|
|
||||||
}
|
|
||||||
rotateClockwise(rad:number){
|
|
||||||
quat.rotateZ(this.rot,this.rot,rad);
|
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);
|
const r = mat4.fromQuat(mat4.create(),this.rot);
|
||||||
mat4.translate(r,r,this.pos);
|
return mat4.mul(mat4.create(),r,t);
|
||||||
return r;
|
}
|
||||||
|
/**
|
||||||
|
* 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
|
#version 300 es
|
||||||
precision highp float;
|
precision highp float;
|
||||||
layout(location=0) out vec4 outColor;
|
layout(location=0) out vec4 outColor;
|
||||||
//in vec4 gl_FragCoord;
|
in vec3 fragNormal;
|
||||||
//in vec2 gl_PointCoord;
|
|
||||||
uniform vec4 u_color;
|
|
||||||
|
|
||||||
void main() {
|
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
|
#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() {
|
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