Implementing a 32-bit heightmap vertex shader in threejs

帅比萌擦擦* 提交于 2019-12-20 06:57:43

问题


I am attempting to repurpose the heightmap shader example found here into one that will work with 32-bits of precision instead of 8. The work-in-progress code is on github: https://github.com/bgourlie/three_heightmap

The height map is being generated in .NET. The heights are within 0f...200f and converted into a 32-bit color value (Unity's Color struct) using the following method:

private static Color DepthToColor(float height)
{
    var depthBytes = BitConverter.GetBytes(height);
    int enc = BitConverter.ToInt32(depthBytes, 0);
    return new Color((enc >> 24 & 255)/255f, (enc >> 16 & 255)/255f, (enc >> 8 & 255)/255f,
            (enc & 255)/255f);
}

The color data is encoded as a png, with the result looking like this:

The vertex shader is taking this image data and coverting the RBGA values back to the original height value (using the technique answered in my question here):

uniform sampler2D bumpTexture; // defined in heightmap.js
varying float vAmount;
varying vec2 vUV;

void main()
{
  vUV = uv;
  vec4 bumpData = texture2D( bumpTexture, uv );
  vAmount = dot(bumpData, vec4(1.0, 255.0, 65025.0, 16581375.0));
  // Uncomment to see a "flatter" version
  //vAmount = dot(bumpData, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/160581375.0));

  // move the position along the normal
  vec3 newPosition = position + normal * vAmount;
  gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}

The result is definitely messed up:

I can make it flatter by changing this line:

vAmount = dot(bumpData, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/16581375.0));

This will give me a much flatter image, which at least shows a nice outline of the generated terrain, but with an almost entirely flat plane (there is slight, albeit unnoticeable variation):

I assume I'm doing a few things wrong, I just don't know what. I'm not sure if I'm encoding the original float correctly. I'm not sure if I'm decoding it correctly in the vertex shader (the value I'm getting is certainly outside the range of 0...200). I'm also not very experienced in 3d graphics in general. So any pointers as to what I'm doing wrong, or generally how to achieve this would be greatly appreciated.

Again, the self contained work-in-progress code can be found here: https://github.com/bgourlie/three_heightmap


回答1:


Your colour:

return new Color((enc >> 24 & 255)/255f, (enc >> 16 & 255)/255f, (enc >> 8 & 255)/255f,
        (enc & 255)/255f);

... contains the most significant byte of enc in r, the second most significant in g, etc.

This:

vAmount = dot(bumpData, vec4(1.0, 255.0, 65025.0, 160581375.0));

builds vAmount with r in the least significant byte, g in the next-least significant, etc (though the multiplicands should be 256, 65536, etc*). So the bytes are in the incorrect order. The flatter version:

vAmount = dot(bumpData, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/160581375.0));

gets the bytes in the correct order but scales the output values into the range [0.0, 1.0], which is probably why it looks essentially flat.

So switch the order of encoding or of decoding the bytes and pick an appropriate scale.

(*) think about it this way: the smallest number that can go on any channel is 1.0 / 255.0. The least significant channel will be in the range [0, 1.0] — from 0 / 255.0 to 255.0 / 255.0. You want to scale the next channel so that its smallest value is the next thing on that scale. So its smallest value should be 256 / 255.0. So you need to turn 1.0 / 255.0 into 256.0 / 255.0. You achieve that by multiplying by 256, not by 255.




回答2:


If you encode a wide integer into the components of a RGBA vector it's essential that you turn off filtering so that no interpolation happens between the values. Also OpenGL may internally convert to a different format, but that should only reduce your sample depth.



来源:https://stackoverflow.com/questions/28663001/implementing-a-32-bit-heightmap-vertex-shader-in-threejs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!