着色器用于预处理弹簧物理模拟的结果异常

9
我正在使用2D采样器在片段着色器中存储和预处理一些位置数据,进行弹簧物理模拟,但得到了非常奇怪的结果。如果我从16个分别定位的弹簧(从一个不可见锚点发出的不可见弹簧末端的点)开始,可视化最终将得到8对,每对都悬挂在相同的弹簧锚点上。然而,如果我仅使用值运行可视化来放置点,则所有计算每个锚点所需的信息都存在,并且正确显示(当然没有物理效果)。只有当我再次添加弹簧物理效果时,才会出现成对结果。此外,从观察可视化过程中,可以看出配对的锚点值都不是原始的16个锚点值。这里到底发生了什么?(请参见下面的fiddle和星号内联注释。)
(three.js v80)
请查看使用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代码片段:

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:

也许问题与从这些纹理中读取texel的方式有关?可能它正在两个texel之间进行读取,因此得出了由两个弹簧共享的平均位置?这种情况可能吗?如果是这样,我应该在哪里查找并解决它?

1个回答

0

我从未发现我上面问题中小提琴的问题; 然而,我最终找到了我上面使用的THREE.FBOUtils脚本的更新版本 - 现在称为THREE.GPUComputationRenderer。实施后,我的脚本终于起作用了!

对于那些试图解决类似问题的人,这里是使用GPUComputationRenderer替换旧的FBOUtils的新的和改进的fiddle

这里,从脚本文档中,是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 );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接