Create Plane from Bounding Box


#1

I need to make a plane to replace a 3d object as a card in a render. Struggling to think how to make this work…

I’m making a plane with TM of the camera, then positioning the plane at the object center… and setting the size of the plane based on some object.max.x - object.min.x type thing… but that doesn’t work for obscure camera angles.

I guess I need to get the bounding box corners… test in screenspace for min/max X/Y

Is there a simple way to get the node bouding box in camera view?


#2

assuming it’s an editable mesh this gives the “exact” screen bounding box…

fn GetScreenBounds obj =
	(
		maxy = maxx = -99999999.0;
		miny = minx = 99999999.0;
		
		gw.setTransform(Matrix3 1);
		
		for v = 1 to obj.numverts  do
		(
			spos = gw.hTransPoint (getvert obj v);
			if spos.x > maxx then maxx = spos.x;
			if spos.x < minx then minx = spos.x;	
			if spos.y > maxy then maxy = spos.y;
			if spos.y < miny then miny = spos.y;	
		)
		[minx,maxx,maxy,miny]	
	)

#3

Sadly I’m replacing trees so looking up many many many polygons isn’t going to work well.

I’ve also realised it’s slightly more complicated than I first thought as it isn’t quite camera space I need to do this in… I’ve got something half-working… but it’s not super accurate. It also needs to work on multiple objects too.

If you scatter some teapots of different proportions around in a circle around 0,0,0 then run this you’ll see what I mean. Ideally the plane would be tight to the bounding box if a camera was positioned at 0,0,0 and looking at it.

targetObj = Point()


fn getHierarchyBBox objs =
(
	local bMin = [1e100, 1e100, 1e100]
	local bMax = [-1e100, -1e100, -1e100]
	for n in objs do 
	(
		for i = 1 to 3 do
		(
			if n.min[i] < bMin[i] do bMin[i] = n.min[i]
			if n.max[i] > bMax[i] do bMax[i] = n.max[i]
		)
	)
	#(bMin, bMax)
)

fn buildCard obj =
(
	objs = join #() obj
	bbox = getHierarchyBBox objs
 
	select objs
	size = bbox[2] - bbox[1]

	x = (size[1] + size[2]) * 0.8

	if size[1] > size[2] then
		c = size[1]
	else
		c = size[2]

	y = (size[3] + c) * 0.75
	
	
	p = plane length:y width:x lengthsegs:1 widthsegs:1
	p.renderable = false
	--p.pos = obj.pos
	p.center = selection.center
	lookAtCnstr = LookAt_Constraint()
	lookAtCnstr.appendTarget targetObj 100
	lookAtCnstr.target_axis = 2
	lookAtCnstr.upnode_axis = 2
	lookAtCnstr.lookat_vector_length = 0.0
	
	p.rotation.controller = lookAtCnstr
	p.parent = obj
	p.name = "renderCard_" + obj.name 
)
for o in $Teapot* do buildcard o

#4

if it’s trees does it have to be a billboard, would some “simpler” surfice ? crossing quads for example.


#5

For this specific use case, crossing quads won’t work. The are all at a far distance and never going to see the cards from any other angle than facing. The ‘viewing point’ that they are tagetted to could in theory be very high up so the plane replacement for a tree would be a horizontal plane.


#6

Figured it out… curious to know if I can make it any better than this…

Make a Camera001 camera and point it at a Teapot001 (link some other objects to it too) then run this.

targetCam = $Camera001
targetObj = $Teapot001
hierarchyObjs = (join #() targetObj)

function getLinePlaneIntersect p3LinePoint_1 p3LinePoint_2 rPlane  =
(
	--function to get point3 where a line defined by start and end point intersects with an infinite plane
    --thanks Enrico Gullotti
    local p3LineVector = p3LinePoint_2 - p3LinePoint_1
    local p3Vector_1 = rPlane.Pos - p3LinePoint_1

    local fNumer = dot rPlane.dir p3Vector_1
    local fDenom = dot rPlane.dir p3LineVector

    (p3LinePoint_1 + ((fNumer / fDenom) * p3LineVector))

)

fn getBoundingBoxVerts objs =
(
	--Get bounding box corners as point3 array for all objects
	vertArray = #()
	for obj in objs do
	(
	local bb = nodeGetBoundingBox obj obj.transform
		
	local bLength = (bb[2]-bb[1]).x
	local bWidth =(bb[2]-bb[1]).y 
	local bHeight = (bb[2]-bb[1]).z

	local vArray = #([bLength / 2, bWidth / 2, bHeight / 2],
	[-bLength / 2, bWidth / 2, bHeight / 2],
	[bLength / 2, -bWidth / 2, bHeight / 2],
	[bLength / 2, bWidth / 2, -bHeight / 2],
	[-bLength / 2, -bWidth / 2, bHeight / 2],
	[bLength / 2, -bWidth / 2, -bHeight / 2],
	[-bLength / 2, bWidth / 2, -bHeight / 2],
	[-bLength / 2, -bWidth / 2, -bHeight / 2]
	)

	join vertArray (for v in vArray collect (v * obj.transform + (obj.center - obj.pivot)))
)
vertArray
)

theZ = normalize (targetCam.pos-targetObj.pos)
theX = normalize (cross theZ [0,0,1] )
theY = normalize (cross theX theZ) 

card = Plane name:"Card"

card.transform = matrix3 theX theY theZ targetObj.pos

bmin = [0,0]
bmax = [0,0]

vertArray = getBoundingBoxVerts hierarchyObjs

for i = 1 to vertArray.count do
(
	local pos = ((getLinePlaneIntersect targetCam.pos (vertArray[i]) (ray card.pos card.dir)) * inverse card.transform)
	
	--get min and max point2 vals
	if pos.x < bmin.x do
		bmin.x = pos.x
	
	if pos.y < bmin.y do
		bmin.y = pos.y
	
	if pos.x > bmax.x do
		bmax.x = pos.x
	
	if pos.y > bmax.y do
		bmax.y = pos.y
) 
cardSize = -bmin + bmax

card.width = cardSize.x
card.length = cardSize.y

--offset from base objects position to center of card
offset = (bmin + bmax) / 2

in coordsys local
	card.pos += [offset.x,offset.y,0]