![](/i/fill.gif) |
![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Following a problem I had with slow mesh parsing (see povray.general), here
is my solution, with an example pic, using an optimized mesh2 object.
My goal was to create a fairly good mountain landscape for use in
backgrounds, etc, without resorting to fiddling with image heightfields or
waiting for isosurfaces. So this is a heightfield generated using only SDL,
using an 'envelope' function to control the height of mountains generated
from pigment functions. I've included the complete scene, with some brief
comments - hopefully someone will find it useful! I'm using 1 pov-unit = 1
metre, approximately, so by all means have a play with the numbers.
Bill
/* code starts */
#include "colors.inc"
#include "shapes.inc"
global_settings {
assumed_gamma 1
max_trace_level 10 }
camera {
location <0, 100, 0>
right <4/3, 0, 0>
up <0, 1, 0>
direction <0, 0, FoV_90>
look_at <100, 100, 150> }
light_source { <10000, 100000, -50000> color White }
// define basic pigment functions for mountains
// agate for large-scale features, wrinkles for
// fine detail
#declare land1 = function {
pigment {
agate
color_map {
[0 color rgb 1]
[1 color rgb 0] } } }
#declare land2 = function {
pigment {
wrinkles
color_map {
[0 color rgb 1]
[1 color rgb 0] } } }
// global scaling parameters for pigment functions
#declare sc1 = 20;
#declare sc2 = 5;
#declare hilloff = 12;
// macro function to return a sinusoidal edge, so
// that mountains can rise smoothly from a plain without
// cut-off edges
#macro SineEdge(xp,yp,zp)
#if (xp >= 0)
#local Result = 1;
#end
#if (xp < 0 & xp >= -pi)
#local Result = 0.5*cos(xp)+0.5;
#end
#if (xp < -pi)
#local Result = 0;
#end
(Result)
#end
// height macro function to return a mountain height value
// given a point in the x-y plane. vary the hilloff parameter defined
// above to move the pigment function around without changing the envelope.
#macro LandHeight(xp, yp)
#local Result = SineEdge(xp+6,0,yp)
*(0.5*land1((xp+hilloff)/sc1, 0, yp/sc1).x +
0.5*land2((xp+hilloff)/sc2, 0, yp/sc2).x);
(Result)
#end
// texture definitions
#declare p1 = pigment { color Clear }
#declare p2 = pigment {
slope { <0, 1, 0> }
color_map {
[0 color Clear]
[0.75 color Clear]
[0.77 color White]
[1 color White] } }
#declare t1 = texture {
pigment {
slope { <0, 1, 0> }
color_map {
[0 color Gray70]
[0.7 color Gray70]
[0.75 color Tan]
[0.85 color LightWood]
[0.94 color rgb <0.3, 0.6, 0.3>]
[1 color rgb <0.3, 0.6, 0.3>] } }
finish { ambient 0 } }
#declare t2 = texture {
pigment {
gradient y
pigment_map {
[0 p1]
[0.6 p1]
[0.605 p2]
[1 p2] } }
finish { ambient 0.35 } }
// mountain macro to build the mesh2 heightfield
// xs, ys are extent of field in each direction
// (i.e. width = 2*xs etc)
// maxh is maximum altitude of mountains
// dx is grid spacing of heightfield (must divide into
// xs and ys exactly)
#macro Region(xs, ys, maxh, dx)
#local nx = 2*xs/dx + 1;
#local ny = 2*ys/dx + 1;
#local Vertices = nx*ny;
#local Faces = (nx-1)*(ny-1)*2;
mesh2 {
vertex_vectors {
Vertices,
#local xp = -xs;
#local yp = -ys;
#local n = 0;
#while (n < Vertices-1)
<xp, maxh*LandHeight(xp,yp), yp>,
#local n = n + 1;
#local xp = xp + dx;
#if (xp = xs+dx)
#local xp = -xs;
#local yp = yp + dx;
#end
#end
<xp, maxh*LandHeight(xp,yp), yp> }
face_indices {
Faces,
#local n = 0;
#while (n < Vertices-nx-2)
<n, n+1, n+nx>,
<n+1, n+nx+1, n+nx>,
#local n = n + 1;
#if (mod(n-(nx-1), nx) = 0)
#local n = n + 1;
#end
#end
<n, n+1, n+nx>,
<n+1, n+nx+1, n+nx> }
texture { t1 scale maxh }
texture { t2 scale maxh } }
#end
// make mountains.
// they were originally created small during testing and
// then scaled up later using transformations. alter the last
// parameter to change the heightfield resolution.
object {
Region(12, 30, 5, 0.05)
translate <12, 0, 30>
scale 500
translate <1000, 0, 0> }
// ground plane
plane {
<0, 1, 0>, 0.2
pigment { color rgb <0.3, 0.6, 0.3> }
finish { ambient 0 } }
// background & some ground mist
fog {
color rgb <0.9, 0.975, 1>
distance 10000
fog_type 2
fog_offset 0
fog_alt 300 }
background { color NavyBlue }
/* code ends */
Post a reply to this message
Attachments:
Download 'hills.jpg' (36 KB)
Preview of image 'hills.jpg'
![hills.jpg](/povray.binaries.images/attachment/%3Cweb.44759ba38c28dbe6731f01d10%40news.povray.org%3E/hills.jpg?ttop=443866&toff=4450&preview=1)
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Maybe i'm overlooking something, but where's the difference to a
heightfield?
Your approach could however be easily expanded to become capable of doing
overhangs which a heightfield isn't capable of.
Regards Roman
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
"Roman Reiner" <lim### [at] gmx de> wrote:
> Maybe i'm overlooking something, but where's the difference to a
> heightfield?
The main reason I knocked it together was simply to make the landscape
tinkering process easier and faster; resolution, shape, functions can all
be changed in a single render. If I want a really high-res landscape, I
don't have to wait for it to churn out the image and then import it back
again. It seemed like a good excuse to learn how to use mesh2, too.
> Your approach could however be easily expanded to become capable of doing
> overhangs which a heightfield isn't capable of.
And there's that, of course... :-)
I'll have a think, and see what else I could do with it!
Bill
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
"Bill Pragnell" <bil### [at] hotmail com> wrote in message
news:web.44759ba38c28dbe6731f01d10@news.povray.org...
> Following a problem I had with slow mesh parsing (see povray.general),
> here
> is my solution, with an example pic, using an optimized mesh2 object.
>
> My goal was to create a fairly good mountain landscape for use in
> backgrounds, etc, without resorting to fiddling with image heightfields or
> waiting for isosurfaces. So this is a heightfield generated using only
> SDL,
> using an 'envelope' function to control the height of mountains generated
> from pigment functions. I've included the complete scene, with some brief
> comments - hopefully someone will find it useful! I'm using 1 pov-unit = 1
> metre, approximately, so by all means have a play with the numbers.
>
> Bill
>
It's always a good exercise to write a mesh2 generator in POV SDL to better
understand both the programming and mesh2 formats. Good work. A couple
hints for you here:
1) changing both SineEdge and LandHeight to functions rather than macros
adds speed. Parse time dropped from about 90secs to 60secs for me:
#declare SineEdge2 = function
(xp){select(xp,select(xp+pi,0,0.5*cos(xp)+0.5),1)}
#declare LandHeight2=function
(xp,yp){SineEdge2(xp+6)*(0.5*land1((xp+hilloff)/sc1, 0, yp/sc1).x +
0.5*land2((xp+hilloff)/sc2, 0, yp/sc2).x)}
2) There is the function pattern for height_fields which does pretty much
what you did by hand only much faster (drops down to a mere 6sec parse time,
plus smoothing can be added):
#macro Region2(xs, ys, maxh, dx)
height_field {
#local m=(2*xs/dx+2);
#local n=(2*ys/dx+2);
function m,n {pattern{function{LandHeight2( (x)*2*xs-xs
, -((y-1/n)*2*ys-ys) )}}}
//smooth
translate <-1/2,0,-1/2>
scale <2*xs,maxh,2*ys>
texture { t1 scale maxh }
texture { t2 scale maxh }
}
#end
Good work on weeding through the math involved in mesh creation though. I
did it once for a moebius generator and it was quite educational. (You
forgot the smoothing normals though! And uv mapping support!)
-tgq
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
"Trevor G Quayle" <Tin### [at] hotmail com> wrote:
> 1) changing both SineEdge and LandHeight to functions rather than macros
> adds speed. Parse time dropped from about 90secs to 60secs for me:
>
> #declare SineEdge2 = function
> (xp){select(xp,select(xp+pi,0,0.5*cos(xp)+0.5),1)}
> #declare LandHeight2=function
> (xp,yp){SineEdge2(xp+6)*(0.5*land1((xp+hilloff)/sc1, 0, yp/sc1).x +
> 0.5*land2((xp+hilloff)/sc2, 0, yp/sc2).x)}
Well, crikey. I never even knew the select() function existed. Very useful!
> height_field {
> #local m=(2*xs/dx+2);
> #local n=(2*ys/dx+2);
> function m,n {pattern{function{LandHeight2( (x)*2*xs-xs
> , -((y-1/n)*2*ys-ys) )}}}
> //smooth
> translate <-1/2,0,-1/2>
> scale <2*xs,maxh,2*ys>
> texture { t1 scale maxh }
> texture { t2 scale maxh }
> }
That's *very* interesting. Is that feature in 3.6.1? I can't find it
anywhere in the documentation. As you say, it completely does away with the
intermediate image generation / import step which used to be so
time-consuming when I've tried using heightfields in the past.
Anyway, at least I have a nice modifiable rectangular mesh2 generator now.
Cheers for the pointers!
Bill
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |