add texture

This commit is contained in:
monoid 2021-10-16 23:00:34 +09:00
parent cbbb67719e
commit 1202b4faad
6 changed files with 157 additions and 85 deletions

View File

@ -18,6 +18,7 @@
}, },
"devDependencies": { "devDependencies": {
"@parcel/transformer-glsl": "^2.0.0-rc.0", "@parcel/transformer-glsl": "^2.0.0-rc.0",
"@parcel/transformer-image": "^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"

View File

@ -70,6 +70,7 @@ export class CanvasApp{
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);
//this.gl.enable(this.gl.CULL_FACE);
return true; return true;
} }
handleInput(){ handleInput(){

View File

@ -16,7 +16,9 @@ export class Drawer3D implements Drawable{
gl : WebGL2RenderingContext; gl : WebGL2RenderingContext;
program: G.GLProgram; program: G.GLProgram;
camera : Camera; camera : Camera;
model: Model | undefined; teapot: Model | undefined;
cube: Model | undefined;
texture: G.Texture;
constructor(gl: WebGL2RenderingContext){ constructor(gl: WebGL2RenderingContext){
this.gl = gl; this.gl = gl;
this.camera = new Camera([-20,1,-10]); this.camera = new Camera([-20,1,-10]);
@ -24,7 +26,9 @@ export class Drawer3D implements Drawable{
this.camera.near = 0.1; this.camera.near = 0.1;
this.camera.fovY = Math.PI * 90 / 180; this.camera.fovY = Math.PI * 90 / 180;
this.camera.aspect = 1; this.camera.aspect = 1;
this.model = undefined; this.teapot = undefined;
this.cube = undefined;
this.texture = new G.Texture(gl);
try{ try{
this.program = new G.GLProgram(createProgramFromSource(gl,vert_src,frag_src)); this.program = new G.GLProgram(createProgramFromSource(gl,vert_src,frag_src));
const attr = this.program.getActiveAttributes(gl); const attr = this.program.getActiveAttributes(gl);
@ -39,24 +43,43 @@ export class Drawer3D implements Drawable{
} }
async init(){ async init(){
const gl = this.gl; const gl = this.gl;
const url = new URL("../assets/models/teapot/teapot.obj",import.meta.url); const teapot_url = new URL("../assets/models/teapot/teapot.obj",import.meta.url);
this.model = await Model.loadFromOBJ(gl,url.href); 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"); 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 { draw(gl: WebGL2RenderingContext,state:RenderState): void {
if(this.model !== undefined){ this.camera.aspect = gl.canvas.width/gl.canvas.height;
this.camera.aspect = gl.canvas.width/gl.canvas.height; this.camera.UpdateProjectionMat();
this.camera.UpdateProjectionMat(); this.program.use(gl);
this.program.use(gl); this.program.setUniformMat4f(gl,"viewMat",this.camera.viewMatrix);
this.program.setUniformMat4f(gl,"projectionMat",this.camera.projectionMatrix);
this.program.setUniformMat4f(gl,"viewMat",this.camera.viewMatrix); this.texture.bind(gl,0);
this.program.setUniformMat4f(gl,"projectionMat",this.camera.projectionMatrix); this.program.setUniform1i(gl,"mainTexture",0);
if(this.teapot !== undefined){
for(const pos of [[0,0,0],[0,0,25],[40,0,25]]){ 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.program.setUniformMat4f(gl,"modelMat",mat4.fromTranslation(mat4.create(), vec3.fromValues(pos[0],pos[1],pos[2]) ));
this.teapot.draw(gl);
this.model.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);
}
} }
} }

View File

@ -1,11 +1,18 @@
#version 300 es #version 300 es
precision highp float; precision highp float;
layout(location=0) out vec4 outColor; layout(location=0) out vec4 outColor;
uniform sampler2D mainTexture;
in vec3 fragNormal; in vec3 fragNormal;
in vec2 texUV;
void main() { 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)); float intense = dot(c,normalize(fragNormal));
intense = (max(intense,-0.5)+1.0)/2.0; 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);
} }

View File

@ -1,17 +1,17 @@
import { mat4, vec2, vec3, vec4 } from "gl-matrix"; import { mat4, vec2, vec3, vec4 } from "gl-matrix";
import * as util from "./gl_util"; import * as util from "./gl_util";
export class VertexBuffer{ export class VertexBuffer {
readonly id : WebGLBuffer; readonly id: WebGLBuffer;
constructor(id : WebGLBuffer){ constructor(id: WebGLBuffer) {
this.id = id; this.id = id;
} }
bind(gl:WebGL2RenderingContext){ bind(gl: WebGL2RenderingContext) {
gl.bindBuffer(gl.ARRAY_BUFFER,this.id); gl.bindBuffer(gl.ARRAY_BUFFER, this.id);
} }
unbind(gl:WebGL2RenderingContext){ unbind(gl: WebGL2RenderingContext) {
gl.bindBuffer(gl.ARRAY_BUFFER,null); gl.bindBuffer(gl.ARRAY_BUFFER, null);
} }
} }
@ -27,124 +27,161 @@ export class VertexBuffer{
* -0.5,-0.5]); * -0.5,-0.5]);
* ``` * ```
*/ */
export function createVertexBuffer(gl:WebGL2RenderingContext, data:number[]): VertexBuffer{ export function createVertexBuffer(gl: WebGL2RenderingContext, data: number[]): VertexBuffer {
const id = gl.createBuffer(); const id = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,id); gl.bindBuffer(gl.ARRAY_BUFFER, id);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data),gl.STATIC_DRAW); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
return new VertexBuffer(id); return new VertexBuffer(id);
} }
export class IndexBuffer{ export class IndexBuffer {
readonly id: WebGLBuffer; readonly id: WebGLBuffer;
readonly count:number; readonly count: number;
constructor(id: WebGLBuffer, count:number){ constructor(id: WebGLBuffer, count: number) {
this.id = id; this.id = id;
this.count = count; this.count = count;
} }
bind(gl:WebGL2RenderingContext){ bind(gl: WebGL2RenderingContext) {
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,this.id); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.id);
} }
unbind(gl:WebGL2RenderingContext){ unbind(gl: WebGL2RenderingContext) {
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,null); 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(); const id = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,id); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, id);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,new Uint16Array(data),gl.STATIC_DRAW); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(data), gl.STATIC_DRAW);
return new IndexBuffer(id,data.length); return new IndexBuffer(id, data.length);
} }
export class GLProgram{ export class GLProgram {
readonly program: WebGLProgram; readonly program: WebGLProgram;
#uniformLoc : Map<string,WebGLUniformLocation>; #uniformLoc: Map<string, WebGLUniformLocation>;
constructor(program: WebGLProgram){ constructor(program: WebGLProgram) {
this.program = program; this.program = program;
this.#uniformLoc = new Map<string,WebGLUniformLocation>(); this.#uniformLoc = new Map<string, WebGLUniformLocation>();
} }
getActiveUniforms(gl:WebGL2RenderingContext):WebGLActiveInfo[]{ getActiveUniforms(gl: WebGL2RenderingContext): WebGLActiveInfo[] {
const num = gl.getProgramParameter(this.program,gl.ACTIVE_UNIFORMS); const num = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS);
const info = [...new Array(num).keys()].map(i=>gl.getActiveUniform(this.program,i)); const info = [...new Array(num).keys()].map(i => gl.getActiveUniform(this.program, i));
return info; return info;
} }
getActiveAttributes(gl:WebGL2RenderingContext):WebGLActiveInfo[]{ getActiveAttributes(gl: WebGL2RenderingContext): WebGLActiveInfo[] {
const num = gl.getProgramParameter(this.program,gl.ACTIVE_ATTRIBUTES); const num = gl.getProgramParameter(this.program, gl.ACTIVE_ATTRIBUTES);
const info = [...new Array(num).keys()].map(i=>gl.getActiveAttrib(this.program,i)); const info = [...new Array(num).keys()].map(i => gl.getActiveAttrib(this.program, i));
return info; return info;
} }
getAttribLocation(gl:WebGL2RenderingContext,name:string):number{ getAttribLocation(gl: WebGL2RenderingContext, name: string): number {
return gl.getAttribLocation(this.program,name); return gl.getAttribLocation(this.program, name);
} }
getUniformLocation(gl:WebGL2RenderingContext,name:string):WebGLUniformLocation{ getUniformLocation(gl: WebGL2RenderingContext, name: string): WebGLUniformLocation {
if(this.#uniformLoc.has(name)){ if (this.#uniformLoc.has(name)) {
return this.#uniformLoc.get(name); return this.#uniformLoc.get(name);
} }
else{ else {
const location = gl.getUniformLocation(this.program,name); const location = gl.getUniformLocation(this.program, name);
this.#uniformLoc.set(name,location); this.#uniformLoc.set(name, location);
return location; return location;
} }
} }
use(gl:WebGL2RenderingContext):void{ use(gl: WebGL2RenderingContext): void {
gl.useProgram(this.program); gl.useProgram(this.program);
} }
setUniform1i(gl:WebGL2RenderingContext,name:string,v:number){ setUniform1i(gl: WebGL2RenderingContext, name: string, v: number) {
const loc = this.getUniformLocation(gl,name); const loc = this.getUniformLocation(gl, name);
gl.uniform1i(loc,v); gl.uniform1i(loc, v);
} }
setUniform1f(gl:WebGL2RenderingContext,name:string,v:number){ setUniform1f(gl: WebGL2RenderingContext, name: string, v: number) {
const loc = this.getUniformLocation(gl,name); const loc = this.getUniformLocation(gl, name);
gl.uniform1f(loc,v); gl.uniform1f(loc, v);
} }
setUniform2fv(gl:WebGL2RenderingContext,name:string,v:vec2){ setUniform2fv(gl: WebGL2RenderingContext, name: string, v: vec2) {
const loc = this.getUniformLocation(gl,name); const loc = this.getUniformLocation(gl, name);
gl.uniform2fv(loc,v); gl.uniform2fv(loc, v);
} }
setUniform3fv(gl:WebGL2RenderingContext,name:string,v:vec3){ setUniform3fv(gl: WebGL2RenderingContext, name: string, v: vec3) {
const loc = this.getUniformLocation(gl,name); const loc = this.getUniformLocation(gl, name);
gl.uniform3fv(loc,v); gl.uniform3fv(loc, v);
} }
setUniform4fv(gl:WebGL2RenderingContext,name:string,v:vec4){ setUniform4fv(gl: WebGL2RenderingContext, name: string, v: vec4) {
const loc = this.getUniformLocation(gl,name); const loc = this.getUniformLocation(gl, name);
gl.uniform4fv(loc,v); gl.uniform4fv(loc, v);
} }
setUniformMat4f(gl:WebGL2RenderingContext,name:string,v:mat4){ setUniformMat4f(gl: WebGL2RenderingContext, name: string, v: mat4) {
const loc = this.getUniformLocation(gl,name); const loc = this.getUniformLocation(gl, name);
gl.uniformMatrix4fv(loc,false,v); gl.uniformMatrix4fv(loc, false, v);
} }
unuse(gl:WebGL2RenderingContext):void{ unuse(gl: WebGL2RenderingContext): void {
gl.useProgram(null); gl.useProgram(null);
} }
} }
export class VertexArray{ export class VertexArray {
readonly vao:WebGLVertexArrayObject; readonly vao: WebGLVertexArrayObject;
constructor(vao:WebGLVertexArrayObject){ constructor(vao: WebGLVertexArrayObject) {
this.vao = vao; this.vao = vao;
} }
bind(gl:WebGL2RenderingContext){ bind(gl: WebGL2RenderingContext) {
gl.bindVertexArray(this.vao); gl.bindVertexArray(this.vao);
} }
unbind(gl:WebGL2RenderingContext){ unbind(gl: WebGL2RenderingContext) {
gl.bindVertexArray(null); gl.bindVertexArray(null);
} }
addBuffer(gl:WebGL2RenderingContext,va:VertexBuffer,loc:number,layout:{ addBuffer(gl: WebGL2RenderingContext, va: VertexBuffer, loc: number, layout: {
/**count of one element */ /**count of one element */
count: GLint, count: GLint,
type: GLenum, type: GLenum,
normalized: GLboolean, normalized: GLboolean,
stride: GLsizei, stride: GLsizei,
offset: GLintptr offset: GLintptr
}){ }) {
this.bind(gl); this.bind(gl);
va.bind(gl); va.bind(gl);
gl.enableVertexAttribArray(loc); 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()); 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;
}

View File

@ -9,8 +9,11 @@ uniform mat4 viewMat;
uniform mat4 projectionMat; uniform mat4 projectionMat;
out vec3 fragNormal; out vec3 fragNormal;
out vec2 texUV;
void main() { void main() {
gl_Position = projectionMat * viewMat * modelMat * vec4(position,1); gl_Position = projectionMat * viewMat * modelMat * vec4(position,1);
fragNormal = mat3(transpose(inverse(modelMat))) * normal; fragNormal = mat3(transpose(inverse(modelMat))) * normal;
texUV = textureUV;
} }