简体   繁体   English

如何处理WebGL GLSL着色器中的大数字?

[英]How to handle big numbers in WebGL GLSL shaders?

How can I handle big numbers, such as the one below, in GLSL? 我如何处理GLSL中的大数字,例如下面的数字?

I am supplying a shader with Date.now() as a uniform, which is described as: 我提供了一个带有Date.now()作为制服的着色器,其描述如下:

The Date.now() method returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC. Date.now()方法返回自1970年1月1日00:00:00 UTC以来经过的毫秒数。 MDN - MDN

For example, 1514678400000 being the last day of the year. 例如, 1514678400000是一年中的最后一天。

Passing this value to my ShaderMaterial results in not much happening, unless I scale the value down by a lot. 将此值传递给我的ShaderMaterial导致不会发生太多事情,除非我将该值大幅缩减。

Specifically, this is the part where the behavior seems to diverge from my expectation of it mapping the last 2500 ms to a value ranging from 0–1: 具体来说,这是行为似乎与我对将最后2500毫秒映射到0-1范围内的值的期望不同的部分:

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

GLSL: mod( time, 2500.0 ) / 2500.0 GLSL: mod( time, 2500.0 ) / 2500.0

I would prefer to do these calculations on the GPU instead, but am unsure as to how I should approach this? 我宁愿在GPU上进行这些计算,但我不确定如何处理这个问题?

Below is a small scene which illustrates the issue: 下面是一个小场景,说明了这个问题:

 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> 

I am supplying a shader with Date.now() 我正在使用Date.now()提供着色器

It produces unpredictable things in shaders, especially when you use trigonometrical functions, like sin() , cos() and so on. 它在着色器中产生不可预测的东西,特别是当你使用三角函数时,比如sin()cos()等。 The reason is that you pass milliseconds as a big integer number. 原因是您将毫秒作为一个大整数传递。 That's why you have to divide it by 1000 to make them a float number, ie transform milliseconds to seconds. 这就是为什么你必须将它除以1000以使它们成为一个浮点数,即将毫秒转换为秒。

So, dividing is one appoach. 所以,划分是一个适用。 Another one is to use THREE.Clock() and its .getDelta() method. 另一个是使用THREE.Clock()及其.getDelta()方法。 Have a look at the code snippet. 看看代码片段。

 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; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.js"></script> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM