Passing arguments into POV-ray objects

978 Views Asked by At

I'm trying to make a scene with POV-ray, where I would like to make several objects of the same type but with different position, rotation and color. The object I want to make looks like

#declare Width = 30;
#declare Length = 120;
#declare Thickness = 4;
#declare TipHeight = 17;


// Single Beam------------
#declare Beam = union{            
// beam
box {           
     <-Width/2, TipHeight, 0>,
     < Width/2, TipHeight+Thickness, Length>
}
//Triangle head
prism { TipHeight TipHeight+Thickness , 4
      <-Width/2, Length>, 
      < Width/2, Length>, 
      < 0, Length+Length/8>,
      <-Width/2, Length>
     }  
// tip
  cone {
    <0, 0, Length>, 0
    <0, TipHeight, Length>, TipHeight/2
  }
}

What I do next is to create several of these beam-objects as

// Sine formed beams--------------
#declare EndValue = 20;
#declare MaxTranslation = 100;
#declare MaxRotation = 10; //degrees

#declare BeamsSine = union{             

    #for (Cntr, 0, EndValue, 1)

        #local NormalizedValue = Cntr/EndValue;

        object {Beam
                rotate y*90
                rotate -z*sin(NormalizedValue*2*pi)*MaxRotation
                translate z*NormalizedValue*MaxTranslation
                texture { pigment {  
                            color Gray
                            }
                        }
                }  

    #end              
} 

Adding #include colors.inc in the very beginning and

object{ BeamsSine no_shadow }
light_source { <500, 50, 300> color White} 
camera {
    location <400, 100, 300>
    look_at  <0, 0,  0>
}

in the end you have a minimun working example.

Now comes my question: I would like to change the color of the tip-cone in the Beam-object by applying a gradient. The problem is that the gradient should be shifted depending on the value of the sine-function (which is used to determine the tilting angle).

From object oriented programming, I would write something like

class MYBEAM(position):
    ...make the beam
    cone {
        <0, 0, Length>, 0
        <0, TipHeight, Length>, TipHeight/2
        pigment{ gradient{cmap_depending_on_variable_"position"}  }
         }

and then create each object as

for i = 1:10
    pos = calculate_position_function(i)
    MYBEAM(pos)
    ...
end

I do not know how to do this in POV-ray! I do not manage to pass extra arguments into my beam-object. The only way I can think of is to use the function-declaration method, but it cannot return an object? (I only manage to get it to return a float).

I also tried to make a variable #declare mypos = 55; before the definition of my object, and then update it in every loop by redefining it as #declare mypos = calculate_position_function(i) before a new object is created. This does not work either (always uses the first position...).

Anyone have some idea/solution to my problem?

1

There are 1 best solutions below

0
On
#declare mypos = calculate_position_function(i)

Defining custom functions, esp vector-valued ones, is somewhat little intuitive in povray; pls attend e.g.

http://povray.org/documentation/3.7.0/r3_3.html#r3_3_1_8_4


Concerning paradigmata, esp OO, and POV-Ray:

I will not dig deeply into that, generally I would advise not to delegate much application logic to POV-Ray, maybe with the exception of CSG, although even for that I'd prefer other tools, e.g. OpenSCAD.

POV-Ray's mesh2 is an excellent interface for a 3D pipeline; the meshes for primitives like Cones, Boxes etc can easily be generated with very little maths from within general purpose languages like C++ or python (the latter esp if used in conjunction with numpy) and with reasonable small effort be exported(A) as a mesh2

http://povray.org/documentation/3.7.0/r3_4.html#r3_4_5_2_4 ,

or, which is more versatile, the arbitrarily meshes exported to a custom XML format and then transformed into POV-Ray source by means of XSLT or programatically (B).

From my experience, implementing (A) takes about one and (B) takes about two working days to code, but that extra day is spent well.


Anyway - this produces a bunch of simplified "beams" in a loop:

#include "colors.inc"
#declare BEAM_LENGTH = 200;
#declare CUT_RADIUS = 10;
#declare NUM_BEAMS = 11;

camera { 
    perspective
    location <0, 1.8, -100> 
    look_at  0
    up y
    angle 30 
}

sky_sphere {
    pigment {
        color Blue
    }
    emission rgb <0.5,0.5,1>
}

light_source { 
    <0, 100, -100>, 
}

plane { 
    +y, 0 
    texture {
        pigment { color Green }
    }
}


#declare Beam =  cone  { 
    // top
    0, 0,
    // bottom
    -y * BEAM_LENGTH, CUT_RADIUS
}

#for (i, 0, NUM_BEAMS-1, 1)
    #declare q = i/NUM_BEAMS;
    #declare r = 100;
    #declare theta = pi/8; 
    #declare phi = q*2*pi;
    #declare pos = <r*sin(theta)*cos(phi), r*cos(theta), r*sin(theta)*sin(phi)>;

    #switch (mod(i,3))
        #case (0) 
            #declare d = <q,.1,.1,0>; 
        #break
        #case (1) 
            #declare d = <.1,q,.1,0>;  
        #break
        #case (2) 
            #declare d = <.1,.1,q,0>;  
        #break
    #end // switch

    object { Beam
        translate pos
        texture {
            pigment {
                rgbt d + <0,0,0,q/2>
            }
        }
    }
#end // for