Probably again problem with cam.getScreenCoordinates

Hi all,
im trying to mark target with some gunsight and project it onto gui and ran into problems with getScreenCoordinates
[java]
/**

  • Hud controller.

  • @author Ascaria
    */
    public class HudController extends BaseScreenController
    {
    protected Element gunSight;
    protected Geometry target;

    @Override
    public void bind(Nifty nifty, Screen screen)
    {
    super.bind(nifty, screen);

     gunSight = screen.findElementByName("hud-gun-sight");
     lockTarget(null);
    
     Main.LOG.info("HudController");
    

    }

    public void lockTarget(Geometry target) {
    this.target = target;
    if(null == target) {
    projectGunSight(settings.getWidth() / 2, settings.getHeight() / 2);
    }
    }

    public void update(float tpf) {
    if(null != target) {
    Vector3f enemyPosProjected = cam.getScreenCoordinates(target.getWorldTranslation());
    projectGunSight((int)enemyPosProjected.x, settings.getHeight() - (int)enemyPosProjected.y);
    }
    }

    protected void projectGunSight(int x, int y) {
    if(null != gunSight) {
    gunSight.setConstraintX(SizeValue.px(x - gunSight.getWidth() / 2));
    gunSight.setConstraintY(SizeValue.px(y - gunSight.getHeight() / 2));
    gunSight.getParent().layoutElements();
    }
    }
    }
    [/java]
    with this code, if im facing opposite direction from target, gunsight thinks target is in front of him, only with z greater than 1. i would expect that if im facing back then my crosshair will be at either side of the screen, but not in the middle…

can anyone give me help, how to handle target at the back? i tried some weird stuff like
[java]
if(null != target) {
Vector3f enemyPosProjected = cam.getScreenCoordinates(target.getWorldTranslation());
System.out.println("enemyPosProjected " + enemyPosProjected);
int wHalf = settings.getWidth() / 2;
int hHalf = settings.getHeight() / 2;
int x = 0;
int y = 0;
if(enemyPosProjected.z > 1) {
enemyPosProjected.x = enemyPosProjected.x > wHalf ? enemyPosProjected.x + wHalf : enemyPosProjected.x - wHalf;
enemyPosProjected.y = enemyPosProjected.y > hHalf ? enemyPosProjected.y + hHalf : enemyPosProjected.y - hHalf;

            x = (int)enemyPosProjected.x - gunSight.getWidth() / 2;
            y = settings.getHeight() - (int)enemyPosProjected.y - gunSight.getHeight() / 2;
           
        } else {
            x = (int)enemyPosProjected.x - gunSight.getWidth() / 2;
            y = settings.getHeight() - (int)enemyPosProjected.y - gunSight.getHeight() / 2;
        }
        projectGunSight(x, y);
    }

[/java]
but this is as wretched as it looks… i dont know how to handle back targeting hemisphere

The thing you ask by invoking the command is “Where does a line that crosses the cam location and the location of the object cross the screen plane?” If the object is right behind you that line still crosses the screen plane in the center.

ahaa, so it have two correct results, i now understand why this happens. so this is not what i want.

i see some similarity with ray cast, only difference is that ray have origin, so it doesnt go backward and dont hit enemies behind. if ray will be defined by two points as infinite line, it will hit enemies in the front and also back

so my question can be something like how target marks in fps games are made and how can this be done with jme3 ? :slight_smile: so if target is behind player slightly to the left, mark will be on one side of the screen and if target is slightly to the right, mark will be on opposite side of the screen

how can i “limit” that line to be only on one side ?

and im stupid enough i cannot formulate question for google how to program target marking, it returning me tons of useless results :frowning: it bothers me with tons of useless marketing topics

I either don’t understand the question or I’m not sure what part is giving you trouble.

If the target is in front of you… do the normal thing.

If it is behind you, figure out if it is to the left or right and indicate accordingly on the edge of the screen.

If it is directly behind you, pick one.

Which parts of that give you trouble? It will save me time answering.

yea google cannot understand me because noone understands me :slight_smile:

if enemy is in front of me, it works well

if enemy is behind, it looks like he is in front of me. i tried to glue crosshair to the side when enemy is behind me, but unsuccessfuly…
so trouble is when z > 1

next problem is when enemy is on the plane that cuts front and back “hemisphere”, so at about 90° angle ± some decimals, my crosshair is on the side, which is correct, but also it is forced to be in the upper or lower corner, which is bad.

i simply want crosshair to be in the line of sight everytime, clamped to the visible screen coordinates of course, so absolutly common thing what every game with some targeting system have, for example exactly like sturmovik have those red marks on the sides

im thinking about some orthogonal quad 1wu distant from camera, orbiting that camera and clamped into camera’s frustum

Yes, I kind of understood what you wanted… but short of writing “all the code” for you… I thought I’d ask which part was giving you issues. I’m still not sure.

It’s not really about clamping unless the object is actually of the sides of the screen (and then of course you want to clamp)… otherwise, you just project the vector out to the edge of the screen. Is that what’s giving you issues?

#1
i try to keep things simple :slight_smile: i dont want written code, but some tips how can i theoretically do it

@pspeed said: If it is behind you, figure out if it is to the left or right and indicate accordingly on the edge of the screen.
this is the problem :) and i failed yesterday doing this so from your text, you suggesting me simply to detect if enemy is on my right or left side and then simply move marker accordingly to the side of the screen. i also thought about this but failed

#2
is big overkill this idea?
create a node “targeting” on rootnode by camera.getlocation, then use targeting.lookat(target.getworldtranslation), then clamp rotation to view angle of camera (i must discover how to do this), then move node forward by 1wu, then use cam.getscreencoordinates on targeting rather than on target… so node targeting will never be on camera’s back

For objects that are behind the camera, invert the y position of the screen coordinate and fix the x position to the side of the screen depending on its x position being on the right half of the screen (fix to left) or the lest half of the screen (fix to right).

thanks normen, i did it as you suggested and when im backwards, crosshair are roughly accurate, but one problem persists, when im at 90° angle, its like hyperbola, but both sides are going up when approacing 0

i dont know how to correct this

Well given the explanation I gave about the result of the method thats normal, the line will never cross the screen plane. You will either have to simply handle these situations in your code or make a similar calculation yourself.

If the object is directly behind you… don’t change it’s target location from last time.

so i came with this solution, its doing about 40-60% of what i want, its pain to look at, so if anyone is interested…

it is done by using two independent nodes (not attached to rootnode). base node have rotation and location same as camera, child node is looking at targets, then limiting rotation of child node to cam.getFrustumXxx methods (those seems to be radians)