如果DataTextures不是正方形(1:1)

时间:2017-03-14 15:00:25

标签: three.js glsl textures webgl shader

我有一对着色器程序,如果我的DataTextures是方形(1:1),一切都很好,但如果一个或两个是2:1(宽度:高度)比例,行为就会搞砸了。我可以使用未使用的填充程序扩展每个缓冲区,以确保它们始终是方形的,但从长远来看,这似乎是不必要的代价(内存方面),因为两个缓冲区大小中的一个非常大。在这种情况下,有没有办法处理2:1缓冲区?

我有一对着色器程序:

  1. 第一个是用于计算程序物理的单个frag着色器(它写出要由第二组着色器读取的纹理tPositions)。它由Three.js的GPUComputeRenderer脚本驱动(分辨率设置为我最大缓冲区的大小。)
  2. 第二对着色器(vert和frag)使用第一个着色器程序生成的数据纹理tPositions,然后渲染可视化(在窗口大小设置的分辨率)。
  3. 可视化是各种形状的粒子云网格。在着色器程序中,有两种不同尺寸的纹理:较小尺寸的纹理包含每个粒子云的信息(每个云一个纹素),较大尺寸的纹理包含所有云中每个粒子的信息(每个粒子一个纹素) )。两者都有一定数量的未使用的填充物在末端加上,以填充它们的功率为2。

    Texel-per-particle大小纹理(大): tPositionstOffsets

    Texel-per-cloud尺寸纹理(小): tGridPositionsAndSeedstSelectionFactors

    正如我之前所说,问题是当这两个缓冲区大小(大和小)的比例为1:1(宽度:高度)时,程序运行正常;然而,当一个或两个处于2:1(宽度:高度)比率时,行为就是一团糟。是什么原因造成的,我该如何解决?提前谢谢!

    更新:问题可能与我的住房相关,纹理编码器读取第二个着色器程序中着色器的tPosition属性中的position纹理?如果是这样,或许position关于function initComputeRenderer() { textureData = MotifGrid.getBufferData(); gpuCompute = new GPUComputationRenderer( textureData.uPerParticleBufferWidth, textureData.uPerParticleBufferHeight, renderer ); dtPositions = gpuCompute.createTexture(); dtPositions.image.data = textureData.tPositions; offsetsTexture = new THREE.DataTexture( textureData.tOffsets, textureData.uPerParticleBufferWidth, textureData.uPerParticleBufferHeight, THREE.RGBAFormat, THREE.FloatType ); offsetsTexture.needsUpdate = true; gridPositionsAndSeedsTexture = new THREE.DataTexture( textureData.tGridPositionsAndSeeds, textureData.uPerMotifBufferWidth, textureData.uPerMotifBufferHeight, THREE.RGBAFormat, THREE.FloatType ); gridPositionsAndSeedsTexture.needsUpdate = true; selectionFactorsTexture = new THREE.DataTexture( textureData.tSelectionFactors, textureData.uPerMotifBufferWidth, textureData.uPerMotifBufferHeight, THREE.RGBAFormat, THREE.FloatType ); selectionFactorsTexture.needsUpdate = true; positionVariable = gpuCompute.addVariable( "tPositions", document.getElementById( 'position_fragment_shader' ).textContent, dtPositions ); positionVariable.wrapS = THREE.RepeatWrapping; // repeat wrapping for use only with bit powers: 8x8, 16x16, etc. positionVariable.wrapT = THREE.RepeatWrapping; gpuCompute.setVariableDependencies( positionVariable, [ positionVariable ] ); positionUniforms = positionVariable.material.uniforms; positionUniforms.tOffsets = { type: "t", value: offsetsTexture }; positionUniforms.tGridPositionsAndSeeds = { type: "t", value: gridPositionsAndSeedsTexture }; positionUniforms.tSelectionFactors = { type: "t", value: selectionFactorsTexture }; positionUniforms.uPerMotifBufferWidth = { type : "f", value : textureData.uPerMotifBufferWidth }; positionUniforms.uPerMotifBufferHeight = { type : "f", value : textureData.uPerMotifBufferHeight }; positionUniforms.uTime = { type: "f", value: 0.0 }; positionUniforms.uXOffW = { type: "f", value: 0.5 }; } 属性中的texel坐标可能是相关的,尽管我在SO上找不到相应的问题/答案。

    更新2: 我也在研究这可能是Github issue。想法?

    以下是第一个着色器程序在Three.js中的设置:

       // tPositions is handled by the GPUCompute script
        uniform sampler2D tOffsets; 
        uniform sampler2D tGridPositionsAndSeeds;
        uniform sampler2D tSelectionFactors;
        uniform float uPerMotifBufferWidth;
        uniform float uPerMotifBufferHeight;
        uniform float uTime;
        uniform float uXOffW;
    
        [...skipping a noise function for brevity...]
    
        void main() {
    
            vec2 uv = gl_FragCoord.xy / resolution.xy;
    
            vec4 offsets = texture2D( tOffsets, uv ).xyzw;
            float alphaMass = offsets.z;
            float cellIndex = offsets.w;
    
            if (cellIndex >= 0.0) {
    
                float damping = 0.98;
    
                float texelSizeX = 1.0 / uPerMotifBufferWidth;
                float texelSizeY = 1.0 / uPerMotifBufferHeight;
                vec2 perMotifUV = vec2( mod(cellIndex, uPerMotifBufferWidth)*texelSizeX, floor(cellIndex / uPerMotifBufferHeight)*texelSizeY );
                perMotifUV += vec2(0.5*texelSizeX, 0.5*texelSizeY);
    
                vec4 selectionFactors = texture2D( tSelectionFactors, perMotifUV ).xyzw;
                float swapState = selectionFactors.x;
                vec4 gridPosition = texture2D( tGridPositionsAndSeeds, perMotifUV ).xyzw;
                vec2 noiseSeed = gridPosition.zw;
                vec4 nowPos;
                vec2 velocity;
    
                nowPos = texture2D( tPositions, uv ).xyzw;
                velocity = vec2(nowPos.z, nowPos.w);
    
                if ( swapState == 0.0 ) {
                    nowPos = texture2D( tPositions, uv ).xyzw;
                    velocity = vec2(nowPos.z, nowPos.w);
                } else { // if swapState == 1
                    //nowPos = vec4( -(uTime) + gridPosition.x + offsets.x, gridPosition.y + offsets.y, 0.0, 0.0 );
                    nowPos = vec4( -(uTime) + offsets.x, offsets.y, 0.0, 0.0 );
                    velocity = vec2(0.0, 0.0);
                }
    
                [...skipping the physics for brevity...]
    
                vec2 newPosition = vec2(nowPos.x - velocity.x, nowPos.y - velocity.y);
                // Write new position out
                gl_FragColor = vec4(newPosition.x, newPosition.y, velocity.x, velocity.y);
       }
    

    这是第一个着色器程序(仅用于物理计算的碎片):

    function makePerParticleReferencePositions() {
    
        var positions = new Float32Array( perParticleBufferSize * 3 );
    
        var texelSizeX = 1 / perParticleBufferDimensions.width;
        var texelSizeY = 1 / perParticleBufferDimensions.height;
    
        for ( var j = 0, j3 = 0; j < perParticleBufferSize; j ++, j3 += 3 ) {
    
            positions[ j3 + 0 ] = ( ( j % perParticleBufferDimensions.width ) / perParticleBufferDimensions.width ) + ( 0.5 * texelSizeX );
            positions[ j3 + 1 ] = ( Math.floor( j / perParticleBufferDimensions.height ) / perParticleBufferDimensions.height ) + ( 0.5 * texelSizeY );
            positions[ j3 + 2 ] = j * 0.0001; // this is the real z value for the particle display
    
        }
    
        return positions;
    }
    
    var positions = makePerParticleReferencePositions();
    
    ...
    
    // Add attributes to the BufferGeometry: 
    gridOfMotifs.geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
    gridOfMotifs.geometry.addAttribute( 'aTextureIndex', new THREE.BufferAttribute( motifGridAttributes.aTextureIndex, 1 ) );
    gridOfMotifs.geometry.addAttribute( 'aAlpha', new THREE.BufferAttribute( motifGridAttributes.aAlpha, 1 ) );
    gridOfMotifs.geometry.addAttribute( 'aCellIndex', new THREE.BufferAttribute(
            motifGridAttributes.aCellIndex, 1 ) );
    
    uniformValues = {};
    uniformValues.tSelectionFactors = motifGridAttributes.tSelectionFactors;
    uniformValues.uPerMotifBufferWidth = motifGridAttributes.uPerMotifBufferWidth;
    uniformValues.uPerMotifBufferHeight = motifGridAttributes.uPerMotifBufferHeight;
    
    gridOfMotifs.geometry.computeBoundingSphere();
    
    ...
    
    function makeCustomUniforms( uniformValues ) {
    
        selectionFactorsTexture = new THREE.DataTexture( uniformValues.tSelectionFactors, uniformValues.uPerMotifBufferWidth, uniformValues.uPerMotifBufferHeight, THREE.RGBAFormat, THREE.FloatType );
        selectionFactorsTexture.needsUpdate = true;
    
        var customUniforms = {
            tPositions : { type : "t", value : null },
            tSelectionFactors : { type : "t", value : selectionFactorsTexture },
            uPerMotifBufferWidth : { type : "f", value : uniformValues.uPerMotifBufferWidth },
            uPerMotifBufferHeight : { type : "f", value : uniformValues.uPerMotifBufferHeight },
            uTextureSheet : { type : "t", value : texture }, // this is a sprite sheet of all 10 strokes
            uPointSize : { type : "f", value : 18.0 }, // the radius of a point in WebGL units, e.g. 30.0
            // Coords for the hatch textures:
            uTextureCoordSizeX : { type : "f", value : 1.0 / numTexturesInSheet },
            uTextureCoordSizeY : { type : "f", value : 1.0 }, // the size of a texture in the texture map ( they're square, thus only one value )
        };
        return customUniforms;
    }
    

    以下是第二个着色器程序的设置: 注意:此部分的渲染器是窗口大小为

    的WebGLRenderer
        uniform sampler2D tPositions;
        uniform sampler2D tSelectionFactors;
        uniform float uPerMotifBufferWidth;
        uniform float uPerMotifBufferHeight;
        uniform sampler2D uTextureSheet;
        uniform float uPointSize; // the radius size of the point in WebGL units, e.g. "30.0"
        uniform float uTextureCoordSizeX; // vertical dimension of each texture given the full side = 1
        uniform float uTextureCoordSizeY; // horizontal dimension of each texture given the full side = 1
    
        attribute float aTextureIndex;
        attribute float aAlpha;
        attribute float aCellIndex;
    
        varying float vCellIndex;
        varying vec2 vTextureCoords;
        varying vec2 vTextureSize;
        varying float vAlpha;
        varying vec3 vColor;
        varying float vDensity;
    
       [...skipping noise function for brevity...]
    
        void main() {
    
            vec4 tmpPos = texture2D( tPositions, position.xy );
            vec2 pos = tmpPos.xy;
            vec2 vel = tmpPos.zw;
    
            vCellIndex = aCellIndex;
    
            if (aCellIndex >= 0.0) { // buffer filler cell indexes are -1
    
                float texelSizeX = 1.0 / uPerMotifBufferWidth;
                float texelSizeY = 1.0 / uPerMotifBufferHeight;
                vec2 perMotifUV = vec2( mod(aCellIndex, uPerMotifBufferWidth)*texelSizeX, floor(aCellIndex / uPerMotifBufferHeight)*texelSizeY );
                perMotifUV += vec2(0.5*texelSizeX, 0.5*texelSizeY);
    
                vec4 selectionFactors = texture2D( tSelectionFactors, perMotifUV ).xyzw;
                float aSelectedMotif = selectionFactors.x;
                float aColor = selectionFactors.y;
                float fadeFactor = selectionFactors.z;
    
                vTextureCoords = vec2( aTextureIndex * uTextureCoordSizeX, 0 );
                vTextureSize = vec2( uTextureCoordSizeX, uTextureCoordSizeY );
    
                vAlpha = aAlpha * fadeFactor;
                vDensity = vel.x + vel.y;
                vAlpha *= abs( vDensity * 3.0 );
    
                vColor = vec3( 1.0, aColor, 1.0 ); // set RGB color associated to vertex; use later in fragment shader.
    
                gl_PointSize = uPointSize;
    
            } else { // if this is a filler cell index (-1)
                vAlpha = 0.0;
                vDensity = 0.0;
                vColor = vec3(0.0, 0.0, 0.0);
                gl_PointSize = 0.0;
            }
            gl_Position = projectionMatrix * modelViewMatrix * vec4( pos.x, pos.y, position.z, 1.0 ); // position holds the real z value. The z value of "color" is a component of velocity
        }
    

    以下是相应的着色器程序(vert&amp; frag):

    顶点着色器:

        uniform sampler2D tPositions;
        uniform sampler2D uTextureSheet;
    
        varying float vCellIndex;
        varying vec2 vTextureCoords;
        varying vec2 vTextureSize;
        varying float vAlpha;
        varying vec3 vColor;
        varying float vDensity;  
    
        void main() {
            gl_FragColor = vec4( vColor, vAlpha );
    
            if (vCellIndex >= 0.0) { // only render out the texture if this point is not a buffer filler
                vec2 realTexCoord = vTextureCoords + ( gl_PointCoord * vTextureSize );
                gl_FragColor = gl_FragColor * texture2D( uTextureSheet, realTexCoord );
            }
        }
    

    片段着色器:

    DataTextures

    预期行为:我可以通过强制所有DataTextures为1:1来实现此目的 unpack alignment issue

    奇怪的行为:当较小的DataTextures为2:1时,下图中右上角的完美水平云会形成物理效果。当较大的import Moment as 'moment'; 为2:1时,网格会偏斜,并且云似乎缺少部分(如下所示)。当小和大纹理都是2:1时,两种奇怪的行为都会发生(这是下图中的情况)。 expected behavior - shaped particle clouds correctly assembled and displayed in an offset grid

1 个答案:

答案 0 :(得分:0)

感谢我对相关问题here的回答,我现在知道出了什么问题。问题在于我使用索引数组(1,2,3,4,5 ......)访问着色器中的DataTextures'纹素。

在此函数中(以及用于较大DataTextures的函数)...

float texelSizeX = 1.0 / uPerMotifBufferWidth;
float texelSizeY = 1.0 / uPerMotifBufferHeight;
vec2 perMotifUV = vec2( 
    mod(aCellIndex, uPerMotifBufferWidth)*texelSizeX, 
    floor(aCellIndex / uPerMotifBufferHeight)*texelSizeY );
perMotifUV += vec2(0.5*texelSizeX, 0.5*texelSizeY);

...我假设为了为我的自定义uv y创建perMotifUV值,我需要将aCellIndex除以缓冲区的高度,{ {1}}(它是“垂直”维度)。然而,正如SO Q&amp; A here中所解释的那样,索引当然应该除以缓冲区的宽度,然后告诉你你有多少行!

因此,该功能应修改为......

uPerMotifBufferHeight

我的程序在方形DataTextures(1:1)上工作的原因是在这种情况下高度和宽度相等,所以我的函数在不正确的行中有效地除以宽度,因为height = width!

相关问题