Vertax Shader
precision mediump float; attribute vec3 vertPosition; attribute vec2 vertTexCoord; //$$택스쳐 이미지 배열. attribute vec3 vertNormal; //phong uniform mat4 mWorld; uniform mat4 mView; //camera uniform mat4 mProj; varying vec2 fragTexCoord; varying vec3 fragNormal; void main() { fragTexCoord = vertTexCoord; fragNormal = (mWorld * vec4(vertNormal, 0.0)).xyz; //phong 모델 스페이스를 월드 스페이스로 변경.하려고 mWorld와 곱한다. //fragNormal = mWorld * vec4(vertNormal, 0.0).xyz * vec3(1.0,1.0,-1.0); //phong z를 역방향으로 해줄수 있음. gl_Position = mProj * mView * mWorld * vec4(vertPosition, 1.0); }
Fragment Shader
precision mediump float; struct DirectionalLight { vec3 direction; vec3 color; }; varying vec2 fragTexCoord; varying vec3 fragNormal; //phong uniform sampler2D sampler; //texture zero to texture size uniform vec3 ambientLightIntensity; uniform DirectionalLight sun; void main(){ //vec3 ambientLightIntensity = vec3(0.2, 0.2, 0.5); //phong 강렬 밤낮 //vec3 sunlightIntensity = vec3(0.9, 0.9, 0.9); //phong 태양광 강도 컬러 (저녁 낮) //vec3 sunlightDirection = normalize(vec3(1.0,4.0,-1.0)); //phong 방향 z가 -여야 앞에서 비춘다. vec3 surfaceNormal = normalize(fragNormal); //phong 택스쳐의 노멀. vec3 normSunDir = normalize(sun.direction); //phong 택스쳐의 노멀. vec4 texel = texture2D(sampler, fragTexCoord); //phong 택스쳐를 곱해야함. vec3 lightIntensity = ambientLightIntensity + sun.color * max(dot(fragNormal, normSunDir),0.0); gl_FragColor = vec4(texel.rgb * lightIntensity, texel.a); //phong //gl_FragColor = vec4(fragNormal, 1.0); //phong }
Script
var runWebGLApp = function(){ loadJSONResource('/models/Susan.json', function(modelErr, modelObj){ if(modelErr){ alert('Fatal Error getting Model (see console)'); console.error(modelErr); }else{ WebGLRenderApp(modelObj, '/models/SusanTexture.png'); } }); }; var gl; var program; var canvas; function WebGLRenderApp(modelObj,imgSource) { canvas = document.getElementById("canvas-element-id"); gl = canvas.getContext('webgl'); if(!gl){ console.log("WebGL not supported falling back on experimental-webgl"); gl = canvas.getContext('experimental-webgl'); } if(!gl){ alert("Your browser does not support WebGL"); } gl.clearColor(0.75, 0.85, 0.8, 1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.enable(gl.DEPTH_TEST); gl.enable(gl.CULL_FACE); gl.frontFace(gl.CCW); gl.cullFace(gl.BACK); var fragmentShader = getShader(gl, "shader-fs"); var vertexShader = getShader(gl, "shader-vs"); //program program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { console.log('There was a problem with the PROGRAM :\n\n'+ gl.getProgramInfoLog(program)); gl.deleteProgram(program); } gl.validateProgram(program); if (!gl.getProgramParameter(program, gl.VALIDATE_STATUS)) { console.error('Error validating program!', gl.getProgramInfoLog(program)); } gl.useProgram(program); //buffer // var triagleVertex = [ //X,Y,Z R,G,B // 0.0, 0.5, 0.0, 1.0,1.0,0.0, // -0.5, -0.5, 0.0, 0.7,0.0,1.0, // 0.5, -0.5, 0.0, 0.1,1.0,0.6 // ]; // 객체를 할당. var modelVertices = modelObj.meshes[0].vertices; var modelIndices = [].concat.apply([], modelObj.meshes[0].faces); //[[0,2,1],[0,2,3]] 이런식이라.. var modelTexCoords = modelObj.meshes[0].texturecoords[0]; var modelNormal = modelObj.meshes[0].normals; //$$$ light //===================== // pos버퍼 var modelPosBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, modelPosBuffer); //gl에 버퍼를 바인딩 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(modelVertices), gl.STATIC_DRAW); //버퍼에 버텍스 연결. //index버퍼 (나중에 그릴때 사용.) var modelIndexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, modelIndexBuffer); //gl에 버퍼를 바인딩 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(modelIndices), gl.STATIC_DRAW); //버퍼에 버텍스 연결. //texture 버퍼 var modelTextureBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, modelTextureBuffer); //gl에 버퍼를 바인딩 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(modelTexCoords), gl.STATIC_DRAW); //버퍼에 버텍스 연결. // normal 버퍼 var modelNormalBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, modelNormalBuffer); //gl에 버퍼를 바인딩 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(modelNormal), gl.STATIC_DRAW); //버퍼에 버텍스 연결. gl.bindBuffer(gl.ARRAY_BUFFER, modelPosBuffer); //gl에 버퍼를 바인딩 var positionLocation = gl.getAttribLocation(program,'vertPosition'); gl.vertexAttribPointer(positionLocation, 3, //Number of elements per attribute gl.FLOAT, //type of elements gl.FALSE, 3 * Float32Array.BYTES_PER_ELEMENT, //size of an individual vertex 5*4 //$$택스쳐 간격이 5 0 //offset from the beginning of a single vertext to this attribute ); gl.enableVertexAttribArray(positionLocation); //=================================== gl.bindBuffer(gl.ARRAY_BUFFER, modelTextureBuffer); //gl에 버퍼를 바인딩 var texCoordAttribLocation = gl.getAttribLocation(program,'vertTexCoord'); //$$택스쳐 gl.vertexAttribPointer(texCoordAttribLocation, 2, //Number of elements per attribute //$$택스쳐 gl.FLOAT, //type of elements gl.FALSE, 2 * Float32Array.BYTES_PER_ELEMENT, //size of an individual vertex 5*4 //$$택스쳐 5 0 //offset from the beginning of a single vertext to this attribute ); gl.enableVertexAttribArray(texCoordAttribLocation); //==================================== gl.bindBuffer(gl.ARRAY_BUFFER, modelNormalBuffer); //gl에 버퍼를 바인딩 var normalLocation = gl.getAttribLocation(program,'vertNormal'); gl.vertexAttribPointer(normalLocation, 3, //Number of elements per attribute gl.FLOAT, //type of elements gl.TRUE, //normal은 true 3 * Float32Array.BYTES_PER_ELEMENT, //size of an individual vertex 5*4 //$$택스쳐 간격이 5 0 //offset from the beginning of a single vertext to this attribute ); gl.enableVertexAttribArray(normalLocation); //==================================== //$$$ 텍스쳐 // https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texParameter //create Texture // 1. vertexBuffers carousel1.png var modelTexture = gl.createTexture(); // 이미지 로드 var image = new Image(); image.onload = function(){ console.log("image onload"); gl.bindTexture(gl.TEXTURE_2D, modelTexture); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,true); //webgl은 택스쳐 멥핑의 y가 역방향입니다. 이거로보정. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 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); // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); gl.bindTexture(gl.TEXTURE_2D, null); } image.src = imgSource; //============================== //uniform - useProgram이 선언되야 한다. var mWorldLocation = gl.getUniformLocation(program, 'mWorld'); var mViewLocation = gl.getUniformLocation(program, 'mView'); var mProjLocation = gl.getUniformLocation(program, 'mProj'); var worldMatrix = new Float32Array(16); var viewMatrix = new Float32Array(16); var projMatrix = new Float32Array(16); glMatrix.mat4.identity(worldMatrix); glMatrix.mat4.lookAt(viewMatrix,[0,0,-5],[0,0,0],[0,1,0]); //카메라. eye, center, up glMatrix.mat4.perspective(projMatrix, 45 * Math.PI / 180 ,canvas.width/canvas.height, 0.1, 1000.0); //projection fovy 45도 라디안, aspect:뷰포트 w/h 임 0.333, near:플러스트럼 영역 ,far 플러스트럼 영역 gl.uniformMatrix4fv(mWorldLocation, gl.FALSE, worldMatrix); //must be FALSE, gl.uniformMatrix4fv(mViewLocation, gl.FALSE, viewMatrix); //must be FALSE, gl.uniformMatrix4fv(mProjLocation, gl.FALSE, projMatrix); //must be FALSE, //=========================================== // lighting uniform - 유니폼 전에는 useProgram이 먼저와야한다. gl.useProgram(program); var ambientLightIntensityLocation = gl.getUniformLocation(program, 'ambientLightIntensity'); var sunlightIntensityLocation = gl.getUniformLocation(program, 'sun.color'); var sunlightDirectionLocation = gl.getUniformLocation(program, 'sun.direction'); gl.uniform3f(ambientLightIntensityLocation, 0.2, 0.2, 0.5); gl.uniform3f(sunlightIntensityLocation, 0.9, 0.9, 0.9); gl.uniform3f(sunlightDirectionLocation, 1.0,4.0,-1.0); //vec3 ambientLightIntensity = vec3(0.2, 0.2, 0.5); //phong 강렬 밤낮 //vec3 sunlightIntensity = vec3(0.9, 0.9, 0.9); //phong 태양광 강도 컬러 (저녁 낮) //vec3 sunlightDirection = normalize(vec3(1.0,4.0,-1.0)); //phong 방향 z가 -여야 앞에서 비춘다. //================================================== //회전 관련. 루프. var xRotateMat4= new Float32Array(16); var yRotateMat4= new Float32Array(16); //rotation 메트릭스. var identityMatrix = new Float32Array(16); glMatrix.mat4.identity(identityMatrix); var loop = function(){ //회전을 월드 메트릭스에 적용. var angle = performance.now() / 1000/ 6 * 2 * Math.PI; //12초동안 한바퀴 회전 glMatrix.mat4.rotate(yRotateMat4,identityMatrix, angle, [0,1,0]); //y축 glMatrix.mat4.rotate(xRotateMat4,identityMatrix, angle/4, [1,0,0]); //x축 glMatrix.mat4.mul(worldMatrix,xRotateMat4,yRotateMat4); gl.uniformMatrix4fv(mWorldLocation, gl.FALSE, worldMatrix); gl.clearColor(0.75, 0.85, 0.8, 1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); //$$$ 텍스쳐 gl.bindTexture(gl.TEXTURE_2D, modelTexture); gl.activeTexture(gl.TEXTURE0); //0,1 순서대로 들어간다. gl.drawElements(gl.TRIANGLES, modelIndices.length, gl.UNSIGNED_SHORT, 0); //처음엔 없어서 에러.. // gl.drawArrays(gl.TRIANGLES, 0, 3); //처음엔 없어서 에러.. requestAnimationFrame(loop); } requestAnimationFrame(loop); }