4
$\begingroup$

I know there are a lot of tutorials out there that tell you how to create a mesh from a height map. E.g. to create some terrain. I wish to know how I can do the reverse. So I have a mesh with a surface going from 0 to 10mm in height for example, and map the 0-10mm range to a grayscale 8bit grayscale bitmap (so 0 to 256). Is this possible with Blender? I do know a way how to convert it to a bitmap by exporting the mesh to *.dae and read the coordinates of the vertices in a script, and create the bitmap myself. But maybe there is an easier way.

The reason I want to do this is the following: A DLP UV light 3D resin printer has an uneven spread of light. There is intensity fall of to the sides. For this one can correct using a mask. But of course, you have to create that mask yourself. So I used a LDR, did some calibration measurements to be able to know what values represents what light intensities.

The box below represents the build area of the printer (X and Y), the Z axis represents relative light intensity (just from 0 to 100%). The plane with the 9 vertices represents the relative light intensity measured. So I have done 9 measurements on the build plate, a the same locations as those of the vertices.

enter image description here

Then the plane was subdivided once (simpel) and the additional edges slided to the outer of the plane, so that the catmull clark subdivision leaves the rectangular shape of the plane as is, but does smooth out the rest. This is seen in the image below (slighty different angle than the previous image).

enter image description here

Then the mask for the printer requires it to be inverted. So the least light intensity from the measurement should be 100% white, and the center with the most light should be filtered the most. This is seen in the image below, which is a Z mirror of the subdivided plane.

enter image description here

Now of this smoothed out, inverted plane I wish to make a relative height mask. Where 0 is black (pixel value of 0), and the point touching the wire cube at the top is absolutely white (pixel value of 256). (Pixel values consider 8-bit grayscale image).

$\endgroup$
  • $\begingroup$ What would you want to do with the resulting height map? You could create a Normal map from a mesh - is that useful to you? $\endgroup$ – OroNZ Mar 30 '18 at 7:05
  • $\begingroup$ @OroNZ DLP 3D UV resin printers have fall off of light intensity. To correct for that you can specify a mask. I measured the light intensity at 9 points on the build plate. I want to create an evenly distributed weighted mask. For that I created a quadrant plane (so equal nr of vertices as measurements), put the vertices at global height corresponding to light intensity and use subdivide catmull clark to create a smooth surface that represents the light fall off. This is mirrored, and now those values need to be converted to a bitmap to function as a mask for the 3D printer. $\endgroup$ – Mike de Klerk Mar 30 '18 at 8:10
  • $\begingroup$ @OroNZ I have no experience with creating normal maps. Sounds interesting. I am going to check it out. $\endgroup$ – Mike de Klerk Mar 30 '18 at 8:35
  • $\begingroup$ If this is for 3D printing normal map won't help since it fakes unevenness of surface, it doesn't create real bumps. Baking a texture as explained below should be a way to go $\endgroup$ – Mr Zak Mar 30 '18 at 18:14
  • $\begingroup$ Just in case it causes you rounding errors somewhere along the line, a byte counts from 0 to 255, not 256. Easy to forget. $\endgroup$ – Robin Betts Mar 31 '18 at 7:38
8
$\begingroup$

If this is for a terrain (I mean the heights are considered from a base plane), you can use a bake to the texture:

enter image description here

This is done using Cycles.

You can see the material nodes settings above:

  • Input is the location (the location is given from the object's origin, here for simplicity, the object origin is at its baseline)
  • Only keep the Z value
  • Divide by the real height of your object (in order to have a resulting value between 0 and 1)
  • Then put it in a diffuse shader as color (the texture node have to be present and be the selected node for the bake described below)

To bake:

  • Go to the render panel and the bake section
  • Choose diffuse and keep only the "color" option (deselect "direct" and "indirect" as we here want the color only with no environment or other effects)

As indicated in the comments, the previous setting leads to a sharp cutout (visible in the image above: the surrounding is suddenly black).

To avoid that, a possibility is to use another function than just dividing by the object height. What I propose here is to use a sigmoid:

  • the output is between 0 and 1
  • the output limits slowly tend to 0 on left and 1 on right

That leads to this kind of result which you can compare to the image above:

enter image description here

In the blend file below, the higher the value for the multiply node is, the more limit rendered values will be sharp.

$\endgroup$
  • 1
    $\begingroup$ Man... That is elegant. When you say 'real height', do you mean from origin or from the lowest vertex? $\endgroup$ – OroNZ Mar 30 '18 at 10:08
  • $\begingroup$ @OroNZ, Yes the dimension (here in Z) of your object: the point behind that is to keep the resulting value between 0 and 1. But you can change this function as needed (for instance using some variation around a logarithm to tune the color differently, what is important is to keep the final result between 0 and 1) $\endgroup$ – lemon Mar 30 '18 at 10:15
  • $\begingroup$ And yes... the origin point matters as the locations (in input) are given from it. $\endgroup$ – lemon Mar 30 '18 at 10:16
  • $\begingroup$ Wow great! I think this is exactly what I am looking for. I will try this this weekend. Of I follow the steps as you mentioned I will accept and upvote the answer. Thanks so much in advance! $\endgroup$ – Mike de Klerk Mar 30 '18 at 17:46
  • 1
    $\begingroup$ @lemon I can not thank you enough through this stackexchange site IMO. Many thanks for helping so much. I will post the file later. Maybe today. I am eager to learn what I am doing wrong or are over looking. Again, many thanks. $\endgroup$ – Mike de Klerk Apr 1 '18 at 7:14
1
$\begingroup$

Just a quick edit to the answer above (which is really, really appreciated!).

First, I noticed that (I am in Blender 2.8 now) the Z vector of the 'Location' output of the 'Geometry' node contains the values measured from the center of coordinates, not the origin of the object. Probably, this depends on particular settings in Blender? If someone could clarify, would be great: otherwise, set the Z location of your geometry to 0.

Second, there was the problem of unwrapping high-poly that took some time to accomplish. Just a quick comment on the alternative procedure: you can create a low-poly plane consisting of one face, unwrap this one and then bake the color from the high poly to the low-poly mesh. This is how it works:

  1. In the image below are the high poly mesh on the left (storing the information about the heights) and the low poly mesh - a simple plane, consisting of one face. The material setup for the highpoly mesh is as specified by the author of the original answer: it takes the Z-heights of the geometry and puts them into the color input of diffuse shader. Only the low poly mesh must be UV unwrapped. You can also notice that I have adjusted the UV unwrap to take in the whole space of an image.

enter image description here

  1. The baking setup is slightly different (see the exact values below). You have to set baking type 'From selected to Active' (that is, select the low poly plane last. Also, take care of the ray distance. When the map will be baked, engine will cast rays emitted by the faces (the single face in our case) of the low poly geometry. I think, there will be one ray for each pixel of the resulting map, and the ray must be sufficiently long to 'reach' your geometry. That's why set the ray length to the Z-Dimension of your geometry. And that's why place your low poly right beneath your high poly! Remember that the rays cast from your low poly will be cast in the (0,0,90) direction (having supposed this is the direction of the low poly normal), and they must hit the high-poly everywhere. The image output storing the baked colors must also belong to the material of the low-poly mesh, and it must be selected while baking.

Please, comment if I missed something or have explained incorrectly.

enter image description here

$\endgroup$
1
$\begingroup$

I have found another way to do this in that tutorial: https://www.youtube.com/watch?v=z_jh_PrZzOs

Use Blender render

In the node editor, under compositing (check use node) add those nodesenter image description here

Then in the scene settings under display, choose none (to remove the noise) enter image description here

Here is a quick test and the result: enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.