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 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.