WebGL独学コース(2):カスタムglTranslateとglRotateの使用
OpenGLではglTranslateとglRotateを直接使用できますが、WebGL 1.0仕様にはこの関数は含まれていません.使用するには、自分で実装する必要があります.サンプルコードは次のとおりです.
<!doctype html>
<html>
<head>
<title>World</title>
<meta http-equiv="Content-Type" content="text/html" />
<meta name="charset" content="utf-8"/>
<style type="text/css">
html,body,div{margin:0;padding:0}
</style>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aPosition;
uniform mat4 uModelView;
uniform mat4 uProj;
void main()
{
gl_Position = uProj * uModelView * vec4(aPosition,1.0);
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
void main()
{
gl_FragColor = vec4(0.5,0.5,0,1.0);
}
</script>
<script type="text/javascript" src="http://localhost/arcgis_js_api/library/2.7/jsapi/"></script>
<script type="text/javascript">
var canvas = null;
var gl = null;
var shaderProgram = null;
var aPositionLocation;
var uModelViewLocation;
var uProjLocation;
var vertexPositionBuffer = null;
var mvMatrix = null;
var projMatrix = null;
var mvMatrixStack = [];
var angle=0;
function mvPushMatrix(){
var array = [];
for(i=0;i<mvMatrix.length;i++){
array.push(mvMatrix[i]);
}
var matrix = new Float32Array(array);
mvMatrixStack.push(matrix);
}
function mvPopMatrix(){
if(mvMatrixStack.length==0){
throw "Invalid PopMatrix";
}
mvMatrix = mvMatrixStack.pop();
}
function initWebGL(canvas){
try{
gl = canvas.getContext("experimental-webgl",{antialias:true});
}
catch(e){
alert(" WebGL!");
}
if(!gl)
alert(" WebGL!");
}
function getShader(gl,id){
var shaderScript = document.getElementById(id);
if(!shaderScript)
return null;
var shader = null;
if(shaderScript.type=="x-shader/x-vertex"){
shader = gl.createShader(gl.VERTEX_SHADER);
}
else if(shaderScript.type=="x-shader/x-fragment"){
shader = gl.createShader(gl.FRAGMENT_SHADER);
}
else{
return null;
}
gl.shaderSource(shader,shaderScript.text);
gl.compileShader(shader);
if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS)){
alert(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
function initShaders(){
var vertexShader = getShader(gl,"shader-vs");
var fragmentShader = getShader(gl,"shader-fs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram,vertexShader);
gl.attachShader(shaderProgram,fragmentShader);
gl.linkProgram(shaderProgram);
if(!gl.getProgramParameter(shaderProgram,gl.LINK_STATUS)){
alert("Could not link program");
gl.deleteProgram(shaderProgram);
gl.deleteShader(vertexShader);
gl.deleteShader(fragmentShader);
return;
}
gl.useProgram(shaderProgram);
aPositionLocation = gl.getAttribLocation(shaderProgram,"aPosition");
gl.enableVertexAttribArray(aPositionLocation);
uModelViewLocation = gl.getUniformLocation(shaderProgram,"uModelView");
uProjLocation = gl.getUniformLocation(shaderProgram,"uProj");
}
function initBuffer(){
vertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vertexPositionBuffer);
var vertices = [ 0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0];
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(vertices),gl.STATIC_DRAW);
}
function getPerspectiveMatrix(fov,aspect,near,far){
var a = 1.0/Math.tan(fov / 2 * Math.PI / 180);
var b = far/(far-near);
var c = -near*far/(far-near);
var perspectiveMatrix = new Float32Array([
a/aspect, 0, 0, 0,
0, a, 0, 0,
0, 0, b, c,
0, 0, 1, 0
]);
return perspectiveMatrix;
}
function drawScene(){
var width = dojo.style(canvas,"width");
var height = dojo.style(canvas,"height");
gl.viewport(0,0,width,height);
gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
projMatrix = getPerspectiveMatrix(90,width/height,1.0,100.0);
mvMatrix = new Float32Array([1.0,0.0,0.0,0.0,
0.0,1.0,0.0,0.0,
0.0,0.0,1.0,0.0,
0.0,0.0,0.0,1.0]);
mvPushMatrix();
translate(mvMatrix,0,0,-5);
angle++;
rotateMatrix44(mvMatrix,angle*Math.PI/180,0,1,0);
gl.bindBuffer(gl.ARRAY_BUFFER,vertexPositionBuffer);
gl.vertexAttribPointer(aPositionLocation,3,gl.FLOAT,false,0,0);
gl.uniformMatrix4fv(uModelViewLocation,false,mvMatrix);
gl.uniformMatrix4fv(uProjLocation,false,projMatrix);
gl.drawArrays(gl.TRIANGLES,0,3);
mvPopMatrix();
}
function loadIdentity(){
mvMatrix = new Float32Array([1.0,0.0,0.0,0.0,
0.0,1.0,0.0,0.0,
0.0,0.0,1.0,0.0,
0.0,0.0,0.0,1.0]);
}
function translate(M16,x,y,z){
M16[12] += x;
M16[13] += y;
M16[14] += z;
return M16;
}
function rotateMatrix44(M16, angle, x, y, z) {
var length, s, c;
var xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;
s = Math.sin(angle);
c = Math.cos(angle);
length = Math.sqrt( x*x + y*y + z*z );
// Rotation matrix is normalized
x /= length;
y /= length;
z /= length;
//#define M(row,col) m[col*4+row]
xx = x * x;
yy = y * y;
zz = z * z;
xy = x * y;
yz = y * z;
zx = z * x;
xs = x * s;
ys = y * s;
zs = z * s;
one_c = 1.0 - c;
M16[0] = (one_c * xx) + c;//M(0,0)
M16[4] = (one_c * xy) - zs;//M(0,1)
M16[8] = (one_c * zx) + ys;//M(0,2)
//M16[12] = 0.0;//M(0,3) X
M16[1] = (one_c * xy) + zs;//M(1,0)
M16[5] = (one_c * yy) + c;//M(1,1)
M16[9] = (one_c * yz) - xs;//M(1,2)
//M16[13] = 0.0;//M(1,3) Y
M16[2] = (one_c * zx) - ys;//M(2,0)
M16[6] = (one_c * yz) + xs;//M(2,1)
M16[10] = (one_c * zz) + c;//M(2,2)
//M16[14] = 0.0;//M(2,3) Z
M16[3] = 0.0;//M(3,0)
M16[7] = 0.0;//M(3,1)
M16[11] = 0.0;//M(3,2)
M16[15] = 1.0;//M(3,3)
return M16;
}
function initRequestAnimationFrame(){
window.requestAnimationFrame = window.requestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.msRequestAnimationFrame
|| window.oRequestAnimationFrame
|| function(callback) {
setTimeout(callback, 1000 / 60);
};
}
function tick() {
window.requestAnimationFrame(tick);
drawScene();
}
function startWebGL(){
canvas = document.getElementById("iCanvas");
initWebGL(canvas);
initShaders();
initBuffer();
gl.clearColor(0.0,0.0,1.0,1.0);
gl.enable(gl.DEPTH_TEST);
//gl.clearDepth(1.0);
//gl.depthFunc(gl.LEQUAL);
initRequestAnimationFrame();
tick();
}
</script>
</head>
<body onload="startWebGL();">
<canvas id="iCanvas" style="border: 1px solid #000;width:800px;height: 600px;"></canvas>
</body>
</html>