[Bf-python] New Patch Mesh.transform(mat), Docs included

Campbell Barton cbarton at metavr.com
Fri Mar 4 12:14:24 CET 2005


Hi, just wondering if there is anything that needs fixing with the 
transform patch.
- Cam


Campbell Barton wrote:

> Hi All, just updated my mesh.transfrom function. as well as  docs. I 
> think its stable.
>
> Works like this.
> loc_only = 0
> mesh.transform(mat_4x4, loc_only)
>
> If the 2nd parm is 0 then vertex normals are transformed and 
> normalized (default behavior)
> so you can just do-
>  mesh.transform(mat_4x4)
> if you want normals transformed too.
> -
> If loc_only is 1 then only vert locations will be tx'd.
>
>
> There is realy no resion to do a full vertex recalculation, this may 
> even be bad for sombody who sets the vert normals, then wantes to TX 
> THEIR normal and not have blender re-apply normals.
>
> Also- moving a vert in a mesh does not modify the verts normal, I 
> tested this, transforming should only transform existing normals, not 
> recalculate them.
>
> The default behavior is good- You do a GetRawFromObject(ob), then 
> transform by the objects matrix - in1 line.
> Then export the mesh- verts and vert normals are correct.
>
> I have a test blend file that uses DupliVerts with Rot enabled to see 
> the matrix applied- You can see the normal direction from teh 
> dupliverts. (Proof it works :) )
>
> Patch- Docs included.
> + Test Blendfile
>
> - Cam
>
>------------------------------------------------------------------------
>
>Index: source/blender/python/api2_2x/NMesh.c
>===================================================================
>RCS file: /cvsroot/bf-blender/blender/source/blender/python/api2_2x/NMesh.c,v
>retrieving revision 1.57
>diff -u -p -u -r1.57 NMesh.c
>--- source/blender/python/api2_2x/NMesh.c	1 Mar 2005 02:37:19 -0000	1.57
>+++ source/blender/python/api2_2x/NMesh.c	2 Mar 2005 06:13:36 -0000
>@@ -251,6 +251,15 @@ Optional arguments: if given and nonzero
> 'store_edges': edges data is stored.\n\
> 'vertex_shade': vertex colors are added based on the current lamp setup.";
> 
>+static char NMesh_recalcNormals_doc[] = \
>+"(recalc_normals = 0, store_edges = 0, vertex_shade = 0) - Updates the Mesh.\n\
>+Optional arguments: if given and nonzero:\n\
>+'recalc_normals': normal vectors are recalculated;\n\
>+'store_edges': edges data is stored.\n\
>+'vertex_shade': vertex colors are added based on the current lamp setup.";
>+
>+
>+
> static char NMesh_getMode_doc[] =
> 	"() - get the mode flags of this nmesh as an or'ed int value.";
> 
>@@ -272,6 +281,10 @@ static char NMesh_setSubDivLevels_doc[] 
> 	"([int, int]) - set the subdivision levels for [display, render] -- they are\n\
> clamped to the range [0,6].";
> 
>+static char NMesh_transform_doc[] =
>+	"(matrix, loc_only) - Transform the mesh by the supplied 4x4 matrix.\n\
>+(loc_only) - Optional, If set to 1, transforming the vertex normals is skipped";
>+
> static char M_NMesh_New_doc[] =
> 	"() - returns a new, empty NMesh mesh object\n";
> 
>@@ -1346,6 +1359,71 @@ static PyObject *NMesh_update( PyObject 
> 	return PyInt_FromLong( 1 );
> }
> 
>+static PyObject *NMesh_recalcNormals( PyObject *self, PyObject *a, PyObject *kwd )
>+{
>+	BPy_NMesh *nmesh = ( BPy_NMesh * ) self;
>+	Mesh *mesh = nmesh->mesh;
>+	int recalc_normals = 0, store_edges = 0, vertex_shade = 0;
>+	static char *kwlist[] = {"recalc_normals", "store_edges",
>+		"vertex_shade", NULL};
>+	int needs_redraw = 1;
>+
>+	if (!PyArg_ParseTupleAndKeywords(a, kwd, "|iii", kwlist, &recalc_normals,
>+		&store_edges, &vertex_shade ) )
>+		return EXPP_ReturnPyObjError( PyExc_AttributeError,
>+	    "expected nothing or one to three bool(s) (0 or 1) as argument" );
>+
>+	if( mesh ) {
>+		unlink_existingMeshData( mesh );
>+		convert_NMeshToMesh( mesh, nmesh, store_edges );
>+	} else {
>+		nmesh->mesh = Mesh_fromNMesh( nmesh, store_edges );
>+		mesh = nmesh->mesh;
>+	}
>+
>+	if( recalc_normals )
>+		vertexnormals_mesh( mesh, 0 );
>+
>+	mesh_update( mesh );
>+
>+	nmesh_updateMaterials( nmesh );
>+
>+	if( nmesh->name && nmesh->name != Py_None )
>+		new_id( &( G.main->mesh ), &mesh->id,
>+			PyString_AsString( nmesh->name ) );
>+
>+	if (vertex_shade) {
>+		Base *base = FIRSTBASE;
>+
>+		if (!nmesh->object)
>+			return EXPP_ReturnPyObjError(PyExc_RuntimeError,
>+	    	"link this mesh to an object first with ob.link(mesh)" );
>+
>+		if (G.obedit)
>+			return EXPP_ReturnPyObjError(PyExc_RuntimeError,
>+	    	"can't shade vertices while in edit mode" );
>+
>+		while (base) {
>+			if (base->object == nmesh->object) {
>+				base->flag |= SELECT;
>+				nmesh->object->flag = base->flag;
>+				set_active_base (base);
>+				needs_redraw = 0; /* already done in make_vertexcol */
>+				break;
>+			}
>+			base = base->next;
>+		}
>+		make_vertexcol();
>+
>+		countall();
>+	}
>+
>+	if( !during_script(  ) && needs_redraw)
>+		allqueue( REDRAWVIEW3D, 0 );
>+
>+	return PyInt_FromLong( 1 );
>+}
>+
> /** Implementation of the python method getVertexInfluence for an NMesh object.
>  * This method returns a list of pairs (string,float) with bone names and
>  * influences that this vertex receives.
>@@ -1493,6 +1571,55 @@ static PyObject *NMesh_setSubDivLevels( 
> 	return Py_None;
> }
> 
>+static PyObject *NMesh_transform( PyObject * self, PyObject * args )
>+{
>+	BPy_NMesh *nmesh = ( BPy_NMesh * ) self;
>+	BPy_NMVert *mv;
>+	PyObject *ob1 = NULL;
>+	MatrixObject *mat;
>+	float vx, vy, vz;
>+	int i;
>+	int loc_only = 0;
>+	
>+	if( !PyArg_ParseTuple( args, "O!|i", &matrix_Type, &ob1, &loc_only ) )
>+		return ( EXPP_ReturnPyObjError( PyExc_TypeError,
>+						"expected matrix\n" ) );
>+	
>+	mat = ( MatrixObject * ) ob1;
>+	
>+	if( mat->colSize != 4 || mat->rowSize != 4 )
>+		return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
>+						"matrix must be a 4x4 transformation matrix as returned by object.getMatrix()\n" ) );
>+	
>+	/* Loop through all the verts and transform locations by the supplied matrix */
>+	for( i = 0; i < PySequence_Length(nmesh->verts); i++ ) {
>+		mv = ( BPy_NMVert * ) PySequence_GetItem( nmesh->verts, i );
>+		vx = mv->co[0];
>+		vy = mv->co[1];
>+		vz = mv->co[2];
>+		mv->co[0] = vx*mat->matrix[0][0] + vy*mat->matrix[1][0] + vz*mat->matrix[2][0] + mat->matrix[3][0];
>+		mv->co[1] = vx*mat->matrix[0][1] + vy*mat->matrix[1][1] + vz*mat->matrix[2][1] + mat->matrix[3][1];
>+		mv->co[2] = vx*mat->matrix[0][2] + vy*mat->matrix[1][2] + vz*mat->matrix[2][2] + mat->matrix[3][2];
>+	}
>+	if ( ! loc_only ) {
>+		/* Loop through all the verts and transform normals by the supplied matrix */
>+		for( i = 0; i < PySequence_Length(nmesh->verts); i++ ) {
>+			mv = ( BPy_NMVert * ) PySequence_GetItem( nmesh->verts, i );
>+			vx = mv->no[0];
>+			vy = mv->no[1];
>+			vz = mv->no[2];
>+			mv->no[0] = vx*mat->matrix[0][0] + vy*mat->matrix[1][0] + vz*mat->matrix[2][0];
>+			mv->no[1] = vx*mat->matrix[0][1] + vy*mat->matrix[1][1] + vz*mat->matrix[2][1];
>+			mv->no[2] = vx*mat->matrix[0][2] + vy*mat->matrix[1][2] + vz*mat->matrix[2][2];
>+			Normalise(mv->no);
>+		}
>+	}
>+	
>+	Py_DECREF( mv );
>+	Py_INCREF( Py_None );
>+	return Py_None;
>+}
>+
> static PyObject *NMesh_getMode( BPy_NMesh * self )
> {
> 	PyObject *attr = PyInt_FromLong( self->mode );
>@@ -1579,6 +1706,7 @@ static struct PyMethodDef NMesh_methods[
> 	MethodDef( setMode ),
> 	MethodDef( setMaxSmoothAngle ),
> 	MethodDef( setSubDivLevels ),
>+	MethodDef( transform ),
> 
> /* METH_NOARGS: function(PyObject *self) */
> #undef MethodDef
>Index: source/blender/python/api2_2x/doc/NMesh.py
>===================================================================
>RCS file: /cvsroot/bf-blender/blender/source/blender/python/api2_2x/doc/NMesh.py,v
>retrieving revision 1.30
>diff -u -p -u -r1.30 NMesh.py
>--- source/blender/python/api2_2x/doc/NMesh.py	1 Mar 2005 02:37:19 -0000	1.30
>+++ source/blender/python/api2_2x/doc/NMesh.py	2 Mar 2005 06:13:36 -0000
>@@ -568,6 +568,35 @@ class NMesh:
>         L{setMode}) need their display lists updated, too.
>     """
> 
>+  def transform(matrix, loc_only = 0):
>+    """
>+    Transforms the mesh by the spesified 4x4 matrix, as returned by object.matrix
>+    though this will work with any 4x4 matrix type.
>+    Ideal Useage for this is exporting to an external file, where global vertex
>+    locations are required for each object.
>+    Somtimes external renderers/file formats do not use vertex normals,
>+    In this case you can skip transforming teh vertex normals by setting
>+    the optional parm (loc_only) to 1
>+    
>+    Example::
>+     # This script outputs deformed meshes worldspace vertex locations
>+     # for a selected object
>+     import Blender
>+     from Blender NMesh, Object
>+     
>+     ob = Object.GetSelected()[0] # Get the first selected object
>+     me = NMesh.GetRawFromObject(ob) # Get the objects deformed mesh data
>+     me.transform(ob.matrix)
>+   
>+     for v in me.verts:
>+       print 'worldspace vert', v.co
>+    
>+    @type matrix: Py_Matrix
>+    @param matrix: 4x4 Matrix which can contain location, scale and rotation. 
>+    @type loc_only: int (bool)
>+    @param loc_only: if 1, will only transform vertex locations.
>+    """
>+
>   def getMode():
>     """
>     Get this mesh's mode flags.
>  
>
>------------------------------------------------------------------------
>
>_______________________________________________
>Bf-python mailing list
>Bf-python at projects.blender.org
>http://projects.blender.org/mailman/listinfo/bf-python
>  
>


-- 
Campbell J Barton

133 Hope Street
Geelong West, Victoria 3218 Australia

URL:    http://www.metavr.com
e-mail: cbarton at metavr.com
phone: AU (03) 5229 0241




More information about the Bf-python mailing list