From 1202b4faad6a7a7866db284db4dec610573d7d22 Mon Sep 17 00:00:00 2001 From: monoid Date: Sat, 16 Oct 2021 23:00:34 +0900 Subject: [PATCH] add texture --- package.json | 1 + src/app.ts | 1 + src/drawer3D.ts | 51 ++++++++++---- src/fragment.frag | 11 ++- src/glWrapper.ts | 175 ++++++++++++++++++++++++++++------------------ src/vertex.vert | 3 + 6 files changed, 157 insertions(+), 85 deletions(-) diff --git a/package.json b/package.json index 3a4b514..7908ecb 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ }, "devDependencies": { "@parcel/transformer-glsl": "^2.0.0-rc.0", + "@parcel/transformer-image": "^2.0.0-rc.0", "@types/react": "^17.0.27", "parcel": "^2.0.0-rc.0", "webgl-strict-types": "^1.0.5" diff --git a/src/app.ts b/src/app.ts index 15be461..0fd4dd3 100644 --- a/src/app.ts +++ b/src/app.ts @@ -70,6 +70,7 @@ export class CanvasApp{ this.gl.clearColor(0,0,0,0); this.gl.clearDepth(1); this.gl.enable(this.gl.DEPTH_TEST); + //this.gl.enable(this.gl.CULL_FACE); return true; } handleInput(){ diff --git a/src/drawer3D.ts b/src/drawer3D.ts index 321477b..8dff96a 100644 --- a/src/drawer3D.ts +++ b/src/drawer3D.ts @@ -16,7 +16,9 @@ export class Drawer3D implements Drawable{ gl : WebGL2RenderingContext; program: G.GLProgram; camera : Camera; - model: Model | undefined; + teapot: Model | undefined; + cube: Model | undefined; + texture: G.Texture; constructor(gl: WebGL2RenderingContext){ this.gl = gl; this.camera = new Camera([-20,1,-10]); @@ -24,7 +26,9 @@ export class Drawer3D implements Drawable{ this.camera.near = 0.1; this.camera.fovY = Math.PI * 90 / 180; this.camera.aspect = 1; - this.model = undefined; + this.teapot = undefined; + this.cube = undefined; + this.texture = new G.Texture(gl); try{ this.program = new G.GLProgram(createProgramFromSource(gl,vert_src,frag_src)); const attr = this.program.getActiveAttributes(gl); @@ -39,24 +43,43 @@ export class Drawer3D implements Drawable{ } 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); + const teapot_url = new URL("../assets/models/teapot/teapot.obj",import.meta.url); + this.teapot = await Model.loadFromOBJ(gl,teapot_url.href); + const cube_url = new URL("../assets/models/cube/cube.obj",import.meta.url); + this.cube = await Model.loadFromOBJ(gl,cube_url.href); console.log("loading model complete"); - this.model.ready(gl,this.program); + this.teapot.ready(gl,this.program); + this.cube.ready(gl,this.program); + + this.texture; + const texture_url = new URL("../assets/uv-grid.png",import.meta.url); + const texture_image = G.makeImageElement(texture_url.href); + texture_image.onload = ()=>{ + this.texture.setImage(gl,texture_image); + } } 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.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.texture.bind(gl,0); + this.program.setUniform1i(gl,"mainTexture",0); + if(this.teapot !== undefined){ 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.teapot.draw(gl); } } + if(this.cube !== undefined){ + const modelMat = mat4.create(); + mat4.identity(modelMat); + mat4.translate(modelMat,modelMat,[45,0,0]); + mat4.scale(modelMat,modelMat,[5,5,5]); + //mat4.rotateX(modelMat,modelMat,Math.PI * 30 / 180); + this.program.setUniformMat4f(gl,"modelMat",modelMat); + this.cube.draw(gl); + } } } \ No newline at end of file diff --git a/src/fragment.frag b/src/fragment.frag index 5751df1..d289497 100644 --- a/src/fragment.frag +++ b/src/fragment.frag @@ -1,11 +1,18 @@ #version 300 es precision highp float; + layout(location=0) out vec4 outColor; + +uniform sampler2D mainTexture; + in vec3 fragNormal; +in vec2 texUV; void main() { - vec3 c = normalize(vec3(20,20,1)); + vec3 lightPos = vec3(20,20,1); + vec3 c = normalize(lightPos); float intense = dot(c,normalize(fragNormal)); intense = (max(intense,-0.5)+1.0)/2.0; - outColor = vec4(vec3(1,1,0) * intense,1); + vec4 objectColor = texture(mainTexture,texUV); + outColor = vec4(objectColor.xyz * intense,1); } \ No newline at end of file diff --git a/src/glWrapper.ts b/src/glWrapper.ts index a6723cc..c4a41db 100644 --- a/src/glWrapper.ts +++ b/src/glWrapper.ts @@ -1,17 +1,17 @@ import { mat4, vec2, vec3, vec4 } from "gl-matrix"; import * as util from "./gl_util"; -export class VertexBuffer{ - readonly id : WebGLBuffer; +export class VertexBuffer { + readonly id: WebGLBuffer; - constructor(id : WebGLBuffer){ + constructor(id: WebGLBuffer) { this.id = id; } - bind(gl:WebGL2RenderingContext){ - gl.bindBuffer(gl.ARRAY_BUFFER,this.id); + bind(gl: WebGL2RenderingContext) { + gl.bindBuffer(gl.ARRAY_BUFFER, this.id); } - unbind(gl:WebGL2RenderingContext){ - gl.bindBuffer(gl.ARRAY_BUFFER,null); + unbind(gl: WebGL2RenderingContext) { + gl.bindBuffer(gl.ARRAY_BUFFER, null); } } @@ -27,124 +27,161 @@ export class VertexBuffer{ * -0.5,-0.5]); * ``` */ -export function createVertexBuffer(gl:WebGL2RenderingContext, data:number[]): VertexBuffer{ +export function createVertexBuffer(gl: WebGL2RenderingContext, data: number[]): VertexBuffer { const id = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER,id); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data),gl.STATIC_DRAW); + gl.bindBuffer(gl.ARRAY_BUFFER, id); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW); return new VertexBuffer(id); } -export class IndexBuffer{ +export class IndexBuffer { readonly id: WebGLBuffer; - readonly count:number; - constructor(id: WebGLBuffer, count:number){ + readonly count: number; + constructor(id: WebGLBuffer, count: number) { this.id = id; this.count = count; } - bind(gl:WebGL2RenderingContext){ - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,this.id); + bind(gl: WebGL2RenderingContext) { + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.id); } - unbind(gl:WebGL2RenderingContext){ - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,null); + unbind(gl: WebGL2RenderingContext) { + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); } } -export function createIndexBuffer(gl:WebGL2RenderingContext, data:number[]){ +export function createIndexBuffer(gl: WebGL2RenderingContext, data: number[]) { const id = gl.createBuffer(); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,id); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,new Uint16Array(data),gl.STATIC_DRAW); - return new IndexBuffer(id,data.length); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, id); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(data), gl.STATIC_DRAW); + return new IndexBuffer(id, data.length); } -export class GLProgram{ +export class GLProgram { readonly program: WebGLProgram; - #uniformLoc : Map; - constructor(program: WebGLProgram){ + #uniformLoc: Map; + constructor(program: WebGLProgram) { this.program = program; - this.#uniformLoc = new Map(); + this.#uniformLoc = new Map(); } - getActiveUniforms(gl:WebGL2RenderingContext):WebGLActiveInfo[]{ - const num = gl.getProgramParameter(this.program,gl.ACTIVE_UNIFORMS); - const info = [...new Array(num).keys()].map(i=>gl.getActiveUniform(this.program,i)); + getActiveUniforms(gl: WebGL2RenderingContext): WebGLActiveInfo[] { + const num = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS); + const info = [...new Array(num).keys()].map(i => gl.getActiveUniform(this.program, i)); return info; } - getActiveAttributes(gl:WebGL2RenderingContext):WebGLActiveInfo[]{ - const num = gl.getProgramParameter(this.program,gl.ACTIVE_ATTRIBUTES); - const info = [...new Array(num).keys()].map(i=>gl.getActiveAttrib(this.program,i)); + getActiveAttributes(gl: WebGL2RenderingContext): WebGLActiveInfo[] { + const num = gl.getProgramParameter(this.program, gl.ACTIVE_ATTRIBUTES); + const info = [...new Array(num).keys()].map(i => gl.getActiveAttrib(this.program, i)); return info; } - getAttribLocation(gl:WebGL2RenderingContext,name:string):number{ - return gl.getAttribLocation(this.program,name); + getAttribLocation(gl: WebGL2RenderingContext, name: string): number { + return gl.getAttribLocation(this.program, name); } - getUniformLocation(gl:WebGL2RenderingContext,name:string):WebGLUniformLocation{ - if(this.#uniformLoc.has(name)){ + getUniformLocation(gl: WebGL2RenderingContext, name: string): WebGLUniformLocation { + if (this.#uniformLoc.has(name)) { return this.#uniformLoc.get(name); } - else{ - const location = gl.getUniformLocation(this.program,name); - this.#uniformLoc.set(name,location); + else { + const location = gl.getUniformLocation(this.program, name); + this.#uniformLoc.set(name, location); return location; } } - use(gl:WebGL2RenderingContext):void{ + use(gl: WebGL2RenderingContext): void { gl.useProgram(this.program); } - - setUniform1i(gl:WebGL2RenderingContext,name:string,v:number){ - const loc = this.getUniformLocation(gl,name); - gl.uniform1i(loc,v); + + setUniform1i(gl: WebGL2RenderingContext, name: string, v: number) { + const loc = this.getUniformLocation(gl, name); + gl.uniform1i(loc, v); } - setUniform1f(gl:WebGL2RenderingContext,name:string,v:number){ - const loc = this.getUniformLocation(gl,name); - gl.uniform1f(loc,v); + setUniform1f(gl: WebGL2RenderingContext, name: string, v: number) { + const loc = this.getUniformLocation(gl, name); + gl.uniform1f(loc, v); } - setUniform2fv(gl:WebGL2RenderingContext,name:string,v:vec2){ - const loc = this.getUniformLocation(gl,name); - gl.uniform2fv(loc,v); + setUniform2fv(gl: WebGL2RenderingContext, name: string, v: vec2) { + const loc = this.getUniformLocation(gl, name); + gl.uniform2fv(loc, v); } - setUniform3fv(gl:WebGL2RenderingContext,name:string,v:vec3){ - const loc = this.getUniformLocation(gl,name); - gl.uniform3fv(loc,v); + setUniform3fv(gl: WebGL2RenderingContext, name: string, v: vec3) { + const loc = this.getUniformLocation(gl, name); + gl.uniform3fv(loc, v); } - setUniform4fv(gl:WebGL2RenderingContext,name:string,v:vec4){ - const loc = this.getUniformLocation(gl,name); - gl.uniform4fv(loc,v); + setUniform4fv(gl: WebGL2RenderingContext, name: string, v: vec4) { + const loc = this.getUniformLocation(gl, name); + gl.uniform4fv(loc, v); } - setUniformMat4f(gl:WebGL2RenderingContext,name:string,v:mat4){ - const loc = this.getUniformLocation(gl,name); - gl.uniformMatrix4fv(loc,false,v); + setUniformMat4f(gl: WebGL2RenderingContext, name: string, v: mat4) { + const loc = this.getUniformLocation(gl, name); + gl.uniformMatrix4fv(loc, false, v); } - - unuse(gl:WebGL2RenderingContext):void{ + + unuse(gl: WebGL2RenderingContext): void { gl.useProgram(null); } } -export class VertexArray{ - readonly vao:WebGLVertexArrayObject; - constructor(vao:WebGLVertexArrayObject){ +export class VertexArray { + readonly vao: WebGLVertexArrayObject; + constructor(vao: WebGLVertexArrayObject) { this.vao = vao; } - bind(gl:WebGL2RenderingContext){ + bind(gl: WebGL2RenderingContext) { gl.bindVertexArray(this.vao); } - unbind(gl:WebGL2RenderingContext){ + unbind(gl: WebGL2RenderingContext) { gl.bindVertexArray(null); } - addBuffer(gl:WebGL2RenderingContext,va:VertexBuffer,loc:number,layout:{ + addBuffer(gl: WebGL2RenderingContext, va: VertexBuffer, loc: number, layout: { /**count of one element */ count: GLint, type: GLenum, normalized: GLboolean, stride: GLsizei, offset: GLintptr - }){ + }) { this.bind(gl); va.bind(gl); gl.enableVertexAttribArray(loc); - gl.vertexAttribPointer(loc,layout.count,layout.type,layout.normalized,layout.stride,layout.offset); + gl.vertexAttribPointer(loc, layout.count, layout.type, layout.normalized, layout.stride, layout.offset); } } -export function createVertexArray(gl:WebGL2RenderingContext){ +export function createVertexArray(gl: WebGL2RenderingContext) { return new VertexArray(gl.createVertexArray()); +} + +export class Texture { + readonly id: WebGLTexture; + constructor(gl: WebGL2RenderingContext) { + this.id = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.id); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + //1x1 texture를 생성합니다. + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 255, 255])); + gl.bindTexture(gl.TEXTURE_2D, null); + } + bind(gl: WebGL2RenderingContext, slot: number) { + gl.activeTexture(gl.TEXTURE0 + slot); + gl.bindTexture(gl.TEXTURE_2D, this.id); + } + + unbind(gl: WebGL2RenderingContext) { + gl.bindTexture(gl.TEXTURE_2D, null); + } + + setImage(gl: WebGL2RenderingContext, image: HTMLImageElement) { + gl.bindTexture(gl.TEXTURE_2D, this.id); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.generateMipmap(gl.TEXTURE_2D); + gl.bindTexture(gl.TEXTURE_2D, null); + } +} + +export function makeImageElement(url: string) { + const image = new Image(); + image.src = url; + image.crossOrigin = ""; + return image; } \ No newline at end of file diff --git a/src/vertex.vert b/src/vertex.vert index 64d4a0b..626b745 100644 --- a/src/vertex.vert +++ b/src/vertex.vert @@ -9,8 +9,11 @@ uniform mat4 viewMat; uniform mat4 projectionMat; out vec3 fragNormal; +out vec2 texUV; + void main() { gl_Position = projectionMat * viewMat * modelMat * vec4(position,1); fragNormal = mat3(transpose(inverse(modelMat))) * normal; + texUV = textureUV; } \ No newline at end of file