1

我正在尝试在 WebGL 中使用 3D 纹理,但由于它目前不受本地支持,因此我必须使用 2D 图像的技巧。它由 64 张图片组成,每张图片大小为 64px x 64px(总共 64x4096)。我想发布一个链接,但我在 SO 上没有足够的 xp(真的吗?),你仍然可以在下面的小提琴中找到文件 url。

我使用了gman以及我自己(最近的邻居)的解决方案。在这两种情况下,当我使用倾斜投影 ( capture )时,我都会遇到灰色条纹伪影的奇怪渲染问题。

当投影倾斜时,条纹/短划线似乎出现在切片之间,并且根据相机位置,它们不会以相同的频率出现。这就是为什么我在考虑渲染问题而不是采样问题。

有谁知道如何摆脱这些文物?是否有一些内置的 OpenGL ES 东西可以启用/禁用?

这是着色器代码:

<!-- FRAGMENT SHADER -->
<script id="fragment_shader1_custom3" type="x-shader/x-fragment">

uniform sampler2D texture;
uniform float imageIndex;
varying vec4 worldCoord;
varying vec2 vUv;

// tex is a texture with each slice of the cube placed in grid in a texture.
// texCoord is a 3d texture coord
// size is the size if the cube in pixels.
// slicesPerRow is how many slices there are across the texture
// numRows is the number of rows of slices

vec2 computeSliceOffset(float slice, float slicesPerRow, vec2 sliceSize) {
  return sliceSize * vec2(mod(slice, slicesPerRow),
  floor(slice / slicesPerRow));
}

vec4 sampleAs3DTexture(sampler2D tex, vec3 texCoord, float size, float numRows, float slicesPerRow){

  float slice   = texCoord.z * size;
  float sliceZ  = floor(slice);                         // slice we need
  float zOffset = fract(slice);                         // dist between slices

  vec2 sliceSize = vec2(1.0 / slicesPerRow,             // u space of 1 slice
    1.0 / numRows);                 // v space of 1 slice

  vec2 slice0Offset = computeSliceOffset(sliceZ, slicesPerRow, sliceSize);
  vec2 slice1Offset = computeSliceOffset(sliceZ + 1.0, slicesPerRow, sliceSize);

  vec2 slicePixelSize = sliceSize / size;               // space of 1 pixel
  vec2 sliceInnerSize = slicePixelSize * (size - 1.0);  // space of size pixels

  vec2 uv = slicePixelSize * 0.5 + texCoord.xy * sliceInnerSize;
  vec4 slice0Color = texture2D(tex, slice0Offset + uv);
  vec4 slice1Color = texture2D(tex, slice1Offset + uv);
  return mix(slice0Color, slice1Color, zOffset);
}


void main( void ) {
  // the position within the shader
  vec2 shaderPos = vUv;

  // if outside the texture cube, use a yellow color
  if(worldCoord.x < 0.0 || worldCoord.x >= 1.0 || worldCoord.y < 0.0 || worldCoord.y >= 1.0 || worldCoord.z < 0.0 || worldCoord.z >= 1.0){
    gl_FragColor = vec4(1.0, 1.0 , 0.0, 1.0);
  }else{

    vec3 chunkPosition = vec3(worldCoord.x, worldCoord.y, worldCoord.z);

    // 63.0 instead of 64.0 to avoid a edge situation
    gl_FragColor = sampleAs3DTexture(texture, chunkPosition, 63.0, 64.0, 1.0);

  }
}
</script> <!-- END FRAGMENT SHADER -->



<!-- VERTEX SHADER -->
<script id="vertexShader_custom1" type="x-shader/x-vertex">
varying vec2 vUv;
varying vec4 worldCoord;

void main()
{
  vUv = uv;
  vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
  gl_Position = projectionMatrix * mvPosition;
  worldCoord = modelMatrix * vec4( position, 1.0 );
}
</script> <!-- END VERTEX SHADER -->

这是小提琴

请注意,我使用 ThreeJS。谢谢你的帮助。

4

1 回答 1

1

As you found by yourself, the solution was to set texture.minFilter = THREE.NearestFilter after loading the texture with THREE.TextureLoader() in your js code (for this reason, please append the js code in your question, this may help a future user that would step on this question on stackoverflow).

Now an explanation of the stripes: when your pixel is close to one of the planes where you change slice, the variable sliceZ jumps. You get in the situation where the pixel covers more than one texel. Note that part of the pixel is at some v coordinate, and part of the pixel is at a v coordinate that is bigger by a quantity that corresponds to 64 pixels of the texture (to get to the image below)/ My guess is that the hidden machinery believes that your pixel covers a v-span of 64 texture pixels and thus takes the average value of those pixels (that has been pre-computed by the default mip-map setting in .minFilter).

于 2016-10-25T20:05:35.330 回答