1. κΈ°λ³Έ μ»¨μ ¶
OpenGLμμ μ λ§ μ€λ¬΄μμ μ°λ λΆλΆλ§ λ°λ‘ λΌμ΄λΈ OpenGL ES(Embeded System)μ Javascript ꡬν체μ΄λ©° HTML5 Canvasλ₯Ό ν΅ν΄ λνλλ€. λ°λΌμ μ΄λ³΄μκ° μ½κ² λ°°μ°λλ°μ μ΄μ μ΄ λ§μΆμ΄μ Έ μμ§ μκ³ μ€μ§ μ λ¬Έκ°κ° ꡬνμ νλλ°μ μ΄μ μ΄ λ§μΆμ΄μ Έ μλ€.
2. νΉμ§ ¶
Javascriptμμλ λΆκ΅¬νκ³ λ§μΉ Cνλ‘κ·Έλλ° μ€νμΌμ ν¨μλ€μ΄ μ‘΄μ¬νλ€. WinAPIκ° Cμ€νμΌμ OOPμ΄λ― WebGL λν Cμ€νμΌμ OOPμ΄λ€. λͺ¨λ ν¨μλ WebGLcontextλΌλ κ°μ²΄μ μλλ° λ³΄λ©΄ κ·Έλ₯ μ λμ΄λ₯Ό λΆμ΄λ λλμ΄λ€.
var gl = canvas.getContext("experimental-webgl");
gl.attachShader(shaderProgram, fragmentShader);
gl.attachShader(shaderProgram, vertexShader);
μμ μ½λλ₯Ό 보면 μμ΄λ νλ‘κ·Έλ¨μ fragmentShaderμ vertexShaderλ₯Ό Link μν€λ ꡬ문μΈλ° μ£Όμ²΄μΈ shaderProgramμ 첫λ²μ¨° μΈμμ΄κ³ glμ κ·Έλ₯ μ λμ΄ μ²λΌ 보μΈλ€. μ κ΅¬λ¬Έλ§ κ·Έλ°κ²μ΄ μλλΌ λ€λ₯Έ λͺ¨λ ν¨μλ€μ΄ μ gl κ°μ²΄μ λΆμ΄μλ€. νμ§λ§ μ μ glμ΄ μ£Όμ²΄κ° μλ κ²λ€μ΄ λ§λ€. λ°λΌμ λνν κ°μ²΄λ₯Ό λ§λ€μ΄ μ°λ κ²μ΄ μνΈνλ° μ΄μ€νκ² νλ€κ°λ λ¬΄μ² κΌ¬μ΄κ² λλ€. μ΄ κ΄μ΅μ OpenGLμ΄ κΈ°λ³Έμ μΌλ‘ CλΌμ΄λΈλ¬λ¦¬μ΄λΌ κ·Έλ°λ― νλ€. μ€μ λνμ μ§νν΄λ³Έκ²°κ³Ό λ§μΉ MFCλ₯Ό 보λλ―ν λλμ κ°νκ² λ°κ³ μλ€.
2.1. OpenGLκ³Ό μ°¨μ΄μ ¶
- WebGLμ κΈ°μ‘΄ OpenGLκ³Ό λ€λ₯΄κ² μ§μ κ·Έλ¦¬κΈ°κ° μ§μλμ§ μλλ€. κΈ°μ‘΄μ glBegin()μ glEnd()μ¬μ΄μμ κ°μ κ³μμ μΌλ‘ μ λ¬νμ μκ³ μ€μ§ glDrawElement()λ₯Ό ν΅ν λ°°μ΄μ νκΊΌλ²μ μ λ¬νλ κ²'λ§' μ§μνλ€. μ΄λ³΄μλ€μ 첫λκ΄μ΄λ€.
- μ¬κ°ν그리기 λ° λ€κ°ν κ·Έλ¦¬κΈ°κ° μ§μλμ§ μλλ€. μ€μ λ‘ λ€κ°ν 그리기λ μ°μ΅μμλ§ μμ£Ό μ°κ³ μ€μ μ½λμμλ μΌκ°νμΌλ‘ μ΄λ£¨μ΄μ§ λͺ¨λΈμ κ°μ Έλ€ μ°κΈ° λλ¬ΈμΈ κ²μΌλ‘ 보μΈλ€. κ·Έλ¦¬κ³ λ€κ°νμ μΌκ°νμ μ§ν©μΌλ‘ ννν μ μλ€.
- μ νΈλΌμ΄λΈλ¬λ¦¬λ‘ μ 곡λλ νλΈ, ꡬ, μ€λ¦°λ, ν°ν¬νΈκ° λͺ¨λ μ§μλμ§ μλλ€. μμ μμ μλ§ μ°μ΄κ³ μ°μ§ μκΈ° λλ¬Έμ κ³Όκ°ν μ κ±°νκ²μΌλ‘ 보μΈλ€.
- κ΄μ, μΉ΄λ©λΌ μ‘°μ, νμ λ±μ΄ μ 곡λμ§ μλλ€. λͺ¨λ μμ μ΄ μ§μ μ°μ°μ ν΅ν΄ νλ ¬μ ꡬν΄μ£Όμ΄μΌ νλ€. μ΄λ³΄μλ€μ λμ¨° λκ΄μ΄λ€.
- ν
μ€μ³ λͺ¨λμ μ‘°λͺ
λͺ¨λκ° λ§€μ° μ νλμ΄ μλ€.
- μμ΄λλ₯Ό μ§μ§μμΌλ©΄ μΈμκ° μλ€. μ¬μ§μ΄ ν
μ€μ³λ₯Ό μ
νλ κ²λ μμ΄λμμ μ²λ¦¬νλ€. κ·Έλ₯ λ¨μμΌλ‘ μ²λ¦¬νλ μ½λλ μμ΄λ μ½λλ₯Ό μ§μ§ μμΌλ©΄ κ·Έλ₯ νμ κ²λ§ 보κ²λλ€. κ·Έλ¦¬κ³ κ·Έκ²λ νμ μν¬μλ μλ€.
3.1. νμ΄ν λΌμΈ ¶
WebGLμ μΌμ ν νλ¦κ΅¬μ‘°λ₯Ό λ§λ€μ΄ λκ³ κ·Έ κ°λΆλΆμ λ§λ€μ μλλ‘ ν΄ λμλ€. μλ§ μ΅μ νκ° μ¬μ΄ νμ κ·Έλ¬νμΌλ¦¬κ³ μκ°λλ€.

Attributeλ κ° ν¬μΈνΈ λ³λ‘ μ λ¬λλ μ 보μ΄κ³ uniform μ μ 체μμ 곡ν΅μ μΈ μ 보μ΄λ€. μΌλ°μ μΌλ‘ Attributeλ κ° μ μ μ μμΉ μ 보μ κ° μ§μ μ λ²μ λ²‘ν° μ 보λ₯Όμ μ λ¬νλ€. uniformμ μΌλ°μ μΌλ‘ μΉ΄λ©λΌμ μμΉλ νκ²½κ΄μ μμΉμ²λΌ μ 체μ μΈ κ²μ μ λ¬νλ€. Attributeλ uniformμ μΌμ’ μ λ³μμΈλ° νΈλ€μ μ»μ΄μμ κ·Έκ²μ ν΅ν΄ κ°μ μ λ¬ν μ μλ€. μ¦ Atrributeλ Uniformμ JavascriptμΈ‘μμ μμ΄λλ‘ μ 보λ₯Ό 보λ΄λ κ²μ΄λ€. varyingμ μμ΄λ κ°μ μ 보 μ λ¬μ μ¬μ©λλ€. vertex shaderμμ fragment shaderλ‘ κ°μ΄ μ λ¬λλ©° λ°λλ λΆκ°λ₯νλ€(νμ΄νλΌμΈ ꡬ쑰μ λΉμ°ν κ²μ΄λ€). μ΄λ vertex shaderλ κ° μ μ (κΌμ§μ ) fragment shaderλ κ° ν½μ μ νλ² νΈμΆλκ² λλλ° κ° μ μ μ¬μ΄μ κ°λ€μ 보κ°λ²μ κ±°μ³ μ λ¬λκ² λλ€(κ·ΈλΌλμΈνΈ κ°μ λλμ΄λ€ μ€κ°κ°μ μμμ λ§λ€μ΄ μ€λ€).

[PNG image (52.47 KB)]
Attributeλ κ° ν¬μΈνΈ λ³λ‘ μ λ¬λλ μ 보μ΄κ³ uniform μ μ 체μμ 곡ν΅μ μΈ μ 보μ΄λ€. μΌλ°μ μΌλ‘ Attributeλ κ° μ μ μ μμΉ μ 보μ κ° μ§μ μ λ²μ λ²‘ν° μ 보λ₯Όμ μ λ¬νλ€. uniformμ μΌλ°μ μΌλ‘ μΉ΄λ©λΌμ μμΉλ νκ²½κ΄μ μμΉμ²λΌ μ 체μ μΈ κ²μ μ λ¬νλ€. Attributeλ uniformμ μΌμ’ μ λ³μμΈλ° νΈλ€μ μ»μ΄μμ κ·Έκ²μ ν΅ν΄ κ°μ μ λ¬ν μ μλ€. μ¦ Atrributeλ Uniformμ JavascriptμΈ‘μμ μμ΄λλ‘ μ 보λ₯Ό 보λ΄λ κ²μ΄λ€. varyingμ μμ΄λ κ°μ μ 보 μ λ¬μ μ¬μ©λλ€. vertex shaderμμ fragment shaderλ‘ κ°μ΄ μ λ¬λλ©° λ°λλ λΆκ°λ₯νλ€(νμ΄νλΌμΈ ꡬ쑰μ λΉμ°ν κ²μ΄λ€). μ΄λ vertex shaderλ κ° μ μ (κΌμ§μ ) fragment shaderλ κ° ν½μ μ νλ² νΈμΆλκ² λλλ° κ° μ μ μ¬μ΄μ κ°λ€μ 보κ°λ²μ κ±°μ³ μ λ¬λκ² λλ€(κ·ΈλΌλμΈνΈ κ°μ λλμ΄λ€ μ€κ°κ°μ μμμ λ§λ€μ΄ μ€λ€).
κ° μμ΄λλ λμμ λμν μ μλλ° λΉμ°ν μ΄λ€μ μλ‘κ°μ λ
립μ μ΄μ΄μΌ νλ€.
3.2. μμ΄λ ¶
μμ΄λλ μμ΄λ μΈμ΄λ‘ λ°λ‘ μ§μ£Όκ³ μ»΄νμΌ ν΄μΌνλ©° μ¬μ§μ΄ λ§ν¬κΉμ§ μμΌμ£Όμ΄μΌ νλ€. GPUμ κ°λ ₯ν νλ ¬μ°μ° λ₯λ ₯μ κ°μ Έλ€ μ°κΈ° μν΄μμΈκ²μΌλ‘ 보μ΄λλ° μ΄κ²μ μ¬μ©νμ§ μκ³ μλ μμ νμΌλ λλ €λ³Όμκ° μλ€. λ€νμ΄ μΈμ΄λ CμΈμ΄μ λ§€μ° μ μ¬νκ³ νλ ¬μ°μ°μ΄ λͺ¨λ μκΈ° λλ¬Έμ λ±ν μ΄λ ΅κ±°λ νμ§ μλ€. λ€λ§ μ΄λλΆλΆμμ μ΄λμ μ°κ²°λλμ§ μ΄ν΄νλλ° μκ°μ΄ κ±Έλ¦°λ€.
3.2.1. vertex shader ¶
κ° μ μ (vertex, κΌμ§μ )λ§λ€ νΈμΆλλ©° μ£Όλ‘ κΌμ§μ μ μμΉλ₯Ό μ°μ°νκ³ μ€μ Viewμ ν¬μνλ μ°μ°μ μ£Όλ‘ νκ² λλ€. νλ§λλ‘ λͺ¨λΈμ μμΉ λ³νκ³Ό μΉ΄λ©λΌ μμ μ λ°λ₯Έ λ³ν μκ·Όλ²μ μ μ©νλ λ³νλ±μ μννλ€.
3.2.2. fragment shader ¶
κ° μ μ μ¬μ΄μ μλ ν½μ
λ§λ€ νΈμΆλλ€. μ£Όλ‘ κ΄μν¨κ³Όλ₯Ό μ μ©ν ν½μ
μ μ΅μ’
μ μΈ μκΉμ΄λ ν
μ€μ³ μ°μ°μ μ¬μ©λλ€. varyingλ³μλ₯Ό vertex shaderμμ fragment shaderλ‘ λ겨주면 κ° μ μ μ¬μ΄μλ 보κ°λ²μΌλ‘ λ³νλ κ°μ΄ λμ΄ μ¨λ€.
4. μμ μ½λ ¶
μλ μ½λλ μ ννμ§ μμΌλ©° μ°μ΅ λμ€μ μ½λμ
λλ€. λν WebGLμ νΉμ±μ μ½λκ° λΆμ°λμ΄ μμ΅λλ€. νμ¬ κ°μ²΄ λνμ μ§νμ€μ
λλ€.
νμ¬ κ°μ²΄ λνμ€ μ€λν λ¬Έμ μ λ΄μ°©. λλΆλΆμ λͺ¨λκ³Ό μΈμ΄λ μ½λλ μ½λ°±μΌλ‘ νΈμΆλλλ° μ΄κ²μ μ μ ν λνν λ°©λ²μ΄ μλ€. webGLκ³Όλ νλ± μ°κ΄μ΄ μλ λΆλΆμ΄λΌμ κ°μ μμμ ꡬννλλ‘ ν΄λ λμ§λ§ λλΆλΆμ κ²½μ° κ°μ μ½λλ₯Ό λ€μ€ μ§κ³ μλ λλ₯Ό λ³΄κ² λλ€. μ΄κ²μ μ΄λ»κ² ν΄μΌ μν λνμ΄λΌ ν μ μμκΉ?
4.1. vertexShader ¶
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
uniform mat4 matCamara;
uniform mat4 matProject;
uniform vec3 lightPos;
uniform vec3 lightDirection;
uniform vec4 materialDiffuse;
uniform vec4 lightDiffuse;
varying vec4 vFinalColor;
varying vec3 vNormal;
void main(void){
vec3 N = normalize((vec4(aVertexNormal, 1.0) * matCamara).xyz);//nomal compute
vec3 L = normalize(lightDirection); //lightDrection
float lambertTerm = max(dot(N, -L), 0.0);
vec4 Id = lightDiffuse * materialDiffuse * lambertTerm;
vNormal = normalize((vec4(aVertexNormal, 1.0) * matCamara).xyz);
vFinalColor = Id;
vFinalColor.a = 1.0;
gl_Position = matProject * matCamara * vec4((aVertexPosition), 1.0);
gl_Position.w = 1.0;
}
4.2. fragmentShader ¶
#ifdef GL_ES
precision highp float;
#endif
uniform vec3 lightPos;
uniform vec3 lightDirection;
uniform vec4 materialDiffuse;
uniform vec4 lightDiffuse;
varying vec4 vFinalColor;
varying vec3 vNormal;
void main(void) {
vec3 L = normalize(lightDirection);
gl_FragColor = vFinalColor + vec4(0.01,0.01,0.01, 1.0);
}
4.3. javascript ¶
var cube = {
"vertices": [
0.2, 0.2, 0.2, //0
0.2, 0.2,-0.2, //1
0.2,-0.2, 0.2, //2
0.2,-0.2,-0.2, //3
-0.2, 0.2,-0.2, //4
-0.2, 0.2, 0.2, //2
-0.2,-0.2,-0.2, //6
-0.2,-0.2, 0.2 //7
],
"normals": [
1, 1, 1, //0
1, 1,-1, //1
1,-1, 1, //2
1,-1,-1, //3
-1, 1,-1, //4
-1, 1, 1, //5
-1,-1,-1, //6
-1,-1, 1 //7
],
"indices" : [
0,2,3, 0,3,1,
4,6,7, 4,7,5,
4,5,0, 4,0,1,
7,6,3, 7,3,2,
5,7,2, 5,2,0,
1,3,6, 1,6,4
]
}
var init = function(){
var gl = getGLContext();
var cubeBuffer = new GLBuffer(gl, cube);
var shader;
async.parallel([
function(callback){
var url = document.getElementById("vertexShader").getAttribute("src");
ajax(url, callback);
},
function(callback){
var url = document.getElementById("fragmentShader").getAttribute("src");
ajax(url, callback);
},
], function (err, data){
shader = new GLShader(gl, data[0], data[1]);
gl.useProgram(shader.program);
shader.aVertexPosition = gl.getAttribLocation(shader.program, "aVertexPosition");
shader.aVertexNormal = gl.getAttribLocation(shader.program, "aVertexNormal");
var cam = gl.getUniformLocation(shader.program, "matCamara");
var camMat = mat4.identity(mat4.create());
mat4.translate(camMat, camMat, [0, 0, 0.1]);
mat4.rotate(camMat, camMat, Math.PI/4, [1,0.5,0.5]);
gl.uniformMatrix4fv(cam, false, camMat);
var lightPos = shader.getUniformLocation("lightPos");
gl.uniform3fv(lightPos, [0.1,0.1,0.1]);
var lightDirection = shader.getUniformLocation("lightDirection");
gl.uniform3fv(lightDirection, [-1, -1, -1]);
var materialDiffuse = shader.getUniformLocation("materialDiffuse");
gl.uniform4fv(materialDiffuse, [0.8, 0.2, 0.2, 1.0]);
var lightDiffuse = shader.getUniformLocation("lightDiffuse");
gl.uniform4fv(lightDiffuse, [1,1,1,1]);
var matProject = mat4.identity(mat4.create());//2PI = 360d -> 1d = PI/180
mat4.perspective(matProject, Math.PI/180 * 80, 1, 0, 1);
gl.uniformMatrix4fv(
shader.getUniformLocation("matProject"),
false,
matProject
);
onReady(gl, cubeBuffer, shader);
});
}
setTimeout(init, 0);
function onReady(gl, buffer, shader){
onDraw();
function onDraw(){
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0,0,300,300);
gl.enableVertexAttribArray(shader.aVertexPosition);
gl.enableVertexAttribArray(shader.aVertexNormal);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer.vertex);
gl.vertexAttribPointer(shader.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer.normal);
gl.vertexAttribPointer(shader.aVertexNormal, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer.index);
gl.drawElements(gl.TRIANGLES, buffer.index.length, gl.UNSIGNED_SHORT, 0);
}
}
function ajax(url, callback){
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = function(){
if(ajax.readyState === 4){
//complete requset
if(ajax.status === 200){
//not error
callback(null, ajax.responseText);
}
}
}
ajax.open("GET", url, true);//if need Sync method set false;
ajax.send(null);
}
//Lib function
function getGLContext(){
var canvas = document.getElementsByTagName("canvas");
canvas = [].filter.call(canvas, function(element){
if(element.getAttribute("WebGL") != null)
return true;
else
return false;
});
canvas = canvas[0];
return canvas.getContext("experimental-webgl");
}
//Lib Class
function GLBuffer(gl, model){
this.model = model;
try {
//only binded buffer can send data
//vertex is coord of points
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(model.vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
//index is triangle point index of suface
var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(model.indices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
//normals Buffer
var normalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(model.normals), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
this.vertex = vertexBuffer;
this.index = indexBuffer;
this.index.length = model.indices.length;
this.normal = normalBuffer;
} catch(e){
throw Error("Can not create Buffer");
}
}
function GLShader(gl, vertexSource, fragmentSource){
var shaderProgram = gl.createProgram();
//compile Source
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexSource);
gl.compileShader(vertexShader);
checkCompile(vertexShader);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentSource);
gl.compileShader(fragmentShader);
checkCompile(fragmentShader);
//attach shader
gl.attachShader(shaderProgram, fragmentShader);
gl.attachShader(shaderProgram, vertexShader);
//link
gl.linkProgram(shaderProgram);
this.program = shaderProgram;
this._private = {
gl : gl
}
function checkCompile(shader){
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
throw Error(gl.getShaderInfoLog(shader));
}
}
}
GLShader.prototype.getUniformLocation = function(name){
return this._private.gl.getUniformLocation(this.program, name);
}
GLShader.prototype.uniform4fv = function(name, arr){
this._private.gl.uniform4fv(this.getUniformLocation(name), arr);
}
GLShader.prototype.uniform3fv = function(name, arr){
this._private.gl.uniform3fv(this.getUniformLocation(name), arr);
}
GLShader.prototype.uniformMatrix4fv = function(name, arr){
this._private.gl.uniformMatrix4fv(this.getUniformLocation(name), false, arr);
}









