add texture
This commit is contained in:
parent
cbbb67719e
commit
1202b4faad
@ -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"
|
||||||
|
@ -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(){
|
||||||
|
@ -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,"viewMat",this.camera.viewMatrix);
|
||||||
this.program.setUniformMat4f(gl,"projectionMat",this.camera.projectionMatrix);
|
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]]){
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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);
|
||||||
}
|
}
|
171
src/glWrapper.ts
171
src/glWrapper.ts
@ -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;
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user