利用者:SaphireS/gsoc2016/codedoc

提供: wiki
移動先: 案内検索

Code Documentation

Since I'm digging and learing the relevant code I take a lot of notes, so I figured I'd create a wiki page for all my findings so others can profit from them too.

Old but useful informations: https://wiki.blender.org/index.php/Dev:Source/Textures/UV/Unwrapping

File structure

All the relevant code for UV stuff is located in the blender/source/blender/editors/uvedit directory. It contains the following files:

  • uvedit_intern.h :Contains declarations of the most important uv operators and structs
  • uvedit_ops.c :Contains definitions of all UV_OT_* operators that are not in uvedit_unwrap_ops.c
  • uvedit_parametrizer.h :Header file with declarations for all parametrizer functions
  • uvedit_parametrizer.c :Code for all param_* functions which are used for topological operations in operators like unwrap, pack islands, minimize stretch, etc...
  • uvedit_smart_stitch.c :Code for the smart stitching operator
  • uvedit_unwrap_ops.c :Contains definitions for all operators that are somewhat related to unwrapping, like unwrap, pack islands, etc..
  • uvedit_buttons.c :Button functions
  • uvedit_draw.c :Drawing of UVs in image space
  • ED_uvedit.h :Found at blender/source/blender/editors/include, contains entry points for editmesh operators that are called from uv operators if sync selection is enabled

General UV Code

Probably the first thing you want to get in a new operators *_exec() function are the following:

Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
Image *ima = CTX_data_edit_image(C);
ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;

where C is the bContext passed to the operator. The ToolSettings struct is very useful and used often in UV code. Among others it contains these useful members:

/* UV Calculation */
char unwrapper;
char uvcalc_flag;
char uv_flag;
char uv_selectmode;
float uvcalc_margin;

Of these flags, uv_flag is often checked if UV_SYNC_SELECTION is set. If sync selection is enabled the operator directly uses BMesh structures or even calls an editmesh operator which has similar functionality to the uv space one. The second important flag of ToolSettings is uv_selectmode, since you can check the current selection mode with it:

/* toolsettings->uv_selectmode */
#define UV_SELECT_VERTEX	1
#define UV_SELECT_EDGE		2
#define UV_SELECT_FACE		4
#define UV_SELECT_ISLAND	8

Often used structs:

BMFace *efa;
BMEdge *e;
BMLoop *l;
BMEditSelection *ese;
BMElem *ele;
MTexPoly *tf;
MLoopUV *luv;

The for UV tools important structs are MTexPoly and MLoopUV which describe a mesh in UV space/editor. MLoopUV contains nothing more than a single UV vertex coordinate (luv->uv[0] and luv->uv[1]) and a flag.

Iterating over UVmesh elements:

BMIter iter, liter;

//get customdata offset
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);

//iterate over faces of mesh
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
	MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);

        //Check if face is visible in UV editor
	if (uvedit_face_visible_test(scene, ima, efa, tf)) {
                //iterate over loops of face/MTexPoly
		BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE)  {
					
			MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
           
                        //Do stuff with luv here 
                }
        }
}

This iterates over all faces/MTexPolys and for each face over all MLoopUV of the face. Available BMIterTypes for the iterators are:

typedef enum BMIterType {
	BM_VERTS_OF_MESH = 1,
	BM_EDGES_OF_MESH = 2,
	BM_FACES_OF_MESH = 3,
	/* these are topological iterators. */
	BM_EDGES_OF_VERT = 4,
	BM_FACES_OF_VERT = 5,
	BM_LOOPS_OF_VERT = 6,
	BM_VERTS_OF_EDGE = 7, /* just v1, v2: added so py can use generalized sequencer wrapper */
	BM_FACES_OF_EDGE = 8,
	BM_VERTS_OF_FACE = 9,
	BM_EDGES_OF_FACE = 10,
	BM_LOOPS_OF_FACE = 11,
	BM_LOOPS_OF_LOOP = 12,
	BM_LOOPS_OF_EDGE = 13
} BMIterType;

Random useful functions:

  • uvedit_face_visible_test() Check if MTexPoly is even visible/existing in UV editor
  • uvedit_pixel_to_float()
  • ...

Parametrizer

Big thanks to my mentor Howard Trickey for helping me finding my way around this part of the code!

These structures, used for representing and manipulating topology-related UV stuff, are found in uvedit_parametrizer.h/.c Important structs:

  • PHandle: Main state holder, has memory arena, hash tables and an array of PChart.
  • PChart: This represents an UV island. Has arrays of PVert/PEdge/PFace as well as collapsed verts, edges and faces.
  • PFace: UV face, they all seem to be triangles. Edges are linked off of the edge pointer and form a circular list through their next pointers.
  • PEdge: UV edge, contains PVert pointer which points to the origin vertex of the edge. Also has a PFace pointer pointing to the face it belongs to: PEdge is like a loop, only belonging to one PFace! Has pair and next PEdge pointers. Pair if connected to another face along this edge, this is then the (reversed direction) PEdge belonging to the other face (non-manifold shouldnt happen in UV space, eg one edge with 3 faces).
  • PVert: UV Vertex, contains 2d (uv) and 3d coordinates. Has a PEdge pointer to the outgoing edge. Seems like there is onle PVert per BMesh Vertex, since lookup key just uses BMesh vert index.

Topology:

  • p_wheel_edge_prev/next(e): if e’s outgoing edge is from a vertex that has other faces attached to it: imagine traversing the edges in a CCW manner (where faces are also CCW). Then the ‘wheel’ is the set of outgoing edges around the vertex in the CCW order, where you can get from one edge to the next by finding the next face in the wheel (using the paired incoming edge and finding which face that is part of), and then find the edge in that next face that is also outgoing from the edge in question.
  • p_boundary_edge_prev/next(e): similar, but only returns boundary edges.

UV unwrap operators usually start by calling construct_param_handle() to construct the UV data structures from the given Object and BMesh. It consists of calls to param_construct_begin(), construct_param_handle_face_add(), param_edge_set_seam(), param_construct_end().

Selection

There are a bunch of convenient functions to check if elements are selected or if one wants to select/deselect elements:

  • uvedit_uv_select_test(...): Checks if the uv vertex is currently selected.
  • uvedit_uv_select_set(...,cont bool select,...): Calls either uvedit_uv_select_enable() or uvedit_uv_select_disable() depending on the select parameter. Can be used to select or deselect.
  • uvedit_uv_select_enable(...): Selects the uv vertex.
  • uvedit_uv_select_enable(...): Deselects the uv vertex.

The same functions are also available for faces and edges, instead of uvedit_uv_* just use uvedit_edge_* or uvedit_face_* !

Additionally MLoopUVs can be checked if they're currently selected using the MLOOPUV_VERTSEL flag:

if ((luv->flag & MLOOPUV_VERTSEL) != 0)
	printf("------------ Found selected Vert at: %f, %f -------------\n", luv->uv[0], luv->uv[1]);

After all tagging/selecting is done the operator should call

DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);

before returning OPERATOR_FINISHED (or Cancelled, etc.).

I documented how the shortest path operator works here: Select Shortest Path Editmesh