【问题标题】:WebGL draw loop and translationWebGL 绘制循环和翻译
【发布时间】:2014-12-26 12:08:38
【问题描述】:

我希望我的 javascript 程序向右移动一个三角形。 我现在关注的是矩阵和绘制循环。我从来没有做过这样的事情,所以我可能不在路上,但出于学习目的,我正在尝试做的是:

-设置 webgl 管道,以便正确显示三角形(OK)

-写一个带有矩阵的函数,允许我传入翻译值(看起来不错,但我不确定)

var translation_prototype = [1,0,0,0,
                             0,1,0,0,
                             0,0,1,0,
                             tx,ty,0,1]; 

暂时不考虑旋转缩放和模型视图,因为我对 webgl 提供的正交视图非常满意(只是为了练习)。

-设置一个循环遍历drawArrays(即使在这里我也不确定循环是否在正确的位置开始和结束)

我怀疑我真的很近,但三角形没有移动(tx 保持不变)。

这是代码(我想我什至不需要清除颜色和深度缓冲区,因为我只在 x 轴上平移)

    <!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 triangles = [-0.8,-0.8,0,0.8,-0.8,0,0,0.8,0];
            var vertexBuffer = gl.createBuffer();
            var tx = 0.1;
            var ty = 0;
            var translation_prototype = [1,0,0,0,
                                         0,1,0,0,
                                         0,0,1,0,
                                         tx,ty,0,1]; 
            
            var vertexShader_source = 'attribute vec3 a_position;' + 'uniform vec4 u_translation;' + 'void main() { gl_Position = u_translation * vec4 (a_position,1);}';
            var fragmentShader_source = 'precision mediump float;' + 'void main() { gl_FragColor = vec4 (0.9,0,0.1,1); }';

            function getTimeInSeconds () {
                return Date.now() * 0.001;
            }
            
            function makeTranslation (tx, ty) {
                return translation_prototype;  
            }
            
            //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);
            
            //Fill the buffer with vertex data
            
            gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
            gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(triangles), gl.STATIC_DRAW); 
            vertexBuffer.itemSize = 3;
            vertexBuffer.numItems = 3;

            gl.clear(gl.COLOR_BUFFER_BIT);
            var positionLocation = gl.getAttribLocation(program,"a_position");
            gl.enableVertexAttribArray(positionLocation);
            gl.useProgram(program);
            var shaderTranlsationMatrix = gl.getUniformLocation(program, "u_translation");
            gl.uniformMatrix4fv(shaderTranlsationMatrix,false,new Float32Array(translation_prototype));
            gl.vertexAttribPointer(positionLocation, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
        
            var startTime = 0;
            function animate (time) {
                //Draw loop
                gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
                var deltaTime = (time - startTime);
                makeTranslation((tx*deltaTime),(ty*deltaTime));
                console.log(tx,ty,deltaTime);
        
                gl.drawArrays (gl.TRIANGLES, 0, vertexBuffer.numItems);
                startTime = time;
    
                window.requestAnimationFrame(animate);
            }
    
            animate(0);
        </script>
    </html>
<!-- start last edited snippet -->


<!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 vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,0,1,-1,0,0,1,0]), gl.STATIC_DRAW); 

vertexBuffer.itemSize = 3;
vertexBuffer.numItems = 3;

var identityMatrix = [1,0,0,0,
                      0,1,0,0,
                      0,0,1,0,
                      0,0,0,1];

function translation (tx,ty,tz) {
    return [1,0,0,0,
            0,1,0,0,
            0,0,1,0,
           tx,ty,tz,1]
}


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 tx = 0, ty = 0, tz = 0;
var translate = gl.getUniformLocation (program, "u_move");
gl.uniformMatrix4fv(translate,false,new Float32Array(identityMatrix));
gl.vertexAttribPointer(positionLocation, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);

//Draw
var start_time =0;
var animate=function(time) {
var dt= time-start_time;
tx+=0.5;
translation((dt*tx),0,0);
console.log(dt);
console.log(tx);
start_time=time;
gl.drawArrays (gl.TRIANGLES, 0, vertexBuffer.numItems);
window.requestAnimationFrame(animate);
}
animate(0);
</script>

</html>

<!-- end last edited snippet -->

【问题讨论】:

  • 如果你 console.log 循环函数中的 translation_prototype 变量,你会发现它没有改变!所以你的三角形不会移动
  • 是的,博伊德,我知道。我不明白为什么。
  • 你的顶点着色器也是错误的。你必须将你的平移制服与位置向量相乘才能得到最终的移动结果
  • 操作,抱歉,忘记了。我已将乘法放在 EDIT 中。但现在三角形消失了。
  • 哦,当你使用 uniformMatrix4fv() 函数传递它时,你的制服应该是 mat4,而不是 vec4

标签: javascript webgl


【解决方案1】:

这里是工作的 sn-p

JSFIDDLE

您的顶点着色器应如下所示:

attribute vec3 a_position;' + 'uniform mat4 u_translation;' + 'void main() { gl_Position = u_translation*vec4 (a_position,1);}
  • 为了使对象在空间中移动,您必须将所有向量和矩阵与位置向量相乘才能得到结果。 Tranlation Wiki

您必须在每个循环周期更新您的 translation_prototype 变量:

    deltaTime += 0.005;
    makeTranslation(tx+deltaTime,ty+deltaTime);
  • deltaTime 在循环外声明并在每个循环中递增

您的makeTranslation 函数也应如下所示:

function makeTranslation (x, y) {
    translation_prototype = 
            [1,0,0,0,
             0,1,0,0,
             0,0,1,0,
             x,y,0,1]
    return translation_prototype;  
}
  • (如果使用全局变量,可以去掉return语句,但建议使用局部变量)

(我不得不尝试这个新的 sn-p 功能:D)

 var webgl_canvas = document.getElementById('can');
    var gl = webgl_canvas.getContext('experimental-webgl');
    var triangles = [-0.5,-0.5,0,0.5,-0.5,0,0,0.5,0];
    var vertexBuffer = gl.createBuffer();
    var tx = 0;
    var ty = 0;
    var translation_prototype = [1,0,0,0,
                 -               0,1,0,0,
                                 0,0,1,0,
                                 0,0,0,1]; 
    
    var vertexShader_source = 'attribute vec3 a_position;' + 'uniform mat4 u_translation;' + 'void main() { gl_Position = u_translation*vec4 (a_position,1);}';
    var fragmentShader_source = 'precision mediump float;' + 'void main() { gl_FragColor = vec4 (0.9,0,0.1,1); }';
    
    
    
    function getTimeInSeconds () {
    	return Date.now() * 0.001;
    }
    
    function makeTranslation (x, y) {
        translation_prototype = 
                [1,0,0,0,
                 0,1,0,0,
                 0,0,1,0,
                 x,y,0,1]
    	return translation_prototype;  
    }
    
    
    //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);
    
    //Fill the buffer with vertex data
    
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(triangles), gl.STATIC_DRAW); 
    vertexBuffer.itemSize = 3;
    vertexBuffer.numItems = 3;
    
    
    gl.clear(gl.COLOR_BUFFER_BIT);
    var positionLocation = gl.getAttribLocation(program,"a_position");
    gl.enableVertexAttribArray(positionLocation);
    gl.useProgram(program);
    var shaderTranlsationMatrix = gl.getUniformLocation(program, "u_translation");
    gl.uniformMatrix4fv(shaderTranlsationMatrix,false,new Float32Array(translation_prototype));
    gl.vertexAttribPointer(positionLocation, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
    	
    var startTime = 0;
    var deltaTime = 0;
    function animate (time) {
    
    	//Draw loop
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    	deltaTime += 0.005;
        makeTranslation(tx+deltaTime,ty+deltaTime);
        
        gl.useProgram(program);
        var shaderTranlsationMatrix = gl.getUniformLocation(program, "u_translation");
        gl.uniformMatrix4fv(shaderTranlsationMatrix,false,new Float32Array(translation_prototype));
        gl.vertexAttribPointer(positionLocation, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
    	
    	gl.drawArrays (gl.TRIANGLES, 0, vertexBuffer.numItems);
    	startTime = time;
    
    	window.requestAnimationFrame(animate);
    }
    
    animate(0);
<canvas id = "can" width="300" height="300">

</canvas>

【讨论】:

  • 绘制循环不应该改变运动变量而不是时间吗?看起来这段代码在慢速机器上运行得更慢。虽然输出没问题,但我正在考虑使用滑块或其他东西来控制网格的移动。现在它完全独立于时间。还是我错过了什么?
  • 你也可以使用时间。只需将 += 0.005 替换为你的函数getTimeInSeconds() (jsfiddle.net/w9m5qc9a/1)
  • 好的,我快到了。我需要的不仅仅是一个工作代码,只是为了让我了解一些概念。所以,基本上,感谢您的输入,我了解到:1)我需要和单位矩阵,只是为了填充 gl.matrixuniform,然后我可以调用转换矩阵并进行乘法运算。 2)我需要将一些值传递给矩阵,这些值将在绘制循环中发生变化(查看控制台,它每 16 毫秒正确绘制一次,或多或少)。现在,即使平移 x 参数是增量的,但三角形仍然没有移动。我在 EDIT 中附上了代码。
  • 它正在移动(jsfiddle.net/tzvdLsxn)。您的问题:您没有使用translation 函数的返回值更新顶点着色器中的 u_move 矩阵。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-29
  • 1970-01-01
  • 2011-12-08
  • 1970-01-01
  • 2015-03-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多