目前解决这个问题的方法包括几个部分。我正在使用 EffectComposer 制作渲染场景的多个通道,其中之一 - VelocityPass。它采用当前和以前的模型视图矩阵和投影矩阵并产生两个位置。然后它们都用于计算一个点的速度。
着色器看起来像这样
"void main() {",
"vec2 a = (pos.xy / pos.w) * 0.5 + 0.5;",
"vec2 b = (prevPos.xy / prevPos.w) * 0.5 + 0.5;",
"vec2 oVelocity = a - b;",
"gl_FragColor = vec4(oVelocity, 0.0, 1.);",
"}"
这个决定有几个问题。
Three.js 在将矩阵注入到与对象相关的着色器中具有一定的优势。 SetProgram 闭包的结尾,它位于WebGLRenderer。这就是为什么我使用了整个渲染器文件,将渲染器重命名为 THREE.MySuperDuperWebGLRenderer 并在其中添加了几行代码:
访问闭包的闭包,在用户空间中定义:
function materialPerObjectSetup(material, object){
if( material.customUniformUpdate ){
material.customUniformUpdate( object, material, _gl ); // Yes, I had to pass it...
}
}
并在renderBuffer 和renderBufferDirect 中调用它;
var program = setProgram( camera, lights, fog, material, object );
materialPerObjectSetup(material, object);
现在 - 用户空间部分:
velocityMat = new THREE.ShaderMaterial( THREE.VelocityShader );
velocityMat.customUniformUpdate = function(obj, mat, _gl){
// console.log("gotcha");
var new_m = obj.matrixWorld;
var p_uniforms = mat.program.uniforms;
var mvMatrix = camera.matrixWorldInverse.clone().multiplyMatrices(camera.matrixWorldInverse, obj._oldMatrix );
_gl.uniformMatrix4fv( p_uniforms.prevModelViewMatrix, false, mvMatrix.elements );
_gl.uniformMatrix4fv( p_uniforms.prevProjectionMatrix, false, camera.projectionMatrix.elements );
obj._pass_complete = true; // Необходимо сохранять состояние старой матрицы пока не отрисуется этот пасс.
// А то матрицы обновляются каждый рендеринг сцены.
}
当我们多次重新渲染场景时需要_pass_complete - 每次重新计算矩阵。这个技巧可以帮助我们保存之前的矩阵,直到我们使用它。
_gl.uniformMatrix4fv 是必需的,因为three.js 在渲染前会为宇宙服务一次。不管我们有多少对象——其他方法将传递给最后一个的着色器modelViewMatrix。发生这种情况是因为我想完全使用VelocityShader 来绘制这个场景。没有其他方法可以让渲染器为对象使用一些替代材料。
作为本说明的最后一点,我在这里放了一个技巧来管理对象的先前矩阵:
THREE.Mesh.prototype._updateMatrixWorld = rotatedObject.updateMatrixWorld;
THREE.Mesh.prototype._pass_complete = true;
Object.defineProperty(THREE.Mesh.prototype, "updateMatrixWorld", {get: function(){
if(this._pass_complete){
this._oldMatrix = this.matrixWorld.clone();
this._pass_complete = false;
}
this._updateMatrixWorld();
return (function(){
});
}})
我相信,可能会有更好的解决方案。但有时我需要仓促行事。而这种猴子的事情可能会发生。