[SDK] IntersectRay troubles


#1

Hi there,
I recently became a dev for my employer’s 3D design department and you people have already been a huge help in my endeavors to rewrite an old, old MaxScript into a plugin (for performance reasons) but I’ve kinda hit a snag with the IntersectRay function that I can’t really find a solution for.

I’ve already seen that IntersectRay isn’t the best way, but it really only gets called for maybe 20 specific objects, so it shouldn’t be an issue.

Okay, so here’s the code from my test plugin:

int RefTest::PewPew(MSTR nodeName, MSTR targetname)
{
	// Create Interface and Node Pointers
	Interface* ip = GetCOREInterface();
	if (!ip) return 1;

	INode* inCaster = ip->GetINodeByName(nodeName);
	if (!inCaster) return 1;

	INode* inTarget = ip->GetINodeByName(targetname);
	if (!inTarget) return 1;

	Point3 rayCasterPosition(0, 0, 0);
	Point3 surfaceNormal(0, 0, 0);
	float intersectPosition = 0.0f;

	ip->GetINodeByName(nodeName)->GetTMController()->GetPositionController()->GetValue(0, &rayCasterPosition, FOREVER, CTRL_ABSOLUTE);

	Ray positionRay(rayCasterPosition, Point3(0, 0, 1));
	
	if (inTarget->GetObjectRef()->IntersectRay(0, positionRay, intersectPosition, surfaceNormal))
	{
		MSTR s(_T("HIT!"));
		RefTest::GetInstance()->SetText(s);
	}
	else
	{
		MSTR s(_T("MISS!"));
		RefTest::GetInstance()->SetText(s);
	}
	return 0;
}

nodeName being the node whose position should be used for the ray’s origin and targetName obviously for the target object.

For testing purposes, I simply created two boxes and passed the names to the function.

Now the issue is that I don’t actually get a hit when I place the raycaster underneath the target box.
I DO however get hits when I place it below 0,0,0, no matter where the target box is.
Going by the value I get in intersectionPosition, that seems to be what I’m receiving hits for.
The other weird thing is that the surfaceNormal values always end up being 0, 0, -1

What am I doing wrong here?

Thanks a lot!


#2

you need to working in object space to call intersectRay, so the ray needs to xformed into object space from it’s world space coords you are using to work properly… here’s how the mxs function does it…

Value*
IntersectRayEx_cf(Value** arg_list, int count)
{
	float		at;
	Point3		pt, normal, bary;
	Ray			ray, os_ray;
	GeomObject*	obj;	
	DWORD		fi;

	check_arg_count(intersectRayEx, 2, count);
	INode* node = get_valid_node(arg_list[0], intersectRayEx);

	// Get the object from the node
	ObjectState os = node->EvalWorldState(MAXScript_time());
	if (os.obj->SuperClassID()==GEOMOBJECT_CLASS_ID) {
		obj = (GeomObject*)os.obj;
		if (obj->ClassID() != GetEditTriObjDesc()->ClassID() &&
			obj->ClassID() != Class_ID(TRIOBJ_CLASS_ID, 0))		
			return &undefined;
	}
	else
		return &undefined;
	
	// Back transform the ray into object space.		
	Matrix3 obtm  = node->GetObjectTM(MAXScript_time());
	Matrix3 iobtm = Inverse(obtm);
	ray = arg_list[1]->to_ray();
	os_ray.p   = iobtm * ray.p;
	os_ray.dir = VectorTransform(iobtm, ray.dir);
	
	// See if we hit the object
	if (((TriObject*)obj)->GetMesh().IntersectRay(os_ray, at, normal, fi, bary))
	{
		// Calculate the hit point
		pt = os_ray.p + os_ray.dir * at;

		// transform back into world space & build result ray
		pt = pt * obtm;
		normal = Normalize(VectorTransform(obtm, normal));
		
		// Return the array containing the intersection details 
		one_typed_value_local(Array* result);
		vl.result = new Array(3);
		vl.result->append(new RayValue (pt, normal));
		vl.result->append(Integer::intern (fi+1));
		vl.result->append(new Point3Value (bary));
		return_value (vl.result); // LAM - 5/18/01 - was return vl.result
	}
	else
		return &undefined;
}

#3

The ray intersection methods were broken after Max 2016 and haven’t been fixed yet. Someone from Autodesk recently said it’s been fixed and tested internally, though they didn’t mention when it would be released to the public.

Here is a link to that post, which also links to my post which has a test case that illustrates the issue with intersectray:

What I found is that it was broken with edit poly objects, but worked fine with edit mesh or primitives. Until they release a fix, you could convert edit poly objects to edit mesh.


#4

don’t think it’s ever worked with editable poly as you can see from the above code if it’s not trimesh then it returns undefined.


#5

Blockquote

I misspoke about edit poly objects not working, that was for IntersectRayScene.

I use edit poly objects with no issue calling intersectRay in conjunction with RayMeshGridIntersect() and addnode.


#6

Woo! Thanks a lot!
That’s exactly what I needed!

I just added

	Matrix3 obtm = inTarget->GetObjectTM(0);
	Matrix3 iobtm = Inverse(obtm);
	Ray os_positionRay((iobtm * positionRay.p), VectorTransform(iobtm, positionRay.dir));

and

	hitPoint = os_positionRay.p + os_positionRay.dir * intersectPosition;
	hitPoint = hitPoint * obtm;

on a hit and I got the data I needed.

Say… can I actually find all the MXS function implementations in maxsdk\samples\maxscript?
Because hoo boy do I feel stupid for not checking there before.


#7

yes (well not all but a lot of them) it’s in the mxsagni project in the samples