I know this has been brought up and discussed outside this group but I thought I’d share it in case there’s a half cooked piece of code that could be tested in the WIP or included in release.
A billboard image, like a 2D RPC or a sketchup face-me component would be extremely helpful for architecture visualizations. The support would be for image transparency and constant facing camera and a proper export to render. I know that Archvision support was added in 5 and it seems Archvision claims that you can make your own RPCs for free but I don’t think they work with Rhino…
Maybe another drag-and-drop option for images to convert them to billboards…
A billboard option to the picture frame would be nice indeed.
In the meantime you can try this bit of python, it orients all selected surfaces to face the camera of the selected viewport with the option of full and constrained rotation.
from Rhino import Commands, DocObjects, Geometry, Input
import scriptcontext
def generate_frame(forward):
forward.Unitize() # could fail should really check
up = Geometry.Vector3d.ZAxis
if forward.IsParallelTo(up) != 0:
up = Geometry.Vector3d.YAxis
side = Geometry.Vector3d.CrossProduct(forward, up)
side.Unitize() # could fail should really check
up = Geometry.Vector3d.CrossProduct(side, forward)
return (forward, side, up)
def orient_unconstrained(surface, camera_pt):
u = (surface.Domain(0).T0 + surface.Domain(0).T1) / 2.0
v = (surface.Domain(1).T0 + surface.Domain(1).T1) / 2.0
srf_pt = surface.PointAt(u, v)
srf_fwd = surface.NormalAt(u, v)
srf_fwd, srf_side, srf_up = generate_frame(srf_fwd)
target_fwd = camera_pt - srf_pt
target_fwd, target_side, target_up = generate_frame(target_fwd)
trans = Geometry.Transform.Translation(-Geometry.Vector3d(srf_pt))
rot = Geometry.Transform.Rotation(srf_side, srf_up, srf_fwd, target_side, target_up, target_fwd)
inv_trans = Geometry.Transform.Translation(Geometry.Vector3d(srf_pt))
return inv_trans * rot * trans
def orient_constrained(surface, camera_pt):
u = (surface.Domain(0).T0 + surface.Domain(0).T1) / 2.0
v = (surface.Domain(1).T0 + surface.Domain(1).T1) / 2.0
srf_pt = surface.PointAt(u, v)
srf_fwd = surface.NormalAt(u, v)
srf_fwd.Z = 0
target_fwd = camera_pt - srf_pt
target_fwd.Z = 0
return Geometry.Transform.Rotation(srf_fwd, target_fwd, srf_pt)
def orient_to_camera():
result, obj_refs = Input.RhinoGet.GetMultipleObjects("Select objects", False, DocObjects.ObjectType.Surface)
if result != Commands.Result.Success:
return
result, constrained = Input.RhinoGet.GetBool("Constrain z-axis", True, "no", "yes", True)
if result != Commands.Result.Success:
return
result, view = Input.RhinoGet.GetView("Select view")
if result != Commands.Result.Success:
return
camera_pt = view.ActiveViewport.CameraLocation
for obj_ref in obj_refs:
surface = obj_ref.Surface()
if not surface:
continue
xform = None
if constrained:
xform = orient_constrained(surface, camera_pt)
else:
xform = orient_unconstrained(surface, camera_pt)
scriptcontext.doc.ActiveDoc.Objects.Transform(obj_ref, xform, True)
if( __name__ == '__main__' ):
orient_to_camera()
scriptcontext.doc.ActiveDoc.Views.Redraw()
Tobias, thanks for sharing. I do use a similar version of this script for aligning pictureframes for renders. You’re right it’s a decent alternative. The version I have flip-flops people sometimes so they’re facing the wrong direction.
Hi Jorgen - - I tweaked an ancient RhinoScript - in case it helps, for now -
Unzip, save, then drag and drop to add these aliases
FaceCamera
ClearFaceCamera
FaceCamera lets you pick objects to face the camera - it tries to find a reasonable plane in non planar objects. If you have already set some objects to face the camera, Enter and the previously tagged objects will face the camera. Once an object is selected to face the camera once, running this command will update it to the current camera.
To remove the FaceCamera tag so that an object no longer updates, use ClearFaceCamera (no, it’s not an acne medication for fashion models, but you’re right, it could be).
Definitely good to have non-realtime solution for this too, but in case there was an option to make the realtime orient work, maybe it could be implemented like this:
Make it another object ‘property’ (like Material, Mapping, EdgeSoftening etc.) - a checkbox to LookAt camera. Within that have options which axis has to ‘look at’ and optionally to maintain vertical axis. I guess each object would have to have its ‘look at’ frame defined, which for planar objects by default would be their plane, for 3D objects a center of bounding box. This frame can be customized by user (similar way the Gumball frame may be adjusted) and reset to default. This could help to avoid the confusion that to do with non-planar objects, but also could open up few more options like text always facing the camera etc.
Also, I think in Display Modes we will need a setting to make it work real-time or only update when the view camera is still (so the view manipulation is not slowed down with many of billboards)
Good point Pascal. I initially thought it will just update to any active view, but you are right, it will make sense to specify which viewport it will apply to.
The other way to think about it is to have views (viewports) have a setting to “Use Billboarding”, that is OFF by default, so user can enable it per-viewport. This way the billboarded objects UI can be simpler…