webgl来自2D图像的3D纹理,但有渲染问题

时间:2016-10-25 15:40:58

标签: three.js textures webgl shader 3d-texture

我正在尝试在WebGL中使用3D纹理,但由于它目前不受原生支持,我不得不使用2D图像技巧。它由64个图像组成,每个图像为64px×64px(总共64x4096)。我想发布一个链接,但我没有足够的x在SO(严重吗?),你仍然可以找到文件网址低于小提琴。

我使用了solution by 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 -->

Here is the fiddle

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

1 个答案:

答案 0 :(得分:1)

正如您自己发现的,解决方案是在您的js代码中使用THREE.TextureLoader()加载纹理后设置texture.minFilter = THREE.NearestFilter(因此,请在您的问题中附加js代码,可以帮助未来的用户在stackoverflow上踩到这个问题。)

现在对条纹的解释:当你的像素接近你改变切片的一个平面时,变量sliceZ会跳跃。你会遇到像素覆盖多个纹素的情况。请注意,像素的一部分位于某个v坐标处,并且像素的一部分位于av坐标处,该坐标大于对应于纹理的64个像素的数量(以获取下面的图像)/我的猜测是隐藏的机械认为你的像素覆盖了64个纹理像素的v-span,因此获取了这些像素的平均值(已经通过.minFilter中的默认mip-map设置预先计算)。