Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Help with HUD Sensor-Follower Reticle

Glantor Enzo
Registered User
Join date: 30 Jan 2008
Posts: 5
08-17-2008 21:28
Hi everyone,

This is my first post and I'm still relatively new with SL scripts, so please forgive me if I made any glaring errors that only a noob can make.

What I am trying to accomplish here is a HUD "targeting reticle" that will always float over the closest avatar within radar range. However, the results have been largely inaccurate, especially when moving further away from the avatar. I suspect it's a logic problem, but my maths isn't the best in class and my brain cells are fried already. =(

Kindly help me out with the following script I have put together. This goes into a prim that is attached to the HUD.

CODE

//--------------------------------
//adjust sensor setting
float sensor_dist=95;
float sensor_time=1.0;
//--------------------------------

integer x=0;
float dist=0;
vector ownervector;
vector avatarvector;
vector displayvector;


default
{
state_entry()
{
llSensorRepeat("",NULL_KEY,AGENT,sensor_dist,PI,sensor_time);
llRequestPermissions(llGetOwner(), PERMISSION_TRACK_CAMERA);
}

sensor(integer total_number)
{


for(x=0;x<1;x++)
{
if(llDetectedName(x) == "00000000-0000-0000-0000-000000000000") { jump getout;}
if(llDetectedKey(x) != llGetOwner())
{
if (x==0)
{
llSetText(llDetectedName(x),<0,1,0>,1);
}
avatarvector = llDetectedPos(x);
ownervector = llGetCameraPos();
displayvector = (avatarvector-ownervector);
displayvector = displayvector/llGetCameraRot();
displayvector.z = displayvector.z*0.09;
displayvector.y = displayvector.y*0.09;
displayvector.x = 0;
llSetPos(displayvector);


}

}

@getout;

}

no_sensor()
{
llSetText("No Agents Detected",<0,1,0>,1);
llSetPos(<0,0,0>);
}


}


Any help or advice will be greatly appreciated!
Kaluura Boa
Polygon Project
Join date: 27 Mar 2007
Posts: 194
08-18-2008 08:42
Hmmm... First, let's clean a bit that script.

- There's no need to use global variables if you use them only in one event.
- "00000000-0000-0000-0000-000000000000" isn't a valid avatar's name in SL. So your test is always false. (btw, this string is NULL_KEY.)
- If you want to quit immediately an event, don't jump to the end! Use: return;
- A HUD sensor will never detect its owner. No need to check.
- Very important: Before to think about moving a HUD item, it's better to be sure that it's attached where it's supposed to be or it means that you will (try to) move it to the SW corner of the sim. IOW, the HUD item will jump toward ZERO_VECTOR, 10 meters farther and farther away from you with each jump.

---------------------------------------------------------------

key OwnerKey;

uuCheckAttachment()
{
if (llGetAttached() < 31)
{
llOwnerSay("Attach me to at HUD position or I won't work. Period.";);
}
else
{
llRequestPermissions(OwnerKey, PERMISSION_TRACK_CAMERA);
}
}

default
{
on_rez(integer param) { llResetScript(); }

attach(key id)
{
OwnerKey = id; // Can't be anybody else...
uuCheckAttachment();
}

state_entry()
{
OwnerKey = llGetOwner();
uuCheckAttachment();
}

run_time_permissions(integer perms)
{
if (perms & PERMISSION_TRACK_CAMERA)
{
llSetPos(<0.0, 0.0, -0.5>;); // That's the center of the screen for a HUD item.
llSensorRepeat("", NULL_KEY, AGENT, 96.0, PI, 0.5);
// Sensor will be activated only after the permission is (automatically) granted
}
}

no_sensor()
{
llSetText("No Agents Detected", <0.0, 1.0, 0.0>, 1.0);
llSetPos(<0.0, 0.0, -0.5>;); // That's the center of the screen for a HUD item.
}

sensor(integer total)
{
llSetText(llDetectedName(0), <0.0, 1.0, 0.0>, 1.0);
vector avatar = llDetectedPos(0);
vector camera = llGetCameraPos();
rotation cam_rot = llGetCameraRot();
//
// Some deep thinking is needed... I'm going in world.
}
} // EOF

---------------------------------------------------------------
Quote me and you'll retrieve the formatting of the script.
Kaluura Boa
Polygon Project
Join date: 27 Mar 2007
Posts: 194
Food for the brain
08-18-2008 15:04
Finally, here is a working script. It's far from perfect but it works... sometimes. Don't ask how the mathematics work, I just made some trials and errors to reach this result. That's why it sucks so much. Besides, it's not fast enough! Wait for Mono... ;-)

----------------------------------------------------------------
key OwnerKey;

uuCheckAttachment()
{
if (llGetAttached() < 31)
{
llOwnerSay("Attach me to at HUD position or I won't work. Period.";);
}
else
{
llRequestPermissions(OwnerKey, PERMISSION_TRACK_CAMERA);
}
}

vector uuAngles(vector pos)
{
vector norm_direction = llVecNorm(<1.0, 0.0, 0.0> * llGetCameraRot());
vector norm_target = llVecNorm(pos - llGetCameraPos());
vector target = norm_target;
target.z = 0.0;
vector result = ZERO_VECTOR;
vector tempo = llRot2Euler( llRotBetween(norm_direction, target) );
result.y = tempo.z;
target = norm_target;
target.y = 0.0;
tempo = llRot2Euler( llRotBetween(norm_direction, target) );
result.z = tempo.y;
return result;
}

default
{
on_rez(integer param) { llResetScript(); }

attach(key id)
{
OwnerKey = id; // Can't be anybody else...
uuCheckAttachment();
}

state_entry()
{
OwnerKey = llGetOwner();
uuCheckAttachment();
}

run_time_permissions(integer perms)
{
if (perms & PERMISSION_TRACK_CAMERA)
{
llSetPos(<0.0, 0.0, -0.5>;); // That's the center of the screen for a HUD item.
llSensorRepeat("", NULL_KEY, AGENT, 96.0, PI, 0.3);
// Sensor will be activated only after the permission is (automatically) granted
}
}

no_sensor()
{
llSetText("No Agents Detected", <0.0, 1.0, 0.0>, 1.0);
llSetPos(<0.0, 0.0, -0.5>;); // That's the center of the screen for a HUD item.
}

sensor(integer total)
{
llSetText(llDetectedName(0), <0.0, 1.0, 0.0>, 1.0);
vector avatar = llDetectedPos(0);
vector angle = uuAngles(avatar);
float yy = llSin(angle.y);
float zz = llSin(angle.z) - 0.5;
if (yy < -0.75) { yy = -0.75; }
else if (yy > 0.75) { yy = 0.75; }
if (zz > 0.05) { zz = 0.05; }
else if (zz < -0.95) { zz = -0.95; }
llSetPos(<0.0, yy, zz>;);
}
} // EOF
----------------------------------------------------------------
Glantor Enzo
Registered User
Join date: 30 Jan 2008
Posts: 5
08-19-2008 02:06
Hey thanks for the advice and reworking the script Kaluura. I will try to make my future scripts better.

I tried your script in-world, but the prim still doesn't stick onto the closest avatar, especially when you move further back. For example, when I move my avatar from 5m to 25m away, the prim flies off screen. >_<

Sigh, hope what I am trying to ask for is not impossible to do in SL.
Kaluura Boa
Polygon Project
Join date: 27 Mar 2007
Posts: 194
08-19-2008 05:09
Yeah... I told you so, my maths suck a lot! ;-) It worked rather nicely when I took care only of left/right position. Now it just work at its best when the target is the closest from the center of the screen. But I know the real maths we need: Projection from 3D coordinates on a plane. Raytracing stuff... or very close from it.

I talk to a friend about the whole stuff and we found a project in which we could insert such a targetting HUD... so I'm not giving up. (I'm aiming the library bump...) ;-)
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
08-19-2008 10:58
This--from the OP--is actually not a bad start for perspective transformation:

CODE

avatarvector = llDetectedPos(x);
ownervector = llGetCameraPos();
displayvector = (avatarvector-ownervector);
displayvector = displayvector/llGetCameraRot();
displayvector.z = displayvector.z*0.09;
displayvector.y = displayvector.y*0.09;
displayvector.x = 0;
llSetPos(displayvector);


However, before you set the x components to zero, you might want to divide it into the y and z components (checking first to make sure x > 0, or better yet some "near clipping distance"; i.e. the position is in front of the camera). Something like:

CODE

avatarvector = llDetectedPos(x);
ownervector = llGetCameraPos();
displayvector = (avatarvector-ownervector);
displayvector = displayvector/llGetCameraRot();

if (displayvector.x < EPSILON)
{
// Target not "in front" enough; ignore it
return;
}

displayvector.z *= Z_CORRECTION*/displayvector.x;
displayvector.y *= Y_CORRECTION*/displayvector.x;
displayvector.x = 0;

llSetPos(displayvector);


Another thing to watch out for might be aspect ratio. You might want a calibration step of some kind to deal with folks who have screens/windows with different aspect ratios.
Kaluura Boa
Polygon Project
Join date: 27 Mar 2007
Posts: 194
Working script
08-20-2008 03:51
Thx Hewee. I knew there was some simple projection formula that I used to play with in the 8-bit's era... ;-) Any way, I managed to do something that is working pretty well.

-----------------------------------------------------------------------
key OwnerKey;

uuNoTarget()
{
llSetText("No Target", <0.0, 1.0, 0.0>, 1.0);
llSetPos(<0.0, 0.0, -0.5>;); // That's the center of the screen for a HUD item.
}

uuCheckAttachment()
{
llSetTimerEvent(0.0);
if (llGetAttached() < 31)
{
llOwnerSay("Attach me to at HUD position or I won't work. Period.";);
}
else
{
uuNoTarget();
llRequestPermissions(OwnerKey, PERMISSION_TRACK_CAMERA);
}
}

default
{
on_rez(integer param) { llResetScript(); }

attach(key id)
{
OwnerKey = llGetOwner();
uuCheckAttachment();
}

state_entry()
{
OwnerKey = llGetOwner();
uuCheckAttachment();
}

run_time_permissions(integer perms)
{
if (perms & PERMISSION_TRACK_CAMERA)
{
llSetTimerEvent(0.3);
// Sensor will be activated only after the permission is (automatically) granted
}
}

timer()
{
llSensor("", NULL_KEY, AGENT, 96.0, PI);
//llSensor("Target", NULL_KEY, PASSIVE, 32.0, PI);
}

no_sensor()
{
uuNoTarget();
}

sensor(integer total)
{
integer DONE = FALSE;
integer num = 0;
while ( (num < total) && (! DONE) )
{
vector target = (llDetectedPos(0) + <0.0, 0.0, 0.5> - llGetCameraPos()) / llGetCameraRot();

if (target.x < 1.0)
{
jump skip;
}


target.y *= 0.875 / target.x;
target.z = -0.5 + target.z * (0.875 / target.x);

if ( (llFabs(target.y) > 0.75) || (target.z > -0.05) || (target.z < -0.95) || (target.x < 0.0) )
{
jump skip;
}
else
{
llSetText(llDetectedName(num), <0.0, 1.0, 0.0>, 1.0);
target.x = 0;
llSetPos(target);
DONE = TRUE;
}
@skip;
++num;
}
if (! DONE)
{
uuNoTarget();
}
}
} // EOF
-----------------------------------------------------------------------
(Quote me to retrieve the script indentation.)

Note that I used a sensor in timer because llSensorRepeat() has the nasty habit to detect avies in the neighboring sims from time to time. Very annoying...

I added a little vertical offset to the AV's position in order no to aim only crotches.

"My" EPSILON seems rather universal and since there are other tests, you shouldn't need to touch it.

The Y_CORRECTION and Z_CORRECTION may need some adjustment. Y_ is the horizontal axis of the screen and Z_ the vertical one. From my experience, if the target doesn't move enough on one axis, increase *a little* the correction factor (like 0.9 instead of 0.875), if it moves too much reduce it *a little*.

As for the borders of the HUD screen, I kinda remember that it's the same whatever the actual size of real screen. So you shouldn't need to change that. [left-right: (0.75, -0.75) and top-bottom: (0, -1)]

Have fun!
Glantor Enzo
Registered User
Join date: 30 Jan 2008
Posts: 5
08-23-2008 00:32
Hi Kaluura and Hewee,

Thank you so much for your help! It works like a charm now. =)

LOL at this statement "I added a little vertical offset to the AV's position in order not to aim only crotches."