Difference between revisions of "Talk:LlCastRay"
Jack Abraham (talk | contribs) |
|||
Line 392: | Line 392: | ||
That said, if it can be done, RC_DAMAGE would be a nice thing to have. I do build my weapons to fail down to Linden damage if no supported combat system is found, and if Linden damage is enabled. <tt>ray_impact</tt> would also be nice, especially if it's only explicitly triggered; UUID, impact point, and an arbitrary integer constant sent by the ray caster would be the values I'd see as most useful. Perhaps rather than go the whole list of parameters route for RC_DAMAGE, just add another integer parameter to <tt>llCastRay</tt> that would be used differently with different flags? In any event, not having either of these would in no way dampen my enthusiasm for this feature or impact my plans for using it, assuming it gets deployed. [[User:Jack Abraham|Jack Abraham]] 19:23, 6 July 2010 (UTC) | That said, if it can be done, RC_DAMAGE would be a nice thing to have. I do build my weapons to fail down to Linden damage if no supported combat system is found, and if Linden damage is enabled. <tt>ray_impact</tt> would also be nice, especially if it's only explicitly triggered; UUID, impact point, and an arbitrary integer constant sent by the ray caster would be the values I'd see as most useful. Perhaps rather than go the whole list of parameters route for RC_DAMAGE, just add another integer parameter to <tt>llCastRay</tt> that would be used differently with different flags? In any event, not having either of these would in no way dampen my enthusiasm for this feature or impact my plans for using it, assuming it gets deployed. [[User:Jack Abraham|Jack Abraham]] 19:23, 6 July 2010 (UTC) | ||
== Get Alt-Zoom camera cursor position and surface orientation == | |||
Here is an example I made, how to get the camera cursor position when you Alt-Zoom on any object surface with the '''llCastRay''' function. | |||
The script also calculates the surface orientation at the cursor position and rezes a prim on a top of surface. The Z-Axis of a rezed prim is aligned with the Normal vector of a surface at a given point and the X-Axis points in a way of your camera sight. | |||
The calculation of surface orientation is made by casting 3 rays on a surface, very close together, to get two vectors (named U and V) on a surface. then the Normal vector is get by a vector product of these two vectors. | |||
To test the script make a new HUD object and put the script below into it. Also put one standard cube prim (named Object) into its inventory. Attach the HUD and Alt-Zoom to any curved surface in region, but not more than 10m far from you. Then click on the HUD and a new prim will be rezed on a top of surface where the Alt-Zoom cursor of your camera points. | |||
<lsl> | |||
// | |||
// Scriptname: Get Alt-Zoom position and Surface Orentation | |||
// Version: 1.0 | |||
// Date: 06.07.2010 | |||
// | |||
// Description: Gets the position of the camera cursor | |||
// when a user Alt-Zumes on a surface of any object and | |||
// rezes a prim on this point and orients it with a surface | |||
// | |||
// How To: - Create a new HUD (cube), size = X=0.05 y=0.05 Z=0.05 | |||
// - Put this script on it and attach it as a HUD | |||
// - Insert a standard prim (Cube 0.5m) into HUD inventory (named as Object) | |||
// - Alt-Zoom (not far than 64m from you) with your mouse to any object surface in the region | |||
// - Without moving your camera, click on this HUD | |||
// - You will get the camera cursor position and surface orentation | |||
// - An Object from HUD inventory will be rezed on a top of Alt-Zoomed surface | |||
// perfectly aligned with surface and with X-axis pointed to your line of sight | |||
// | |||
// Tips: To see the camera cursor, enable: Advanced->Character->Show Look At in your Advaned Menu | |||
// Rez a big sphere to make a curved surface in a region and Alt-Zoom on it. | |||
// | |||
// Notes: You must be at least 10m close to Alt-Zoom position (llRezObject() limitation) | |||
// There's no "clamping code" included to cut the rays to be inside of a region | |||
// | |||
// Additional: The script cast 3 rays to a prim surface very close to each other to make 2 different | |||
// short (not paralel) vectors U and V laying on the hit surfaces. The Normal vector on | |||
// the surfaces is calculated as a vector product of U and V. From these tree axes a rotation | |||
// of a prim (to be positioned on a top surface) is calculated. | |||
// | |||
// Creator: Teleworm Gelber | |||
// | |||
default | |||
{ | |||
state_entry() | |||
{ | |||
if (llGetAttached() > 0) | |||
{ | |||
llRequestPermissions(llGetOwner(), PERMISSION_TRACK_CAMERA); | |||
} | |||
else | |||
{ | |||
llOwnerSay("Attach me as a HUD"); | |||
} | |||
} | |||
run_time_permissions(integer permissions) | |||
{ | |||
llOwnerSay("Alt-Zoom on any curved surface in the region"); | |||
llOwnerSay("Then click me to get the Alt-Zoom cursor coordinates and an Object will be rezed there"); | |||
} | |||
touch_start(integer total_number) | |||
{ | |||
vector camPos; // camera position | |||
rotation camRot; // camera rotation | |||
vector rayStart; // ray start vector | |||
vector rayEnd; // ray end vector | |||
vector curPos; // Alt-Zoom cursor position | |||
rotation pointRot; // Point on a surface rotation (Z-axis = SurfaceNormal, X-axis = line of sight) | |||
vector uVec; // U-vector on a hit surface | |||
vector vVec; // V-vector on a hit surface | |||
vector fwd; // surface point orentation forward vector ( | |||
vector left; // surface point orentation left vector | |||
vector up; // surface point orentation up vector (Normal vector) | |||
list rayData; // ray cast return data | |||
if ((llGetPermissions() & PERMISSION_TRACK_CAMERA) != 0) | |||
{ | |||
// getting camera location | |||
camPos = llGetCameraPos(); | |||
camRot = llGetCameraRot(); | |||
// Cast a ray in a line of your sight (10.0 means llRezObject() limitation) | |||
rayStart = camPos; | |||
rayEnd = camPos + 10.0 * llRot2Fwd(camRot); | |||
rayData = llCastRay(rayStart, rayEnd, 0, RC_GET_NORMAL); | |||
if (llList2Integer(rayData, -1) > 0) // check status code | |||
{ | |||
// get the Alt-Zoom cursor position | |||
curPos = llList2Vector(rayData, 1); | |||
// make a new ray cast for the U-vector on the hit surface (delta X) | |||
rayEnd = rayStart + 10.0 * llVecNorm(curPos + <0.01, 0.0, 0.0> - rayStart); | |||
rayData = llCastRay(rayStart, rayEnd, 0, RC_GET_NORMAL); | |||
if (llList2Integer(rayData, -1) <= 0) | |||
{ | |||
llOwnerSay("Nothing hit, try again"); | |||
return; | |||
} | |||
uVec = llVecNorm(llList2Vector(rayData, 1) - curPos); | |||
// make a another ray cast for the V-vector on the hit surface (delta Y) | |||
rayEnd = rayStart + 10.0 * llVecNorm(curPos + <0.0, 0.01, 0.0> - rayStart); | |||
rayData = llCastRay(rayStart, rayEnd, 0, RC_GET_NORMAL); | |||
if (llList2Integer(rayData, -1) <= 0) | |||
{ | |||
llOwnerSay("Nothing hit, try again"); | |||
return; | |||
} | |||
vVec = llVecNorm(llList2Vector(rayData, 1) - curPos); | |||
// surface normal vector is vector product of UxV | |||
up = llVecNorm(uVec % vVec); | |||
// forward vector points in a way you are looking | |||
left = llVecNorm(up % llRot2Fwd(camRot)); | |||
fwd = left % up; | |||
// calculate prim rotation to be put on a top of hit surface | |||
pointRot = llAxes2Rot(fwd, left, up); | |||
llOwnerSay("Alt-Zoom Position: " + (string) curPos); | |||
llOwnerSay("Point Rotation: " + (string) pointRot); | |||
// rez an Object on a top of hit surface, 0.25 means the prim center offset from surface (0.5m cube) | |||
llRezObject("Object", curPos + <0.0, 0.0, 0.25> * pointRot, ZERO_VECTOR, pointRot, 0); | |||
} | |||
else | |||
{ | |||
llOwnerSay("Nothing hit, try again"); | |||
} | |||
} | |||
else | |||
{ | |||
llOwnerSay("Attach me as a HUD first"); | |||
} | |||
} | |||
on_rez(integer par) | |||
{ | |||
llResetScript(); | |||
} | |||
}</lsl> | |||
--[[User:Teleworm Gelber|Teleworm Gelber]] 23:08, 6 July 2010 (UTC) |
Revision as of 15:08, 6 July 2010
llSonar please?
I would appreciate if you took in consideration my suggestions at http://jira.secondlife.com/browse/SVC-2486 please; any feedback is more than welcome.
ps:llCastRay is already awesome, you rock! Please try the hardest you can to figure out how to get this to come to the maingrid with the least crippling as possible.
--TigroSpottystripes Katsu 03:01, 3 July 2010 (UTC)
Hi Tigro,
If I understand your feature request, it sounds much like the shape cast described in SVC-5381 (http://jira.secondlife.com/browse/SVC-5381) for a sphere or a cylinder cast along its primary axis. Is that correct?
Thanks, Falcon Linden
- I have just skimmed thru the comments there, do shape casting allow for somthing liek for example have a nonphys object recognize the geometry so it could rest against a jumbled pile of prims as if it was laying against them physicly? (in the ASCII art in SVC-2486 it would be having the object represented by the O's resting in the diagonal line as if it was solid) --TigroSpottystripes Katsu 05:44, 3 July 2010 (UTC)
- A practical example, imagine a giant mecha, with big flat feet, now imagine a landscape littered with prims of all sorts of shapes and sizes, to make it look realistic, on each step the foot should be rotated to rest against the highest points under it ; just raycasting you have the risk of shooting between prims, and with shapecast you don't get the rotation for the foot. --TigroSpottystripes Katsu 03:04, 4 July 2010 (UTC)
What am I looking at?
A function I just threw in to replace phantom bullets for quickly acquiring a point of interest -- whatever your camera's focused on (in this sim, within 20m) is returned, allowing quicker, more intuitive targeting of other objects. PERMISSION_TRACK_CAMERA must be previously set.
<lsl>key camPing() {
// End points at the camera and 20m in front of it vector camPos = llGetCameraPos(); vector endPos = camPos + ( <20.0, 0., 0.> * llGetCameraRot() );
// Clamp the end position to within the sim // Except what I originally posted was wrong, and I'm too tired to do trig
// Cast the ray; ignore hits on land, otherwise get the root key list contacts = llCastRay( camPos, endPos, RC_REJECT_LAND, RC_GET_ROOT_KEY );
// Return values if ( llList2Integer( contacts, -1 ) > 0 ) { // Got a return return llList2Key( contacts, 0 ); } return NULL_KEY;
} </lsl>
Jack Abraham 04:42, 3 July 2010 (UTC)
RC_GET_LINK_NUM? Not RC_GET_LINK_KEY?
I can't think of a circumstance where knowing the link number of the return would be useful. UUID of the prim hit would be far more useful; is that within the realm of possibility? Jack Abraham 04:47, 3 July 2010 (UTC)
Hi Jack,
The default behavior is to return the UUID of the prim hit. If you want the root key instead, you have to use RC_GET_ROOT_KEY. The intended purpose of RC_GET_LINK_NUM was for scripts like your camera targeting system where it is expected that the camera will be pointed at a child of the linkset performing the cast. For example, suppose you make a minesweeper game where each tile is a prim in the linkset. And suppose you script it so that the use can select a tile by focusing on it and clicking. The script could cast a ray from the camera and determine the link number of the tile in the player's line of sight. Then it could use that link number in an llMessageLinked or some other LSL function to modify the appropriate child prim. Does that make sense? If it turns out no one has any use for RC_GET_LINK_NUM, I'll eliminate it for the sake of simplicity. But the behavior you're looking for is already there by default! Yay.
Cheers, Falcon Linden
Makes perfect sense; I need to read better. Thanks. Jack Abraham 05:44, 3 July 2010 (UTC)
Memory concerns
Dumping all possible avaible information into a list regardless of whether any of them will be used seems severely wasteful. If you really need to dump all the info as soon as the command is called straight into script memory, at least do somthing like adding a parameter to the command that is a list where each item identifies which pieces of information the scripter wants (like with llGetPrimtiveParams ) --TigroSpottystripes Katsu 05:51, 3 July 2010 (UTC)
I think we basically have that, Tigro; we only get UUID and hit position unless we set additional flags. Falcon indicated that we will not get all hits in the final version; that'll further reduce the size of the list. Jack Abraham 07:50, 3 July 2010 (UTC)
Clamping
It would be a waste of server resources if every script has to add clamping code to make sure their begin and end are inside the region! Instead, do not return an error code but just stop and return only the hits inside the region. That might mean you have to add the clamping code in the server, but that would be a hell of a lot more efficient than doing that in the LSL scripts.
Note that clamping is relatively easy, in C++ it shouldn't cost more than a few microseconds. The algorithm would be something like:
1) A bounding box can be given with two vectors: bbmin and bbmax, where bbmin is the bottom, south/west corner of the sim (0,0,0), and bbmax the upper, north/east corner of the sim (256,256,4096).
2) Let the ray begin at vector begin and end at vector end (using the same coordinate system as the bounding box).
3) Calculate bbmine = bbmin - end, and bbmaxe = bbmax - end. Check if end is outside the sim, so clamping is needed at all, by checking that at least one coordinate in bbmine is positive or one coordinate in bbmaxe is negative (set 'clamping_needed').
4) Shift coordinates so that begin becomes the origin and end becomes the direction (bbmin -= begin; bbmax -= begin; dir = end - begin). Lets call end dir from now on.
5) Check that bbmin has three negative coordinates and bbmax has three positive coordinates. If not then begin is outside the bounding box (if the signs are correct, except there are one or more zeroes, it's on the border and you can just return begin). Not sure if you should return an error code or return just no results. Finally, if begin is outside the bounding box, but end was inside, you might want to clamp begin instead of end. Lets assume that begin is inside the bounding box for now. If end was also inside it, then no clamping is needed and we stop here.
6) Clamping is needed. Calculate dir.x / bbmin.x, dir.x / bbmax.x, dir.y / bbmin.y, dir.y / bbmax.y, dir.z / bbmin.z and dir.z / bbmax.z.
7) Find the largest value 'max' of those six and return begin + dir / max as the collision point of the ray in the direction dir.
As you can see, this is a very fast routine. Still, I think it should be added to the server side. I didn't add code in order to avoid any license problems ;)
Aleric Inglewood 12:00, 3 July 2010 (UTC)
Actually, using SSE2, clamping would take just a few cpu instructions. It's not a question of efficiency for me, it's a question of future compatibility. Since we don't have script versioning for LSL, if we later add the ability to cast rays between sims or change the size of a region, existing scripts will break. I've been thinking of adding a version parameter to this function in order to deal with that possibility, in which case I could clamp in native code.
Cheers Falcon Linden 17:20, 3 July 2010 (UTC)
return also types casted
since filters RC_REJECT_AGENTS, RC_REJECT_PHYSICAL, RC_REJECT_NONPHYSICAL, and RC_REJECT_LAND are used, and therefore detected, it would be handy if in the results returned, the status AGENT, NON_PHYSICAL, PHYSICAL and LAND would also be returned. Is it douable ? --
I've been thinking about that. Either I'll somehow include the type in the list of returned data (perhaps only if you add the flag RC_GET_TYPE or something) or else modify llGetObjectDetails to return the data. You'll definitely have access one way or the other. Regarding land, though, you can definitively identify that because it will return null UUID.
Falcon Linden 17:20, 3 July 2010 (UTC)
Meep
Heya Falcon, really would absolutely love to have an llCastRay function in production.
I saw you had a concern of versioning issues. To overcome that, I heavily recommend using a list as an input, as that would be far more flexible on the kind of parameters and options you can push through rather than fooling yourself into using a hardcoded structure of llCastRay(vector start, vector end, other stuff) etc. A bit like how llSetPrimitiveParams works basically. For example in the past, LL upgraded the prim type interface from legacy to a more advanced and flexible set of input (torii, tubes and rings, yey), they could do this easily because a list was used as a parameter in the function, instead of having to expend resources on adding more functions, bloating LSL and causing legacy issues.
I also have a question, when you cast a ray and it hits an avatar, that hits the avatars' actual sphere-ish phys mesh, correct?
I have actually experimented personally with LSL and my custom client with a prototype LSL Script API, I could offload raycast processing into nearby clients easily and even built a half-working hexapod spider that can walk on a prim landscape, as well as all the fun raycasting combat gun stuff :). So, I have some serious experience to share in this field and having the raycasts locally processed would be really useful in a more timely manner (rather than suffering the delays of network lag).
What are your thoughts on the kind of filtering? Whitelist versus Blacklist? Whitelists are apparently more effective based on desire. (Would be good for consistency (which is hard enough to come by..): llSensors, llListen, ...)
On a last note, you might be wondering about my achievement with my custom client, I couldn't get raycasting weapons taking off because there is a missing critical element to gameplay: Tracers. The user of a gun MUST be able to see WHERE their bullets went (guns use fire cone spread algorithms for added realism). This is one of the significant problems that keep raycasting usage in weaponry really taking off. Otherwise I could have seriously introduced raycasting and changed the face of SL combat with my custom client. If only particle systems could be spontaneously created midair (without requiring the particle system to be 'attached' to the prim (it's possible code-wise in the client btw)) via scripts to simulate tracer effects, then raycasting would seriously be able to take off socially.
--Nexii Malthus 02:10, 4 July 2010 (UTC)
Hi Nexii,
Let me take these one at a time. First, in regard to versioning, LSL lists are very inefficient on the C++ side. They're implemented as linked lists (yuck). I do see the advantage to using a list for parameters, but it would make parsing it slower and I'd rather pull a Windows API (heh, also yuck) style move and (a) add a reserved version number parameter and (b) if necessary later, create an llCastRayEx function. Not the world's most extensible implementation, but c'est la vie.
Second, an avatar's shape isn't sphere shaped at all...and it's not a mesh, it's a convex hull. Its basic shape is kind of like a capsule. I'll leave the process of determining its exact shape via llCastRay calls with RC_GET_NORMAL as an exercise to the reader. :) (And if you do it, be sure to post pictures! That would rock.)
Third, I'm pushing hard for LL to provide client side prediction/client side physics. Although that wouldn't immediately lead to client side scripting, it eventually might. And in the meantime, although open source viewers would need to replace the physics module with an open source version (of which there are plenty), you would have a framework for doing physics-based raycasts locally.
Fourth, regarding filtering, it just made the most sense to use blacklists as it's most common to want to know "What's the first thing I'm hitting?" It's less common to want to know "what's the first avatar/prim/land triangle that I'm hitting?"
Finally, after seeing your comment about tracers I looked up the details of llParticleSystem and was astonished to see that, as far as I could tell, you're totally right. Here's one idea as a temporary workaround: rez a transparent, phantom, nonphysical sphere (perfect, solid spheres are the simplest physics shape available) at the location you need your particle effect, create it there, and then call llDie(). It sucks, I know, but I'm not a graphics programmer and can't add an appropriate particle system function. Another idea, though much much less efficient, would be to rez a set of long, colored, phantom cylinders the length of the raycast. It's still much more efficient than prim bullets since it would be nonphysical and phantom, though.
Hope that helps, Falcon Linden 05:44, 4 July 2010 (UTC)
Function to not fail, what do you think?
I made this:
<lsl>list JustRayIt(vector start, vector end, integer filter, integer flags) {
list temp; while((llList2Integer(temp, -1) < 0) || (llGetListLength(temp) == 0)) { temp = llCastRay(start, end, filter, flags); } return temp;
} </lsl>
The idea being to halt the rest of the script until it can get a valid trace; does it work the way i intended it to? Is there any downside to using this? Is there a better way to get the same result? --TigroSpottystripes Katsu 04:14, 4 July 2010 (UTC)
Hi Tigro,
The script you're suggesting would, sadly, be hugely inefficient. It would hog system resources until the script's time slice ran out. And, to make matters worse, once you fail you're guaranteed not succeed until at least the next frame anyway. I'm not a huge lsl scripter, so I'm not 100% sure, but I believe if you added an llSleep(0) call in the while loop, your script would be put to sleep until the next frame. Failing that, try llSleep(0.1) or some other small number.
Good luck, Falcon Linden 05:29, 4 July 2010 (UTC)
- The way it is on the Oatmeals, do tracing ever fail in the frame? --TigroSpottystripes Katsu 05:40, 4 July 2010 (UTC)
- Also, doesn't llSleep hog systems resources just the same? --TigroSpottystripes Katsu 05:44, 4 July 2010 (UTC)
On Oatmeal, casts will fail if the overall physics FPS drops too low. It will never fail due to too many raycasts in the same frame, however. In production it will, but I wanted to see how people used it before determining appropriate limits.
llSleep stops execution of your script and allows the simulator to move on to processing another script. It is not implemented as a busy-wait. (At least, I sure hope not. I haven't actually checked the code.)
Falcon Linden 05:50, 4 July 2010 (UTC)
Partially offtopic: about SVC-4606 "Surface conveyour belt"
Falcon, if it's not you, could you please bring SVC-4606 to the attention of whatever Linden that would be able to evaluate it and get it in the plans if it's possible please? (If it's you, then please take a look and see what you can do) --TigroSpottystripes Katsu 04:43, 4 July 2010 (UTC)
I have thought about adding a much, much simpler version of this (where you simply get to specify a velocity vector and a face of the prim), but it would be at least a little tricky to implement and there are a number of things of more general use that I'd like to get to first. Some day, though, it would be a great feature. Falcon Linden 05:51, 4 July 2010 (UTC)
- If the server already knows about which face collided and things like the normal of the collision point (and of course the texture parameters of the prim), wouldn't it be just a matter of basic vector math to get the resulting force and stuff? I imagine this could be a game changer close to the scale of flexies, people moving around a mall on flat conveyors like those on some airports, working escalators, more realistic wheeled and tracked vehicle behavior, people will find all sorts of uses for it. Is there somewhere i can see the stuff you got planned? --TigroSpottystripes Katsu 06:01, 4 July 2010 (UTC)
I'm about to head out (it IS a Saturday night here, haha), so this is probably my last post, at least for a few hours, probably until tomorrow. The problem is related to stability and details about determining which objects to apply the force to and how. In the physics engine, this would be done by modifying the contact points between the conveyor belt and the other bodies. Also, the server doesn't really know which face collided, which makes it trickier still, as that info would have to be derived dynamically any time a body came in contact with the conveyor belt object. Finally, it would almost certainly break avatar animations which rely on the avatar's velocity (not the requested motion of the user) to determine when to play a particular animation. Unfortunately, I don't have a publicly visible list of projects I'd like to complete. But they do include llCastRay (yay progress!), llCastShape (see SVC-5389...I think...the raycast SVC, exposing the Havok vehicle kit, providing for alternative physics representation (so that the shape you see isn't tied to the shape the physics engine sees, allowing simpler collision geometry), providing control of friction, density, restitution, and gravity, ... the list goes on. Please bear in mind, however, that there is absolutely no guarantee any of these will be shipped as they are mostly unscheduled it isn't clear what LL's priorities will be in the coming months. Oh, and of course, given the opportunity, I'd put all of these ideas aside to work on client side prediction which would have HUGE impact on lag, although it wouldn't provide much in the way of new resident-facing features.
Have a good night, Falcon Linden 06:24, 4 July 2010 (UTC)
selfignoring?
Is there a way to have the raytrace ignore prims in the same linkset? --TigroSpottystripes Katsu 05:42, 4 July 2010 (UTC)
No, unfortunately this is not possible and would be hacky to implement (though it could be done if there were enough demand for it). It will, however, always ignore a shape that the ray begins inside of. So if you use llGetPos() from a convex prim, that prim will not be returned by the cast. You can always use the UUID of the prim to ignore the result as well.
Falcon Linden 05:46, 4 July 2010 (UTC)
On the topic of limiting it to not work past a distance
It was done with llSensor, and what happened? People wasted server resources to overcome the limitation; you still think it's a good idea? --TigroSpottystripes Katsu 08:04, 4 July 2010 (UTC)
Nope. I don't. But llCastRay isn't artificially limited to a distance. It's simply limited to work within the region. But that isn't an artificial limit, it's a fundamental one: llCastRay uses the physics engine for raycasts. On a given simulator, nothing exists in the physics world outside the region boundaries.
Falcon Linden 09:47, 4 July 2010 (UTC)
- Hm, sorry, i'm not finding it now, but i could swear i had read you saying somthing along the lines of "you wouldn't want people raycasting from the other side of the sim", dunno... --TigroSpottystripes Katsu 09:56, 4 July 2010 (UTC)
Yes, I did say that. I then proceeded to change my mind. :) Falcon Linden 18:59, 4 July 2010 (UTC)
Is it a logical bug on my script or does it not update fast enough?
Does the data llCastRay reads from gets update as often as the position and rotation of phys objects or does it get updated less often? I'm mostly confident that the start position is inside the prim but somtimes the trace will hit the prim somehow, it happens more often when the prim is bouncing around fast. --TigroSpottystripes Katsu 11:23, 4 July 2010 (UTC)
That depends on how you're updating the objects. If you're calling llSetPos() or similar in your script, those updates will not be processed until later, whereas the llCastRay call will be processed immediately. I suspect llGetPos() will return the value you set with llSetPos() even though the physics object isn't there yet. Falcon Linden 19:01, 4 July 2010 (UTC)
"I'm personally praying that llCastRay will make simulated projectile weapons essentially obsolete in SL. "
I've spent a little time exploring the functionality of llCastRay today. From the perspective of a veteran LL damage combat scripter;
In terms of raw utility, llCastRay effectively provides the ability to determine a bullet's target without the intervening physics. This is an advantage because it means that traditional region crawl caused by irresponsible people spamming physical objects is significantly reduced. It also means that the number of bullets required to send an individual home is reduced; in the case of the firer being able to aim, of course.
The function seems more fitted to abstracted combat with meters and script awareness (determining distance to surfaces, etc) however, because it provides a very large volume of data back to the script calling it but does not impact what it is detecting in any way. While it is possible to build a weapon that uses it for projectiles with traditional LL damage, the benefits do not necessarily outweigh the negatives; it effectively moves the majority of work from the source system to the projectiles instead. Using communications such as listens to transfer a target vector from a gun to a bullet on each rez is obviously absurdly inefficient considering the rates at which most people like to fire them and therefore the cast is better placed in the bullets themselves; this means that the bullets cannot be temporary prior to casting and therefore realistically on rez, although they can simply be set temporary subsequent to casting. Regardless of the method of acquiring the target position, the bullet must still travel to the location to inflict damage; a stacked primparams position is the obvious solution, as it also allows for temponrez and physics to be set in the same call.
Would it be possible to implement a sister (if somewhat crippled) function to llCastRay that has the capability to inflict LL damage on agents? While I see a great deal of value in llCastRay it is not necessarily preferable to physics as a combat tool. Something along the lines of an llCastDamage which is restricted to cast from the root position of the object calling it along a fixed axis. In a similar manner to a sensor, except with a damage variable similar to the llDamage() prim param setter that affects only the first thing it intersects. Additional fluff could be a contact sound triggered at the point of intersection, contact particles and so forth.
tested projectile, just for reference: <lsl> vector xyz(vector in) {
if (in.x > 255.9) in.x = 255.9; else if (in.x < 0.1) in.x = 0.1; if (in.y > 255.9) in.y = 255.9; else if (in.y < 0.1) in.y = 0.1; if (in.z > 4095.9) in.z = 4095.9; else if (in.z < 0.1) in.z = 0.1; return in;
}
default {
state_entry() { llCollisionSound("",0.0); llCollisionSprite(""); llSetDamage(100.0); } on_rez(integer s) { if (!s) return; vector p = llGetPos(); vector d = <20.0,0.0,0.0>*llGetRot(); list ray = llCastRay(p,xyz(p+d),0,0); list tgt = [PRIM_POSITION,llList2Vector(ray,1)]; tgt += tgt += tgt += tgt += tgt += tgt;//1,2,4,8etc llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_TEMP_ON_REZ,TRUE]+tgt+[PRIM_PHYSICS,TRUE]); llDie(); }
} </lsl> Jeremy Duport 19:51, 4 July 2010 (UTC)
This is *not* a viable replacement for projectiles
llCastRay is a great idea, and I'll make heavy use of it in a wide range of applications, but there's no way it's going to replace scripted bullets in any meaningful way.
There's just no other way to get a decent visual effect for bullets. Particles are an enormous performance drain on the client [and don't anyone tell me to just get a better machine, I'm a poor student, damnit], and of course look the same from every direction. Scripted bullets are also the only timely way to get a particle effect at unscripted impact locations.
There's also the problem of communicating effectively between a gun and a scripted target. With combat going on, something like a listen on targets and regionsay from guns is going to trigger zillions of unnecessary events. Sure, *I* know how to properly hash UUIDs to integers, and there's reasonable code for that on this wiki, but have you actually seen the kind of shit most scripters in SL try to pull? Note that people are *still* using resizer scripts in every prim of a linkset and controlling them with linked messages.
Also, despite being sidetracked by https://jira.secondlife.com/browse/SVC-5953, I'm a week or so of work away from releasing several weapons that trigger bullet rezzes via changed events, rather than by inked messages. Tyro Dreamscape has already successfully demonstrated this method as a near-zero-sim-impact way of squeezing high firing rates of scripted bullets out of as few rezzing scripts as possible. Sure, you could bring up sim garbage collector woes, or my argument from above about the absurdly low coding standards among scripters, but the former has not been an issue in practice, at least with intentionally minimalist bullet scripts, and the latter is something I'm expecting market forces to help with. We *can* do scripted bullets the right way.
I'd really like someone to prove me wrong. Thoughts?
--Michelle Resistance 15:55, 5 July 2010 (UTC)
Ummm, you do realize that you're still just calling a function in one script, that triggers an event in another, right? Except that where a linked message merely communicates between scripts, the changed() event requires triggering a function that changes some parameter of the other object, so you're asking the simulator to do a small bit of extra unnecessary work in between calling the function and triggering the event.
You are right that scripted bullets can be done the right way. But the right way doesn't mean reinventing the wheel or creating a Rube Goldberg machine, it requres understanding what the wrong way is, why certain things use extra processing resources, and finding the most effective ways to mitigate those problems. Keep in mind that people have tried to use llResetOtherScript() and actually believed that it was more efficient. It was the same sort of reasoning involved, where someone thought "method A is laggy, therefore method B will be better."
It is quite possible to make efficient physical projectile weapons. But just because many people are unable to do so does not mean that you need to find some supersekret new method for doing so. It is simply a matter of using good coding practices like KISS. Granted, it's oh so much easier to market something that's new and different, but that doesn't make it so.
Jahar Aabye 19:24, 5 July 2010 (UTC)
Passing data through a changed event, at least the way Tyro and I have been doing it, has far less impact on the sim than the string operations that most people do when communicating between scripts via link messages. Try it, it's rather impressive. And, to dispel concerns that it's just a gimmick, I'll explain exactly what I'm doing and (probably) why it works better.
I've got a main script and several rezzer "thread" scripts, all in the same prim (they don't need to be, but that's how I'm doing it), a hollow sphere. When a user pulls the trigger (or an automated weapon decides to open fire), llSetColor(<AUTO, timer, aim>) is called [llSetLinkColor also works, though llSetLinkPrimitiveParams and the fast variant don't, as they don't trigger a changed event], where AUTO is a predefined floating-point number identifying that it's a firing order, timer is the argument we want the thread to past to llSetTimerEvent to control the firing rate, and aim is either 1.0 or 0.0, signifying if I'm using the prim's other face to provide additional data about where to aim the bullets (which we can do without triggering a second changed event, if the llSetColor call for the other face is done immediately before or after the firing-order call). This has been significantly more responsive (in LSO, anyhow) than a linked message in all my tests, and can easily support rather egregious firing rates [~25 bullets per second with five threads - well under the goo fence limit, though probably more than you'd want] from many simultaneous users without affecting sim FPS. My team's theory, that led us to try this in the firs place, was that the link_message dispatch code on the sim side is slowed by argument passing and filtering in a way that the changed event is not. That we're only performing floating-point operations when using face color as an argument buffer seems to make the difference. Certainly, one could use the link_message integer parameter to do filtering, and I write all my APIs that way, but it appears the extra overhead of passing string and key arguments, even when not used, is enough to upset the sim when performed at high speed. As a side benefit, using the changed event keeps the rezzer threads from needing link_message handlers, reducing the number of scripts that need to filter out other communication happening in the linkset.
Hope that allays your concerns. If not, I'll be here all week. ~_^
--Michelle Resistance 23:06, 5 July 2010 (UTC)
- Well yes, you're simply shifting a portion of the load from the VM (which would handle the linked messages) to the Database and Simulator (which are handling the altering of the primitive's parameters and which then triggers the VM's changed() event). This does not make it particularly more efficient, as I mentioned before you still have a function call and an event triggered, you're merely routing it through another method, in this case the simulator, which has to then alert every client within draw/LOD distance as to the nature of the change. I am fully aware of what you are doing and how you are doing it, you are at least the third person in as many years who has mentioned it.
- Rather than a lecture on how to script guns, I'll simply say that if it works for you, then that's all that matters. There are efficient ways to use linked messages, and there are incredibly inefficient ways to use linked messages. Similarly, I am certain that people will find right ways and wrong ways to handle llRayCast() if it is ever implemented. Incorrect methods will undoubtedly spread through the grapevine with assurances that "this supersekrit way is teh best evar!!!11!!" Market forces have as of yet had minimal effect on poor scripting with regards to guns in SL, I wouldn't expect that to change at any time in the future. As you correctly note, many fashion designers still put resize scripts into every prim of hair.
- In some respects, I doubt that many amateur gun scriptors will be much different after raycasting than before. It may be less likely to be used by many amateur gun scripters simply because the default LL Damage system is built around physical collisions, and presumably that would remain the same. Also, combat systems that use raycasting would likely require at least a decent understanding LSL or else might use prewritten no-mod scripts to do the raycasting. To that extent, I do worry that raycasting may appear to be more efficient when it debuts on the grid, if only because of self-selection in terms of who is using it and how it is used. This is probably something that should be considered if llCastRay() is ever implemented, as it does have an effect on how to interpret any sort of metrics gathered when trying to determine its relative efficiency compared to bullet-based guns.
- In the end, it will be one more tool. I would hope that the devs at LL do not really think that this will completely replace physical projectiles, but it is nice to have the option. Similarly, I do hope that people understand that the relative efficiency of various guns on the grid varies wildly, and that the scriptor has a far greater impact on the relative efficiency of a gun than whether it uses physical bullets or llCastRay() when it is implemented.
Jahar Aabye 00:18, 6 July 2010 (UTC)
- Latelly i've been using llTarget and not_at_target to have stuff run as fast as the server allows without actually using somthing like while(true) --TigroSpottystripes Katsu 00:31, 6 July 2010 (UTC)
- In my tests, I've found that LSO loops seem to end up *slower* than repeating events like timers and not_at_target. 'Sweird. --Michelle Resistance 00:47, 6 July 2010 (UTC)
- Latelly i've been using llTarget and not_at_target to have stuff run as fast as the server allows without actually using somthing like while(true) --TigroSpottystripes Katsu 00:31, 6 July 2010 (UTC)
- You could use llRayCast to verify if the aiming hits anyone,and then rez a "bullet", posJump it to the target and make it phys to collide if you wanna use collisions to relay hits. --TigroSpottystripes Katsu 23:57, 5 July 2010 (UTC)
- Actually, that would probably be the worst of all worlds. You're still rezzing a bullet, still moving it to the target, still making it physical, still colliding it. All of the things that llCastRay() is attempting to prevent. Also, most combat systems that involve collisions limit (or should limit) the minimum velocity of a collision. To get around this, one would probably have to add a call to llApplyImpulse() or something similar. At the end of the day, you wind up with a situation not much better off than just firing a bullet.
- llCastRay() is probably best implemented in a combat system in a manner similar to current sensor-based combat systems, which have been around for years. I'm not sure that sensor-based (or raycasting-based) combat is any better or worse than physical bullet-based combat. Each has different tradeoffs, and at the end of the day it's going to come down to how these functions are worked into the system that gets set up. Whether using sensors, raycasting, or bullets, it's all about understanding the strengths and weaknesses of each system, and working with that in mind. Raycasting does have some significant strengths, but only if you take advantage of them. Raycasting, if done correctly, will probably take some load off the physics engine at the possible cost of runtime efficiency and memory. Physical bullet systems are simpler and may have an advantage in terms of runtime efficiency and memory use if done correctly, at the expense of offloading more of the work on the physics engine that has to deal with all of the active objects and the collisions generated.
Jahar Aabye 00:18, 6 July 2010 (UTC)
Ahoy folks!
I don't know enough about the issues in LSL to comment on most of the topics brought up in this thread. But with regard to the issues around the appearance of raycasts vs rezzed bullets, once you use llCastRay, you'll at least be able to set your bullets phantom. This prevents the physics engine from needing to check for collisions with anything but the land. Unfortunately, due to an old bug, collision checks against the ground are still very expensive. We expect to fix this by 1.44 at the latest. Once that's done, phantom bullets will be much more efficient.
- Phantom bullets would give us the problem of having to inform them somehow of a hit so they can [promptly] self-destruct instead of continuing to pass through things… unless you're suggesting the bullets themselves do llCastRay and short circuit the physics system. That sounds like a terrible hack, though. Shouldn't it be more efficient to let the physics engine do its thing, rather than going through the twisty little passages of LSL VMs? --Michelle Resistance 17:02, 6 July 2010 (UTC)
Regarding the matter of rezzing a bullet and then using the posjump trick (assuming that refers to the llSetPrimitiveParams hack where you repeatedly set the prim's position in a second call), that will actually be substantially less inefficient in 1.40 (when we finally get it right!). The reason is that in the past, each time you set the prim's position, the physics world would be updated, sometimes many many times in a frame. That is no longer the case (only the final position is actually used).
- "PosJump" actually refers to a different >10m movement hack than what you're talking about, which is known as "WarpPos". PosJump is very much preferable, as the LSL script doesn't have to waste time and memory calculating a series of intermediate steps… but it doesn't work with llSetLinkPrimitiveParamsFast, just the slow variety. --Michelle Resistance 17:02, 6 July 2010 (UTC)
- Last i tried it did work with llSetLinkPrimitiveParamsFast, did you test it yourself? --TigroSpottystripes Katsu 17:31, 6 July 2010 (UTC)
And yes, an LSL busy loop (e.g., while(TRUE)) is very, very inefficient. It uses as much of the sim's resources as available until it is cut off for the frame. Even the most inefficient event scheme would probably be better than a busy loop.
- I've found that even a bounded for loop is slower than a timer, in practice. Any idea why this might be? --Michelle Resistance 17:02, 6 July 2010 (UTC)
Falcon Linden 03:25, 6 July 2010 (UTC)
Possibility to limit list length?
I am concerned about the memory issues posed by this function. It was mentioned above, but not really fleshed out. In order to be useful for a combat perspective, you can't really set any of the flags (that is, it must return all agents and objects) so that you know whether there is a wall or some other barrier between yourself and the target. This means that you can get a potentially very long list with a UUID and vector position for each object hit. This could easily eat up several kb of script memory.
However, limiting the function to returning the first object hit (as has been mentioned as the possible final version) also removes some potentially interesting uses of this function. For example, you could have a situation where you get one result if it reaches an avatar unimpeded, another if there is a single object between you and the other av, and then no result if there is more than one object.
Would it be possible to compromise, and add another variable to input into the function to select the total number of objects to return? So you could have:
list llCastRay(vector start,vector end,integer filters,integer flags,integer num_returned)
Where num_returned would be the total number of objects hit, starting with the closest. It could be enumerated starting from 0 so as to match the values in the returned list, or from 1 if you would need to use 0 to set it to no limit.
As for this function making physical projectile combat obsolete, I do not believe that this will happen. I see this as akin to how sculpties have enhanced building: they give builders more options and allow for a greater variety of creative designs, but they have not obviated the use of regular prims. Similarly, I think that this feature may increase the options available when developing combat systems and weapons. However, I think that there are advantages to physical projectiles (such as the ability to code for ballistic trajectory). I have used sensor-based combat systems before (although this has many advantages over those as well), and I have found that those feel a bit too much like playing "laser tag" especially when used over longer distances.
I think that this will create more options for combat, it may allow for new types of combat, but there are always tradeoffs inherent in any system. Raycasting methods will have advantages and disadvantages, they will be more efficient in some ways and less in others. It will be nice to have this as a new option, but I worry about overselling this as a complete replacement. After all, the Mono VM was marketed as being the wave of the future that would make LSL-compiled scripts obsolete. While many scriptors knew to be cautious with a new VM, LL's overhyping of the system created a marketing environment where customers were asking if every product was Mono. This resulted in Mono being used in a vast number of situations where it was not only unnecessary but entirely inappropriate.
I worry about a similar situation unfolding here, where marketing llCastRay as a complete replacement for physical projectiles will encourage non-technical people to demand "those new ray guns LL keeps telling us about, why haven't you been making those?" Then these same people will inevitably come back a week later demanding why the RayCast "bullets" behave differently. All that I am asking is that you please acknowledge that non-technical people will read these announcements without understanding the technical nuance and the inherent tradeoffs. Overhyping something as a "complete replacement" when it is a new feature that allows for new options may only wind up creating new headaches. A new feature that opens new doors and allows for new options for creators is great, it is wonderful. No need to oversell a good thing.
Jahar Aabye 19:24, 5 July 2010 (UTC)
In the final version of llCastRay, if more than 1 hit can be returned I'll be sure to give you the ability to select some kind of limit (even if it's only a binary "first hit or all N hits" choice--where N is definitely a finite number determined by the specification).
Also, if using llCastRay feels too much like laser tag, try adding a small delay before the raycast executes or adding some randomness to the cast's direction. As for the ballistic trajectory, if that's really critical, there are ways to simulate it. For example, you could make 4 ray casts approximating the parabolic curve, but you'd have the possibility of performing an early-out if one of the first casts hits something.
Falcon Linden 03:33, 6 July 2010 (UTC)
Raycast Damage
Hey folks,
I've been trying to coalesce some of the most significant suggestions for llCastRay, and one theme that seems consistent is that weapon system makers need a way to be notified when hit by a ray. I'm thinking of two possible features:
1) For integration with LL damage, it might be possible to create another parameter that takes a list of parameters (albeit with a bit more strict requirements than in primparams args due to inefficiencies in list processing). In the future, this could include a version number, but in the meantime, one possible parameter could be RC_DAMAGE which would apply a requested amount of damage to the first object hit if that object is an avatar and if the region is damage enabled, etc.
2) An event, ray_impact, that the caster script could choose to trigger in impacted objects. This would, in principle, alleviate many of the security concerns around raycast-based weapons systems. In the interests of full disclosure, however, I should tell you that (a) I don't know how to create a new event (I'll have to speak to Kelly Linden) and therefore, (b), I don't know if implementing this feature would be prohibitive in terms of engineering time. But let's suppose I could implement this. What information would you want the receiving object to be able to obtain in this event? The fewer the better, so my first instinct would be no information (it's enough to know you were hit). Beyond that, knowing the exact location of the hit could be nice, as would knowing the UUID of the casting object (maybe?) and perhaps receiving bit of user data provided in the llCastRay call. Would that be helpful? How might you use it?
Cheers,
Falcon Linden 03:47, 6 July 2010 (UTC)
- #1 sounds excellent, though it's been notoriously difficult to get people to play fair with LL damage.
- A ray_impact event would be a godsend. The UUID of the casting object would be essential, and a hit location [and maybe hit normal] would be very useful. Ideally, an appropriate set of llDetected* functions should work inside the ray_impact event similarly to how they're used in a touch event. Might need a new one, like llDetectedRayNormal. Still, just an event with a signature like ray_impact(key id, vector pos, vector norm) would be massively useful. Let's see… I'd be using llCastRay for collision avoidance on robots, and ray_impact would make it easier for the robots to exhibit schooling behaviors. Similarly, such robots could interact with scripted objects in their environment (door controls, moveable boxes?) elegantly. Other uses… target ranges for raycast-based weapons… missile lock detection in fighter combat… assuming we could use it in attachments for impacts to the avatar, combat meters for raycast-based guns… AR-like user interfaces implemented by raycasts from a HUD [though the math for generating such rays may be rather complicated]… line-of-sight communication between objects and avatars… I'm sure there are more that I can't think of at the moment. Bottom line, adding functionality to LSL is a Very Good Thing. --Michelle Resistance 17:46, 6 July 2010 (UTC)
Falcon, I've been silent on this point because I don't agree with the naysayers; llCastRay is exactly what I've been needing for the combat system I'm building. For those that want to use Linden Damage, I think llTakeDamage() (perhaps accepting negative values to allow for healing) would be valuable, but beyond the scope of this project. I don't personally hold with the logic that it's marginally hard to write non-laggy chat communications, so we should expect people to write non-laggy bullets and guns. It'll require combat to be done differently, so it's not an evolutionary change, but I don't see that as a barrier.
That said, if it can be done, RC_DAMAGE would be a nice thing to have. I do build my weapons to fail down to Linden damage if no supported combat system is found, and if Linden damage is enabled. ray_impact would also be nice, especially if it's only explicitly triggered; UUID, impact point, and an arbitrary integer constant sent by the ray caster would be the values I'd see as most useful. Perhaps rather than go the whole list of parameters route for RC_DAMAGE, just add another integer parameter to llCastRay that would be used differently with different flags? In any event, not having either of these would in no way dampen my enthusiasm for this feature or impact my plans for using it, assuming it gets deployed. Jack Abraham 19:23, 6 July 2010 (UTC)
Get Alt-Zoom camera cursor position and surface orientation
Here is an example I made, how to get the camera cursor position when you Alt-Zoom on any object surface with the llCastRay function.
The script also calculates the surface orientation at the cursor position and rezes a prim on a top of surface. The Z-Axis of a rezed prim is aligned with the Normal vector of a surface at a given point and the X-Axis points in a way of your camera sight.
The calculation of surface orientation is made by casting 3 rays on a surface, very close together, to get two vectors (named U and V) on a surface. then the Normal vector is get by a vector product of these two vectors.
To test the script make a new HUD object and put the script below into it. Also put one standard cube prim (named Object) into its inventory. Attach the HUD and Alt-Zoom to any curved surface in region, but not more than 10m far from you. Then click on the HUD and a new prim will be rezed on a top of surface where the Alt-Zoom cursor of your camera points.
<lsl> // // Scriptname: Get Alt-Zoom position and Surface Orentation // Version: 1.0 // Date: 06.07.2010 // // Description: Gets the position of the camera cursor // when a user Alt-Zumes on a surface of any object and // rezes a prim on this point and orients it with a surface // // How To: - Create a new HUD (cube), size = X=0.05 y=0.05 Z=0.05 // - Put this script on it and attach it as a HUD // - Insert a standard prim (Cube 0.5m) into HUD inventory (named as Object) // - Alt-Zoom (not far than 64m from you) with your mouse to any object surface in the region // - Without moving your camera, click on this HUD // - You will get the camera cursor position and surface orentation // - An Object from HUD inventory will be rezed on a top of Alt-Zoomed surface // perfectly aligned with surface and with X-axis pointed to your line of sight // // Tips: To see the camera cursor, enable: Advanced->Character->Show Look At in your Advaned Menu // Rez a big sphere to make a curved surface in a region and Alt-Zoom on it. // // Notes: You must be at least 10m close to Alt-Zoom position (llRezObject() limitation) // There's no "clamping code" included to cut the rays to be inside of a region // // Additional: The script cast 3 rays to a prim surface very close to each other to make 2 different // short (not paralel) vectors U and V laying on the hit surfaces. The Normal vector on // the surfaces is calculated as a vector product of U and V. From these tree axes a rotation // of a prim (to be positioned on a top surface) is calculated. // // Creator: Teleworm Gelber //
default {
state_entry() { if (llGetAttached() > 0) { llRequestPermissions(llGetOwner(), PERMISSION_TRACK_CAMERA); } else { llOwnerSay("Attach me as a HUD"); } }
run_time_permissions(integer permissions) { llOwnerSay("Alt-Zoom on any curved surface in the region"); llOwnerSay("Then click me to get the Alt-Zoom cursor coordinates and an Object will be rezed there"); }
touch_start(integer total_number) { vector camPos; // camera position rotation camRot; // camera rotation
vector rayStart; // ray start vector vector rayEnd; // ray end vector
vector curPos; // Alt-Zoom cursor position rotation pointRot; // Point on a surface rotation (Z-axis = SurfaceNormal, X-axis = line of sight)
vector uVec; // U-vector on a hit surface vector vVec; // V-vector on a hit surface vector fwd; // surface point orentation forward vector ( vector left; // surface point orentation left vector vector up; // surface point orentation up vector (Normal vector)
list rayData; // ray cast return data
if ((llGetPermissions() & PERMISSION_TRACK_CAMERA) != 0) { // getting camera location camPos = llGetCameraPos(); camRot = llGetCameraRot();
// Cast a ray in a line of your sight (10.0 means llRezObject() limitation) rayStart = camPos; rayEnd = camPos + 10.0 * llRot2Fwd(camRot);
rayData = llCastRay(rayStart, rayEnd, 0, RC_GET_NORMAL);
if (llList2Integer(rayData, -1) > 0) // check status code { // get the Alt-Zoom cursor position curPos = llList2Vector(rayData, 1);
// make a new ray cast for the U-vector on the hit surface (delta X) rayEnd = rayStart + 10.0 * llVecNorm(curPos + <0.01, 0.0, 0.0> - rayStart); rayData = llCastRay(rayStart, rayEnd, 0, RC_GET_NORMAL);
if (llList2Integer(rayData, -1) <= 0) { llOwnerSay("Nothing hit, try again"); return; } uVec = llVecNorm(llList2Vector(rayData, 1) - curPos); // make a another ray cast for the V-vector on the hit surface (delta Y) rayEnd = rayStart + 10.0 * llVecNorm(curPos + <0.0, 0.01, 0.0> - rayStart); rayData = llCastRay(rayStart, rayEnd, 0, RC_GET_NORMAL); if (llList2Integer(rayData, -1) <= 0) { llOwnerSay("Nothing hit, try again"); return; } vVec = llVecNorm(llList2Vector(rayData, 1) - curPos);
// surface normal vector is vector product of UxV up = llVecNorm(uVec % vVec);
// forward vector points in a way you are looking left = llVecNorm(up % llRot2Fwd(camRot)); fwd = left % up; // calculate prim rotation to be put on a top of hit surface pointRot = llAxes2Rot(fwd, left, up);
llOwnerSay("Alt-Zoom Position: " + (string) curPos); llOwnerSay("Point Rotation: " + (string) pointRot);
// rez an Object on a top of hit surface, 0.25 means the prim center offset from surface (0.5m cube) llRezObject("Object", curPos + <0.0, 0.0, 0.25> * pointRot, ZERO_VECTOR, pointRot, 0); } else { llOwnerSay("Nothing hit, try again"); } } else { llOwnerSay("Attach me as a HUD first"); } } on_rez(integer par) { llResetScript(); }
}</lsl>
--Teleworm Gelber 23:08, 6 July 2010 (UTC)