【问题标题】:GLSL uv lookup and precision with FBO / RenderTarget in Three.jsGLSL uv 查找和精度与 Three.js 中的 FBO / RenderTarget
【发布时间】:2018-03-19 23:11:48
【问题描述】:

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

我使用FBOHelper 来调试 FBO。

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

2) 这些是 200 条曲线,以及它们的所有点,一个接一个:linesTexture

黑色部分是这里的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);
}

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

【问题讨论】:

    标签: three.js glsl webgl shader gpgpu


    【解决方案1】:

    纹理坐标来自像素的边缘而不是中心,因此计算 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,它采用整数像素坐标从纹理中获取值

    【讨论】:

    • mod(index % widthOfTexture); 不应该是 mod(index, widthOfTexture); 吗?
    • 非常感谢您的回答,它立即修复了错误案例!我会测试更多,看看其他查找功能是否正常。您认为我在问题中发布的match() 函数有意义吗?
    • 之所以有效,是因为unit1 / sizeOfTexture.x:所以它会检查uv.x 是否在纹素的开头和结尾之间,但我认为这很糟糕。您将如何测试以“匹配”给定的 uv 坐标(来自索引值)与当前 uv?假设您使用 getUVfromIndex 函数获取 uv 坐标
    • 你混淆了 x 和 uv。我们需要测试的是uv(当前片段)是否在两个值之间。有用。也许反过来更清楚:uv.x &gt;= x &amp;&amp; uv.x &lt; x + unit。但它是一样的。我想知道是否有更好的方法,但您似乎没有发现方法错误。
    • 就像我提到的,大脑放屁。出于某种原因,我的大脑一直在另一边签名+ unit ?
    猜你喜欢
    • 2012-05-18
    • 1970-01-01
    • 2014-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-24
    • 2013-11-22
    • 2018-03-25
    相关资源
    最近更新 更多