利用者:Artificer/ModifierStackUpgrade

提供: wiki
< 利用者:Artificer
2018年6月29日 (金) 02:47時点におけるYamyam (トーク | 投稿記録)による版 (1版 をインポートしました)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
移動先: 案内検索

目次

Overview

Blender SoC 2006 main page | Summer of Code Proposal

New Modifiers: EdgeSplit | Displace | UVProject


This page documents the design and progress of the modifier stack upgrade I am working on as part of Google's Summer of Code. My attempt to document the current modifier stack implementation can be found at BlenderDev/Modifier_Stack_Implementation.

The main intent of the upgrade is to remove the modifier stack's "original data" constraint, where some modifiers require the base object's original data and thus cannot be placed in the stack after any non-deforming modifiers.

Artificer


Features Committed To CVS

The project has now been integrated into the main Blender CVS tree. The main features committed are:

  • Modifiers can now be in any order in the modifier stack
  • DerivedMesh now has a standard framework for custom element data to be passed through the stack with mesh data (being copied and interpolated as appropriate), so modifiers can access whatever data they need
  • The modifier stack code has been refactored and a number of bugs have been removed
  • The EdgeSplit modifier has been added, along with the sharp edge flag and the ability to set/clear it in the edit mode Edge Specials (CtrlE) menu
  • The Displace modifier has been added
  • The UVProject modifier has been added


Demonstration/Tutorial Videos

ZanQdo has very kindly made some videos demonstrating the new capabilities of the modifier stack. They are:

Thanks ZanQdo!

Design

My original proposal was to create a new datatype, ModifierMesh, which would keep track of the mapping between source mesh data and final (post-modifier) data to allow propagation of changes (e.g. deleted vertices) to related parts of the mesh (e.g. vertex colours). However, Zr has convinced me that it is better to take a "custom element data" approach. Brecht has a proposal to add custom element data to all of Blender (not just the modifier stack) at BlenderDev/CustomElementData. The design here is based on his design.

Custom Element Data

This design is implemented as an addition to the DerivedMesh API. All data associated with a mesh element (Vertex, Edge or Face) is stored in the DerivedMesh structure in a generic way, similar to that described in Brecht's work. When modifiers need to copy or add elements, they call appropriate DerivedMesh API functions which take care of copying all the per-element data. Thus, modifiers only need to know how to handle the data which they want to modify.

Memory layout
An example of the memory layout for per-element (in this case, per-vertex) data storage.

As all data access takes place through the API, the storage details can be changed at a later date if necessary. Currently the layers of custom data are stored in multiple arrays, rather than being grouped per element, as shown in (Memory layout). I have changed to this approach because it is much simpler to manage.

In the current implementation, there is a new DerivedMesh type called CDDerivedMesh (CD = Custom Data) wherein vertices, edges & faces are stored in a custom data layer. This unifies the layer interface, so all data access takes place the same way.

DerivedMesh API

The DerivedMesh structure has been changed to store custom element data, in the form of CustomData objects for vertices, edges and faces, as shown:

struct DerivedMesh {
   /* custom data for verts, edges & faces */
   CustomData vertData, edgeData, faceData;

/* ... function pointers go here ... */
};

New functions have been added to the DerivedMesh interface to access this custom element data, and default implementations are provided. The actual mesh elements (vertices, edges and faces) are still stored in one of the DerivedMesh backends, preserving the current DerivedMesh generality.

DerivedMesh functions

Function pointers

The DerivedMesh structure includes a set of function pointers, which point to different implementations depending on the backend used by a DerivedMesh object. If a new DerivedMesh backend is being created, it must provide implementations for all of these functions.

These functions are described below.

int getNum{Vert,Edge,Face}s
int (*getNumVerts)(DerivedMesh *dm);
int (*getNumFaces)(DerivedMesh *dm);
int (*getNumEdges)(DerivedMesh *dm);

These functions return the number of vertices, edges or faces in the DerivedMesh.

void get{Vert,Edge,Face}
void (*getVert)(DerivedMesh *dm, int index, struct MVert *vert_r);
void (*getEdge)(DerivedMesh *dm, int index, struct MEdge *edge_r);
void (*getFace)(DerivedMesh *dm, int index, struct MFace *face_r);

These functions copy a single vertex, edge or face from the DerivedMesh into the memory pointed to by vert_r, edge_r or face_r respectively.

void get{Vert,Edge,Face}Array
void (*getVertArray)(DerivedMesh *dm, struct MVert *vert_r);
void (*getEdgeArray)(DerivedMesh *dm, struct MEdge *edge_r);
void (*getFaceArray)(DerivedMesh *dm, struct MFace *face_r);

These functions copy all vertices, edges or faces from the DerivedMesh into the buffer pointed to by vert_r, edge_r or face_r respectively (which must point to a buffer large enough).

struct {MVert,MEdge,MFace} *dup{Vert,Edge,Face}Array
struct MVert *(*dupVertArray)(DerivedMesh *dm);
struct MEdge *(*dupEdgeArray)(DerivedMesh *dm);
struct MFace *(*dupFaceArray)(DerivedMesh *dm);

These functions return a copy of all the vertices, edges or faces from the DerivedMesh.

  • It is the caller's responsibility to free (with MEM_freeN) the returned pointer when it is no longer needed.
void *get{Vert,Edge,Face}Data
void *(*getVertData)(DerivedMesh *dm, int index, int type);
void *(*getEdgeData)(DerivedMesh *dm, int index, int type);
void *(*getFaceData)(DerivedMesh *dm, int index, int type);

These functions return a pointer to a single element of vertex, edge or face custom data of the specified type from the DerivedMesh.

  • This gives a pointer to the actual data, not a copy - any changes made will affect the DerivedMesh.
void *get{Vert,Edge,Face}DataArray
void *(*getVertDataArray)(DerivedMesh *dm, int type);
void *(*getEdgeDataArray)(DerivedMesh *dm, int type);
void *(*getFaceDataArray)(DerivedMesh *dm, int type);

These functions return a pointer to the entire array of vertex, edge or face custom data of the specified type from the DerivedMesh.

  • This gives a pointer to the actual data, not a copy - any changes made will affect the DerivedMesh.
void foreachMappedVert
void (*foreachMappedVert)(DerivedMesh *dm,
                          void (*func)(void *userData, int index, float *co,
                                       float *no_f, short *no_s),
                          void *userData);

Iterates over each mapped vertex in the DerivedMesh, calling the given function (func) with the original vertex index and the mapped vertex's new coordinate and normal.

  • For historical reasons the normal can be passed as a float or short array, only one should be non-NULL.
void foreachMappedEdge
void (*foreachMappedEdge)(DerivedMesh *dm,
                          void (*func)(void *userData, int index,
                                       float *v0co, float *v1co),
                          void *userData);

Iterates over each mapped edge in the DerivedMesh, calling the given function (func) with the original edge index and the mapped edge's new coordinates.

void foreachMappedFaceCenter
void (*foreachMappedFaceCenter)(DerivedMesh *dm,
                                void (*func)(void *userData, int index,
                                             float *cent, float *no),
                                void *userData);

Iterates over each mapped face in the DerivedMesh, calling the given function (func) with the original face index and the mapped face's (or faces') center and normal.

struct DispListMesh *convertToDispListMesh
struct DispListMesh* (*convertToDispListMesh)(DerivedMesh *dm,
                                              int allowShared);

Converts the DerivedMesh to a new DispListMesh, which should be freed by the caller.

  • If allowShared is true then the caller is committing to not freeing the DerivedMesh before freeing the DispListMesh. This means that certain fields of the returned DispListMesh can safely be shared with the DerivedMesh's internal data.
void getMinMax
void (*getMinMax)(DerivedMesh *dm, float min_r[3], float max_r[3]);

Iterates over all vertex coordinates, calling DO_MINMAX with the given arguments.

  • Also called in Editmode.
void getVertCo
void (*getVertCo)(DerivedMesh *dm, int index, float co_r[3]);

Gets a vertex's location.

  • Undefined if index is not valid.
  • Can be undefined.
  • Must be defined for modifiers that only deform however.


void getVertCos
void (*getVertCos)(DerivedMesh *dm, float (*cos_r)[3]);

Fill the array (length given by getNumVerts()) with all vertex locations.

  • Can be undefined.
  • Must be defined for modifiers that only deform however.
void getVertNo
void (*getVertNo)(DerivedMesh *dm, int index, float no_r[3]);

Get a vertex's normal.

  • Undefined if index is not valid.
  • Can be undefined.
  • Must be defined for modifiers that only deform however.
void drawVerts
void (*drawVerts)(DerivedMesh *dm);

Draws all vertices as bgl points.

void drawUVEdges
void (*drawUVEdges)(DerivedMesh *dm);

Draws edges in the UV mesh (if it exists).

void drawEdges
void (*drawEdges)(DerivedMesh *dm, int drawLooseEdges);

Draws all edges as lines.

  • Also called for *final* editmode DerivedMeshes.
void drawLooseEdges
void (*drawLooseEdges)(DerivedMesh *dm);

Draw all loose edges (edges with no adjoining faces).

void drawFacesSolid
void (*drawFacesSolid)(DerivedMesh *dm, int (*setMaterial)(int));

Draws all faces.

  • Sets face normal or vertex normal based on inherited face flag.
  • Uses inherited face material index to call setMaterial.
  • Only if setMaterial returns true.
  • Also called for *final* editmode DerivedMeshes.
void drawFacesColored
void (*drawFacesColored)(DerivedMesh *dm, int useTwoSided,
                         unsigned char *col1, unsigned char *col2);

Draws all faces.

  • If useTwoSided, draw front and back using col arrays.
  • col1 and col2 are arrays of length numFace*4 of 4 component colors in ABGR format, and should be passed as per-face vertex color.
void drawFacesTex
void (*drawFacesTex)(DerivedMesh *dm,
                     int (*setDrawOptions)(struct TFace *tface, int matnr));

Draws all faces using TFace data.

  • Drawing options too complicated to enumerate, look at code.
void drawMappedFaces
void (*drawMappedFaces)(DerivedMesh *dm,
                        int (*setDrawOptions)(void *userData, int index,
                                              int *drawSmooth_r),
                        void *userData, int useColors);

Draws mapped faces (with no color or texture).

  • Only if !setDrawOptions or setDrawOptions(userData, mapped-face-index, drawSmooth_r) returns true.
  • If drawSmooth is set to true then vertex normals should be set and glShadeModel called with GL_SMOOTH. Otherwise the face normal should be set and glShadeModel called with GL_FLAT.
  • The setDrawOptions function is allowed to not set drawSmooth (for example, when lighting is disabled), in which case the implementation should draw as smooth shaded.
void drawMappedFacesTex
void (*drawMappedFacesTex)(DerivedMesh *dm,
                           int (*setDrawOptions)(void *userData,
                                                 int index),
                           void *userData);

Draws mapped faces using TFace data.

  • Drawing options too complicated to enumerate, look at code.
void drawMappedEdges
void (*drawMappedEdges)(DerivedMesh *dm,
                        int (*setDrawOptions)(void *userData, int index),
                        void *userData);

Draws mapped edges as lines.

  • Only if !setDrawOptions or setDrawOptions(userData, mapped-edge) returns true
void drawMappedEdgesInterp
void (*drawMappedEdgesInterp)(DerivedMesh *dm, 
                              int (*setDrawOptions)(void *userData,
                                                    int index), 
                              void (*setDrawInterpOptions)(void *userData,
                                                           int index,
                                                           float t),
                              void *userData);

Draws mapped edges as lines with interpolation values.

  • Only if !setDrawOptions or setDrawOptions(userData, mapped-edge, mapped-v0, mapped-v1, t) returns true.
  • NOTE: This routine is optional!
void release
void (*release)(DerivedMesh *dm);

Releases the DerivedMesh and all associated data using MEM_freeN.

Global functions
void DM_init_funcs
void DM_init_funcs(DerivedMesh *dm);

A utility function used by DerivedMesh backends to initialise a DerivedMesh's function pointers to the default implementation (for those functions which have a default).

void DM_init
void DM_init(DerivedMesh *dm, int numVerts, int numEdges, int numFaces);

A utility function used by DerivedMesh backends to initialise a DerivedMesh for the desired number of vertices, edges and faces (doesn't allocate memory for them, just sets up the custom data structures and calls DM_init_funcs to set up default function implementations).

void DM_from_template
void DM_from_template(DerivedMesh *dm, DerivedMesh *source,
                      int numVerts, int numEdges, int numFaces);

A utility function used by DerivedMesh backends to initialise a DerivedMesh for the desired number of vertices, edges and faces, with a layer setup copied from the source DerivedMesh.

void DM_release
void DM_release(DerivedMesh *dm);

A utility function used by DerivedMesh backends to release a DerivedMesh's layers.

void DM_to_mesh
void DM_to_mesh(DerivedMesh *dm, struct Mesh *me);

A utility function to convert a DerivedMesh to a Mesh.

void DM_add_{vert,edge,face}_layer
void DM_add_vert_layer(struct DerivedMesh *dm, int type, int flag,
                       void *layer);
void DM_add_edge_layer(struct DerivedMesh *dm, int type, int flag,
                       void *layer);
void DM_add_face_layer(struct DerivedMesh *dm, int type, int flag,
                       void *layer);

Adds a vertex, edge or face custom data layer to a DerivedMesh, optionally backed by an external data array.

  • If layer != NULL, it is used as the layer data array, otherwise new memory is allocated.
  • The layer data will be freed by dm->release unless (flag & LAYERFLAG_NOFREE) is true.
void *DM_get_{vert,edge,face}_data
void *DM_get_vert_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_edge_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_face_data(struct DerivedMesh *dm, int index, int type);

Custom data access functions. These return a pointer to the data at the given index from the first layer of the specified type.

  • If they return NULL for valid indices, there is no data of that type.
  • Note that these return pointers, not copies - any change modifies the internals of the DerivedMesh.
void *DM_get_{vert,edge,face}_data_layer
void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_face_data_layer(struct DerivedMesh *dm, int type);

Custom data layer access functions. These return a pointer to the first data layer which matches the specified type (this will be a flat array).

  • If they return NULL, there is no data of that type.
  • Note that these return pointers, not copies - any change modifies the internals of the DerivedMesh.
void DM_set_{vert,edge,face}_data
void DM_set_vert_data(struct DerivedMesh *dm, int index, int type, void *data);
void DM_set_edge_data(struct DerivedMesh *dm, int index, int type, void *data);
void DM_set_face_data(struct DerivedMesh *dm, int index, int type, void *data);

Custom data setting functions. These copy the supplied data into the first layer of the specified type using the layer's copy function (which will be a deep copy if appropriate).

void DM_copy_{vert,edge,face}_data
void DM_copy_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest,
                       int source_index, int dest_index, int count);
void DM_copy_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest,
                       int source_index, int dest_index, int count);
void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
                       int source_index, int dest_index, int count);

Custom data copy functions. These copy count elements from source_index in source to dest_index in dest.

  • These copy all layers for which the LAYERFLAG_NOCOPY flag is not set.
void DM_free_{vert,edge,face}_data
void DM_free_vert_data(struct DerivedMesh *dm, int index, int count);
void DM_free_edge_data(struct DerivedMesh *dm, int index, int count);
void DM_free_face_data(struct DerivedMesh *dm, int index, int count);

Custom data free functions. These call the layer's free function on count elements, starting at index.

  • These free all layers for which the LAYERFLAG_NOFREE flag is not set.
void DM_interp_vert_data
void DM_interp_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest,
                         int *src_indices, float *weights,
                         int count, int dest_index);

Interpolates vertex data from the count vertices indexed by src_indices in the source DerivedMesh using the given weights and stores the result in the vertex indexed by dest_index in the dest DerivedMesh.

  • If weights is NULL, all weights default to 1.
void DM_interp_edge_data
typedef float EdgeVertWeight[SUB_ELEMS_EDGE][SUB_ELEMS_EDGE];
void DM_interp_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest,
                         int *src_indices,
                         float *weights, EdgeVertWeight *vert_weights,
                         int count, int dest_index);

Interpolates edge data from the count edges indexed by src_indices in the source mesh using the given weights and stores the result in the edge indexed by dest_index in the dest mesh.

  • If weights is NULL, all weights default to 1.
  • If vert_weights is non-NULL, any per-vertex edge data is interpolated using vert_weights[i] multiplied by weights[i].
void DM_interp_face_data
typedef float FaceVertWeight[SUB_ELEMS_FACE][SUB_ELEMS_FACE];
void DM_interp_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
                         int *src_indices,
                         float *weights, FaceVertWeight *vert_weights,
                         int count, int dest_index);

Interpolates face data from the count faces indexed by src_indices in the source mesh using the given weights and stores the result in the face indexed by dest_index in the dest mesh.

  • If weights is NULL, all weights default to 1.
  • If vert_weights is non-NULL, any per-vertex face data is interpolated using vert_weights[i] multiplied by weights[i].

CustomData API

The CustomData API provides a generic way to manipulate per-element custom data. Each unit of custom data is called a layer. Each layer is identified by a type, which has a size and a set of data-handling functions associated with it.

CustomData structure

The CustomData structure stores a collection of custom data layers associated with a mesh element type.

typedef struct CustomData {
   struct LayerDesc *layers; /* data layer descriptors */
   int numLayers;            /* current number of layers */
   int maxLayers;            /* maximum number of layers */
   int numElems;             /* current number of elements */
   int maxElems;             /* maximum number of elements */
} CustomData;

LayerDesc structure

Each layer is described by the LayerDesc structure:

typedef struct LayerDesc {
   short type; /* type of data in layer */
   short flag; /* general purpose flag */
   void *data; /* layer data */
} LayerDesc;

The LayerDesc.type field is passed to the layerType_getInfo function, where it is used as an index into the LAYERTYPEINFO array (an array of LayerTypeInfo structures). It can hold any value from the following enumeration except LAYERTYPE_NUMTYPES:

/* custom data types */
enum {
   LAYERTYPE_MVERT = 0,
   LAYERTYPE_MSTICKY,
   LAYERTYPE_MDEFORMVERT,
   LAYERTYPE_MEDGE,
   LAYERTYPE_MFACE,
   LAYERTYPE_TFACE,
   LAYERTYPE_MCOL,
   LAYERTYPE_ORIGINDEX,
   LAYERTYPE_NORMAL,
   LAYERTYPE_FLAGS,
   LAYERTYPE_NUMTYPES
};

LayerTypeInfo structure

The LayerTypeInfo structure holds information about a layer type, including its size and various functions which are used to access or modify it. The LAYERTYPEINFO array is a static array of LayerTypeInfo structures indexed by type ID and accessed via layerType_getInfo(). When a new layer type is added, a new entry must be added to this array, giving the size and data manipulation functions (if needed) for the new type.

typedef struct LayerTypeInfo {
   int size; /* the memory size of one element of this layer's data */

   /* a function to copy count elements of this layer's data
    * (deep copy if appropriate)
    * size should be the size of one element of this layer's data (e.g.
    * LayerTypeInfo.size)
    */
   void (*copy)(const void *source, void *dest, int count, int size);

   /* a function to free any dynamically allocated components of this
    * layer's data (note the data pointer itself should not be freed)
    * size should be the size of one element of this layer's data (e.g.
    * LayerTypeInfo.size)
    */
   void (*free)(void *data, int count, int size);
   
   /* a function to interpolate between count source elements of this
    * layer's data and store the result in dest
    * if weights == NULL or sub_weights == NULL, they should default to 1
    *
    * weights gives the weight for each element in sources
    * sub_weights gives the sub-element weights for each element in sources
    *    (there should be (sub element count)^2 weights per element)
    * count gives the number of elements in sources
    */
   void (*interp)(void **sources, float *weights, float *sub_weights,
                  int count, void *dest);
} LayerTypeInfo;

const LayerTypeInfo LAYERTYPEINFO[LAYERTYPE_NUMTYPES] = {
   {sizeof(MVert), NULL, NULL, NULL},
   {sizeof(MSticky), NULL, NULL, NULL},
   {sizeof(MDeformVert),
    layerCopy_mdeformvert, layerFree_mdeformvert, layerInterp_mdeformvert},
   {sizeof(MEdge), NULL, NULL, NULL},
   {sizeof(MFace), NULL, NULL, NULL},
   {sizeof(TFace), NULL, NULL, layerInterp_tface},
   /* 4 MCol structs per face */
   {sizeof(MCol) * 4, NULL, NULL, layerInterp_mcol},
   {sizeof(int), NULL, NULL, NULL},
   /* 3 floats per normal vector */
   {sizeof(float) * 3, NULL, NULL, NULL},
   {sizeof(int), NULL, NULL, NULL},
};

const LayerTypeInfo *layerType_getInfo(int type);

CustomData functions

These functions provide a generic interface to a custom element data stack.

void CustomData_init
void CustomData_init(CustomData *data,
                    int maxLayers, int maxElems, int subElems);

Initialises a CustomData object with space for the given number of data layers and the given number of elements per layer.


void CustomData_from_template
void CustomData_from_template(const CustomData *source, CustomData *dest,
                             int maxElems);

Initialises a CustomData object with the same layer setup as source and memory space for maxElems elements.


void CustomData_free
void CustomData_free(CustomData *data);

Frees data associated with a CustomData object (doesn't free the object itself, though).


int CustomData_add_layer
int CustomData_add_layer(CustomData *data, int type, int flag, void *layer);

Adds a data layer of the given type to the CustomData object, optionally backed by an external data array.

  • If layer != NULL, it is used as the layer data array, otherwise new memory is allocated.
  • The layer data will be freed by CustomData_free unless (flag & LAYERFLAG_NOFREE) is true.
  • This function grows the number of layers in data if data->maxLayers has been reached.
  • Returns 1 on success, 0 on failure.


int CustomData_compat
int CustomData_compat(const CustomData *data1, const CustomData *data2);

Returns 1 if the two objects are compatible (same layer types and flags in the same order), 0 if not.


int CustomData_copy_data
int CustomData_copy_data(const CustomData *source, CustomData *dest,
                        int source_index, int dest_index, int count);

Copies data from one CustomData object to another.

  • The objects need not be compatible; each source layer is copied to the first dest layer of correct type (if there is none, the layer is skipped)
  • Returns 1 on success, 0 on failure


int CustomData_free_elem
int CustomData_free_elem(CustomData *data, int index, int count);

Frees count data elements on each layer starting at index in a CustomData object.

  • Returns 1 on success, 0 on failure.


int CustomData_interp
int CustomData_interp(const CustomData *source, CustomData *dest,
                     int *src_indices, float *weights, float *sub_weights,
                     int count, int dest_index);

Interpolates data from one CustomData object to another.

  • The objects need not be compatible, each source layer is interpolated to the first dest layer of the correct type (if there is none, the layer is skipped).
  • If weights == NULL or sub_weights == NULL, they default to all 1's.
  • src_indices gives the source elements to interpolate from.
  • weights gives the weight for each source element.
  • sub_weights is an array of matrices of weights for sub-elements (matrices should be source->subElems * source->subElems in size).
  • count gives the number of source elements to interpolate from.
  • dest_index gives the dest element to write the interpolated value to.
  • Returns 1 on success, 0 on failure.


void *CustomData_get
void *CustomData_get(const CustomData *data, int index, int type);

Gets a pointer to the data element at index from the first layer of the specified type.

  • Returns NULL if there is no layer of the specified type.


void *CustomData_get_layer
void *CustomData_get_layer(const CustomData *data, int type);

Gets a pointer to the first layer of the specified type.

  • Returns NULL if there is no layer of the specified type.


void CustomData_set
void CustomData_set(const CustomData *data, int index, int type, void *source);

Copies the data from source to the data element at index in the first layer of the specified type.

  • No effect if there is no layer of the specified type.


void CustomData_set_num_elems
void CustomData_set_num_elems(CustomData *data, int numElems);

Sets the number of elements in a CustomData object.

  • If the value given is more than the CustomData object's maximum (set by CustomData_init), the maximum is used.

CDDerivedMesh API

These functions are used to create and manipulate CDDerivedMesh objects.

struct DerivedMesh *CDDM_new

struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces);

Creates a new CDDerivedMesh with space for the specified number of vertices, edges and faces.

struct DerivedMesh *CDDM_from_mesh

struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh);

Creates a CDDerivedMesh from the given Mesh.

struct DerivedMesh *CDDM_from_editmesh

struct DerivedMesh *CDDM_from_editmesh(struct EditMesh *em, struct Mesh *me);

Creates a CDDerivedMesh from the given EditMesh, retrieving element data from the given Mesh where necessary.

struct DerivedMesh *CDDM_copy

struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm);

Copies the given DerivedMesh with verts, faces & edges stored as custom element data.

struct DerivedMesh *CDDM_from_template

struct DerivedMesh *CDDM_from_template(struct DerivedMesh *source,
                                 int numVerts, int numEdges, int numFaces);

Creates a CDDerivedMesh with the same layer stack configuration as the given DerivedMesh and containing the requested numbers of elements.

  • Elements are initialised to all zeros.

void CDDM_apply_vert_coords

void CDDM_apply_vert_coords(struct DerivedMesh *cddm, float (*vertCoords)[3]);

Applies vertex coordinates to a CDDerivedMesh.

void CDDM_calc_normals

void CDDM_calc_normals(struct DerivedMesh *dm);

Recalculates normals for a CDDerivedMesh.

void CDDM_calc_edges

void CDDM_calc_edges(struct DerivedMesh *dm);

Calculates edges for a CDDerivedMesh (from face data).

  • This completely replaces the current edge data in the DerivedMesh.

void CDDM_set_num_{vert,edge,face}s

void CDDM_set_num_verts(struct DerivedMesh *dm, int numVerts);
void CDDM_set_num_edges(struct DerivedMesh *dm, int numEdges);
void CDDM_set_num_faces(struct DerivedMesh *dm, int numFaces);

Sets the number of vertices/edges/faces in a CDDerivedMesh. If the value given is more than the maximum (as defined at creation time), the maximum is used.

struct {MVert,MEdge,MFace} *CDDM_get_{vert,edge,face}

struct MVert *CDDM_get_vert(struct DerivedMesh *dm, int index);
struct MEdge *CDDM_get_edge(struct DerivedMesh *dm, int index);
struct MFace *CDDM_get_face(struct DerivedMesh *dm, int index);

Vertex, edge or face access functions.

  • These should always succeed if index is within bounds.
  • Note these return pointers - any change modifies the internals of the mesh.

struct {MVert,MEdge,MFace} *CDDM_get_{vert,edge,face}s

struct MVert *CDDM_get_verts(struct DerivedMesh *dm);
struct MEdge *CDDM_get_edges(struct DerivedMesh *dm);
struct MFace *CDDM_get_faces(struct DerivedMesh *dm);

Vertex, edge or face array access functions - these return the array holding the desired data.

  • Should always succeed.
  • Note these return pointers - any change modifies the internals of the mesh.

Progress Log

I will try to update this with a status report at least every friday.

2006/08/19

What I've done this week
  • Added the UV projection modifier.
  • Added an option to enable/disable automatic (threshold-based) sharp edges in the Autosmooth modifier.
  • Changed the Displace modifier to use a texture instead of a material for the displacement input.
  • Added limited texture coordinate support to the Displace modifier - Local, Global, Object and UV are supported.
  • Added the foreachIDLink function to the modifier API, and added the corresponding modifiers_foreachIDLink function to BKE_modifier.h (this function is called when reading files & elsewhere to apply a function to all datablocks linked by modifiers).
  • Fixed the modifier Apply button to bake all data to the mesh.
  • Fixed the "Subsurf UV" option in the Subsurf modifier.
  • Refactored and (slightly) optimised modifier stack code.
What remains to be done
  • Update modifier stack API documentation in the wiki.
  • Attempt to fix the orco calculation problem outlined in the previous update.
  • Fix an issue with the Displace modifier where UV coordinates do not map correctly.
  • Further refactoring and optimisation.

2006/08/12

What I've done this week
  • Continued work on the Autosmooth modifier, adding support for user-defined sharp edges and non-manifold meshes.
  • Continued work on the Displace modifier, adding support for vertex groups, better material handling and a midlevel input.
  • Discovered a problem with orco calculation - the wrong number of coordinates can be generated from the modifier stack, leading to random orcos and occasional crashes (this problem appears to have been lurking in bf-blender for some time).
  • Changed derivedmesh drawing functions to use derivedmesh face smooth flags rather than flags from the original mesh. CCGDerivedMesh assumes all faces are smooth, this needs to be fixed.
  • A bunch of small bugfixes and improvements.
What I plan to do next week
  • Update modifier stack API documentation in the wiki.
  • Add the UV projection modifier.
  • Refactor and optimise modifier stack code.
  • Add an option to enable/disable automatic (threshold-based) sharp edges in the Autosmooth modifier.
  • Attempt to add proper texture coordinate support to the Displace modifier.
  • Attempt to fix the orco calculation problem outlined above.

2006/08/08

What I've done this week
  • Added a first draft of the Displace modifier.
  • Added a "set smooth" option to the Autosmooth modifier.
  • Investigated a bug with the Autosmooth modifier - it doesn't handle non-manifold meshes properly; a fix is on the way.
What I plan to do next week
  • Continue work on the Autosmooth modifier, adding support for user-defined sharp edges and non-manifold meshes.
  • Continue work on the Displace modifier, adding support for vertex groups, proper texture mapping and better material handling.
  • Update modifier stack API documentation in the wiki.

2006/07/28

What I've done this week
  • Added a first draft of the Autosmooth modifier.
  • Worked on modifier stack performance, achieving some speedups (mostly in CustomData and CDDerivedMesh code).
  • Refactored and tidied up modifier stack code in places.
What I plan to do next week
  • Continue work on the Autosmooth modifier, adding a "set smooth" option and support for user-defined sharp edges.
  • Add a first draft of the Displace modifier.
  • Continue optimisation and refactoring of modifier stack code.

2006/07/22

What I've done this week
  • Added support infrastructure for interpolation/copying of dynamically allocated data (such as vertex groups).
  • Added vertex group interpolation to the Subsurf modifier.
  • Spent a large part of the week trying to improve the performance of the Subsurf modifier. I've had some small successes, but there's still a reasonably significant slowdown relative to current Blender CVS.
  • Made some minor refactoring and bugfixing changes.
What I plan to do next week
  • Begin work on the Autosmooth modifier (for real this time).
  • Work on modifier stack performance.
  • Refactor and tidy up modifier stack code where needed.

2006/07/12

  • Added custom data interpolation functions for verts, edges & faces.
  • Updated the Subsurf modifier to interpolate face data (UV coords and vert colours) using the new interpolation function. The "Subsurf UV" option is not yet supported.

2006/07/09

  • Changed Subsurf modifier and modified CCGDerivedMesh so CCGDerivedMesh can be used when in edit mode (as before). This gives comparable performance to Blender main when the Subsurf modifier is last in the list, but is still slow otherwise.

2006/06/30

What I've done this week
  • Re-enabled the Subsurf modifier in the new modifier stack (with some limitations - it doesn't subsurf UVs correctly, and it's slower than before).
  • Restored the modifier type enumeration and re-ordered type info initialisation to match the blender main branch (this means that files saved from the blender main branch should open correctly).
  • Integrated the Mirror modifier into the new modifier stack.
  • Integrated the Decimate modifier into the new modifier stack.
  • Integrated the Wave modifier into the new modifier stack.
  • Integrated the Armature modifier into the new modifier stack.
  • Re-enabled the Boolean modifier in the new modifier stack. It's not fully integrated yet (it still has the limitations of the old modifier).
  • All the old modifiers are now enabled. Some need more work to make them correctly pass all mesh data through.
  • Updated the wiki page to reflect the current design: http://mediawiki.blender.org/index.php/User:Artificer/ModifierStackUpgrade
What I plan to do next week
  • Fix outstanding issues with modifiers (Subsurf, Decimate and Boolean in particular).
  • Refactor and tidy up modifier stack code where needed.
  • Begin work on the Autosmooth modifier.
Other issues
  • I'll be away over the weekend, so I won't be able to attend the Sunday meeting.

2006/06/29

  • Re-enabled the Subsurf modifier in the new modifier stack (with some limitations - it doesn't subsurf UVs correctly, and it's slower than before).
  • Restored the modifier type enumeration and re-ordered type info initialisation to match the blender main branch (this means that files saved from the blender main branch should open correctly).

2006/06/26

  • Integrated the Mirror modifier into the new modifier stack.
  • Integrated the Decimate modifier into the new modifier stack.
  • Integrated the Wave modifier into the new modifier stack.
  • Integrated the Armature modifier into the new modifier stack.
  • Re-enabled the Boolean modifier in the new modifier stack. It's not fully integrated yet (it still has the limitations of the old modifier).

2006/06/25

What I've done this week
  • Integrated the Array modifier into the new stack
  • Integrated the Build modifier into the new stack
  • Added an original index custom data layer to allow for mapping to original mesh indices
What I plan to do next week
  • Integrate the remainder of the current modifiers into the new stack.
  • Fix the wiki page to reflect the current design
Other issues
  • I didn't get much done this week - life got in the way a bit. Next week will be better.

2006/06/16

  • Changed archictecture somewhat so that custom data is now stored in DerivedMesh, rather than in a specific backend
  • Created a CustomData API (replaces LayerStack), with its own header and implementation files
What I've done this week
What I plan to do next week
  • Complete new modifier stack implementation
  • Integrate the remainder of the current modifiers into the new stack.
Other issues
  • I have an exam on Tuesday (2006/06/20), so I'll be somewhat distracted up to then.

2006/06/15

  • Added support for editmode modifiers
  • Added support for mesh deformations
  • Re-integrated the Curve modifier
  • Removed the original data constraint from the Curve modifier

2006/06/14

  • Commited a first hack at a basic modifier stack implementation

2006/06/09

What I've done this week
What I plan to do next week
  • Code & test a basic modifier stack implementation with one "do nothing" modifier working.
  • Expand the implementation as far as time allows to support as many modifers as possible.
  • Expand modifier stack documentation.
Other issues
  • None that I'm aware of.

2006/06/04

What I've done this week
What I plan to do next week
  • Expand upon current modifier stack documentation
  • Finish first draft of new modifier stack design
Other issues
  • I'm taking exams at the moment, so I may be a little distracted over the next week. It should be OK after that.