From BlenderWiki
This is the design document for the Render API interface which will be used to translate between blender and a given renderer (including the internal renderer). The design document for the implementation is here: Render API Implementation.
[edit] Render API Design
I am going to explain my system in a conceptual way.
[edit] Concepts
Here are brief descriptions of some ideas that my design is based on.
Render Context. A render context is a state. Specifically, it is the list of render settings that are currently in effect. When you query the render API, the results of that query depend on the render context. Example: what frame are we currently on, what render layer are we working on? Similarly, when you are declaring data to a renderer that uses a render context, the results of that declaration depend on the context. Example: When you declare geometry in a RIB file the current shader of the context is applied to that geometry.
Abstraction. One of the basic principles of my design was providing an interface which abstracted away everything the renderer doesn't need to know. For example, the API doesn't allow you to get empty objects because they are completely irrelevant from a rendering standpoint. Furthermore, in many places my interface does not look like blender's internal implementation. This is because 1) we want to be able to change the internal implementation without changing the interface, and 2) to keep the API simple and organized.
Symmetry. Much of the render data requires the same types of access functions. Whenever possible I have made the function interfaces for these different data types look the same. This keeps everything simple and organized and makes the API easier to learn and use.
Lists. Specifically, it is very natural to access render data as lists. A scene is a list of objects and within that you can break it down to a list of lights and a list of geometry, a mesh has a list of vertices, edges, and faces, etc. All of these lists are accessed the same way.
[edit] Naming Conventions
Here are the naming conventions used throughout the API. I've tried to keep it systematic, clean, and readable. Also, the API does not use abbreviations in order to maintain readability. Code is read more often than written, so I've placed a high value on readability.
General Rule: CamelCase for types, underscores for names, CAPS for constants.
Callbacks, Plugin Defined Structures
- no prefix, CamelCase for types, underscores for names.
Enums
- RND_TYPE - RND_SAMPLE_TYPE
- the type is CAPS to to alert the reader that this is an enum type.
- RND_OBJECT_VALUE_NAME - RND_GEOMETRY_POLYGON_MESH
Handler types
- RNDType - RNDObject, RNDVertex, etc.
Functions
- RND_data_operation_underscores - RND_object_get_geometry()
Also: strictly speaking the RND prefix denotes render API member functions and structures. It should not be used to denote:
- functions which use the API
- functions or structures related to or associated with the API but not strictly members.
[edit] Callbacks
The way the render pipeline will work for multiple renderers is a system of callbacks. Each renderer will implement the following functions in its own special way:
- setup( RNDScene )
- render_frame( RNDScene, RNDResult )
- finish( RNDScene )
The setup and finish functions are called at the beginning and end of a render job. The render_frame function is called for each frame, and it is expected that the frame is rendered and sent back via the result handler when this function returns.
The callbacks are given the input and output handlers necessary to perform the job.
[edit] Queries
There are two types of queries involved in the retrieval potion of my system:
- Queries that return handlers or lists of handlers.
- Queries that return data values.
A handler represents a entity that the renderer needs to get information about. Example handlers: RNDObject, RNDLight, RNDVertex.
Handlers will always be the first parameter in the argument list of a query function.
Consistant Results. The result of a list-returning query will always be the same handlers in the same order. This is so that over time the render knows what is the same entity on a different frame and what is a different entity entirely. A result of this rule is that mesh topology will remain constant for the length of a render job. If it doesn't remain constant, it will be considered a different geometry data block. For example, fluid simulation from frame to frame will be considered a new object.
[edit] Looping
Here is an example abstract list:
[item1] - item2 - item3 - item4 - (empty)
The item in braces is selected, meaning it is indicated by the handler.
The lists in this system are singly-linked. I don't think it is ever necessary to go backwards in render exporting, but if it is, these functions can always be a further extension of the API in later years. When in doubt, leave it out.
Here are the traversal functions, handler type object is used for example:
int RND_object_exists( RNDObject object ) void RND_object_first( RNDObject object ) void RND_object_next( RNDObject object )
These check or change the current object. When RND_object_next is run on the last item, RND_object_exists will return false.
A standard loop in this system looks like:
for( object = RND_get_objects( scene, type );
RND_object_exists( object );
RND_object_next( object ) )
{
// code
}
[edit] Local Data: Per-Context
Renderers will want to store local data which will remain the same between callback calls. For example, after setting the render up with the setup() callback, all the information created must be accessible from each call to render_frame(). This information must be stored in association with the render context which is being operated on. This is because blender allows multiple render contexts to be active at once. Therefore, if a second render job begun, it would overwrite all local data if the data was not stored per-context.
The API Constructs Designed to Handle This.
The RND_get_context_name is provided to gain access to the unique identifier for a given context.
Plugin writers should store this context local information on the plugin_instance: functions will be designed for retrieving the plugin instance from the render API.
Furthermore, one the TemporaryData stores context specific data within the API itself, so this can be used when the data pertains to specific objects, lights, or geometry. Note: this structure was designed to handle instancing information.
[edit] Dynamic Arrays
Various renderers want information given to them in bulk inside an array. However these arrays are not necessarily formatted the same way. Therefore I'm following a principle of API design on this point, Displease Everyone Equally. I am not providing access to listed data in arrays. This is a conscious decision in full knowledge that many exporters will have to build them themselves. Let me briefly explain the reasoning.
Providing data in arrays requires one of two things: the render API builds the array from scratch and gives it to the exporter, or the render API gives data which already exists in arrays (vertices, edges, faces), to the exporter. First of all, both are bad because they assumes blender knows the way the renderer wants it's array formatted. Second, the first option has no cost benefit, and the second option exposes implementation details, binding blenders internal implementation to the API interface—big ouch.
Additionally, since this is a place where renderers vary, it is more than natural to make the renderer do it. However, here is an implication of this which will upset internal renderer programmers: you don't have direct access to blender's internal structures anymore. If you want the array of MVerts that you were used to back in the days before the Render API you will have assign new memory and copy the data into it. However, it might make more sense to use these new access methods and re-implement anything that relied on blender's internal structure. Furthermore, this separation is very good in the long run. It means if blender decides to drop MVerts support, you're safe. The API is the only thing that needs to change in that case.
Lastly, though these dynamic arrays will have an impact on performance because they will be duplicate data, their cost is small relative to the cost of rendering. Also, they can be freed in an efficient manner. I can't think of a better alternative.
[edit] Freeing Data
On the subject of memory management, due to the fact that some API functions generate dynamic data (RND_geometry_to_polygon_mesh), there needs to be a way for the user to specify that they no longer need this data and that it may be freed for efficiency's sake.
RND_free_generated_data( RNDScene scene )
The handlers that point to generated data will be managed within the API so that they can be set set to return false when RND_<type>_exists( type ) is called.
[edit] The Scene
The scene that is available through the render API is one filtered for the purpose of rendering. All unnecessary data has been removed. Here are a few of the implications of this:
The scene is a list of instances two types of objects: lights and geometry. There can be multiple instances of the same light or geometry. However,
- Objects which are invisible to the renderer (empty controls, some types of duplicators) will not be in this list.
- There is no hierarchy of transformations present in this list, only one resultant transformation per object. This means that groups and duplicators don't exist from the user of the render API's perspective, only the results of them. They are broken up into the individual instances that they produce: a dupliverts cube would result in six object instances. Furthermore, neither the dupliverts cube or the original duplivert object would be in the list of objects, since they don't appear in the rendering.
- There are no modifiers present, only resultant geometry. Only if resultant geometry has multiple instances is it considered an instance by the render API.
In general all data is available only in its final, resultant, render form, and the render API is ignorant of any steps that were necessary to create that form.
Subdivision Surfaces. Big exception to the above discussion of modifiers. Subdivision surfaces that can be skimmed off the top of the modifier stack will be treated as their own geometry type.
[edit] Core Functionality
Get Objects.
Note: I will discuss shortly, but I wanted to put the core functionality above that discussion.
This is generally the first function that the renderer needs to call to begin accessing data.
RNDObject RND_get_objects( RNDScene Scene, unsigned int type )
Type is a bitwise-or composition of one or more of the following types:
typedef enum RND_DATA_TYPE{
RND_LIGHT_POINT = (1<<0),
RND_LIGHT_SPOT = (1<<1),
RND_LIGHT_SUN = (1<<2),
RND_LIGHT_HEMI = (1<<3),
RND_LIGHT_AREA = (1<<4),
RND_LIGHT =
( RND_LIGHT_POINT +
RND_LIGHT_SPOT +
RND_LIGHT_SUN +
RND_LIGHT_HEMI +
RND_LIGHT_AREA ),
RND_GEOMETRY_POLYGON_MESH = (1<<8),
RND_GEOMETRY_SUBDIVISION_SURFACE = (1<<9),
RND_GEOMETRY_NURB_SURFACE = (1<<10),
RND_GEOMETRY_METABALL = (1<<11),
RND_GEOMETRY_CURVE = (1<<12),
RND_GEOMETRY_PARTICLE_SYSTEM = (1<<13),
RND_GEOMETRY =
( RND_GEOMETRY_POLYGON_MESH +
RND_GEOMETRY_SUBDIVISION_SURFACE +
RND_GEOMETRY_NURB_SURFACE +
RND_GEOMETRY_METABALL +
RND_GEOMETRY_CURVE +
RND_GEOMETRY_PARTICLE_SYSTEM ),
RND_ALL =
( RND_LIGHT,
RND_GEOMETRY )
} RND_DATA_TYPE;
This function is used to get any collection of objects from the scene, organized by type, that is desired. It could be used to get all lights, all geometry, all geometry minus metaballs if they require special handling, etc.
Type.
RND_DATA_TYPE RND_object_get_type( RNDObject object )
This simply gets the current object's type. When processing multiple types of objects, this is how you tell them apart.
Instances.
RNDObject RND_get_instanced_objects( RNDScene Scene, unsigned int type )
For lights or geometry that is instanced multiple times, this returns a list of one object that instances each of them. This allows the setup function to configure object instancing before processing the frames. Objects can be instanced by groups, duplicators, or directly with alt-d. All of these instance hierarchies are flattened to produce this list.
This only retrieves objects that are considered instanced by the render API, see above in "The Scene."
[edit] Bookmarking Data
On the subject of instances, I would like to introduce a bit of functionality for storing custom data needed during rendering on handlers. This is for each of the main types of handlers: object, light, geometry, eventually material, etc. Not for things like vertex. This is particularly relevant for instanced data because it allows the storage of instance ids, renderman handlers, or whatever is needed to plug a predefined instance in in place of exporting the data again.
Allowing the storage of arbitrary data on handlers is a very flexible extension to the system which is potentially useful for more than just instancing, but this is what I can think of so far.
struct TemporaryData; typedef struct TemporaryData TemporaryData; TemporaryData *RND_object_get_temporary_data( RNDObject object ) void RND_object_set_temporary_data( RNDObject object, TemporaryData *temp )
The temporary-data structure must be implemented in some way by the exporter, albeit this could be an empty definition if it's not needed.
[edit] Object
An object is an instance of light or geometry data which has its own transformation information.
Object names are provided chiefly for debugging exporters and inclusion in archive files.
char* RND_object_get_name( RNDObject object )
This function gets final, resultant transformation from the view coordinates into the objects local coordinate system.
void RND_object_get_transformation( RNDObject object, float transformation[][4] )
Note: these functions perform calculations on the same data that is used in get_object_transformation, there is not difference in the data being returned, it's just in a different format.
The translation, rotation, scale, and shear are length 3 arrays, of the x, y, and z components. void RND_object_traslation( RNDObject object, float translation[] ) void RND_object_rotation( RNDObject object, float rotation[] ) void RND_object_scale( RNDObject object, float scale[] ) void RND_object_shear( RNDObject object, float shear[] )
This is for handling instanced data. Returns true if multiple instances of the object's light or geometry data exist.
int RND_object_is_instance( RNDObject object )
Standard funcitons:
int RND_object_exists( RNDObject object ) void RND_object_first( RNDObject object ) void RND_object_next( RNDObject object ) TemporaryData *RND_object_get_temporary_data( RNDObject object ) void RND_object_set_temporary_data( RNDObject object, TemporaryData *temp )
[edit] Context
The render context options. None of these functions perform any changes on the scene data in memory. They simply note that changes will be made to the subject of the next query.
Get the unique name of this render context. Plugin writers should store data which persists between callbacks on a per-context basis, as more than one render job is allowed to be active at one time. char *RND_get_context_name( RNDScene scene ) The renderer is expected to call this function periodically. If it returns true, rendering should be stopped and all current results returned. int RND_stop_render( RNDScene scene )
Motion Blur
Get or set the current frame. This is for motion blur calculations. float RND_get_current_frame( RNDScene scene ) void RND_set_current_frame( RNDScene scene, float new_frame ) Offsets the current frame by offset. void RND_set_frame_offset( RNDScene scene, float offset )
[edit] Settings
Render settings which won't change over a render job.
typedef enum RND_FILTER_TYPE{
RND_FILTER_MITCH,
RND_FILTER_CATROM,
RND_FILTER_GAUSS,
RND_FILTER_CUBIC,
RND_FILTER_QUAD,
RND_FILTER_TENT,
RND_FILTER_BOX
} RND_FILTER_TYPE;
int RND_is_animation( RNDScene scene )
int RND_has_motion_blur( RNDScene scene )
int RND_has_pixel_filter( RNDScene scene )
int RND_get_image_width( RNDScene scene )
int RND_get_image_height( RNDScene scene )
char *RND_get_file_type( RNDScene scene )
char *RND_get_file_name( RNDScene scene )
RND_FILTER_TYPE RND_get_pixel_filter_type( RNDScene scene )
int RND_get_pixel_filter_sample_number( RNDScene scene )
float RND_get_motion_blur_factor( RNDScene scene )
int RND_get_thread_count( RNDScene scene )
axis is 'x' or 'y'
int RND_get_part_count( RNDScene scene, char axis )
[edit] Camera
A note about naming conventions here: camera is not a type in this system. The camera is handled by an implicit transformation into view coordinates.
Returns true if perspective, false if orthagonal. int RND_is_perspective( RNDScene scene ) float RND_get_lens( RNDScene scene ) float RND_get_scale( RNDScene scene ) float RND_get_clipping_start( RNDScene scene ) float RND_get_clipping_end( RNDScene scene ) float RND_get_depth_of_field( RNDScene scene )
[edit] World Settings
void RND_get_horizon_color( RNDScene scene, float color[] ) void RND_get_zenith_color( RNDScene scene, float color[] ) void RND_get_ambient_color( RNDScene scene, float color[] )
[edit] Lights and Geometry
Lights.
RNDLight RND_object_get_light( RNDObject object ) RND_DATA_TYPE RND_light_get_type( RNDLight light ) float RND_light_get_intensity( RNDLight light ) float RND_light_get_falloff_distance( RNDLight light ) void RND_light_get_color( RNDLight light, float color[] )
Geometry.
RNDGeometry RND_object_get_geometry( RNDObject object ) RND_DATA_TYPE RND_geometry_get_type( RNDGeometry geometry ) Converts geometry to polygon mesh type. If geometry is a polygon mesh, does nothing. void RND_geometry_to_polygon_mesh( RNDGeometry geometry ) Returns true if surface interpolation is smooth, and false if surface interpolation is solid. int RND_geometry_is_smooth_interpolation( RNDGeometry geometry ) Returns true if the geometry deforms in this frame. int RND_geometry_deforms( RNDGeometry geometry )
Standard Functions:
TemporaryData *RND_light_get_temporary_data( RNDLight light ) void RND_light_set_temporary_data( RNDLight light, TemporaryData *temp ) TemporaryData *RND_geometry_get_temporary_data( RNDGeometry geometry ) void RND_geometry_set_temporary_data( RNDGeometry geometry, TemporaryData *temp )
[edit] Meshes
These are pretty self explanatory as long as you've read the section on Looping.
The topology and order of vertex coordinates, edge indices, and face indices is guaranteed to stay the same with time-step changes. (I don't think topology can change with key-framing, so this should be possible for all blender situations.)
int RND_vertex_get_count( RNDVertex vertices ) int RND_edge_get_count( RNDEdge edges ) int RND_face_get_count( RNDFace faces ) int RND_face_get_index_count( RNDFace face ) RNDVertex RND_geometry_get_vertices( RNDGeometry geometry ) RNDEdge RND_geometry_get_edges( RNDGeometry geometry ) RNDFace RND_geometry_get_faces( RNDGeometry geometry ) The coordinates parameter is an array of 3. void RND_vertex_get_coordinates( RNDVertex vertex, float coordinates[] ) The indices parameter is an array of 2. void RND_edge_get_indices( RNDEdge edge, int indices[] ) The RNDIndex type is to allow face indices to be of arbitrary length to allow the eventual incorporation of n-gons. RNDIndex RND_face_get_indices( RNDFace face ) int RND_index_get_value( RNDIndex index )
And finally, the standard list traversal functions:
int RND_vertex_exists( RNDVertex vertex ) int RND_edge_exists( RNDEdge edge ) int RND_face_exists( RNDFace face ) int RND_index_exists( RNDIndex index ) void RND_vertex_first( RNDVertex vertex ) void RND_edge_first( RNDEdge edge ) void RND_face_first( RNDFace face ) // haha... RND_index_first( RNDIndex index ) void RND_vertex_next( RNDVertex ) void RND_edge_next( RNDEdge ) void RND_face_next( RNDFace face ) void RND_index_next( RNDIndex index )
[edit] Subdivision Surfaces
The subdivision surfaces interface uses all the same mesh functions from the above section, with a few additions:
typedef enum RND_SUBDIVISION_TYPE{
RND_CATMULL_CLARK,
RND_SIMPLE_SUBDIVISION
}RND_SUBDIVISION_TYPE;
int RND_geometry_get_subdivision_level( RNDGeometry geometry )
RND_SUBDIVISION_TYPE RND_geometry_get_subdivision_type( RNDGeometry geometry )
[edit] Particle Systems
I've made this structure separate from vertices, which it shares almost all methods with because particles have a significantly different nature, and less basic functions for handling them will diverge from vertices quickly.
RNDParticle RND_geometry_get_particles( RNDGeometry geometry ) int RND_particle_get_count( RNDParticle particles ) The coordinates parameter is an array of 3. void RND_particle_get_coordinates( RNDParticle particle, float coordinates[] ) void RND_particle_exists( RNDParticle particle ) void RND_particle_first( RNDParticle particle ) void RND_particle_next( RNDParticle particle )
[edit] Results
Finally, here are functions for returning image data which will fill the render result for this frame. Hierarchy of results:
RenderResult RenderLayer RenderPass RenderFragment
Concerning render layers: in order for a renderer to perform it's job, it does not need to know that they even exist, given that they are merely an organizational level between passes and the whole result, used for compositing. Thus, the render API will provide access to what passes are needed and means to return these passes, but organization into render layers will happen behind the scenes.
Passes.
RNDPass RND_get_passes( RNDResult result )
typedef enum RND_PASS_TYPE{
RND_PASS_RGBA = (1<<0),
RND_PASS_Z = (1<<1),
RND_PASS_SPEED_VECTOR = (1<<2),
RND_PASS_NORMAL = (1<<3),
RND_PASS_UV = (1<<4),
RND_PASS_OBJECT_INDEX = (1<<5),
RND_PASS_SHADELESS = (1<<6),
RND_PASS_DIFFUSE = (1<<7),
RND_PASS_SPECULAR = (1<<8),
RND_PASS_SHADOW = (1<<9),
RND_PASS_AMBIENT_OCCLUSION = (1<<10),
RND_PASS_RAYTRACE_REFLECTION = (1<<11),
RND_PASS_RAYTRACE_REFRACTION = (1<<12),
RND_PASS_RADIOCITY = (1<<13)
} RND_PASS_TYPE;
RND_PASS_TYPE RND_pass_get_type( RNDPass pass )
int RND_pass_get_count( RNDPass pass )
Standard Functions:
int RND_pass_exists( RNDPass pass ) void RND_pass_first( RNDPass pass ) void RND_pass_next( RNDPass pass )
Sending Data.
This is the function for sending image data back. It works for both entire passes or fragments.
Bounds is an array of 4 ints, xmin, xmax, ymin, ymax, which identifies which fragment is being sent back. Top-Right is the origin of the raster space. Buffer contains the image data in a dynamic array: r00, g00, b00, r10, g10, b10, etc. (where r,g,b are channels and rxy one channel for a pixel at x,y) void RND_pass_send_data( RNDPass pass, int bounds[], float *buffer ) A renderer may not support a given pass type. If this is the case, eventually this should show up in the GUI so that the user knows what going on. However, if a renderer is asked to produce a pass that it can't, this is the proper result to return. void RND_pass_send_failure( RNDPass pass )
[edit] Current State of the API
Legend:
working, partially working, does nothing.
[edit] context
- RND_get_context_name
- RND_get_current_frame
- RND_set_current_frame
- RND_set_frame_offset
- RND_stop_render
[edit] settings
- RND_is_animation
- RND_has_motion_blur
- RND_get_image_width
- RND_get_image_height
- RND_get_file_type
- RND_get_file_name
- RND_get_pixel_filter_type
- RND_get_pixel_filter_sample_number
- RND_get_motion_blur_factor
[edit] camera
- RND_is_perspective
- RND_get_lens
- RND_get_scale
- RND_get_clipping_start
- RND_get_clipping_end
- RND_get_depth_of_field
[edit] object
- RND_get_objects
- RND_get_instanced_objects
- RND_object_is_instance
- RND_object_get_name
- RND_object_get_type
- RND_object_get_transformation
- RND_object_get_translation
- RND_object_get_rotation
- RND_object_get_scale
- RND_object_get_shear
- RND_object_exists
- RND_object_first
- RND_object_next
- RND_object_get_temporary_data
- RND_object_set_temporary_data
[edit] light
- RND_object_get_light
- RND_light_get_type
- RND_light_get_intensity
- RND_light_get_falloff_distance
- RND_light_get_color
- RND_light_get_temporary_data
- RND_light_set_temporary_data
[edit] geometry
- RND_object_get_geometry
- RND_geometry_get_type
- RND_geometry_to_polygon_mesh
- RND_geometry_is_smooth_interpolation
- RND_geometry_deforms
- RND_geometry_get_temporary_data
- RND_geometry_set_temporary_data
[edit] meshes
- RND_geometry_get_vertices
- RND_geometry_get_edges
- RND_geometry_get_faces
- RND_vertex_get_count
- RND_edge_get_count
- RND_face_get_count
- RND_face_get_index_count
- RND_vertex_get_coordinates
- RND_edge_get_indices
- RND_face_get_indices
- RND_index_get_value
- RND_vertex_exists
- RND_edge_exists
- RND_face_exists
- RND_index_exists
- RND_vertex_first
- RND_edge_first
- RND_face_first
- RND_index_first
- RND_vertex_next
- RND_edge_next
- RND_face_next
- RND_index_next
[edit] passes
These functions currently only work for the main combined RGBA pass.
- RND_get_passes
- RND_pass_get_type
- RND_pass_get_count
- RND_pass_exists
- RND_pass_first
- RND_pass_next
- RND_pass_send_data
- RND_pass_send_failure
[edit] Vertex Handler
As a sort of proof-of-concept, here is a possible design for a vertex handler.
[edit] Renderman Psuedocode
This is just the bare basics, to get the idea.
/* Simple RenderMan Exporter for Blender - Aaron Moore */
void export_light( RNDObject object );
void export_geometry( RNDObject object );
void render_frame( RNDScene scene, RNDRender render ){
RNDObject object;
RNDLight light;
RNDGeometry geometry;
RiFrameBegin( (int) RND_get_current_frame( scene ) );
/* Setup Rasteriztion */
RiFormat( RND_get_image_width( scene ), RND_get_image_height( scene ), 1 )
RiProjection( RND_is_perspective( scene ) ? "perspective" : "orthagonal" );
RiWorldBegin();
/* Export Lights */
for( object = RND_get_objects( scene, RND_LIGHT );
RND_object_exists( object );
RND_object_next( object ) )
{
export_light( object );
}
/* Export Geometry */
for( object = RND_get_objects( scene, RND_GEOMETRY );
RND_object_exists( object );
RND_get_next_object( object ) )
{
export_geometry( object );
}
RiWorldEnd();
RiFrameEnd();
}
void export_light( RNDObject object ){
RNDLight light = RND_object_get_light( object );
float coordinates[3];
RND_object_get_translation( object, coordinates );
if( RND_light_get_type( light ) == RND_LIGHT_POINT ){
RiLightSource( "pointlight",
"from", coordinates[],
"intensity", RND_light_get_intensity( light ) );
}
}
/* note, these don't use blender's memory management functions
because I haven't had time to learn them yet due to design */
void export_geometry( RNDObjectHandler object ){
/* handlers */
RNDGeometry geometry = RND_object_get_geometry( object );
RND_geometry_to_polygon_mesh( geometry );
RNDVertex vertex = RND_geometry_get_vertices( geometry );
RNDFace face = RND_geometry_get_faces( geometry );
RNDIndex index;
/* counts */
int face_count = RND_face_get_count( face );
int face_indices_total = 0;
/* arrays */
/* old matrix and new matrix are transformation from view > local */
float *all_coors, one_coors[3], old_matrix[4][4], new_matrix[16];
int *vertices; /* the vertex indices of all faces */
int *nvertices; /* the vertex counts of the faces */
int i, j;
/* build array of vertices */
all_coors = malloc( RND_vertex_get_count( vertex ) * 3 * sizeof( float ) );
for( i = 0; RND_vertex_exists( vertex ); i+=3, RND_vertex_next( vertex ) )
{
RND_vertex_get_coordinates( vertex, one_coors );
all_coors[i] = one_coors[0];
all_coors[i+1] = one_coors[1];
all_coors[i+2] = one_coors[2];
}
/* build array of faces index counts */
nvertices = malloc( face_count * sizeof( int ) );
for( i = 0; RND_face_exists( face ); i++, RND_face_next( face ) )
{
nvertices[i] = RND_face_get_index_count( face );
face_indices_total += nvertices[i];
}
/* build array of faces */
vertices = malloc( face_indices_total * sizeof( int ) );
for( i = 0, RND_face_first( face ); RND_face_exists( face ); RND_face_next( face ) )
{
index = RND_face_get_indices( face );
for( ; RND_index_exists( index ); i++, RND_index_next( index ) )
vertices[i] = RND_index_get_value( index );
}
/* flatten transformation matrix */
RND_object_get_transformation( object, old_matrix );
for( i = 0; i < 4; i++ )
for( j = 0; j < 4; j++ )
new_matrix[4*i+j] = old_matrix[i][j];
/* export */
RiAttributeBegin();
RiTransform( new_matrix );
RiSurface( "plastic" );
RiPointsPolygons( nvertices, vertices, "P", all_coors );
RiAttributeEnd();
/* free memory */
free( all_coors );
free( nvertices );
free( vertices );
free( all_coors );
}
[edit] Pipeline Changes
Here are some diagrams and explanations of the changes to the render pipeline which I plan to make.
[edit] Structures
The current Render structure contains:
- Render Context
- Access to the scene.
- A Place to put results.
- Utilities needed: (Callbacks and Stats).
- Blender Internal's Render Database
Since the Render structure will be the general render handle for all render engines, it must not contain information particular to blender internal. Therefore, I've moved the render database out into it's own structure, and added the render API structures to the Render handler.
This does create headache of sorting out what functions that take Render *re as an argument want the render context, the render database, or both.
[edit] Pipeline Flow
Blue is for making perfectly clear what function a given callback is in. Red denotes changes.
I am not redesigning this pipeline, merely placing things in containers. Those containers are either:
- blender internal renderer callbacks (setup, render_frame, finish, abort)
- the generic pipeline for all renderers
The changes consist of renaming, moving, and translating.
Blender internal callbacks will be defined in a separate file. The render database will be accessible only in this file, not in pipeline.c. This means that all blender internal code must be moved out of the pipeline and into callbacks.
All of the blender scene access and result sending will be done through the render API. What this means for blender internal is that the render database will be populated using the render API functions. The current code, therefore, must be translated into the new language of the render API.
Only code that is needed for all render engines will remain in pipeline.c. This is: general error checking, callback initialization, progress drawing, post processing, saving of image data.










![[]](/skins/blender/open.png)
