Editor Translate/Scale/Rotate tools
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 02/09/2006 at 13:28, xxxxxxxx wrote:
Maybe build your matrix starting with an identity, then just apply the (inverse) camera rotation and translation values.
I hadn't specifically looked at how the viewport rendering code works, so if C4D doesn't then apply the current camera/view matrix, you should be able to just multiply your vertices by the above and render...
If it's going to use the camera/view matrix, then you'll need a different approach for your matrix - forget the camera/view translation and rotation values... determine the scaling of the camera/view matrix and multiply your vertices (or the matrix you're going to multiply the vertices by) by the inverse. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 02/09/2006 at 13:50, xxxxxxxx wrote:
I'm using the 'object' matrix to position the 3D Circles - that works. The problem is that BaseDraw::Circle3D() only uses a matrix. How do you set the scaling factor so that the screen display width/height are always the same no matter the camera angle/zoom/position?
For Spherify.cpp, they use this:
m.v1*=rad;
m.v2*=rad;
m.v3*=rad;But 'rad' is a 3D size that varies with the camera (e.g.: as you dolly in, the circles get larger). I need a multiplier that varies with the camera to get the same pixel (screen) dimensions (e.g.: as you dolly in, the circles stay the same size on the display). This is the same behavior as the standard C4D Rotate tool.
Thanks,
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 02/09/2006 at 14:04, xxxxxxxx wrote:
...after briefly looking at this... it looks like you're going to need to find out the current camera scaling information (the second case I described above). There might be something useful in the BaseView SDK section.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 02/09/2006 at 14:06, xxxxxxxx wrote:
Okay, contemplating the 'dolly in' factor, it appears that the orthogonal Z distance from screen to point should be a determining factor in the scaling. So, I decided to try this:
Real rad2 = rad * 0.0005; Vector ctr = bd->WS(m.off); if (ctr.z < 0.0) return; m.v1 *= ctr.z*rad2; m.v2 *= ctr.z*rad2; m.v3 *= ctr.z*rad2;
When ctr is calculated from World m.off to Screen, the Z distance is placed in ctr.z. This gives me a Z determiner. The very small multiplier compensates for the large values of both ctr.z (C4D units) and rad2 (pixels).
This is not working so well with the camera zoom. No idea how to bring that into the mix.
Thanks,
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 02/09/2006 at 14:08, xxxxxxxx wrote:
Oops.. cross-posted :).
Yeah, once you determine what the current camera/view scaling vector is, you multiply the matrix you're passing in by the inverse of that to keep your object the same size. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 02/09/2006 at 14:46, xxxxxxxx wrote:
I don't quite follow you here. BaseView has two methods: GetMg() and GetMi() which return the Camera matrix and inverse matrix, respectively. I've tried multiplying the m.v1 (etc.) by Len(c.v1) where c is either the Camera matrix or inverse. That makes it look proper, but it still scales with the camera. Multiplying m by the camera matrix draws a right mess.
Now, there is GetViewParameter(), but I already get the view pixel dimensions from GetFrame(). I use that to
determine 'rad' (a pixel value) for Circle2D().I should also mention that Circle3D() wants a matrix in World space. So it seems that the projection/camera is considered in the call.
Still lost.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 02/09/2006 at 15:17, xxxxxxxx wrote:
Ahh.. I'll try explaining better in an e-mail...
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 02/09/2006 at 20:46, xxxxxxxx wrote:
This old message:
_despite Begin2d and End2D
the display never seems to get updated
ive gone through just about every way I can think of to get the display to update.as I said , the circle is drawn to the Basedraw bitmap and can only be seen by minimising and then maximimising cinama.
so im at a loss here.maybe the EditorWindow class is in some way blocking this update?
maybe this plugintool class is just not allowed to refresh the screen?
thanks for any help
Paul "baffled" Everett
_Followed by the superbly explanatory:
_
Subject: working now
From: paul Everett
Date: 9/14/2001 3:55 PM GMTthanks David :)_
I'm having this problem as well - only orthographic views - and only some of them. It is so heartwarming to see that the solution was given for posterity (in invisible ink requiring lemon juice LISP code). Tell me the solution, please (this is not directed to you, Keith). Gad - it should be MANDATORY that solutions are posted for everyone either directly or on request. If this continues, I'm moving to Maya...
Robert
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 07/09/2006 at 23:53, xxxxxxxx wrote:
Perhaps the old post about camera projections will help clear this up? <[URL-REMOVED]> Unfortunately I don't have the time right now to look into the math part of it.
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 08/09/2006 at 00:09, xxxxxxxx wrote:
As noted in my other thread, I cannot fathom why a 2D draw (based upon the screen pixels of the view) would be in any way affected by projection (ever!). Sometimes I get the 2D circle, most times not - especially not in axonometric views. OpenGL or Software modes don't make a difference.
I can see how the 3D draws could be affected by the projection considering that they don't have the same 'z-distance' criteria as perspective projection. In that case, I'll have to experiment with the code in the link (and in the documentation).
Nonetheless, one would assume that 2D drawing would be ubiquitous despite the active view unless there is some mitigating factor involved. I have been on the edge of providing the tool code in full to support to see if the error is obvious. May I do this after full investigation?
Thanks,
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 08/09/2006 at 00:14, xxxxxxxx wrote:
(Code is always welcome! As usual, make it as short a snippet as possible but not shorter.)
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 08/09/2006 at 10:51, xxxxxxxx wrote:
Here's the ToolData::Draw() code and one of the Control draw methods, some stuff removed for clarity, but still whopping (hey, my tool plugin is 2000 lines of code and growing).
// ToolData.Draw //*---------------------------------------------------------------------------* LONG IPPTool::Draw(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, BaseDrawHelp* bh, BaseThread* bt, LONG flags) //*---------------------------------------------------------------------------* { LONG drawFlags; // Draw Operation Controls if (selectedBP) { if (operation == IPTOP_ROTATE) DrawRotateControl(bd, bh); else if (operation == IPTOP_TWIST) DrawTwistControl(bd, bh); else if (operation == IPTOP_SCALE) DrawScaleControl(bd, bh); else if (operation == IPTOP_TRANSLATE) DrawTranslateControl(bd, bh); drawFlags = DRAW_HANDLES; } else drawFlags = DRAW_AXIS|DRAW_HANDLES; // Only draw into active view if (bd != doc->GetActiveBaseDraw()) return drawFlags; // Go no further if in dragMode for operation if (dragMode) return drawFlags; // This allows click-deselection hilitedOP = NULL; hilitedBP = NULL; // From here on in, only draw highlighting (if R9.0+) #ifdef C4D_R9 if (!(flags & DRAWFLAGS_HIGHLIGHT)) return drawFlags; #endif // Mouse outside of Editor view if (mouseX < 0.0) return drawFlags; // Add IPP objects under cursor to selection list AutoAlloc<C4DObjectList> objList; if (!objList) return drawFlags; if (!SelectionListCreate(doc, NULL, bd, mouseX, mouseY, NULL, objList)) return drawFlags; LONG cnt = objList->GetCount(); if (!cnt) return drawFlags; // The rest of the code involves Polygon/BoundingBox highlighting. // This is working in all views. // Though I do note that when the operation draws (above), // the BoundingBox highlighting is no longer in the highlight color. ... // So, I've included just a section where a bounding box is highlighted else { hilitedOP = obj; hilitedBP = ippTag->GetDataInstance()->GetObjectLink(IPPOBJECT_ROOTBONE, doc); if (!hilitedBP) return drawFlags; #ifdef C4D_R9 bd->LineZOffset(32); #endif bd->SetTransparency(100); Matrix mg = hilitedBP->GetMg(); // Global position mg.off = mg*hilitedBP->GetMp(); // 'arbitrary cubic form to match bounding box Vector rad = hilitedBP->GetRad()*2; mg.v1 *= rad.x; mg.v2 *= rad.y; mg.v3 *= rad.z; // color[0] is from the Vector color[4] array of colors used in polygon highlighting bd->Box3D(mg, 0.5, color[0]); #ifdef C4D_R9 bd->LineZOffset(0); return drawFlags|DRAW_HIGHLIGHTS; #else return drawFlags; #endif } return drawFlags; } // IPPTool.DrawRotateControl //*---------------------------------------------------------------------------* void IPPTool::DrawRotateControl(BaseDraw* bd, BaseDrawHelp* bh) //*---------------------------------------------------------------------------* { Matrix m = selectedBP->GetMg(); Vector ctr = bd->WS(m.off); if (ctr.z <= 0.0) return; // BaseView dimensions LONG left, top, right, bottom, width, height; bd->GetFrame(&left;, ⊤, &right;, ⊥); width = right - left + 1; height = bottom - top + 1; Real rad = (Real)((width > height)?(height>>2) :(width>>2)); // rad2 = 0.5 rad * ctr.z * scaling factor 0.0015 Real rad2 = ctr.z * (rad * 0.00075); // Scale for PolygonObject m.v1 = !m.v1 * rad2; m.v2 = !m.v2 * rad2; m.v3 = !m.v3 * rad2; // PolygonObject Color Properties ObjectColorProperties ocp; ocp.usecolor = ID_BASEOBJECT_USECOLOR_ALWAYS; ocp.xray = FALSE; #ifdef C4D_R9 bd->LineZOffset(32); #endif bd->SetTransparency(255); // 'Sphere' bd->SetPen(GetWorldContainer().GetVector(WPREF_SELECT_AXIS_COL)); bd->Circle2D(ctr.x, ctr.y, rad); // 'Rings' ... // Z-Axis ocp.color = GetWorldContainer().GetVector(WPREF_ZAXIS_COL); rotatObj->SetColorProperties(&ocp;); rotatObj->SetMg(m*MatrixRotX(Rad(-90.0))); #ifdef C4D_R9 bd->DrawPolygonObject(bh, rotatObj, 0L); bd->LineZOffset(0); #else bd->PolygonObject(bh, rotatObj, 0L); #endif }
Thanks,
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 08/09/2006 at 11:10, xxxxxxxx wrote:
Eh hem. Well, I found the first mistake - that helps the missing Circle2D partially. I though that I had double-checked this, but too many hours of working can play tricks on the mind. How about 'bd->SetTransparency(0)' instead of (255). Still not showing under every circumstance and most of the axonometric/orthographic views.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 08/09/2006 at 12:19, xxxxxxxx wrote:
Next solution. Removing this for the controls draws them in any view:
if (ctr.z <= 0.0) return;
Seems that this is true for certain situations in axonometric/orthographic views. Now it's just a matter of keeping the control sizes the same relative to the screen space.
Also, I still haven't received any official information on how to factor in camera zoom/focal length with respect to control size.
Thanks,
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 09/09/2006 at 14:48, xxxxxxxx wrote:
Eureka!!!!!!!!!! ;D
For posterity and for the benefit of others to relieve their suffering in purgatory, I present code which ACTUALLY works in all projections, all views, all cameras for displaying Tool controls (similar to Cinema 4D's) using BaseDraw:
First off, implement these. ScreenToWorld is useful for drawing, but WorldToScreen may prove useful for picking.
// IPPTool.WorldToScreen (see BaseView.GetViewParameter) //*---------------------------------------------------------------------------* Vector IPPTool::WorldToScreen(const Vector& pp, BaseDraw* bd, LONG projection) //*---------------------------------------------------------------------------* { Vector p = pp*bd->GetMi(); Vector off, scale, scalez; bd->GetViewParameter(&off;, &scale;, &scalez;); if (projection == Pperspective) { Real nz = (p.z <= 0.0) ? 20.0 : 1.0/(p.z + 0.05); p.x = p.x*scale.x*nz+off.x; p.y = p.y*scale.y*nz+off.y; return p; } p.x = (p.x*scale.x)+off.x; p.y = (p.y*scale.y)+off.y; switch (projection) { case Pmilitary: case Pfrog: case Pbird: case Pgentleman: p.x += p.z*scale.x*scalez.x; p.y -= p.z*scale.y*scalez.y; break; } return p; } // IPPTool.ScreenToWorld (see BaseView.GetViewParameter) //*---------------------------------------------------------------------------* Vector IPPTool::ScreenToWorld(const Vector& pp, BaseDraw* bd, LONG projection) //*---------------------------------------------------------------------------* { Vector p = pp; Vector off, scale, scalez; bd->GetViewParameter(&off;, &scale;, &scalez;); switch (projection) { case Pmilitary: case Pfrog: case Pbird: case Pgentleman: p.x -= p.z*scale.x*scalez.x; p.y += p.z*scale.y*scalez.y; break; } p.x = (p.x-off.x)/scale.x; p.y = (p.y-off.y)/scale.y; if (projection==Pperspective) { Real nz = p.z + 0.05; p.x *= nz; p.y *= nz; } return p*bd->GetMg(); }
Then do your controls like so:
// IPPTool.DrawRotateControl //*---------------------------------------------------------------------------* void IPPTool::DrawRotateControl(BaseDraw* bd, BaseDrawHelp* bh) //*---------------------------------------------------------------------------* { Matrix m = selectedBP->GetMg(); Vector ctr = bd->WS(m.off); LONG left, top, right, bottom, width, height; bd->GetFrame(&left;, ⊤, &right;, ⊥); width = right - left + 1; height = bottom - top + 1; Real rad = (Real)((width > height)?(height>>2) :(width>>2)); // Scale for PolygonObject LONG proj = bd->GetProjection(); Vector a = ScreenToWorld(ctr, bd, proj); Vector b = ScreenToWorld(Vector(ctr.x+rad*0.5, ctr.y, ctr.z), bd, proj); Real rad2 = 2.0 * Len(b-a); if (proj == Pfrog) { m.v1 = !m.v1 * rad2; m.v2 = !m.v2 * rad2 * 0.333; m.v3 = !m.v3 * rad2; } else { m.v1 = !m.v1 * rad2; m.v2 = !m.v2 * rad2; m.v3 = !m.v3 * rad2; } #ifdef C4D_R9 bd->LineZOffset(32); #endif bd->SetTransparency(0); // 'Sphere' bd->SetPen(GetWorldContainer().GetVector(WPREF_SELECT_AXIS_COL)); bd->Circle2D(ctr.x, ctr.y, rad); // 'Rings' // X-Axis ocp.color = GetWorldContainer().GetVector(WPREF_XAXIS_COL); rotatObj->SetColorProperties(&ocp;); rotatObj->SetMg(m*zrotMat); #ifdef C4D_R9 bd->DrawPolygonObject(bh, rotatObj, 0L); #else bd->PolygonObject(bh, rotatObj, 0L); #endif // Y-Axis ocp.color = GetWorldContainer().GetVector(WPREF_YAXIS_COL); rotatObj->SetColorProperties(&ocp;); rotatObj->SetMg(m); #ifdef C4D_R9 bd->DrawPolygonObject(bh, rotatObj, 0L); #else bd->PolygonObject(bh, rotatObj, 0L); #endif // Z-Axis ocp.color = GetWorldContainer().GetVector(WPREF_ZAXIS_COL); rotatObj->SetColorProperties(&ocp;); rotatObj->SetMg(m*xrotMat); #ifdef C4D_R9 bd->DrawPolygonObject(bh, rotatObj, 0L); bd->LineZOffset(0); #else bd->PolygonObject(bh, rotatObj, 0L); #endif }
For non-radial controls (translate/scale), rad2 = Len(b-a). This considers projection, camera, view, focus, zoom - so simple and you wonder why NOONE (especially the developers) can provide this for .... sake!!
Thank you, thank me...
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 09/09/2006 at 18:04, xxxxxxxx wrote:
Slight modification to ScreenToWorld() and WorldToScreen() to support pre-R9.0 versions:
replace:
bd->GetViewParameter(&off;, &scale;, &scalez;);
with:
#ifdef C4D_R9 bd->GetViewParameter(&off;, &scale;, &scalez;); #else bd->GetParameter(&off;, &scale;, &scalez;); #endif
More information on the polygon objects used for the control interface. I built the controls in C4D and exported as Wavefront so that the extents were 1x1x1 (the radius is 0.5). The polygon objects are cone (translate), cube (scale) and ring (rotate/twist). These were setup as Vector arrays for the points and LONG arrays for the polygons in a header (could be done with either reading/parsing the Wavefront .obj files or reading some other proprietary format). The objects are created/stored in the constructor and verified in the ToolData::Init() so that they must exist whenever the tool is activated.
zrotMat is a MatrixRotZ(Rad(90)) matrix
xrotMat is a MatrixRotX(Rad(-90)) matrixThese two matrices 'orthogonalize' the polygon objects to the particular local axis.