HetaJs

Phong Light

Your browser does not support the HTML5 canvas element.
- http://en.wikipedia.org/wiki/Phong_reflection_model
- http://mathinsight.org/dot_product
- webgl vertexAttribPointer 로검색.

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);

}