Sebavan Posted December 6, 2016 Share Posted December 6, 2016 I was not thinking about the mesh itself but more its related information like tree, details grass and so on. TBH, it is probably overkill in step 1 but could be cool to keep open enough in the exporter. Sorry for the confusion. Quote Link to comment Share on other sites More sharing options...
GameMonetize Posted December 6, 2016 Share Posted December 6, 2016 You need multiple meshs in order to make efficient use of the LOD. If terrain is only one mesh this is not a good idea Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 6, 2016 Author Share Posted December 6, 2016 This seems backwards: float min = float.MaxValue; float max = float.MinValue; Quote Link to comment Share on other sites More sharing options...
Sebavan Posted December 6, 2016 Share Posted December 6, 2016 Yes, to ensure the value will be well picked up in the loop. else if min was minvalue and max maxvalue you would never change them in the loop. Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 7, 2016 Author Share Posted December 7, 2016 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 Quote Link to comment Share on other sites More sharing options...
Sebavan Posted December 7, 2016 Share Posted December 7, 2016 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) Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 7, 2016 Author Share Posted December 7, 2016 @Sebavan Dude... I would LUV for you to do that code... ill add it to the toolkit just to make the heights more precise for the collision mesh Also... Take a look at the piece of code i used for "Collision Heightmap Strength" to help compensate for LOWERING the ground collision map verts: Collision Heightmap Strength Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 7, 2016 Author Share Posted December 7, 2016 @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(); Quote Link to comment Share on other sites More sharing options...
RaananW Posted December 7, 2016 Share Posted December 7, 2016 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. Quote Link to comment Share on other sites More sharing options...
NasimiAsl Posted December 7, 2016 Share Posted December 7, 2016 this is sample of My Terrain http://www.babylonjs-playground.com/#1QC9DP#61 Quote Link to comment Share on other sites More sharing options...
Sebavan Posted December 8, 2016 Share Posted December 8, 2016 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]; Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 8, 2016 Author Share Posted December 8, 2016 @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 ??? Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 8, 2016 Author Share Posted December 8, 2016 @Sebavan ... Just wondering of that what you were talking about doing instead of use the a picture to encode the heights ??? Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 8, 2016 Author Share Posted December 8, 2016 @Sebavan ... Crap ... I read that wrong... Sorry... But i get you... Use those values 4 bytes (0-255 each) for each Color rgba instead of Color(inverted, inverted, inverted, 1.0f) But i think i still would need to customize createGroundFromHeightmap to use this new packed data... Right??? Quote Link to comment Share on other sites More sharing options...
Sebavan Posted December 8, 2016 Share Posted December 8, 2016 Yep and you can use the second part of the code using array buffer for it. Sorry to have not been clearer Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 8, 2016 Author Share Posted December 8, 2016 @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 Quote Link to comment Share on other sites More sharing options...
Sebavan Posted December 8, 2016 Share Posted December 8, 2016 Because packed is byte not 0 to 1, I think you need Color Pixel = new Color32(packed[0]....).Color; and after that you can do the read. Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 8, 2016 Author Share Posted December 8, 2016 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(); Sebavan 1 Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 8, 2016 Author Share Posted December 8, 2016 @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 Quote Link to comment Share on other sites More sharing options...
Sebavan Posted December 8, 2016 Share Posted December 8, 2016 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); Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 8, 2016 Author Share Posted December 8, 2016 @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); } } Quote Link to comment Share on other sites More sharing options...
Sebavan Posted December 8, 2016 Share Posted December 8, 2016 if that works well, please enclose the creation in an option :-) I am pretty impatient to try your contrib Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 8, 2016 Author Share Posted December 8, 2016 @Sebavan Hmmm... I get no height at all... What value should i be using for the createGroundFromHeightMap... Because I'm still using the terrainHeight from the terrain component in unity editor... Which is set to 100. (Terrain Size: 200W x 200L x 100H) Quote Link to comment Share on other sites More sharing options...
MackeyK24 Posted December 8, 2016 Author Share Posted December 8, 2016 here height map png: Quote Link to comment Share on other sites More sharing options...
Sebavan Posted December 8, 2016 Share Posted December 8, 2016 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. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.