Javascript 在webgl中实现透视矩阵

Javascript 在webgl中实现透视矩阵,javascript,webgl,Javascript,Webgl,我有一个小代码,它在世界原点(0,0,0)沿y轴旋转一个三角形 <!DOCTYPE HTML> <html> <canvas id = "can" width="400" height="400"> </canvas> <script> var webgl_canvas = document.getElementById('can'); var gl = webgl_canvas.getContext('experimental

我有一个小代码,它在世界原点(0,0,0)沿y轴旋转一个三角形

<!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>
把它和制服连在一起

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>

var webgl_canvas=document.getElementById('can');
var gl=webgl_canvas.getContext('experimental-webgl');
webgl_canvas.width=window.innerWidth;
webgl_canvas.height=window.innerHeight;
变量宽度=总帐宽度;
变量顶点=[-1,-1,0,1,-1,0,0,1,0];
var vertexBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY\u BUFFER,vertexBuffer);
gl.bufferData(gl.ARRAY\u BUFFER、新Float32Array(顶点)、gl.STATIC\u DRAW);
vertexBuffer.itemSize=3;
vertexBuffer.numItems=parseInt(顶点.length/vertexBuffer.itemSize);
var tx=0,ty=0,tz=0;
变异度=0.1;
var identityMatrix=[1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1];
功能透视图(角度、纵横比、zMin、zMax){
var tan=数学tan(degToRadians(0.5*角)),
A=-(zMax+zMin)/(zMax-zMin),
B=(-2*zMax*zMin)/(zMax-zMin);
返回值[.5/tan,0,0,0,
0.5*aspect/tan,0,0,
0,0,A,-1,
0,0,B,0
];    
}
函数rotX(度){
m=识别矩阵;
var c=数学cos(度);
var s=数学sin(度);
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;
}
函数旋转(度){
m=识别矩阵;
console.log(identityMatrix);
var c=数学cos(度);
var s=数学sin(度);
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];
函数degToRadians(度){
返回(度*数学PI/180);
}
函数翻译(x){
m=识别矩阵;
返回m[12]+=x;
}
var vertexShader_source='attribute vec3 a_position;'+'均匀mat4 u_移动;'+'均匀mat4 u_透视图;'+'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);}';
//编译着色器
var buildShader=函数(shaderSource,typeOfShader){
var shader=gl.createShader(typeOfShader);
gl.shaderSource(着色器,shaderSource);
gl.compileShader(着色器);
if(!gl.getShaderParameter(着色器,gl.COMPILE_状态)){
警报(gl.getShaderInfoLog(着色器));
}
返回着色器;
}
var compiledVertexShader=buildShader(vertexShader\u源,gl.VERTEX\u着色器);
var compiledFragmentShader=buildShader(fragmentShader\u源,gl.FRAGMENT\u着色器);
//安装GLSL程序
program=gl.createProgram();
gl.attachShader(程序,编译的VertexShader);
gl.attachShader(程序,编译碎片着色器);
总账链接程序(程序);
//将javascript变量链接到着色器
var透视图矩阵=gl.getUniformLocation(程序,“u透视图”);
var translate=gl.getUniformLocation(程序,“u_移动”);
var positionLocation=gl.GetAttriblLocation(程序,“a_位置”);
gl.EnableVertexAttributeArray(位置位置);
gl.useProgram(程序);
var PERSPMATRIX=透视图(40,webgl_画布宽度/webgl_画布高度,1100);
//画
var启动时间=0;
var animate=函数(时间){
var dt=启动时间;
var矩阵=rotX(度);
控制台日志(矩阵);
gl.uniformMatrix4fv(透视矩阵,假,有机矩阵);
gl.统一矩阵X4FV(翻译、假、识别矩阵);
gl.VertexAttribute指针(位置位置,vertexBuffer.itemSize,gl.FLOAT,false,0,0);
gl.bindBuffer(gl.ARRAY\u BUFFER,vertexBuffer);
开始时间=时间;
gl.DrawArray(gl.TRIANGLES,0,vertexBuffer.numItems);
window.requestAnimationFrame(动画);
}
动画(0);

这将只指出特定的问题

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顶点
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
-函数都不会返回任何内容。应该有
返回m内部。

您是否将整个代码发布了三次?ಠ_ಠ不,它每次都会改变。哦,好吧,这是你整个代码的三个不同版本
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
}