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

时间:2016-09-14 15:38:50

标签: three.js glsl shader physics

我正在使用2D采样器进行弹簧物理模拟,以便在片段着色器中容纳和预处理某些位置数据,并获得非常奇怪的结果。如果我从16个单独定位的弹簧开始(一个隐形弹簧末端的一个点来自一个看不见的锚),可视化最终会有八对,每对悬挂在同一个弹簧锚点上。但是,如果我只是运行可视化以仅使用tOffsets值来放置点,则计算每个锚点的所有信息都在那里并正确显示(当然,没有物理)。我曾经在弹簧物理学中加入,我最终再次成对。此外,从观察可视化,我可以看出对的锚点值不是原始的16个锚点值。知道这里发生了什么吗? (请参阅下面的小提琴和星号内联评论。)

(three.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:

的片段
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 个答案:

答案 0 :(得分: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 );