Notifications
Clear all

[Closed] Ray grid between 2 points and a direction

I would like to create a grid of rays given 2 points (P1, P2) and a direction D1.
Imagine this grid as a plane, P1 will be the lower-left corner and P2 the upper right, the plane will have the direction D1 as normal.

In the script you see there are 2 problems :

The 2 points red and black (that should represent the bbox of the projection of the teapot on the light plane) are not planar at all.

The grid it’s not build correctly it’s shifted and anyway not between the red and black point.

Here’s the code so far (sorry it’s not cleaned) but should make clear what’s going on :

function ProjectPointOnPlane thePoint thePlanePos thePlaneDir eps:1e-4 =
  (
  	 thePointVector = thePoint - thePlanePos
  	 cross1 = cross thePointVector thePlaneDir
  	 cross2 = cross thePlaneDir cross1
  	 return (thePlanePos + cross2)
  )
  fn GetScanBounds lSource caster = 
  (
  	delete $tape*
  	delete $point*
  	dir = -lSource.transform.row3
  	pos = lSource.pos
  	r1 = [caster.min.x, caster.min.y, caster.min.z] 
  	r2 = [caster.max.x, caster.min.y, caster.min.z] 
  	r3 = [caster.min.x, caster.max.y, caster.min.z] 
  	r4 = [caster.min.x, caster.min.y, caster.max.z] 
  	r5 = [caster.max.x, caster.max.y, caster.min.z] 
  	r6 = [caster.min.x, caster.max.y, caster.max.z] 
  	r7 = [caster.max.x, caster.min.y, caster.max.z] 
  	r8 = [caster.max.x, caster.max.y, caster.max.z] 	
  	lst = #(r1, r2, r3, r4, r5, r6, r7, r8)	
  
  	x = #()
  	y = #()
  	z = #()
  	for currPoint in lst do 
  	(
  		p = (ProjectPointOnPlane currPoint pos dir)
  		append x p.x
  		append y p.y
  		append z p.z
  		
  		tape pos:p target:(targetObject pos:currPoint) wirecolor:red
  	)
  	currMin = [amin x, amin y, amin z]
  	currMax = [amax x, amax y, amax z]
  	point pos:currMin wirecolor:red
  	point pos:currMax wirecolor:black
  	return #(currMin, currMax)
  )
  
  fn CreateTracePoints lSource minBox maxBox stepx stepy stepz= 
  (
  	delete $dummy*
  	trans = lSource.transform
  	newTrans = rotatezmatrix  (trans.rotationpart as eulerangles).z * trans
  	lightPos = trans.row4
  	pointList = #()
  	
  	x1 = minBox.x
  	x2 = maxBox.x
  	distx = x2 - x1
  	deltax = distx/ stepx
  	
  	y1 = minBox.y
  	y2 = maxBox.y
  	disty = y2 - y1
  	
  	z1 = minBox.z
  	z2 = maxBox.z
  	distz = z2 - z1
  	deltaz = distz/ stepz
  	for x = 0 to distx by deltax do 
  	(
  		for z = 0 to distz by deltaz do 
  		(
  			
  			p = [x , y1, z ]
  			 pos = ProjectPointOnPlane p maxBox -newTrans.row3
  			 pos = [x, pos.y, pos.z]
  			dummy pos:pos boxSize:[1,1,1]
  			append pointList pos
  		)
  	)
  
  	return pointList
  )
  
  fn CreateTestStuff = 
  (
  
  	theLight = DirectionalLight()
  	theLight.rotation = (quat 0.56506 0.101065 0.144166 0.806045)
  	theLight.position = [23,-63,24]
  	theObject = teapot() 
  	bounds = GetScanBounds theLight theObject
  	pList = CreateTracePoints theLight bounds[1] bounds[2]  10 10 10
  )

Thank you in advance,
Dome

7 Replies

What about:

(
	fn getPointRayProjection p r =
		r.pos + r.dir * dot r.dir (p - r.pos)

	fn getPointPlaneProjection p pNorm =
		p + dot (pNorm.pos - p) pNorm.dir * pNorm.dir

	fn getProjectedBounds boundBox pNorm =
		#(getPointPlaneProjection (boundBox[1] * pNorm.transform) pNorm,
		  getPointPlaneProjection (boundBox[2] * pNorm.transform) pNorm)
	
	mapped fn createBoundingPts bounds = Point pos:bounds
	
	fn createTracePoints tm startPos endPos xStepCount:10 yStepCount:10 =
	(
		local points = #()

		local pos = startPos
		local xEndPos = getPointRayProjection endPos (ray startPos tm.row1)
		local yEndPos = getPointRayProjection endPos (ray startPos tm.row2)
		local xStep = (xEndPos - startPos) / xStepCount
		local yStep = (yEndPos - startPos) / yStepCount

		for x = 0 to xStepCount do
		(
			for y = 0 to yStepCount do
			(
				Dummy pos:pos boxSize:[1,1,1]
				append points pos
				pos += yStep
			)
			pos += xStep - (yStepCount + 1) * yStep
		)
		points
	)

	 local theLight = DirectionalLight rotation:(quat 0.56506 0.101065 0.144166 0.806045) pos:[23,-63,24]
	 local theObject = Teapot()

	local projBoundingBox = (nodeGetBoundingBox theObject theLight.transform) 
	local bounds = getProjectedBounds projBoundingBox theLight

	createBoundingPts bounds
	 local pList = createTracePoints theLight.transform bounds[1] bounds[2]
)

Wow , that looks a pretty interesting solution, thank you very much.

There is still a little if i rotate the light in fact a side of the plane should be parallel to the ground plane.
Kinda like the attached image.

Yeah, I was wondering, you didn’t specify it before. Here you go:

(
	fn getPointRayProjection p r =
		r.pos + r.dir * dot r.dir (p - r.pos)

	fn getPointPlaneProjection p pNorm =
		p + dot (pNorm.pos - p) pNorm.dir * pNorm.dir

	fn getProjectedBounds boundBox tm pNorm =
		#(getPointPlaneProjection (boundBox[1] * tm) pNorm,
		  getPointPlaneProjection (boundBox[2] * tm) pNorm)
	
	mapped fn createBoundingPts bounds = Point pos:bounds
	
	fn createTracePoints tm startPos endPos xStepCount:10 yStepCount:10 =
	(
		local points = #()

		local pos = startPos
		local xEndPos = getPointRayProjection endPos (ray startPos tm.row1)
		local yEndPos = getPointRayProjection endPos (ray startPos tm.row2)
		local xStep = (xEndPos - startPos) / xStepCount
		local yStep = (yEndPos - startPos) / yStepCount

		for x = 0 to xStepCount do
		(
			for y = 0 to yStepCount do
			(
				Dummy pos:pos boxSize:[1,1,1]
				append points pos
				pos += yStep
			)
			pos += xStep - (yStepCount + 1) * yStep
		)
		points
	)

	local theLight = DirectionalLight rotation:(quat 0.567879 -0.0837854 0.392897 0.718418) pos:[23,-63,24]
	local theObject = Teapot()
	local parallelTM = matrixFromNormal theLight.dir

	local projBoundingBox = (nodeGetBoundingBox theObject parallelTM) 
	local bounds = getProjectedBounds projBoundingBox parallelTM theLight

	createBoundingPts bounds
	local pList = createTracePoints parallelTM bounds[1] bounds[2]
)

Ok added the rotation to your code, still having an incorrect bounding box with rotated light :

(
  	fn getPointRayProjection p r =
  		r.pos + r.dir * dot r.dir (p - r.pos)
  
  	fn getPointPlaneProjection p pNorm =
  		p + dot (pNorm.pos - p) pNorm.dir * pNorm.dir
  
  	fn getProjectedBounds boundBox pNorm =
  		#(getPointPlaneProjection (boundBox[1] * pNorm.transform) pNorm,
  		  getPointPlaneProjection (boundBox[2] * pNorm.transform) pNorm)
  	
  	mapped fn createBoundingPts bounds = Point pos:bounds
  	
  	fn createTracePoints tm startPos endPos xStepCount:10 yStepCount:10 =
  	(
  		local points = #()
 	   -- ROTATION
  		tm = rotatezmatrix  (tm.rotationPart as eulerangles).y * tm
  		local pos = startPos
  		local xEndPos = getPointRayProjection endPos (ray startPos tm.row1)
  		local yEndPos = getPointRayProjection endPos (ray startPos tm.row2)
  		local xStep = (xEndPos - startPos) / xStepCount
  		local yStep = (yEndPos - startPos) / yStepCount
  
  		for x = 0 to xStepCount do
  		(
  			for y = 0 to yStepCount do
  			(
  				Dummy pos:pos boxSize:[1,1,1]
  				append points pos
  				pos += yStep
  			)
  			pos += xStep - (yStepCount + 1) * yStep
  		)
  		points
  	)
  
  	 local theLight = DirectionalLight rotation:(quat 0.56506 0.101065 0.144166 0.806045) pos:[23,-63,24]
  	 local theObject = Teapot()
  
  	local projBoundingBox = (nodeGetBoundingBox theObject theLight.transform)
  	local bounds = getProjectedBounds projBoundingBox theLight
  
  	createBoundingPts bounds
  	 local pList = createTracePoints theLight.transform bounds[1] bounds[2]
  )

Cool, I did not see your reply cause I was adding mine now it’s much better, thank you!

But try to move the light around, you will see that the 2 points sometime get narrow and the plane gets tilted for example here :
$Fdirect001.transform = (matrix3 [-0.911373,0.411582,0] [-0.13932,-0.308498,0.940967] [0.387285,0.857572,0.338498] [40.57,89.835,35.4594])

Oookay, try replacing matrixFromNormal with arbAxis, better?

Yep! That seems to work! Thanks a lot for your help!