Jump to content

[SOLVED] - Dear Dave, Need Your Help


MackeyK24
 Share

Recommended Posts

Thank you soon much guys... Shout out to @Deltakosh and @Sebavan for all your help. I decided NOT to go with altering the Unity Raw Heights At all... Il keep using the really dark greyscale images the way unity intended its API to work... which it great, then we can come in and USE the raw height into to not only generate a heightmap (only need enough detail in it for a collision mesh anyways) but a a full resolution terrain mesh (with option to scale down).

If you guys got a little time check out where I'm out so far:

U3D - BabylonJS - Terrain and Navigation Concepts

Link to comment
Share on other sites

If you export it in picture, you are altering it due to the storage precision (half float precision to only 1 byte due to gray-scale picture).

If you do not want to renormalize the data (which would still have issue if the terrain deta between min and max is big) I can write the code for you to pack unpack the full data like in unity without loss of precision ? (It is really not much and the quality would be much better)

Link to comment
Share on other sites

@Sebavan Here is the current code for generating the height map... You tweak that guy as you see fit and send it back and ill throw it in the toolkit:

 

float minheight = float.MaxValue;
float maxheight = float.MinValue;
int hwidth = terrain.terrainData.heightmapWidth;
int hheight = terrain.terrainData.heightmapHeight;
float[,] rawHeights = terrain.terrainData.GetHeights(0, 0, hwidth, hheight);
Texture2D heightMap = new Texture2D(hwidth, hheight, TextureFormat.ARGB32, false);

for (int y=0; y < hheight; y++) {
    for (int x=0; x < hwidth; x++) {
        float inverted = rawHeights[y, x];
        minheight = Mathf.Min(minheight, inverted);
        maxheight = Mathf.Max(maxheight, inverted);
    }
}

for (int y=0; y < hheight; y++) {
    for (int x=0; x < hwidth; x++) {
        float inverted = rawHeights[y, x];

        // Pack/Unpack Code Here I Guess???

        if (generator.heightmapStrength > 0) {
            float threadhold = minheight + generator.floorThreashold;
            if (inverted > threadhold) {
                inverted += (generator.heightmapStrength / 100.0f);
            }
        }
        Color pixel = new Color(inverted, inverted, inverted, 1.0f);
        heightMap.SetPixel(x, y, pixel);
    }
}
heightMap.Apply();

 

 

Link to comment
Share on other sites

IMHO - it doesn't make sense if you are walking on this terrain. The distance is calculated from a single point on the mesh (usually the center of the object). It will not react as you expect it to.

You could, however, create many meshes, instead of subdivisions, and set LOD levels for them. So the single terrain is built from many meshes. It will work well then.

Link to comment
Share on other sites

So you can generate 4 bytes from float in csharp using the BitConverter:

       byte[] byteArray = BitConverter.GetBytes(inverted); (This respects the machine endianess but it would be fine for unity users and bytes are 0 - 255)

Then you can put this respectively in the r, g, b, and a channel of your texture. Please note that your texture would not be editable by hand anymore. In the createTerrainFromHeightMap code you can easily unpack this way:

        var buffer = new ArrayBuffer(4);
        var intView = new Uint8Array(buffer);
        var floatView = new Float32Array(buffer);

        intView[0] = r; // r, g, b, a must be in bytes here 0 - 255.
        intView[1] = g;
        intView[2] = b;
        intView[3] = a;

        var heightUnpack = floatView[0];

 

 

Link to comment
Share on other sites

@Sebavan If i am understanding you correctly ... You mean NOT to create an image for the heightmap... But instead encode all the bytes for the height (4 bytes per inverted pixel value) into some kind of transport for metadata (prob just array of total bytes). Then on the javascript client side decode my height map bytes and create a custom version of createGroundFromHeightMap that will use my raw height bytes instead of heights from and image ???

 

Link to comment
Share on other sites

@Sebavan Here is my "Packing" code:

for (int y=0; y < hheight; y++) {
    for (int x=0; x < hwidth; x++) {
        float inverted = rawHeights[y, x];
        if (generator.heightmapStrength > 0) {
            float threadhold = minheight + generator.floorThreashold;
            if (inverted > threadhold) {
                inverted += (generator.heightmapStrength / 100.0f);
            }
        }
        byte[] packed = BitConverter.GetBytes(inverted);
        if (packed != null && packed.Length >= 4) {                        
            Color pixel = new Color(packed[0], packed[1], packed[2], packed[3]);
            heightMap.SetPixel(x, y, pixel);
        }
    }
}

 

If that right, now i will tackle the custom CreateGroundFromHeightMap :)

 

Link to comment
Share on other sites

How bout this one:

float minheight = float.MaxValue;
float maxheight = float.MinValue;
int hwidth = terrain.terrainData.heightmapWidth;
int hheight = terrain.terrainData.heightmapHeight;
float[,] rawHeights = terrain.terrainData.GetHeights(0, 0, hwidth, hheight);
Texture2D heightMap = new Texture2D(hwidth, hheight, TextureFormat.ARGB32, false);
for (int y=0; y < hheight; y++) {
    for (int x=0; x < hwidth; x++) {
        float inverted = rawHeights[y, x];
        minheight = Mathf.Min(minheight, inverted);
        maxheight = Mathf.Max(maxheight, inverted);
    }
}
List<Color32> pixels = new List<Color32>();
for (int y=0; y < hheight; y++) {
    for (int x=0; x < hwidth; x++) {
        float inverted = rawHeights[y, x];
        if (generator.heightmapStrength > 0) {
            float threadhold = minheight + generator.floorThreashold;
            if (inverted > threadhold) {
                inverted += (generator.heightmapStrength / 100.0f);
            }
        }
        byte[] packed = BitConverter.GetBytes(inverted);
        if (packed != null && packed.Length >= 4) {                        
            pixels.Add(new Color32(packed[0], packed[1], packed[2], packed[3]));
        }
    }
}
heightMap.SetPixels32(pixels.ToArray());
heightMap.Apply();

 

Link to comment
Share on other sites

@Sebavan Can you please insert that unpacking code in this section of VertextData.CreateGroundFromHeightMap

 

// Vertices
            for (row = 0; row <= options.subdivisions; row++) {
                for (col = 0; col <= options.subdivisions; col++) {
                    var position = new Vector3((col * options.width) / options.subdivisions - (options.width / 2.0), 0, ((options.subdivisions - row) * options.height) / options.subdivisions - (options.height / 2.0));

                    // Compute height
                    var heightMapX = (((position.x + options.width / 2) / options.width) * (options.bufferWidth - 1)) | 0;
                    var heightMapY = ((1.0 - (position.z + options.height / 2) / options.height) * (options.bufferHeight - 1)) | 0;

                    var pos = (heightMapX + heightMapY * options.bufferWidth) * 4;
                    var r = options.buffer[pos] / 255.0;
                    var g = options.buffer[pos + 1] / 255.0;
                    var b = options.buffer[pos + 2] / 255.0;

                    var gradient = r * 0.3 + g * 0.59 + b * 0.11;

                    position.y = options.minHeight + (options.maxHeight - options.minHeight) * gradient;

                    // Add  vertex
                    positions.push(position.x, position.y, position.z);
                    normals.push(0, 0, 0);
                    uvs.push(col / options.subdivisions, 1.0 - row / options.subdivisions);
                }
            }

PRETTY PLEASE :)

 

Link to comment
Share on other sites

This should be close to :

// var pos = (heightMapX + heightMapY * options.bufferWidth) * 4;
// var r = options.buffer[pos] / 255.0;
// var g = options.buffer[pos + 1] / 255.0;
// var b = options.buffer[pos + 2] / 255.0;

// var gradient = r * 0.3 + g * 0.59 + b * 0.11;

var pos = (heightMapX + heightMapY * options.bufferWidth);
var gradient = floatView[pos];

with the following before the double loop:

var floatView = new Float32Array(options.buffer);

 

Link to comment
Share on other sites

@Sebavan So you say something  like this then: 

            // Heightmap
            var floatView = new Float32Array(options.buffer);

            // Vertices
            for (row = 0; row <= options.subdivisions; row++) {
                for (col = 0; col <= options.subdivisions; col++) {
                    var position = new Vector3((col * options.width) / options.subdivisions - (options.width / 2.0), 0, ((options.subdivisions - row) * options.height) / options.subdivisions - (options.height / 2.0));

                    // Compute height
                    var heightMapX = (((position.x + options.width / 2) / options.width) * (options.bufferWidth - 1)) | 0;
                    var heightMapY = ((1.0 - (position.z + options.height / 2) / options.height) * (options.bufferHeight - 1)) | 0;

                    //var pos = (heightMapX + heightMapY * options.bufferWidth) * 4;
                    //var r = options.buffer[pos] / 255.0;
                    //var g = options.buffer[pos + 1] / 255.0;
                    //var b = options.buffer[pos + 2] / 255.0;
                    //var gradient = r * 0.3 + g * 0.59 + b * 0.11;

                    var pos = (heightMapX + heightMapY * options.bufferWidth);
                    var gradient = floatView[pos];

                    position.y = options.minHeight + (options.maxHeight - options.minHeight) * gradient;

                    // Add  vertex
                    positions.push(position.x, position.y, position.z);
                    normals.push(0, 0, 0);
                    uvs.push(col / options.subdivisions, 1.0 - row / options.subdivisions);
                }
            }

 

Link to comment
Share on other sites

ok, my bad... use the following line instead, your floatArray needs to be initialized on the underlying buffer of the uintarray not the array itself :

//HeightMap

var floatView = new Float32Array(options.buffer.buffer); 

Note for myself, coding in the forum only is dangerous ;-)

also with your case use width 200, height 200 and minheight 0 with maxheight 100 to replicate your unity setup.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...