Deformation in this chapter signifies various operations. It can involve changing the shape of a primitive in a way not possible via a transform (ie bending, warping etc) or modifying texture coordinates or colours to achieve a per-vertex effect. (Deformation in this way is also the only way to get particle primitives to do anything interesting).
Deforming is all about pdata, so, to deform an entire object, you do something like the following:
(hint-unlit) (hint-wire) (line-width 4) (define myobj (build-sphere 10 10)) (define (deform n) (pdata-set "p" n (vadd (pdata-get "p" n) ; the original point, plus (vmul (vector (flxrnd) (flxrnd) (flxrnd)) 0.1))) ; a small random vector (if (< n 0) 0 (deform (- n 1)))) (grab myobj) (deform (pdata-size)) ; for every point (ungrab)
When deforming geometry, moving the positions of the vertices is not usually enough, the normals will need to be updated for the lighting to work correctly.
(recalc-normals smooth)
Will regenerate the normals for polygon and nurbs primitives based on the vertex positions. not particually fast (it is better to deform the normals in your script if you can) and only works on poly primitives of type QUADS and TRILIST. if smooth is 1, the face normals are averaged with the coincident face normals to give a smooth appearance
When working on polygon primitives it will cache certain results, so it will be a lot slower on the first calculation than subsequent calls on the same primitive.
As well as the standard information that exists in primitives, fluxus also allows you to add your own per vertex data to the primitive. User pdata can be written or read in the same way as the built in pdata types.
(pdata-add name type)
Where name is a string with the name you wish to call it, and type is a one character string consisting of:
f : float data v : vector data c : colour data m : matrix data
(pdata-copy source destination)
This will copy a array of pdata, or overwrite an existing one with if it already exists.
So, adding your own storage for data on primitives means you can use it as a fast way of reading and writing data, even if the data doesn't directly affect the primitive.
(define particle-count 1000) (define (init n) ; setup our pdata arrays (pdata-set "vel" n (vmul (vsub (vector (flxrnd) (flxrnd) (flxrnd)) (vector 0.5 0.5 0.5)) 0.1)) ; randomise the velocity (pdata-set "c" n (vector (flxrnd) (flxrnd) 1)) ; randomise the colour (if (< n 0) 0 (init (- n 1)))) (define (update n) (pdata-set "vel" n (vadd (pdata-get "vel" n) (vector 0 -0.001 0))) ; add some gravity (pdata-set "p" n (vadd (pdata-get "p" n) (pdata-get "vel" n))) ; add velocity to the position (if (< n 0) 0 (update (- n 1)))) (define (render) (grab ob) (update (pdata-size)) ; update the particles (ungrab)) ; setup the scene (clear) (show-fps 1) (point-width 4) (hint-anti-alias) ; build our particle primitive (define ob (build-particles particle-count)) (grab ob) (pdata-add "vel" "v") ; add the velocity user pdata of type vector (init (pdata-size)) ; initialise the pdata arrays (ungrab) (blur 0.1) (every-frame (render))
Pdata Operations are a optimisation which takes advantage of the nature of these storage arrays to allow you to process them with a single call to the scheme interpreter. This makes deforming primitive much faster as looping in the scheme interpreter is slow, and it also simplifies your scheme code.
(pdata-op operation pdata operand)
Where operation is a string identifier for the intended operation (listed below) and pdata is the name of the target pdata to operate on, and operand is either a single data (a scheme number or vector (length 3,4 or 16)) or a name of another pdata array.
If the (update)
and (render)
functions in the script above are
changed to the following:
(define (update) (pdata-op "+" "vel" (vector 0 -0.002 0)) ; add this vector to all the velocities (pdata-op "+" "p" "vel")) ; add all the velocities to all the positions (define (render) (grab ob) (update) (ungrab))
On my machine, this script runs over 6 times faster than the first version.
(pdata-op)
can also return information to your script from certain functions called on entire pdata arrays.
Pdata operations
"+" : addition "*" : multiplication "sin" : writes the sine of one float pdata array into another "cos" : writes the cosine of one float pdata array into another "closest" : treats the vector pdata as positions, and if given a single vector, returns the closest position to it - or if given a float, uses it as a index into the pdata array, and returns the nearest position.
For most pdata operations, the vast majority of the combinations of input types (scheme number, the vectors or pdata types) will not be supported, you will receive a rather criptic runtime warning message if this is the case.
The function (build_polygons) allows you to build empty primitives which you can use to either build more types of procedural shapes than fluxus supports natively, or for loading model data from disk. Once these primitives have been constructed they can be treated in exactly the same way as any other primitive, ie pdata can be added or modified, and you can use (recalc-normals) etc.