用于预处理弹簧物理模拟的着色器的奇怪结果
Posted
技术标签:
【中文标题】用于预处理弹簧物理模拟的着色器的奇怪结果【英文标题】:Odd results from shaders used to pre-process spring physics simulation 【发布时间】:2017-01-22 12:03:18 【问题描述】:我正在使用 2D 采样器进行弹簧物理模拟,以容纳和预处理片段着色器中的一些位置数据,并得到非常奇怪的结果。如果我从 16 个单独定位的弹簧开始(一个位于不可见弹簧末端的点,源自一个不可见的锚点),可视化以八对结束,每对都悬挂在同一个弹簧锚点上。但是,如果我只是运行可视化以仅使用 tOffsets
值放置点,则计算每个锚点的所有信息都在那里并正确显示(当然没有物理)。有一次我添加回春季物理学,我最终再次配对。另外,通过观察可视化,我可以看出这些对的锚点值不是原始的 16 个锚点值。知道这里发生了什么吗? (请参阅下面的小提琴和加星标的内联 cmets。)
(三个.js v 80)
在此处查看使用 v79 的 fiddle。
uniform sampler2D tPositions;
uniform sampler2D tOffsets;
varying vec2 vUv;
void main()
float damping = 0.98;
vec4 nowPos = texture2D( tPositions, vUv ).xyzw;
vec4 offsets = texture2D( tOffsets, vUv ).xyzw;
vec2 velocity = vec2(nowPos.z, nowPos.w);
vec2 anchor = vec2( offsets.x, 130.0 );
// Newton's law: F = M * A
float mass = 24.0;
vec2 acceleration = vec2(0.0, 0.0);
// 1. apply gravity's force: **this works fine
vec2 gravity = vec2(0.0, 2.0);
gravity /= mass;
acceleration += gravity;
// 2. apply the spring force ** something goes wrong once I add the spring physics - the springs display in pairs
float restLength = length(yAnchor - offsets.y);
float springConstant = 0.2;
// Vector pointing from anchor to point position
vec2 springForce = vec2(nowPos.x - anchor.x, nowPos.y - anchor.y);
// length of the vector
float distance = length( springForce );
// stretch is the difference between the current distance and restLength
float stretch = distance - restLength;
// Calculate springForce according to Hooke's Law
springForce = normalize( springForce );
springForce *= (1.0 * springConstant * stretch);
springForce /= mass;
acceleration += springForce; // ** If I comment out this line, all points display where expected, and fall according to gravity. If I add it it back in the springs work properly but display in 8 pairs as opposed to 16 independent locations
velocity += acceleration;
velocity *= damping;
vec2 newPosition = vec2(nowPos.x - velocity.x, nowPos.y - velocity.y);
// Write new position out to texture for the next shader
gl_FragColor = vec4(newPosition.x, newPosition.y, velocity.x, velocity.y); // **the pair problem shows up with this line active
// sanity checks with comments:
// gl_FragColor = vec4(newPosition.x, newPosition.y, 0.0, 0.0); // **the pair problem also shows up in this case
// gl_FragColor = vec4( offsets.x, offsets.y, velocity ); // **all points display in the correct position, though no physics
// gl_FragColor = vec4(nowPos.x, nowPos.y, 0.0, 0.0); // **all points display in the correct position, though no physics
更新 1: 问题是否与我的程序的所有部分之间一致的值(rgba,xzyw)的数量有关?我已经在我能想到的任何地方指定了 rgba 值,但也许我错过了某个地方。这是我的 javascript 中的一个 sn-p:
if ( ! renderer.context.getExtension( 'OES_texture_float' ) )
alert( 'OES_texture_float is not :(' );
var width = 4, height = 4;
particles = width * height;
// Start creation of DataTexture
var positions = new Float32Array( particles * 4 );
var offsets = new Float32Array( particles * 4 );
// hardcoded dummy values for the sake of debugging:
var somePositions = [10.885510444641113, -6.274578094482422, 0, 0, -10.12020206451416, 0.8196354508399963, 0, 0, 35.518341064453125, -5.810637474060059, 0, 0, 3.7696402072906494, -3.118760347366333, 0, 0, 9.090447425842285, -7.851400375366211, 0, 0, -32.53229522705078, -26.4628849029541, 0, 0, 32.3623046875, 22.746187210083008, 0, 0, 7.844726085662842, -15.305091857910156, 0, 0, -32.65345001220703, 22.251712799072266, 0, 0, -25.811357498168945, 32.4153938293457, 0, 0, -28.263731002807617, -31.015430450439453, 0, 0, 2.0903847217559814, 1.7632032632827759, 0, 0, -4.471604347229004, 8.995194435119629, 0, 0, -12.317420959472656, 12.19576358795166, 0, 0, 36.77312469482422, -14.580523490905762, 0, 0, 36.447078704833984, -16.085195541381836, 0, 0];
for ( var i = 0, i4 = 0; i < particles; i ++, i4 +=4 )
positions[ i4 + 0 ] = somePositions[ i4 + 0 ]; // x
positions[ i4 + 1 ] = somePositions[ i4 + 1 ]; // y
positions[ i4 + 2 ] = 0.0; // velocity
positions[ i4 + 3 ] = 0.0; // velocity
offsets[ i4 + 0 ] = positions[ i4 + 0 ];// - gridPositions[ i4 + 0 ]; // width offset
offsets[ i4 + 1 ] = positions[ i4 + 1 ];// - gridPositions[ i4 + 1 ]; // height offset
offsets[ i4 + 2 ] = 0; // not used
offsets[ i4 + 3 ] = 0; // not used
positionsTexture = new THREE.DataTexture( positions, width, height, THREE.RGBAFormat, THREE.FloatType );
positionsTexture.minFilter = THREE.NearestFilter;
positionsTexture.magFilter = THREE.NearestFilter;
positionsTexture.needsUpdate = true;
offsetsTexture = new THREE.DataTexture( offsets, width, height, THREE.RGBAFormat, THREE.FloatType );
offsetsTexture.minFilter = THREE.NearestFilter;
offsetsTexture.magFilter = THREE.NearestFilter;
offsetsTexture.needsUpdate = true;
rtTexturePos = new THREE.WebGLRenderTarget(width, height,
wrapS:THREE.RepeatWrapping,
wrapT:THREE.RepeatWrapping,
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
format: THREE.RGBAFormat,
type:THREE.FloatType,
stencilBuffer: false
);
rtTexturePos2 = rtTexturePos.clone();
simulationShader = new THREE.ShaderMaterial(
uniforms:
tPositions: type: "t", value: positionsTexture ,
tOffsets: type: "t", value: offsetsTexture ,
,
vertexShader: document.getElementById('texture_vertex_simulation_shader').textContent,
fragmentShader: document.getElementById('texture_fragment_simulation_shader').textContent
);
fboParticles = new THREE.FBOUtils( width, renderer, simulationShader );
fboParticles.renderToTexture(rtTexturePos, rtTexturePos2);
fboParticles.in = rtTexturePos;
fboParticles.out = rtTexturePos2;
更新 2:
也许问题与如何从这些纹理中读取纹素有关?不知何故,它可能在两个纹素之间读取,因此得出两个弹簧共享的平均位置?这可能吗?如果是这样,我会在哪里解决它?
【问题讨论】:
【参考方案1】:在我上面的问题中,我从来没有发现小提琴的问题;但是,我最终确实找到了我在上面使用的 THREE.FBOUtils 脚本的较新版本 - 现在称为 THREE.GPUComputationRenderer。实施后,我的脚本终于奏效了!
对于那些发现自己试图解决类似问题的人,这里是新的和改进的fiddle,它使用 GPUComputationRenderer 代替旧的 FBOUtils。
这里,来自脚本文档,是 GPUComputationRenderer 的基本用例:
//Initialization...
// Create computation renderer
var gpuCompute = new GPUComputationRenderer( 1024, 1024, renderer );
// Create initial state float textures
var pos0 = gpuCompute.createTexture();
var vel0 = gpuCompute.createTexture();
// and fill in here the texture data...
// Add texture variables
var velVar = gpuCompute.addVariable( "textureVelocity", fragmentShaderVel, pos0 );
var posVar = gpuCompute.addVariable( "texturePosition", fragmentShaderPos, vel0 );
// Add variable dependencies
gpuCompute.setVariableDependencies( velVar, [ velVar, posVar ] );
gpuCompute.setVariableDependencies( posVar, [ velVar, posVar ] );
// Add custom uniforms
velVar.material.uniforms.time = value: 0.0 ;
// Check for completeness
var error = gpuCompute.init();
if ( error !== null )
console.error( error );
// In each frame...
// Compute!
gpuCompute.compute();
// Update texture uniforms in your visualization materials with the gpu renderer output
myMaterial.uniforms.myTexture.value = gpuCompute.getCurrentRenderTarget( posVar ).texture;
// Do your rendering
renderer.render( myScene, myCamera );
【讨论】:
以上是关于用于预处理弹簧物理模拟的着色器的奇怪结果的主要内容,如果未能解决你的问题,请参考以下文章