Turn 3d function (z=f(x,y)) into a heightmap for blender landscape.

I have a function which describes a mesh. Its a function along the lines of z = f(x,y). I want to generate a height map or something similar to import into blender so that I can model the landscape exactly of that mesh described by that function. I also have to put x and y bounds on that mesh because I only want a certain part of it. I don’t know if Octave or Scilab will export a .bmp heightmap of a mesh graph.

Does anyone know how I can accomplish this? Thanks in advance.

I recall a Python script that did this, but don’t remember its name. You could write one too of course. http://www.blender.org/documentation/245PythonDoc/index.html You would just have to sample your function, and create a mesh with a vertex for each output, and add edges and faces for it.

You could probably use gnuplot to create a bitmap image file too. Or Matlab or Mathmatica if you have either of those.

If you can use any kind of graphing program to produce a white-black image of the function, then you can apply that to a subdivided plane by applying the image as a texture mapped to Disp, and then vary the Displacement slider to increase the range of the displacement.

I also think I just saw, this week, a post about something that takes a CSV file (from like Excel) and creates an animation curve…which means if you apply that curve to a cube moving, it will trace out the mesh - which would be very cool animation.

If you modify that script to produce vertex locations instead of IPO curve points, you want to just run your function for whole units of X,Y to produce the datapoints (this depends on the function, of course). The Subsurf function in Blender will fill-in in-between values to produce a smooth mesh.

So I fooled around with this in Matlab.

The biggest kink in the chain is actually Matlab. The way plotting works out in Matlab it doesn’t seem to have enough color resolution to make a smooth surf() plot because the faces (even with interpolated coloring) are shaded a solid color for each face. Increasing the resolution of faces works to a point (i.e. increasing the number of faces), but Matlab quickly runs out of memory to deal with them. As such, the result in blender has the correct overall shape, but is stepped at each level of faces. I’ll attach an image(s). I did a quick test, and with two smooth modifiers (both set to 30 operations at 1.0 strength) and a seperate catmull-clark modifeir, it did smooth out some, but not to a really usable extent. I used the inbuilt Peaks function in Matlab, so it could be something with that, but I noticed similar issues when I tried different functions of my own design.

Obviously, then, the best way to do it would be to export the data obtained from Matlab and reimport the points into Blender. This should be relatively easy to do, with some clever scripting on both ends. I’ll keep working on it and see if I come up with anything.

A couple of quick thoughts are:
-Blur the map in Matlab (I had to script a cropping for the image anyways in Matlab, blurring shouldn’t be excessively hard) or Gimp.
-More Ram? (I have 2 Gigs, which is pretty much enough for most things, but the smoothed scene took up almost .5 gigs).

I haven’t ever really dealt with Octave or Scilab, but I do know from the little experience I have with Octave that it is incredibly close to Matlab. I wouldn’t be surprised if it had similar problems to this. Also note that I may have missed some magic Matlab function that would smooth it out somehow, but I doubt it exists.

Images Are: Displace Modifier (No Smooth), Displace Modifier (Smoothed), Matlab Screen Grab

Attachments




Thanks a done for getting me started on this. I really appreciate the time you’ve spent. This will most definately get me started.

Would a subsurf modifier fix it ?

I don’t believe so. The technique I used only works to a certain extent, unfortunately.

Basically what I did was add a plane and subdivide 6-10 times (can’t remember exactly). From there I basically just used modifiers like this (In this order from top down):

  1. Subsurf-> Simple Subdiv-> Level 3
  2. Displace-> Strength 1
  3. Smooth-> Factor 1.0, Repeat 30
  4. Smooth-> Factor 1.0, Repeat 30
  5. Subsurf-> Catmull-Clark Level 2

I’ve attempted adding Catmull-Clark Modifiers at different points in the stack with varying levels of intensity and in some cases it marginally improves the condition and in others it makes it significantly worse (especially adding it before the displace modifier since it adds more geometry which is what we somewhat don’t want). The problem again is with memory. Adding too much Catmull-Clark with not enough ram is not a good thing. At those levels above, even, it was at .48 gigs in Ram when rendering. If you have more Ram go for it though, and report back.

How did you render the function in Matlab and height map it again? After that I’m good.

To Render the function in Matlab, I used the peaks function (substitute your function/functions for this) with surf() and set the view to to be 90 azimuth, 0 horizon, and a interpolated color map set to gray mapping in the Z direction.

From there its a matter of using the print function to print out the image to an image of the appropriate format and possibly cropping it (I wrote the crop code in matlab, but Gimp and Photoshop work just as well). If you don’t want Matlab to do the cropping (I did not write a very intelligent algorithm), just delete all the code below the “process out white border” comment.

It saves out the raw file (without cropping) as heightmap.png, and the cropped file as hmap.png. Those names are definitely modifiable as well as many of the settings in the script. Just use the Matlab Docs if you want to change stuff, or post back and test my Matlab knowledge :confused:.

Fortunately, I saved the Matlab Code I used for this (thought I had deleted it):


clear
clc
close all

% Example Code For Matlab to Blender workflow for heightmaps
% Copyright 2007

%Example Function
[xx, yy, zz] = peaks(500);

%Plot The Function Using a Gray Map
pHandle = surf(xx, yy, zz, zz);
colormap('gray')

%Make The Shading Smooth
shading interp

%View From Top
view(0, 90)

%Clean up
grid off
axis off
axis square

%Save out as .png
fileName = 'heightmap';

%Change 300 to set Resolution
print('-dpng', '-r300', fileName)

%Process Out White Border
map = imread([fileName '.png']);

[rows, cols, colors] = size(map);
hMid = round(cols/2);
vMid = round(rows/2);

topRow = 0;
for i = 1:round(rows/2)
    if (map(i, hMid, 1) ~= 255) || (map(i, hMid, 2) ~= 255) || (map(i, hMid, 3) ~= 255)
        topRow = i;
        break;
    end
end

bottomRow = 0;
for i = rows:-1:round(rows/2)
    if (map(i, hMid, 1) ~= 255) || (map(i, hMid, 2) ~= 255) || (map(i, hMid, 3) ~= 255)
        bottomRow = i;
        break;
    end
end

leftCol = 0;
for i = 1:round(cols/2)
    if (map(vMid, i, 1) ~= 255) || (map(vMid, i, 2) ~= 255) || (map(vMid, i, 3) ~= 255)
        leftCol = i;
        break;
    end
end

rightCol = 0;
for i = cols:-1:round(cols/2)
    if (map(vMid, i, 1) ~= 255) || (map(vMid, i, 2) ~= 255) || (map(vMid, i, 3) ~= 255)
        rightCol = i;
        break;
    end
end

hmap = map(topRow:bottomRow, leftCol:rightCol, 1:3);
imwrite(hmap, 'hmap.png')

In Blender, you import the image as a texture and apply it to a heavily subdivided plane using the displace modifier. You can find a little more description and example files at:
http://wiki.blender.org/index.php/Manual/Displace_Modifier

Like I previously said blurring may help, and I believe there are functions in Matlab that can do this (imfilter() and fspecial() perhaps? or just code your own).

I have been making 3D worlds with Blender for quite some time now, even mapping the surface with texture, and flying around over the track between the mountains etc. Have used sky boxes with Blender and flew around in them, flying through covered bridges too.

For many topics on this web site by me around this topic with downloadable .blend files to try out and python scripts that go along with them! ( upretirementman )

http://vales.com/evo2/forum.asp?FORUM_ID=27