Somebody Should Set The Title For This Chapter!
Primitives are the most interesting things in fluxus, as they are the things which actually get rendered and make up the scene.
Polygon primitives are the most versatile primitives, as fluxus is really designed around them. The other primitives are added in order to achieve special effects and have specific roles. The other primitive types often have commands to convert them into polygon primitives, for further processing.
There are many commands which create polygon primitives:
(build-cube) (build-sphere 10 10) (build-torus 1 2 10 10) (build-plane) (build-seg-plane 10 10) (build-cylinder 10 10) (build-polygons 100 'triangles)
The last one is useful if you are building your own shapes from scratch, the others are useful for giving you some preset shapes. All build-* functions return an id number which you can store and use to modify the primitive later on.
The pdata arrays available for polygons are as follows:
Vertex normal n 3 vector Vertex texture coords t 3 vector for u and v, the 3rd number is ignored Vertex colours c 4 vector rgba
|Vertex position||p||3 vector|
|Vertex normal||n||3 vector|
|Vertex texture coords||t||3 vector for u and v, the 3rd number is ignored|
|Vertex colours||c||4 vector rgba|
Polygon topology and pdata
With polygonal objects, we need to connect the vertices defined by the pdata into faces that describe a surface. The topology of the polygon primitive sets how this happens:
This lookup is the same for all the pdata on a particular polygon primitive - vertex positions, normals, colours and texture coordinates.
Although using these topologies means the primitive is optimised to be very quick to render, it costs some memory as points are duplicated - this can also cause a big speed impact if you are doing lots of per-vertex calculation. The most optimal poly topology are triangle strips as they maximise the sharing of vertices, but also see indexed polygons for a potentially even faster method.
You can find out the topology of a polygon primitive like this:
(define p (build-cube)) (with-primitive p (display (poly-type))(newline)) ; prints out quad-list
The other way of improving efficiency is converting polygons to indexed mode. Indexing means that vertices in different faces can share the same vertex data. You can set the index of a polygon manually with:
(with-primitive myobj (poly-set-index list-of-indices))
Or automatically – (which is recommended) with:
(with-primitive myobj (poly-convert-to-indexed))
This procedure compresses the polygonal object by finding duplicated or very close vertices and “gluing” them together to form one vertex and multiple index references. Indexing has a number of advantages, one that large models will take less memory - but the big deal is that deformation or other per-vertex calculations will be much quicker.
Problems with automatic indexing
As all vertex information becomes shared for coincident vertices, automatically indexed polygons can’t have different normals, colours or texture coordinates for vertices at the same position. This means that they will have to be smooth and continuous with respect to lighting and texturing. This should be fixed in time, with a more complicated conversion algorithm.
NURBS are parametric curved patch surfaces. They are handled in a similar way to polygon primitives, except that instead of vertices, pdata elements represent control vertices of the patch. Changing a control vertex causes the mesh to smoothly blend the change across it’s surface.
(build-nurbs-sphere 10 10) (build-nurbs-plane 10 10)
|Control vertex position||p||3 vector|
|Control vertex texture coords||t||3 vector for u and v, the 3rd number is ignored|
|Control vertex colours||c||4 vector rgba|
Particle primitives use the pdata elements to represent a point, or a camera facing sprite which can be textured – depending on the render hints. This primitive is useful for lots of different effects including, water, smoke, clouds and explosions.
|Particle position||p||3 vector|
||3 vector for width and height, the 3rd number is ignored|
Geometry hintsParticle primitives default to camera facing sprites, but can be made to render as points in screen space, which look quite different. To switch to points:
(with-primitive myparticles (hint-none) ; turns off solid, which is default sprite mode (hint-points)) ; turn on points rendering
If you also enable (hint-anti-alias) you may get circular points, depending on your GPU – these can be scaled in pixel space using (point-width).
Ribbon primitives are similar to particles in that they are either hardware rendered lines or camera facing textured quads. This primitive draws a single line connecting each pdata vertex element together. The texture is stretched along the ribbon from the start to the end, and width wise across the line. The width can be set per vertex to change the shape of the line.
|Ribbon vertex position
|Ribbon vertex colour
|Ribbon vertex width
Ribbon primitives default to render camera facing quads. You can also switch them to draw wire frame lines in screen space:
(with-primitive myline (hint-none) ; turns off solid, which is default mode (hint-wire)) ; turn on lines rendering
Text primitives allow you to create text based on texture fonts. The font assumed to be non proportional – there is an example font shipped with fluxus.
(texture (load-texture “font.png”)) (build-text text-string)
The primitive makes a set of quads, one for each character, with texture coordinates set to show the correct character from the texture. This provides a fast and cheap way of displaying text, and is useful for debugging, or if the text is quite small. You can probably also find quite creative ways of using this just as a way of chopping up a texture into little squares.
The type primitive provides a much higher quality typeface rendering than the text primitive. It creates polygonal geometry from a ttf font and some text. Optionally you can also extrude the text which results in 3D shapes.
(build-type ttf-font-filename text) (build-extruded-type ttf-font-filename text extrude depth)
You can also convert the type primitive into a polygon primitive for further deformation or applying textures, with:
The locator is a null primitive, as it doesn’t render anything. Locators are useful for various tasks, you can use them as a invisible scene node to group primitive under. They are also used to build skeletons for skinning. To view them, you can turn on hint-origin, which draws an axis representing their transform.
A pixel primitive is used for making procedural textures, which can then be applied to other primitives. For this reason, pixel primitives probably wont be rendered much directly, but you can render them to preview the texture on a flat plane.
(pixel-primitive width height)
Extra pixel primitive commands
A pixel primitive’s pdata corresponds to pixel values in a texture, you write to them to make procedural texture data. The pixel primitive comes with some extra commands:
Uploads the texture data, you need to call this when you’ve finished writing to the pixelprim, and while it’s grabbed.
Returns a texture you can use exactly like a normal loaded one.
See the examples for some procedural texturing. It’s important to note that creating textures involves a large amount of processing time, so you don’t want to plan on doing something per-pixel/per-frame for large textures. The pdata-func extensions could be used to help here in the future.
This is a simple example of creating a noise texture on a pixel primitive:
(with-primitive (build-pixels 100 100) (pdata-map! (lambda (colour) (rndvec)) "c") (pixels-upload))
Blobby primitives are a higher level implicit surface representation in fluxus which is defined using influences in space. These influences are summed together, and a particular value is “meshed” (using the marching cubes algorithm) to form a smooth surface. The influences can be animated, and the smooth surface moves and deforms to adapt, giving the primitive it’s blobby name. (build-blobby) returns a new blobby primitive id. Numinfluences is the number of “blobs”. Subdivisions allows you to control the resolution of the surface in each dimension, while boundingvec sets the bounding area of the primitive in local object space. The mesh will not be calculated outside of this area. Influence positions and colours need to be set using pdata-set.
(build-blobby numinfluences subdivisionsvec boundingvec)
|Use||Name|| Data Type
Converting to polygons
Blobbies can be slow to calculate, if you only need static meshes without animation, you can convert them into polygon primitives with: