在webgl中实现透视矩阵
Implementing perspective matrix in webgl
我有一个小代码,它沿着y轴在世界原点(0,0,0)旋转一个三角形。
<!DOCTYPE HTML>
<html>
<canvas id = "can" width="400" height="400">
</canvas>
<script>
var webgl_canvas = document.getElementById('can');
var gl = webgl_canvas.getContext('experimental-webgl');
var width = gl.width;
var vertices = [-1,-1,0,1,-1,0,0,1,0];
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(vertices), gl.STATIC_DRAW);
vertexBuffer.itemSize = 3;
vertexBuffer.numItems = parseInt(vertices.length/vertexBuffer.itemSize);
var tx = 0, ty = 0, tz = 0;
var degrees = 0.1;
function rotY (degrees) {
m = identityMatrix;
var c = Math.cos(degrees);
var s = Math.sin(degrees);
var mv0=m[0], mv4=m[4], mv8=m[8];
m[0]=c*m[0]+s*m[2];
m[4]=c*m[4]+s*m[6];
m[8]=c*m[8]+s*m[10];
m[2]=c*m[2]-s*mv0;
m[6]=c*m[6]-s*mv4;
m[10]=c*m[10]-s*mv8;
}
var identityMatrix = [1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1];
var translationMatrix = [1,0,0,tx,
0,1,0,ty,
0,0,1,tz,
0,0,0,1];
function degToRadians(deg){
return (deg*MATH.PI/180);
}
function translation(x) {
m = identityMatrix;
return m[12] += x;
}
var vertexShader_source = 'attribute vec3 a_position;' + 'uniform mat4 u_move;' + 'void main() { gl_Position = u_move * vec4 (a_position,1); }';
var fragmentShader_source = 'precision mediump float;' + 'void main() { gl_FragColor = vec4 (0.9,0,0.1,1); }';
//Compile shaders
var buildShader = function (shaderSource, typeOfShader) {
var shader = gl.createShader(typeOfShader);
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert (gl.getShaderInfoLog(shader));
}
return shader;
}
var compiledVertexShader = buildShader (vertexShader_source, gl.VERTEX_SHADER);
var compiledFragmentShader = buildShader (fragmentShader_source, gl.FRAGMENT_SHADER);
//setup GLSL program
program = gl.createProgram();
gl.attachShader(program,compiledVertexShader);
gl.attachShader(program,compiledFragmentShader);
gl.linkProgram(program);
var positionLocation = gl.getAttribLocation(program,"a_position");
gl.enableVertexAttribArray(positionLocation);
gl.useProgram(program);
var translate = gl.getUniformLocation (program, "u_move");
//Draw
var start_time =0;
var animate=function(time) {
var dt= time-start_time;
var matrix = rotY(degrees);
gl.uniformMatrix4fv(translate,false,new Float32Array(identityMatrix));
gl.vertexAttribPointer(positionLocation, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
//console.log(dt);
start_time=time;
gl.drawArrays (gl.TRIANGLES, 0, vertexBuffer.numItems);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</html>
现在,我添加了旋转功能
function rotY (degrees) {
m = identityMatrix;
console.log(identityMatrix);
var c = Math.cos(degrees);
var s = Math.sin(degrees);
var mv0=m[0], mv4=m[4], mv8=m[8];
m[0]=c*m[0]+s*m[2];
m[4]=c*m[4]+s*m[6];
m[8]=c*m[8]+s*m[10];
m[2]=c*m[2]-s*mv0;
m[6]=c*m[6]-s*mv4;
m[10]=c*m[10]-s*mv8;
}
将其与统一联系起来
var perspective_matrix = gl.getUniformLocation (program, "u_perspective");
并启用
gl.uniformMatrix4fv(perspective_matrix,false, PERSPMATRIX);
三角形现在已经消失了。检查控制台时,我的矩阵值返回了未定义的值,所以我怀疑我有什么问题,尽管我没有看到确切的位置。完整代码遵循
<!DOCTYPE HTML>
<html>
<canvas id = "can" width="400" height="400">
</canvas>
<script>
var webgl_canvas = document.getElementById('can');
var gl = webgl_canvas.getContext('experimental-webgl');
webgl_canvas.width=window.innerWidth;
webgl_canvas.height=window.innerHeight;
var width = gl.width;
var vertices = [-1,-1,0,1,-1,0,0,1,0];
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(vertices), gl.STATIC_DRAW);
vertexBuffer.itemSize = 3;
vertexBuffer.numItems = parseInt(vertices.length/vertexBuffer.itemSize);
var tx = 0, ty = 0, tz = 0;
var degrees = 0.1;
var identityMatrix = [1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1];
function perspective(angle,aspect,zMin,zMax){
var tan = Math.tan(degToRadians(0.5*angle)),
A =-(zMax+zMin)/(zMax-zMin),
B = (-2*zMax*zMin)/(zMax-zMin);
return [ .5/tan,0,0,0,
0, .5*aspect/tan, 0, 0,
0,0,A,-1,
0,0,B,0
];
}
function rotX (degrees) {
m = identityMatrix;
var c = Math.cos(degrees);
var s = Math.sin(degrees);
var mv1=m[1], mv5=m[5], mv9=m[9];
m[1]=m[1]*c-m[2]*s;
m[5]=m[5]*c-m[6]*s;
m[9]=m[9]*c-m[10]*s;
m[2]=m[2]*c+mv1*s;
m[6]=m[6]*c+mv5*s;
m[10]=m[10]*c+mv9*s;
}
function rotY (degrees) {
m = identityMatrix;
console.log(identityMatrix);
var c = Math.cos(degrees);
var s = Math.sin(degrees);
var mv0=m[0], mv4=m[4], mv8=m[8];
m[0]=c*m[0]+s*m[2];
m[4]=c*m[4]+s*m[6];
m[8]=c*m[8]+s*m[10];
m[2]=c*m[2]-s*mv0;
m[6]=c*m[6]-s*mv4;
m[10]=c*m[10]-s*mv8;
}
var translationMatrix = [1,0,0,tx,
0,1,0,ty,
0,0,1,tz,
0,0,0,1];
function degToRadians(deg){
return (deg*Math.PI/180);
}
function translation(x) {
m = identityMatrix;
return m[12] += x;
}
var vertexShader_source = 'attribute vec3 a_position;' + 'uniform mat4 u_move;' + 'uniform mat4 u_perspective;' + 'void main() { gl_Position = u_perspective * u_move * vec4 (a_position,1); }';
var fragmentShader_source = 'precision mediump float;' + 'void main() { gl_FragColor = vec4 (0.9,0,0.1,1); }';
//Compile shaders
var buildShader = function (shaderSource, typeOfShader) {
var shader = gl.createShader(typeOfShader);
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert (gl.getShaderInfoLog(shader));
}
return shader;
}
var compiledVertexShader = buildShader (vertexShader_source, gl.VERTEX_SHADER);
var compiledFragmentShader = buildShader (fragmentShader_source, gl.FRAGMENT_SHADER);
//setup GLSL program
program = gl.createProgram();
gl.attachShader(program,compiledVertexShader);
gl.attachShader(program,compiledFragmentShader);
gl.linkProgram(program);
//link javascript variables with shaders uniforms
var perspective_matrix = gl.getUniformLocation (program, "u_perspective");
var translate = gl.getUniformLocation (program, "u_move");
var positionLocation = gl.getAttribLocation(program,"a_position");
gl.enableVertexAttribArray(positionLocation);
gl.useProgram(program);
var PERSPMATRIX = perspective(40,webgl_canvas.width/webgl_canvas.height,1,100);
//Draw
var start_time =0;
var animate=function(time) {
var dt= time-start_time;
var matrix = rotX(degrees);
console.log(matrix);
gl.uniformMatrix4fv(perspective_matrix,false, PERSPMATRIX);
gl.uniformMatrix4fv(translate,false,identityMatrix);
gl.vertexAttribPointer(positionLocation, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
start_time=time;
gl.drawArrays (gl.TRIANGLES, 0, vertexBuffer.numItems);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</html>
这将只指出特定的问题。
1) 使用var identityMatrix = [ ... ]
可以创建一个数组。每次用var m = identityMatrix;
引用它时,您都不会创建新的数组,而是始终只指向原始数组。现在,当您在var m
中更改一个项时,您将在原始identityMatrix
中更改同一项,并且这些更改将显示在整个代码中指向它的所有位置。
使identityMatrix成为返回数组的函数:
var identityMatrix = function() {return [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];}
每次你想从一个新的identityMatrix开始做:
var m = identityMatrix(); // now you get new matrices not affecting each other
var vertices
或var translationMatrix
也可能发生同样的情况,我把支票留给你。
2) 函数translation()
不返回矩阵,只返回一个数字(矩阵的第13项)。必须是:
function translation(x) {
var m = identityMatrix; // don't miss the var keyword
m[12] += x; // change value at index 12
return m; // return the whole matrix
}
3) 两个rotate
-函数都不返回任何内容。里面应该有return m;
。
相关文章:
- 如何使用动画实现纸张推车
- 客户端服务器REST API captcha实现
- 如何实现此布局
- Meteor忘记了密码的实现
- 使用Native Sockets在Android中实现WebSockets
- 在样板文件中实现Ajax
- instanceof是如何在JavaScript中实现的
- 如何正确实现Jquery多选小部件
- 实现一个建立在google.com之上的自定义搜索引擎
- 多个组件是如何实现的
- window.location使用jquery mobile实现chrome跳转
- 如何在OpenERP中实现网络摄像头
- Node.js使用Series函数(模式?)实现流控制时出现意外结果
- javascript加密实现,包括可信否认
- 实现比较方法的最佳实践是什么;s的比较类型是在运行时选择的
- 如何让程序员在javascript中实现正确的回调
- 如何使用自定义辅助对象(handler)实现嵌套的每个循环
- AngularJS智能表全局配置实现
- Expressjs/AngularJS:实现req-flash后出错
- 在webgl中实现透视矩阵