使用Full.js中的FBO / RenderTarget进行GLSL uv查找和精确

时间:2017-10-08 18:34:02

标签: three.js glsl webgl shader gpgpu

我的应用程序是用Javascript + Three.js / WebGL + GLSL编写的。我有200条曲线,每条曲线由85个点组成。要为曲线设置动画,我添加一个新点并删除最后一个。 所以我制作了一个positions着色器,用于将新位置存储到纹理(1)和lines着色器上,该着色器将所有曲线的位置写入另一个纹理(2)。 目标是将纹理用作数组:我知道一行的第一个和最后一个索引,因此我需要将这些索引转换为uv坐标。

我使用FBOHelper来调试FBO。

1)此1D纹理包含每条曲线的新点(总共200个):positionTexture

enter image description here

2)这些是200条曲线,所有点都是一个接一个:linesTexture

enter image description here

黑色部分是这里的BUG。那些纹素不应该是黑色的。 它是如何工作的:在每一帧,着色器为positionTexture中的每一行查找新点并相应地更新linesTextures,并使用for循环:

#define LINES_COUNT = 200
#define LINE_POINTS = 85 // with 100 it works!!!

// Then in main()

vec2 uv = gl_FragCoord.xy / resolution.xy;

for (float i = 0.0; i < LINES_COUNT; i += 1.0) {
    float startIdx = i * LINE_POINTS; // line start index
    float endIdx = beginIdx + LINE_POINTS - 1.0; // line end index
    vec2 lastCell = getUVfromIndex(endIdx); // last uv coordinate reserved for current line

if (match(lastCell, uv)) {
      pos = texture2D( positionTexture, vec2((i / LINES_COUNT) + minFloat, 0.0)).xyz;
    } else if (index >= startIdx && index < endIdx) {
      pos = texture2D( lineTexture, getNextUV(uv) ).xyz;
    }
  }

这很有效,但是当我有很多行(150+)时,它有点小问题:可能是一个精确问题。我不确定我写的用于查找纹理的函数是否正确。我编写了像getNextUV(uv)这样的函数来从下一个索引(转换为uv坐标)获取值并复制到前一个。或者match(xy, uv)知道当前片段是否是我想要的纹素。

我虽然可以简单地使用经典公式:

index = uv.y * width + uv.x

但它比那更复杂。例如match()

// Wether a point XY is within a UV coordinate
float size = 132.0; // width and height of texture
float unit = 1.0 / size;
float minFloat = unit / size;

bool match(vec2 point, vec2 uv) {
    vec2 p = point;

    float x = floor(p.x / unit) * unit;
    float y = floor(p.y / unit) * unit;

    return x <= uv.x && x + unit > uv.x && y <= uv.y && y + unit > uv.y;
}

getUVfromIndex()

vec2 getUVfromIndex(float index) {
  float row = floor(index / size); // Example: 83.56 / 10 = 8
  float col = index - (row * size); // Example: 83.56 - (8 * 10) = 3.56
  col = col / size + minFloat; // u = 0.357
  row = row / size + minFloat; // v = 0.81

  return vec2(col, row);
}

有人可以通过从uv值获取index坐标来解释在纹理中查找值的最有效方法是什么?

1 个答案:

答案 0 :(得分:2)

纹理坐标来自像素的边缘而不是中心,因此计算UV坐标的公式需要

 u = (xPixelCoord + .5) / widthOfTextureInPixels;
 v = (yPixelCoord + .5) / heightOfTextureInPixels;

所以我猜你想要getUVfromIndex

uniform vec2 sizeOfTexture;   // allow texture to be any size
vec2 getUVfromIndex(float index) {
  float widthOfTexture = sizeOfTexture.x;
  float col = mod(index, widthOfTexture);
  float row = floor(index / widthOfTexture);

  return (vec2(col, row) + .5) / sizeOfTexture;
}

或者,based on some other experience with math issues in shaders您可能需要捏造索引

uniform vec2 sizeOfTexture;   // allow texture to be any size
vec2 getUVfromIndex(float index) {
  float fudgedIndex = index + 0.1;
  float widthOfTexture = sizeOfTexture.x;
  float col = mod(fudgedIndex, widthOfTexture);
  float row = floor(fudgedIndex / widthOfTexture);

  return (vec2(col, row) + .5) / sizeOfTexture;
}

如果您使用的是WebGL2,则可以使用texelFetch获取整数像素坐标以获取纹理中的值