【问题标题】:Three.js specific render-time uniformsThree.js 特定的渲染时制服
【发布时间】:2014-09-22 07:11:37
【问题描述】:

我想根据计算着色器中先前的像素位置来实现每个对象的运动模糊效果。

此技术的第一步是构建移动物体的速度图。此步骤要求将当前帧的投影和模型视图矩阵与前一帧的相同矩阵作为统一变量。

我怎样才能将这些矩阵包含到一些特殊着色器的制服中?我应该以某种方式有解决方案,例如:

 uniforms = {
   some_uniform_var : {type: "m4", value: initialMatrix, getter: function(){
      // `this` points to object
      return this.worldMatrix
   }}
 }

但现在在 THREE.js 中这是不可用的。我们可以做某种猴子补丁,但我找不到最好的方法。

有什么建议吗?

【问题讨论】:

  • 您要传递Matrix4 的数组吗?你可以使用m4v 来做到这一点。只需更新渲染循环内的数组值。
  • 是的,我想要。问题是,我想: 1-将此矩阵传递给某些材料的制服,这将被覆盖材料。 2 - 必须为场景中的每个对象传递此矩阵。 3 - 我不想在用户空间中有特殊的循环来遍历每个对象,当渲染器本身执行它时。
  • 我不明白。尝试提供一个有效的实时示例(即使它循环遍历每个对象)。然后问一个具体的问题。
  • 我会尝试在回答中解释这一点。而且,如果你能给出意见,它会是一个 nie 补丁,或者不是......
  • 嗯...从代码片段来看,很难评论...但是无论如何我只能回答有关three.js的问题-否则我将永远无法完成任何事情。 :-)

标签: three.js


【解决方案1】:

目前解决这个问题的方法包括几个部分。我正在使用 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...

    }

}

并在renderBufferrenderBufferDirect 中调用它;

    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(){
                });


            }})

我相信,可能会有更好的解决方案。但有时我需要仓促行事。而这种猴子的事情可能会发生。

【讨论】:

  • "它采用当前和以前的模型视图矩阵和投影矩阵并产生两个位置。"你能详细说明一下吗? vec4 pos, prevPos 是顶点变换?我不确定这里的问题是什么。如果您无论如何都必须在每个对象中克隆这些矩阵,那么是什么阻止您将它们传递/更新到着色器?
  • 第一个障碍 - 是压倒一切的材料 - 我们为每个对象获取一个材料。有一个制服阵列。渲染序列中的最后一个对象获胜。其次 - 我们无法控制在最合适的时刻将矩阵发送到着色器。通用制服在此之前发送很远,THREE.js 已经对此进行了封装并且不提供任何回调。
  • 你有机会设置一个小提琴吗?或者至少有一些截图?
  • 我什至有一个工作演示。这是一堆“我应该把它扔掉”的代码。 stavenko.github.io/shader-develop.html。基本上你想看到PerObjectBlurShader.jsVelocityPass.jsVelocityShader.jscustomWeGLRenderer.jsshader-develop.html 本身。但在深入研究之前,我会三思而后行……
  • 在探索之前 - 这里有一篇文章可以让您了解所有这些的目的。 john-chapman-graphics.blogspot.co.uk/2013/01/…
猜你喜欢
  • 2012-09-22
  • 2016-07-03
  • 1970-01-01
  • 2018-09-10
  • 1970-01-01
  • 2018-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多