UV Mirror H&V
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 08:19, xxxxxxxx wrote:
Thanks for the help Matthias,
uvwtag->Message(MSG_UPDATE); didn't seem to help.I'm not sure how to use UVWTag::GetDataAddressW; like you're suggesting.
How do I use it so it knows which UWV tag I'm referring to?
Do I set the tag active active with: SetBit(BIT_ACTIVE);
Then follow it with: UVWTag::GetDataAddressW;?The UVWTag class is a bit confusing to me trying to use it directly like that.
-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 08:23, xxxxxxxx wrote:
I'll try to come up with an example.
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 08:28, xxxxxxxx wrote:
That would be very helpful. Thank you.
Also.
Is there any way at all that we can execute the UV projection buttons (Sphere, Cylinder, Frontal, etc..)?Thanks,
-ScottA -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 08:33, xxxxxxxx wrote:
Many of the UV commands are avaible through the CallUVCommand function. This would be an alternative for mirroring as well. It's the way BodyPaint works. I'll try to show this in the example rather than through the UVWTag.
So there are several ways to manipulate UVs. In the end it always depends on what you are exactly trying to do.
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 09:06, xxxxxxxx wrote:
You actually already posted an example how to use CallUVCommand() a while back. And that's where I learned how to use it.
But there's a lot of buttons that are not included in it. Like the "Frontal" and "Mirror V"buttons for example. That's why I switched to editing the UV points individually.
I'm looking in the C4D_painter.h file. And I don't see these buttons defined in there.
And in the C4D_painter.cpp file. The function seems to call to a private class:return C4DOS.Pa->CallUVCommand(padr,PointCount,polys,lPolyCount,uvw,polyselection,pointselection,op,mode,cmdid,settings);
Even if the users were smart enough to add new definitions to CallUVCommand(). It seems that we can't access the class that does all the work. But maybe I'm missing something?
That's why I was thinking there might be an undocumented way to execute the actual buttons themselves. Something similar to this:
LONG tool_id = doc->GetAction(); BasePlugin *tool = NULL; tool = FindPlugin(tool_id, PLUGINTYPE_TOOL); if(!tool) return FALSE; DescriptionCommand dc; dc.id = DescID(MDATA_CREATEPOLYGON_BUTTON); tool->Message(MSG_DESCRIPTION_COMMAND, &dc); EventAdd();
-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 10:54, xxxxxxxx wrote:
In case it's useful, here is some code that I cobbled together from some older SDK example code...
//------------------------------------------------------------------------------------------------------ //****************************************************************************************************** // FrontalMapUVs() - perform a simple 'frontal' uv-mapping //****************************************************************************************************** //------------------------------------------------------------------------------------------------------ #define SIGDIG 5.0 static Real sign(Real n) { if( n > 0.0 ) return 1.0; if( n < 0.0 ) return -1.0; return 0.0; } static Real TrimDecimal(Real num, Real digits) { Real n; n = num * Pow((Real)10.0, digits); n = sign(n) * Abs(Floor(n + 0.5)); return n / Pow((Real)10.0, digits); } Bool FrontalMapUVs(PolygonObject *op, Matrix mg) { if( !op ) return false; LONG numFaces = op->GetPolygonCount(); LONG numVerts = op->GetPointCount(); Vector *pVerts = op->GetPointW(); CPolygon *pPolys = op->GetPolygonW(); UVWTag *pUVTag = (UVWTag * )op->MakeVariableTag(Tuvw, numFaces); if( !pUVTag ) return false; #ifdef _R12_SDK_ UVWHandle pUVHndl = pUVTag->GetDataAddressW(); if( !pUVHndl ) return false; #elif _R11p5_SDK_ void *pUVHndl = pUVTag->GetDataAddressW(); if( !pUVHndl ) return false; #else void *pUVHndl = NULL; #endif LONG ndx; Real lenxinv, lenyinv, lenzinv; Vector mapCenter, mapSize, vMin, vMax; vMin.x = 100000.0; vMin.y = 100000.0; vMin.z = 100000.0; vMax.x = -100000.0; vMax.y = -100000.0; vMax.z = -100000.0; for(ndx=0; ndx<numVerts; ndx++) { Vector pt = pVerts[ndx] * mg; if( pt.x < vMin.x ) vMin.x = pt.x; if( pt.x > vMax.x ) vMax.x = pt.x; if( pt.y < vMin.y ) vMin.y = pt.y; if( pt.y > vMax.y ) vMax.y = pt.y; if( pt.z < vMin.z ) vMin.z = pt.z; if( pt.z > vMax.z ) vMax.z = pt.z; } mapSize.x = Abs(vMax.x - vMin.x); mapSize.y = Abs(vMax.y - vMin.y); mapSize.z = Abs(vMax.z - vMin.z); mapCenter.x = vMin.x+(mapSize.x*0.5); mapCenter.y = vMin.y+(mapSize.y*0.5); mapCenter.z = vMin.z+(mapSize.z*0.5); if (mapSize.x!=0.0) lenxinv = 1.0/mapSize.x; else lenxinv = 0.0; if (mapSize.y!=0.0) lenyinv = 1.0/mapSize.y; else lenyinv = 0.0; if (mapSize.z!=0.0) lenzinv = 1.0/mapSize.z; else lenzinv = 0.0; // Walk the list of polygons and map the UVs for(ndx=0; ndx<numFaces; ndx++) { UVWStruct uvw; cmpUVGet(pUVTag, pUVHndl, ndx, uvw); Vector pt_a = (pVerts[pPolys[ndx].a] - mapCenter) + mg.off; Vector pt_b = (pVerts[pPolys[ndx].b] - mapCenter) + mg.off; Vector pt_c = (pVerts[pPolys[ndx].c] - mapCenter) + mg.off; Vector pt_d = (pVerts[pPolys[ndx].d] - mapCenter) + mg.off; uvw.a.x = TrimDecimal((pt_a.x*lenxinv)+0.5, SIGDIG); uvw.a.y = TrimDecimal((-pt_a.y*lenyinv)+0.5, SIGDIG); uvw.b.x = TrimDecimal((pt_b.x*lenxinv)+0.5, SIGDIG); uvw.b.y = TrimDecimal((-pt_b.y*lenyinv)+0.5, SIGDIG); uvw.c.x = TrimDecimal((pt_c.x*lenxinv)+0.5, SIGDIG); uvw.c.y = TrimDecimal((-pt_c.y*lenyinv)+0.5, SIGDIG); uvw.d.x = TrimDecimal((pt_d.x*lenxinv)+0.5, SIGDIG); uvw.d.y = TrimDecimal((-pt_d.y*lenyinv)+0.5, SIGDIG); cmpUVSet(pUVTag, pUVHndl, ndx, uvw); } return true; }
...note that I call that routine IF the mesh is not already uv-mapped...
// start by grabbing the current UVWTag UVWTag *pSrcUVs = (UVWTag* )(op->GetTag(Tuvw, 0)); if( !pSrcUVs ) { // if not already mapped, do a simple frontal mapping if( !FrontalMapUVs(op, op->GetMgn()) ) return NULL; ....
...also note that I'm just passing the mesh's global matrix, so you could remove that argument and just grab it inside that routine.
The only other note is the "cmpUVGet()/cmpUVSet()" calls... those are calls to my version-compatibility routines...
//------------------------------------------------------------- // cmpUVGet() //------------------------------------------------------------- void cmpUVGet(UVWTag *pUVWTag, UVWHandle pUVHndl, LONG ndx, UVWStruct& uvw) { #ifdef _R11p5_SDK_ if( pUVWTag && pUVHndl ) pUVWTag->Get(pUVHndl, ndx, uvw); #else if( pUVWTag ) uvw = pUVWTag->Get(ndx); #endif } //------------------------------------------------------------- // cmpUVSet() //------------------------------------------------------------- void cmpUVSet(UVWTag *pUVWTag, UVWHandle pUVHndl, LONG ndx, const UVWStruct& uvw) { #ifdef _R11p5_SDK_ if( pUVWTag && pUVHndl ) pUVWTag->Set(pUVHndl, ndx, uvw); #else if( pUVWTag ) pUVWTag->Set(ndx, uvw); #endif }
...where my _Rxx_SDK_ defines are cumulative (ie. R11.5 is also defined in my R12 (and later) builds and R11.5 and R12 defines are also defined in my R13 (and later) builds, along with the R13 define, etc.). This is a carry-over from long, long ago... I'm in the process of changing over to a "#if API_VERSION < 13000" type system.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 11:23, xxxxxxxx wrote:
Thanks Giblet.
That might come in handy later on. But right now I can't even manage to make simple UV point move where I want it to go.
I can give them new positions. And those new positions show up as being changed in the console.
But they won't budge on the UV canvas. And I don't know why.-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 11:25, xxxxxxxx wrote:
Just do...
pPolyObj->Message(MSG_UPDATE); EventAdd();
...after changing anything on pPolyObj (including any UVWTag modifications). EDIT: that is... after doing all your changes (you only need to do it once, before returning from your plugin code).
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 11:35, xxxxxxxx wrote:
Yeah. I tried that (see the code example I posted earlier).
It's not working.-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 11:57, xxxxxxxx wrote:
Scott, from where do you call your UV code, e.g. what kind of plugin (tag, command etc.)?
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 12:09, xxxxxxxx wrote:
I'm doing it from a GeDialog plugin. Inside of the Command() method.
We are allowed to edit the existing UV's in existing uvwtags right?
I see lots of MakeTag type UV code in the forums. But not much that deals with editing existing uvwtags.-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 13:01, xxxxxxxx wrote:
The problem is that you are NOT modifying the uvw struct before you Set() it back - you are only modifying (and printing) a local variable.
EDIT: In other words...
ax = 0.5; //Move the vertex res.a.x to 0.5 on the canvas uvwtag->Set(dataptr,i,res); //Update the changes to the UVpolygon in the UVW tag <--------Not working!!
Your comments above are incorrect... modifying the local 'ax' variable is not the same as modifying res.a.x
To fix it, you'd need to...**res.a.x** = 0.5; //Move the vertex res.a.x to 0.5 on the canvas uvwtag->Set(dataptr,i,res); //Update the changes to the UVpolygon in the UVW tag <--------It works!!
Cheers.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 13:29, xxxxxxxx wrote:
..just another comment/suggestion...
If you're going to be calling Get()/Set() on the UVWTag (and/or looping through all the uv-polys), then you typically don't need to do the GetActiveUVSet() stuff... that's mostly useful when you need to know which uv-polys/points are currently selected or if you want to work with the arrays directly (uvhandle->GetUVW() / uvhandle->SetUVW()).
The reason it's needed for 'selected uv-points', for example is that... there are basically 4 uv-points per uv-polygon - which may be a far different number (and different indexing) than the total number of points/vertices of the mesh (a cube has 8 vertices, but it has 6 * 4 = 24 uv-points).
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 16:08, xxxxxxxx wrote:
Ah ha.
Now I think I see what I'm doing wrong. I was assigning variables incorrectly.Here's a working version of my previous example:
BaseObject *obj = doc->GetActiveObject(); if(!obj)return FALSE; PointObject *pobj = ToPoint(obj); //Cast the BaseObject type to a PointObject type and assign it to a variable "pobj" Vector *points = pobj->GetPointW(); //Get the array of points in the object(returns their vector positions) LONG count = pobj->GetPointCount(); BaseContainer bc; //Create an empty container..We'll use this to change some UV attributes TempUVHandle *handle = GetActiveUVSet(doc, GETACTIVEUVSET_ALL); //Create an instance of the TempUVHandle class if (!handle) return FALSE; UVWTag *uvwtag = (UVWTag* )(pobj->GetTag(Tuvw, 0)); //The UVW tag that's on the object UVWHandle UVpolys = uvwtag->GetDataAddressW(); //The array of polygons in the UVWtag LONG UVpolycount = handle->GetPolyCount(); //The number of UVpolygons UVWStruct res; //An empty struct that we will eventually store the UV values in //To access the points in the UV polygons. Use res.a, res.b, res.c, res.d for (LONG i=0; i<UVpolycount; i++) { LONG polyindx = i; //Assign the polygon's index# to a variable uvwtag->Get(UVpolys,i,res); //Store the polygon UVW info into the variable "res" for each UVpolygon //UVWTag::Get(UVpolys, i, res); //Alternative way to do the same thing res.a.x = 0.5; //Move the vertex res.a.x to 0.5 on the canvas uvwtag->Set(UVpolys,i,res); //Update the changes to the UVpolygon in the UVW tag GePrint("ID#: " + LongToString(polyindx)); GePrint("AX: " + RealToString(res.a.x) +".... " + "AY: " + RealToString(res.a.y)); GePrint("BX: " + RealToString(res.b.x) +".... " + "BY: " + RealToString(res.b.y)); } FreeActiveUVSet(handle); //Free the memory pobj->Message(MSG_UPDATE); uvwtag->Message(MSG_UPDATE); EventAdd();
Now all I need is a way to execute those UV projection buttons.
If it's even possible.Thanks a lot Giblet,
-ScottA -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 27/07/2012 at 05:14, xxxxxxxx wrote:
Seems like the only open problem are the UV projection buttons. Btw. I was wrong about CallUVCommand and UV projections. I can't find a way to call them through the API. It looks like you need to do on your own. There is some example code about projections in the TexData structure documentation.
If I've find a simpler way I will get back to it.
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 27/07/2012 at 07:27, xxxxxxxx wrote:
I was pretty sure that was going to be your answer Matthias.
But sometimes you manage to pull a secret button command out of your bag of tricks. So I had to ask.
Body Paint seems to be much less supported by the SDK than the rest of the program.
It's been totally ignored for the last few updates. So maybe someday if they go back to it they will also add SDK support for all of the buttons.Giblet provided some code about Frontal projecting. That's the only one I really was interested in anyway. So I'll study what he provided and see if I can learn how to do it.
Thanks for the help,
-ScottA -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 27/07/2012 at 08:17, xxxxxxxx wrote:
Originally posted by xxxxxxxx
...Giblet provided some code about Frontal projecting...
... that code was originally (at least partially) based on the example code that Matthias mentions above, btw.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 27/07/2012 at 08:54, xxxxxxxx wrote:
^ I actually just got finished with your mapping code Giblet.
I had to strip out a lot of the version checking stuff to make easier to read and see what it is doing.Unfortunately. The result isn't Frontal mapping. It's more like Flat mapping.
As far as I can tell. Your code seems to get the size of the UV canvas then it runs through the UV's and places the UV points at the UV canvas boundaries...Thus producing the same result as the Flat button.I think the "Front" mapping button does a ray projection to get the object's points.
Then passes them to the UV points so the UV's match the orientation of the object in the scene view.
So I think I need to use: RayParameter *param=sd->GetRayParameter();This might be a bit over my head. But I'll try to figure it out.
-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 27/07/2012 at 09:38, xxxxxxxx wrote:
Actually... yeah, if you just pass in the mesh's global matrix, you end up with a (frontal) Flat-mapping. You could manipulate the matrix passed in to account for the camera orientation (no need for ray-tracing).
I usually figure out matrix operations by trial-and-error (which I can't do right now), but basically, you need to combine the Inverse Camera matrix with the mesh's global (if you want to account for current mesh rotations) or local matrix...
Matrix invCam = !pBaseDoc->GetActiveBaseDraw()->GetMg(); // inverse camera matrix // you may or may not also need to zero out the translation vector before combining... // invCam.off = Vector(); Matrix mCombine = op->GetMg() * invCam; // or possibly... // Matrix mCombine = invCam * op->GetMg();
..then pass mCombine to that routine instead of op->GetMg()