[SOLVED] Camera Node and Spot Light and Mouse Cursor - How?

I said what you could do to keep the light direction at z. Changing the direction of the light doesn’t change its speed so you obviously did something wrong.

CODE IN NEXT POST - DIDN’T FIT HERE!!

Probably I did but sure as hell I have no idea what. This is whole code relating to my mouse and light. Just uncomment “dir” parts and comment “UNIT_Z” part to see difference.

And (probably a wild guess) I maybe learning java but I’m pretty good at math and I have an idea why things don’t work as expected (sadly don’t have the solution). Image below, please study it cause it’s the best way I can elaborate on the problem.

public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
spotty = new SpotLight();
spotty.setSpotRange(40f);                           // distance
spotty.setSpotInnerAngle(1f * FastMath.DEG_TO_RAD); // inner light cone (central beam)
spotty.setSpotOuterAngle(1.5f * FastMath.DEG_TO_RAD); // outer light cone (edge of the light)
spotty.setColor(ColorRGBA.Red.mult(1f));         // light color and strength
rootNode.addLight(spotty);

public void update(float tpf) {
Vector2f click2d = inputManager.getCursorPosition();
Vector3f click3d = theapp.getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
//Vector3f dir = theapp.getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d).normalizeLocal();

spotty.setPosition(click3d);
spotty.setDirection(Vector3f.UNIT_Z);
//spotty.setDirection(dir)

“Screen level” (or rather the normal of that) is the camera direction so the code you have in your previous post should be fine.

I needed several edits to make image work. You responded too fast :stuck_out_tongue: Check image please - it shows the effect of different solutions. Situation B is potential explanation of the speed issue (not the solution though).

No, image 3 is what you get when you do

Vector3f click3d = theapp.getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
Vector3f dir = theapp.getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d).normalizeLocal();

Situation B might be what you get when your screen isn’t looking in z direction any you use UNIT_Z. I only gave that solution because you asked for it. Play around a bit, you have all information, now its time to do your homework.

The thing with DIR is situation A and I can prove it. In my code I can move a camera in drag’n’drop fashion (in only one plane - no rotation so the distance from camera to the plane is constant). When I do so mouse stays in “grab” place (above some object for example) while I move my camera around.

If it were situation C my light shouldn’t change at all because mouse didn’t change position relative to the object that is lighted. But it does. It acts exactly as if the light were cast from the middle of my window (meaning: the light gets “bigger” when the distance from the middle of my window becomes larger - and it shouldn’t if it were cast from the mouse cursor).

You get the click position and a direction vector that is from the camera through the click location to 1f behind it. Use the cam direction if you don’t want the actual perspective of the ray from the camera.

Ok I know what’s the issue now (and yes Vector3f.UNIT_Z is the only way to keep the 90 degrees angle between my plane of objects and spotlight - which in turn is the only way to avoid light being distorted).

The reason things moves so “slow” on my plane of objects is the effect of the perspective (field of view). So to calculate point to which I should REALLY move spotlight castpoint (even though it would make an illusion of being on cursor) I need to first calculate mouse collision point, and then move my spotlight to the point above this one (in Z dimension).

The only question left is: how can I get collision point between ray and some arbitrary plane (for example Z = 5 plane) and not with an object?

Found the plane object. Created it using:

colli = new Plane();
colli.setPlanePoints(new Vector3f(1, 1, 3), new Vector3f(2, 2, 3), new Vector3f(2, 1, 3));

Now I need a way to find intersection of a ray and this plane. But by default ray have 2 parameters: position (in my case click3d) and direction (in my case dir). How to find intersection point between this ray and my plane colli?

[EDIT] Enough dying for today. I hope someone will tell me a way to find ray collision point with either plane I created or some arbitrary plane in general.

Assuming no obstacle geometries are there between ray origin and the plane:

CollisionResults results = new CollisionResults();
yourNode.collideWith(ray, results);
CollisionResult c = results.getClosestCollision();
float distance = c.getDistance();

Then using your perspective-whatever-correction you can easily get your point in scene coordinates.

I thought you were good at math…? Just look at the javadoc of Plane.

Plane isn’t even necessary. It can all be done with simple vector math given the camera location, the direction vector, and the click location… all in 3D space.

But I’m not clear on whether or not it’s some fixed distance that the light should shine on or only intersected objects or something. Because for trying to remove the ‘perspective’ part of the light it matters.

Let’s say for the sake of argument that it’s desirable for the spotlight to shine parallel to the camera direction as if it’s shining on a plane 100 meters away.

float distance = 100;
Vector3f farMousePoint = camera.getWorldCoordinates(click2D, camera.getViewToProjectionZ(distance));

/// then go backwards
Vector3f lightLoc = farMousePoint.subtract(camera.getDirection().mult(distance));

Note: physically, this is like holding a spot light way out of view.

As I’m still not sure what exactly he wants to do - Plane will work for all situations :wink: But sure, all that Plane does can be done with Vectors alone.

Yeah, a plane is just a vector and a distance anyway… already have that.

Woops plane is not a geometry. My solution won’t work :expressionless:

[quote=“Torsion, post:51, topic:33264, full:true”]Assuming no obstacle geometries are there between ray origin and the plane:
(…)
Then using your perspective-whatever-correction you can easily get your point in scene coordinates.
[/quote]

Wrong assumption. The whole idea of checking collision with infinite plane is to be able to have objects everywhere, even in collission path. So I need something that will allow me to monitor intersection between 2 objects (ray and my plane) the whole time.

Irony. I like it. But the only thing more or less usefull in plane is GetClosestPoint function which would require me to have a collision point with something beforehand anyway. It doesn’t give me collision point between the ray and plane itself. It gives me closest point to the cursor up there which is the same thing I had before (slow moving illusion).

Yes the light should shine from a fixed distance (let’s say starting point of spotlight at -20 Z) and should allways have direction parallel to the camera (which is also fixed because I only move camera, I never rotate it).

As for removing perspective part what I mean is the fact that I’m (in my example) 20 units away in Z dimension from my objects which means my mouse movements reflected on those objects below are negligible (perspective effect). To create the illusion of light moving the same speed as cursor (even though in real it moves progressively faster the farther mouse is from the screen center) I need collission point with great nothingness (there will be objects here and there but also lots of empty space) at fixed Z distance.

That’s why I thought of using plane but I can’t find a way to check intersection between ray and this plane at all times (and there IS interesection at all times because plane is parallel to the screen and infinite AND I don’t rotate camera).

[EDITING DONE]

THIS

float distance = 17;
Vector3f farMousePoint = theapp.getCamera().getWorldCoordinates(click2d, theapp.getCamera().getViewToProjectionZ(distance));
Vector3f lightLoc = farMousePoint.subtract(theapp.getCamera().getDirection().mult(distance));

spotty.setPosition(lightLoc);

OR THIS (I believe it’s the same but easier for me to think of)

float distance = 17;
Vector3f farMousePoint = theapp.getCamera().getWorldCoordinates(click2d, theapp.getCamera().getViewToProjectionZ(distance));

spotty.setPosition(new Vector3f(farMousePoint.x, farMousePoint.y, -17));

Thanks for help pspeed. For the first time I really feel that You helped me (not an irony I honestly am grateful as I would never find this strange function on my own) :blush:
Also thanks for not keeping promise of not responding to me again :smiley:


P.S. Just to be sure if I understand correctly (I learn after all - I don’t copypaste blindly): this line (most important one):

Vector3f farMousePoint = theapp.getCamera().getWorldCoordinates(click2d, theapp.getCamera().getViewToProjectionZ(distance));

…calculates mouse position on the fictional plane with constant = distance, just like if I casted ray from cursor and checked collision point with this plane?