【问题标题】:GLSL Fragment Shader: control color by time passedGLSL Fragment Shader:按时间控制颜色
【发布时间】:2018-07-10 14:05:10
【问题描述】:

我正在尝试编写一个简单的着色器(在 THREE.js 的帮助下),其中颜色会随着时间的推移而更新(从黑色到白色)。

使用示例我正在计算经过的时间,然后使用它来设置我的 gl_FragColor,但是它不起作用:粒子保持黑色,然后在某个时间(大约 10 秒)突然弹出到 100%。

这是我的片段着色器:

precision highp float;

uniform float uTime;
uniform float uStartTime;

void main() {
    float timePassed = (uTime - uStartTime) / 1000.0 * 0.1;

    gl_FragColor = vec4(fract(timePassed), fract(timePassed), fract(timePassed), 1.0);
}

这是我设置材料的方式:

const simulationMaterial = new THREE.ShaderMaterial({
        uniforms: {
            tPositions: { type: 't', value: positionsTexture },
            tOrigins: { type: 't', value: originsTexture },
            tPerlin: { type: 't', value: perlinTexture },
            uTime: { type: 'f', value: 0.0 },
            uStartTime: { type: 'f', value: Date.now() },
        },
        vertexShader: vertexSimulationShader,
        fragmentShader: fragmentSimulationShader,
        side: THREE.DoubleSide,
        transparent: true,
    });

这是我更新制服的方式(循环)

simulationMaterial.needsUpdate = true;
simulationMaterial.uniforms.uTime.value = Date.now();

我的顶点着色器工作正常:

precision highp float;

        uniform vec3 color;
        uniform sampler2D tPositions;

        uniform mat4 modelViewMatrix;
        uniform mat4 projectionMatrix;

        attribute vec2 uv;
        attribute vec3 position;
        attribute vec3 offset;
        attribute vec3 particlePosition;
        attribute vec4 orientationStart;
        attribute vec4 orientationEnd;

        varying vec3 vPosition;
        varying vec3 vColor;

        void main(){
            vPosition = position;
            vec4 orientation = normalize( orientationStart );
            vec3 vcV = cross( orientation.xyz, vPosition );
            vPosition = vcV * ( 2.0 * orientation.w ) + ( cross( orientation.xyz, vcV ) * 2.0 + vPosition );

            vec4 data = texture2D( tPositions, uv );
            vec3 particlePosition = (data.xyz - 0.5) * 1000.0;

            vColor = data.xyz;

            gl_Position = projectionMatrix * modelViewMatrix * vec4(  vPosition + particlePosition, 1.0 );
        }

真的看不出我做错了什么。

【问题讨论】:

  • 一个猜测:乘以 0.1 可能是你得到 10 秒的原因。这相当于除以 10。对于这样的情况,我宁愿定义一个时间常数,该常数将确定转换完成所需的时间。您的问题也可能是 fract() 函数。请记住,您除以 1000.0,因此您的分辨率变为秒。
  • 嘿,乘以 0.1 不是我认为的问题......它不会在 10 秒内突然变为白色......事实上它出现白色的时间似乎没有持续的。毫秒 / 1000 然后 * 0.1 应该使它每 10 秒从黑色变为白色......然后如果它超过 1.0,fract 函数应该使它回到 0.0。 (如果我删除了 fract 函数,或者我用 sin 测试,它也会被破坏)
  • 我也只是尝试使用时间常数方法,它做了同样的事情。
  • 现在,如果我计算 CPU 上经过的时间并将该值作为统一上传,而不是在着色器中计算它,我就可以正常工作了。我想知道 Date.now() 返回的值是否太大/超出范围。
  • 抱歉,您发帖时我正在更新我的评论。我已经包含了 GLSL 文档的链接。希望有帮助!

标签: three.js glsl webgl fragment-shader


【解决方案1】:

着色器的highp float 类型(32 位)不够大,无法准确表示像 Date.now() 这样大的值。事实上,最后一个可以准确表示为 32 位浮点数的整数是 16,777,217,比今天的 Date.now() 小 5 个数量级。也就是说,这个类型不够大,不足以有意义地计算(Date.now()+10) - Date.now())。 Javascript 引擎将数字表示为 64 位浮点数,具有足够精确的算术运算范围。

您自己找到了正确的解决方案 - 在 CPU 上以足够大的类型进行真正的大运算。计算 CPU 上经过的时间,并将其作为统一传递给着色器。

【讨论】:

  • 谢谢!是的,我最终到达了那里……那是艰难的一天! :)
猜你喜欢
  • 1970-01-01
  • 2017-01-13
  • 2019-12-31
  • 2018-01-05
  • 1970-01-01
  • 1970-01-01
  • 2020-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多