【问题标题】:How to handle big numbers in WebGL GLSL shaders?如何处理 WebGL GLSL 着色器中的大数字?
【发布时间】:2018-06-05 19:13:13
【问题描述】:

如何在 GLSL 中处理大数字,例如下面的数字?

我正在提供一个带有Date.now() 作为制服的着色器,它被描述为:

Date.now() 方法返回自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的毫秒数。 ——MDN

例如,1514678400000 是一年中的最后一天。

将此值传递给我的ShaderMaterial 不会发生太多事情,除非我将值缩小很多。

具体来说,这是行为似乎与我的预期不同的部分,它将最后 2500 毫秒映射到 0-1 范围内的值:

JavaScript: ( Date.now() % 2500 ) / 2500

GLSL: mod( time, 2500.0 ) / 2500.0

我更愿意在 GPU 上进行这些计算,但不确定我应该如何处理?

下面是一个说明问题的小场景:

const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 )
const renderer = new THREE.WebGLRenderer()

renderer.setSize( window.innerWidth, window.innerHeight )
camera.position.z = 0.5

document.body.appendChild( renderer.domElement )

const checkbox = document.getElementById( "toggle" )

const geo = new THREE.PlaneGeometry( 1, 1 )
const mat = new THREE.ShaderMaterial({
  vertexShader: `
    void main() {
      gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    }
  `,
  fragmentShader: `
    uniform bool check;
    uniform float time;
    
    const float TAU = 6.2831;
    
    void main() {
      float fColor;
      
      check 
        ? fColor = ( sin( ( time * TAU ) ) + 1.0 ) / 2.0
        : fColor = ( sin( ( ( mod( time, 2500.0 ) / 2500.0 ) * TAU ) ) + 1.0 ) / 2.0;
        
      gl_FragColor = vec4( 1.0, fColor, 1.0, 1.0 );
    }
  `,
  uniforms: {
    "check": { value: false },
    "time": { value: 1.0 },
  },
})

const plane = new THREE.Mesh( geo, mat )
scene.add( plane )

const animate = function() {
  requestAnimationFrame( animate )

  if ( checkbox.checked ) {
    plane.material.uniforms.check.value = true
    plane.material.uniforms.time.value = ( Date.now() % 2500 ) / 2500
  } else {
    plane.material.uniforms.check.value = false
    plane.material.uniforms.time.value = Date.now()
  }

  renderer.render( scene, camera )
}

animate()
body {
  margin: 0;
}

canvas {
  width: 100%;
  height: 100%;
}

#config {
  position: absolute;
  color: #fff;
  cursor: pointer;
  user-select: none;
  font: bold 1em/1.5 sans-serif;
  padding: 1em;
}

#config label,
#config input {
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.js"></script>
<div id="config">
  <input id="toggle" type="checkbox">
  <label for="toggle">Use JavaScript</label>
</div>

【问题讨论】:

    标签: javascript three.js glsl webgl


    【解决方案1】:

    我正在使用 Date.now() 提供着色器

    它会在着色器中产生不可预测的东西,尤其是当您使用三角函数时,例如sin()cos() 等。原因是您将毫秒作为一个大整数传递。这就是为什么你必须将它除以 1000 以使它们成为浮点数,即将毫秒转换为秒。

    所以,划分是一种方法。另一种是使用THREE.Clock() 及其.getDelta() 方法。看一下代码sn-p。

    const scene = new THREE.Scene()
    const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 )
    const renderer = new THREE.WebGLRenderer()
    
    renderer.setSize( window.innerWidth, window.innerHeight )
    camera.position.z = 0.5
    
    document.body.appendChild( renderer.domElement )
    
    
    const geo = new THREE.PlaneGeometry( 1, 1 )
    const mat = new THREE.ShaderMaterial({
      vertexShader: `
        void main() {
          gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        }
      `,
      fragmentShader: `
        uniform bool check;
        uniform float time;
        
        const float TAU = 6.2831;
        
        void main() {
          float fColor;
          
          fColor = ( sin( ( time * TAU ) ) + 1.0 ) / 2.0;
            
          gl_FragColor = vec4( 1.0, fColor, 1.0, 1.0 );
        }
      `,
      uniforms: {
        "check": { value: false },
        "time": { value: 1.0 },
      },
    })
    
    const plane = new THREE.Mesh( geo, mat )
    scene.add( plane )
    
    var clock = new THREE.Clock();
    var time = 0;
    
    const animate = function() {
      requestAnimationFrame( animate )
      
      time += clock.getDelta();
    
      plane.material.uniforms.time.value = time * 0.4; // make it 2.5 times slower
    
      renderer.render( scene, camera )
    }
    
    animate()
    body {
      margin: 0;
    }
    
    canvas {
      width: 100%;
      height: 100%;
    }
    
    #config {
      position: absolute;
      color: #fff;
      cursor: pointer;
      user-select: none;
      font: bold 1em/1.5 sans-serif;
      padding: 1em;
    }
    
    #config label,
    #config input {
      cursor: pointer;
    }
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.js"&gt;&lt;/script&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多