Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question/Discussion: Best practice to import Terrain generated in Blender (and similar) #327

Closed
MJacred opened this issue Jun 30, 2022 · 9 comments

Comments

@MJacred
Copy link
Contributor

MJacred commented Jun 30, 2022

For anyone stumbling over this issue: I wrote a Blender addon bmesh-to-raw to correctly export a mesh to raw file


The Problem

Currently, this plugin allows (out-of-the-box) to create terrains by

a) importing a file with height info
b) using a dialog with some adjustable parameters
c) sculpting by hand using OpenEXR brushes
d) procedurally by code (I think)

b) is not that useful if you desire a bigger map with more variation and c) takes just really long.

For a) there are a lot of terrain generators like world machine, world creator, gaia, gaea, etc. But from what I could see, there is a lack of control over the finer details regarding size and shape (or maybe they just didn't showcase that).

Either way, it's also possible to create heightmap terrains in general purpose 3D modeling software like Blender which allow a great deal of freedom on how to create and edit them quickly. Though there is the issue of getting it into Godot properly.

From time to time there are issues popping up regarding transferring a terrain; currently open are

The Goal

This plugin can import file formats such as PNG, OpenEXR (16-bit (half-precision float mode) greyscale), XYZ and Radiance HDR - and well… RAW (unsigned integer 16-bit), where all except PNG expect real height information and not floating point values between 0-1.

Exporting from Blender to PNG is doable using a node shader (#90 (comment)), but Godot can only import PNG as 8-bit, which creates stepping artifacts.

Blender also supports these formats afaik, though, I could only get OpenEXR to work even remotely. And it still has issues.

Export to OpenEXR in Blender

so I tried what @Zylann mentioned

Did you actually try to put the camera under the terrain in Blender, make it orthographic covering the exact size of the terrain, output height in displacement instead of surface and somehow export the resulting depth as OpenEXR from the compositor instead?

I don't know about how to use the result if you put the height info in displacement port, but I tried sth. similar: still output into surface, but in compositor, read the z-depth of the camera…

But, I still have trouble getting a landscape from Blender to Godot:

blender test file:
terrain-baker.blend.zip

I tried exporting an OpenEXR file using the compositor in blender (select Viewer node, go to Item in the Node tab and click Save This Image as .exr file).

Current issues with export to OpenEXR

Imported into Godot (Godot 3.3.4; addon is version 1.5.2), I get the following issues:

ripped corners
ripped-corners
missing-corners

I can get rid of the ripped corners, if I place the camera above instead and compensate for the camera position by modifying the z-depth values, but then the corners stretch really high (which can be fixed using "flatten" in the addon)

Overall, using either of the 2 approaches, I don't have the stair-cased issue, but the results are never smooth:
not-smooth

The compositor relies on the render to get the depth buffer, but I don't think color management is important here. Though I tested all kinds of combinations (and the sequencer was always set to linear)

  • sRGB + Standard
  • sRGB + Raw
  • None

I also tried what @RonanZe mentioned in his comment here by importing the OpenEXR file into krita and saving as R32, but then on import in Godot, it said that the heightmap is not square (maybe this is because of the ripped/missing corners? I didn't test the OpenEXR file where the corners where upwards stretched once imported into Godot).

Any help would be greatly appreciated!
Maybe @RonanZe can elaborate more on the workflow they succeeded with!?

@Zylann
Copy link
Owner

Zylann commented Jun 30, 2022

At the moment I have no more info on how best to proceed. I was always thinking that if you can get an image out of Blender with sufficient depth precision and not altered by color management, importing into Godot should be fine.
If you get artifacts in the shading, it could be related to the actual precision Blender gives, which might be lower that what the plugin usually works with for some reason? 16-bit float is just enough but what goes inside can still have lower-precision (note that if you had to translate the terrain a lot vertically to center it on Y=0 after import, that might also explain precision loss, as higher numbers loose precision in this format).
So far it seems Blender isn't thought for exporting proper heightmaps? Or maybe there is an even more specific setup to use?

@MJacred
Copy link
Contributor Author

MJacred commented Jul 2, 2022

Hm… it's possible there is a precision loss in the Blender shader or compositor…
(I did no translation or any adjustments in Godot)

There is one more approach that should be possible in vanilla Blender: first render to a 16-bit greyscale image file (without color mgmt) and then import the file in Blender and remap using the compositor as seen here: https://www.youtube.com/watch?v=UPwoG_8KGa4

I'll try it this weekend.


EDIT: If the above does not work out, I'll try this approach first to create a .raw file: https://github.com/Mezaka/UnityHeightmapBaker

If that also does not work, I'll try writing a Blender addon which directly reads the vertex positions Vector3.UP and creates a RAW (unsigned integer 16-bit) file. (While looking at the terrain in Blender from above) I take I would have to read the vertex positions from left to right, bottom to top?
Any tips on sorting that mess or anything else?

if my math skills did not fail me, then I guess I need this formula

h_range = max_up_value - min_up_value
my_unsigned_16_bit_int = (blender_up_value * 65535.0) / h_range

@MJacred
Copy link
Contributor Author

MJacred commented Jul 3, 2022

Hm… So, I tried the approach to png to exr and it did not remove the "grid".

I did some other things

  • update addon to 1.6.1
  • in Blender, I added a subdivision modifier (render level: 2)

After rendering with higher mesh resolution, the grid looks more like little bumps (increasing the render level more made no difference):

(remapping: 0..1 to 0..320 using the meshes dimensions)

image

Then I tried creating a heightmap in gimp (I think I got the color specs right):
image
And if I remap the values from 0..1 to bigger than 0..50 (roughly), then I get artifacts:
image

Either way, once I do smooth operations, it smears (the bumpier it is, the worse it gets):

smear

Playing with Raise + Smooth does not help.

There is probably sth. in the smooth operation using brush which does not like those mini bumps.
Possible action in the addon: Maybe a Smooth whole terrain by strength x logic would help.

(side note: The blender code for remapping in compositor uses normal c++ float…)

To conclude the remapping approach: The difference in the remapping has a much stronger limitation than anticipated

@Naurk
Copy link

Naurk commented Jul 22, 2022

Well, don't know if this can help, but I solved my import problems converting png 16-bit to raw 16-bit shorts unsigned with one line of code with imagemagick:

magick stream -map r -storage-type short image.png image.raw

@MJacred
Copy link
Contributor Author

MJacred commented Jul 22, 2022

But PNG should have the height data only in range 0..1. So you probably scaled the y-axis in map_scale?

Thanks, I'll try it this weekend.

@MJacred
Copy link
Contributor Author

MJacred commented Aug 21, 2022

Ok, I finally did some testing with magick

Note: found issue:

  • rasing terrain is not possible anymore (plugin v 1.6.1)
    • happened either after import of raw file or after i first set one textureset, deleted it and loaded different images into it
    • going back into project overview and back into project fixed it

And using the command above definitely improves the results (thanks @Naurk ):
png-to-raw

But the wireframe is uneven on slope tops -> cannot be fixed with hterrain brushes:
top

top-closeup

@Zylann: being able to set a float for min and max heights on import should help, because my terrain is not in the size of full integers. in _import_heightmap it is used in a float-only context anyway. so there should be no harm. This could fix the unevenness

see blender vs godot (same mesh resolution -> see 1x1x1 cube on top):

blender-godot

blender-godot-wire

@MJacred
Copy link
Contributor Author

MJacred commented Aug 22, 2022

Still Weirdness

with new commit 778907a, there's now more control, but there is still some weirdness there

blender
blender

hterrain (used a script in Blender to get highest and lowest vertex.z position for accuracy)
Screenshot from 2022-08-22 14-03-45

Proposal: recalculate Heightmap from lower LOD to fix imported map

one way to allow fixing issues with imported maps would be to recalculate higher LODs

  • button: autocorrect using lower LOD
  • input field: -1, -2 (the source LOD, as an offset to "highest-detail lod")

LOD -1 is already smoother (better for spiky terrain)
afar 2

LOD -2 would be even more smooth (better for rounder terrain)
from afar

Comparison: Godot <> Blender (using magick process)

i lined up the vertical lines: blender (orange) <> hterrain (blue)
image

@Naurk: As you got so good results using the magick process, could you share an example setup? Would be highly appreciated

@MJacred
Copy link
Contributor Author

MJacred commented Aug 22, 2022

I also tried https://github.com/Mezaka/UnityHeightmapBaker, and had to

  • change line bytes = bytearray(b'\x00\x0F') to bytes = bytearray(b'\x00') or bytes = bytearray(b'\x10'), else the raw file was non-square and could not be imported
  • import as big endian

But the result was quite chunky
image

His import looked smoother, but that might be due to his scaling?
image

As it was rendered at 1025x1025, the height is 0.0-512.5.
image

But dividing map size by 2 (to get this scaling on import) did not improve the spikes…

@MJacred
Copy link
Contributor Author

MJacred commented Apr 24, 2023

@Zylann: I wrote a Blender addon bmesh-to-raw to correctly export a mesh to raw (provided it's clean)

some screenshots: https://github.com/cubiest/bmesh-to-raw/tree/main/docs

As this issue is more or less stale and one sound solution (not counting imagemagick) has been found, I'll be closing this issue.

@MJacred MJacred closed this as completed Apr 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants