当前位置: 首页 > 知识库问答 >
问题:

如果Data纹理不是方形(1:1),则会出现奇怪的行为

益智明
2023-03-14

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

我有两个着色器程序:

  1. 第一个是单个frag着色器,用于为我的程序计算物理量(它写出一个纹理t位置,供第二组着色器读取)。它由三个驱动。js的GPUComputeRenderer脚本(分辨率设置为最大缓冲区的大小。)

可视化是由各种形状的粒子云组成的网格。在着色器程序中,有两种不同大小的纹理:较小大小的纹理包含每个粒子云的信息(每个云一个texel),较大大小的纹理包含所有云中每个粒子的信息(每个粒子一个texel)。两者都有一定数量的未使用的填充物钉在末端,以2的幂填充。

每个粒子大小的纹理(大):tPo的tOffset

每云大小纹理的纹理数(小):tGridPositionsAndSeedst选择因子

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

更新:问题是否与我在第二个着色器程序中放置texel coords以读取着色器的position属性中的tPosition纹理有关?如果是这样的话,也许这个关于位置属性中texel coords的Github问题可能是相关的,尽管我在这里找不到相应的问题/答案。

更新2:我也在研究这是否可能是一个解压对齐问题。想法?

这是三分钟后的布景。js用于第一个着色器程序:

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 };

}

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

   // 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);
   }

这是第二个着色器程序的设置:注意:本节的渲染器是窗口大小的WebGLRenler

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;
}

下面是相应的着色器程序(vert

顶点着色器:

    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
    }

片段着色器:

    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 );
        }
    }

共有1个答案

苍温文
2023-03-14

多亏了这里对我相关问题的回答,我现在知道出了什么问题。问题在于我使用索引数组(1,2,3,4,5...)访问着色器中DataTexture的纹理的方式。

在这个函数中(以及用于较大数据纹理的函数)。。。

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除以缓冲区的高度,uperMotionBufferHeight(它是“垂直”维度)。然而,正如SO Q中所解释的

因此,该函数应修改为。。。

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

我的程序处理square DataTextures(1:1)的原因是,在这种情况下,高度和宽度是相等的,因此我的函数实际上是在错误的行中除以宽度,因为高度=宽度!

 类似资料:
  • 问题内容: 所以我有这个索引 我正在通过轮胎宝石进行搜索 并且我有两个应该匹配的帖子,分别名为“ xyz post”和“ xyz问题”。执行此搜索时,我正确地获得了突出显示的字段 现在这就是事情……一旦我在索引和重新索引中将min_gram更改为1。突出显示的字段开始像这样返回 我根本不明白为什么。 问题答案: 简短答案 您需要检查 映射 并查看是否使用。但是,您仍然需要非常小心自己的查询。 详细

  • 你认为这个表达的结果是什么? 不!!!是15! 现在让我们看看另一个类似的说法: 还是不,现在是10。为什么呢?我不明白。但是等等,还有两个: 最后一点: 那么有人能告诉我们为什么javascript会这样吗?

  • 我有一个简单的平原(正方形),上面有灯光和材料,我想在上面放一个地球纹理。但是什么都没有出现。我检查过,认为它正确加载了RGB数据,所以我的猜测是这一行有问题(数据是*char,图像是BMP24) 这是一个例子。bmp加载功能: 以下是主要和显示功能: 我玩过代码,有时(当我使用int而不是char*时)我会得到一个红色的材料覆盖所有内容,但不知道到底是什么导致了它 更新:必须更改几行才能正常工作

  • 问题内容: 我对为什么该操作有效感到非常困惑。有人可以解释吗? 为了澄清起见,我正在尝试将字符串与变量进行比较。我已经知道要修复可以随便附上in s中的代码 我想知道这是PHP错误,服务器错误还是某种有效的操作。根据此操作 无效 。 编辑: 从头开始,显然它确实提到字符串和0之间的松散比较是正确的。但是我仍然不知道为什么。 编辑2: 我修改了我的问题,为什么值不起作用? 问题答案: 从PHP手册:

  • 我使用的是mongodb(v2.6.7)和mongo(2.6.7)shell客户端。 我正在尝试使用insert和update命令返回的WriteResult对象。 根据mongodocs,如果出现错误,它将返回一个writeResult对象,其中包含writeError子文档。但我无法在shell或mongo的javascript文件中访问此子文档。 下面是我的问题的说明。 我插入一个对象,并获

  • 题目描述 Java 数组扩容问题:实现动态的给数组添加元素效果,实现对数组扩容 原始数组 int[] arr = {1,2,3} 增加的元素 4,直接放在数组的最后 arr = {1,2,3,4} 题目来源及自己的思路 定义 arr1 定义 arr2,比 arr1 的长度长 1 在 arr1 的长度内,把 arr1 的值赋值给 arr2 arr2 的最后一个位置赋值为 4,也就是要加入的数据 因为