- Home /
Shorten Raycast - Line Renderer
Hello,
I'm trying to shorten a line renderer, and I can't for the life of me figure it out! I'm sure it's an easy solution.
Basically, I have two line renderers, one coming from the player (which is a ball), if the player is facing another ball, the first line renderer is drawn between the player, and the other ball. A second line renderer is then draw from the other ball to wherever the balls force will go if I were to hit it... Pretty much like an aiming system you see in pool/billiard games.
All I want to do is shorten the second line renderer. Below is the code I'm using to calculate the second line direction:
var ballRadius = 0.49;
var contactPointSize = 0.1;
var rayLength : float = 30;
var direction = player.transform.TransformDirection(-Vector3.forward);
var hit : RaycastHit;
Physics.Raycast(transform.position, direction, hit, rayLength);
var newDirection = new Vector3();
newDirection = Vector3(hit.normal.x, hit.normal.y, hit.normal.z);
newDirection *= -1;
var hitPos = hit.collider.transform.position;
lineDirection.SetPosition(0, hit.collider.transform.position);
var deflection = Vector3((newDirection.x * rayLength), hitPos.y, (newDirection.z * rayLength));
var newDeflec = (hitPos + deflection) / 2;
lineDirection.SetPosition(1, deflection);
So lineDirection is the second line renderer, I want to always have its length at 5. I tried playing around with the maths, by adding hitPos and deflection, and then dividing by 2. That works fine - I get the middle of the raycast, but then when I try dividing it further, the coordinates go all messed up.
Also, I cant decrease the size the in 'rayLength' as then my Physics.Raycast wont shoot very far.
Any advice? Thanks.
PS, this is pretty much a repeat of a question I asked months ago, but never solved it: http://answers.unity3d.com/questions/485577/linerenderer-setting-max-distance.html
Isn't it the example in the docs? I've only had a glance but it seems like you need to lay down multiple sections of unit length line to the size you want.
Unfortunately the info within the docs isnt what I am looking for, it doesn't show me how to shorten the line - my problem is more of a mathematical issue I guess, rather than the functionality behind the line renderer itself. Thanks anyway
I'm not so sure. The docs set line length by simply adding in more vertex points, I believe. Otherwise the 'sine wave curve' would be some spirograph mess :)
I'm assu$$anonymous$$g the LineRenderer simply draw from a point to the next assigned vertex. If you want to make it shorter, assign a new vertex.
Of course, I could be wrong... I've never used the LineRenderer, I'm just looking at the example.
Will it only have two points? If that is the case, isn´t it enough to normalize like this
deflection = 5*deflection.normalized;
Or did I misunderstood your question?
@$$anonymous$$rVerdoux that won't work, since the direction is changed there(it may not seem like it but it does).
deflection is a displacement from hitpos(well its a reflection but its based of hitpos), if you were to to do a distance check you will find it is 5 meters from zero not hitpos. he needs this
deflection = (deflection -hitPos).normalized * 5 + hitPos;
I went over this in my edited answer, basically this code removes the displacement, normalizes, then displaces it again in order to maintain its direction. with out the displacement being taken to account, the direction will rotate to zero giving weird results.
in other words when you look at a Vector , your look direction is the difference between you and the vector you are trying to look at, makes sense? but the code you use assumes a zero displacement, so if your position was zero and only zero, your code will work(since the difference between an object an zero is always that object).
Answer by Fornoreason1000 · Dec 07, 2013 at 12:40 PM
here is a thought, you can use the "slope" (well in unity it easier to use an angle) of the line between those two to get a direction. then rotate Vector3.fwd*5 by that direction. Its basically aligning a shorter vector between the ball and hit target point.
Get the Y-angle between the two points.
Convert it to a Quaternion(man i hate these things)
Multiply the product of Quaternion and the balls fwd vector by 5.
use it in the Line Direction code.
so we can use
PSEUDO code
a = Vector3.Angle(ballPos, hitpos)
and q = Quetrion.Euler (0,a,0);
lineDirection = q*ballpos.fwd*5;
this way the line direction will always have an "length" of 5.
citation : http://quiz.uprm.edu/visual3d/manual/coor_sys/slope_line.html
http://en.wikipedia.org/wiki/Quaternion (again, I still hate these things)
Update: I overlooked some details, ported and tested you code and got it working
var ballRadius = 0.49;
var contactPointSize = 0.1;
var rayLength : float = 30;
var direction = player.transform.TransformDirection(-Vector3.forward);
var hit : RaycastHit;
Physics.Raycast(transform.position, direction, hit, rayLength);
var newDirection = new Vector3();
newDirection = Vector3(hit.normal.x, hit.normal.y, hit.normal.z);
newDirection *= -1;
var hitPos = hit.collider.transform.position;
lineDirection.SetPosition(0, hit.collider.transform.position);
var deflection = Vector3((newDirection.x * rayLength), hitPos.y, (newDirection.z * rayLength));
deflection = (deflection -hitPos).normalized * 5 + hitPos;
var newDeflec = (hitPos + deflection) / 2; //probably don't need this.
lineDirection.SetPosition(1, deflection);
I have no idea why the other versions of this code messed up for you. division screws up because it transforms based on zero as i said earlier in the comments below(when you wanted to transform it based on hitpos). when calculating the length of deflection(magnitude), remember to subtract hitpos or you will get the distance between deflection and zero instead. also on Quaternion's still hate them.
Isnt this over complicating things? I only want to cap the max line renderer. Right now, the line goes on for a distance of 30. I want to change it to 5, but if I do that, it messes up the coordinates (unless I reduce the raycast length from 30, to 5 too - but then the raycast is restricted to 5, which I don't want)
wait what really? you could normalize it then multiply it by 5. based on that its simple vector math. http://docs.unity3d.com/Documentation/ScriptReference/Vector3-normalized.html
using a piece of paper, i did this.
first subtract ball pos from hitpos, this will give us the direction between the two.
normalize that and multiply by 5,
add the ball vector so it return to normal. the result is your line renderer capped vector.
Hint: do this after you raycast
Okay, this sounds good - let me have a play with my code, and I'll get back to you
Wait, where are you getting ball pos from? Remember, I want to cast this line from my Second ball, which is the 'hitPos', and direct it in 'newDirection * rayLength'.
The second line cast doesn't have an end position, it's just getting the first line cast, and reflecting it really.
Answer by KellyThomas · Dec 07, 2013 at 03:22 PM
Here we use the RayCastHit.point
if applicable, or the point maxRayLength
in that direction if no hit occurs.
This technique should allow you to find the right endpoint for your second LineRenderer
.
var direction: Vector3; //value should be derived from previous collision
var lineStart: Vector3; //value should be derived from previous collision
var maxRayLength: float = 5;
var lineEnd: Vector3;
var hit:RaycastHit;
if(Physics.Raycast(lineStart, direction, hit, maxRayLength)) {
lineEnd = hit.point;
}
else {
//assumes direction is of length 1, change to direction.normalized if required.
lineEnd = lineStart + (direction * maxRayLength);
}
//the following for illustrative purposes only:
var lr:LineRenderer = gameObject.GetComponent(LineRenderer);
lr.useWorldSpace = true;
lr.SetPosition(0,lineStart);
lr.SetPosition(1,lineEnd);
Debug.DrawRay(lineStart, lineEnd - lineStart, Color.red, 1.0f);
Update:
Here is a more complete implementation. The results illustrated can be achieved by placing this script on a GameObject, and then assigning some with LineRenderers to lr1 and lr2.
var lr2:LineRenderer;
var lr1:LineRenderer;
var direction:Vector3 = new Vector3(1,1,0);
var rayLength : float = 30;
var guideLength:float = 5;
function Update () {
var initialPosition: Vector3 = transform.position;
var impactPoint: Vector3;
var guideEndPoint: Vector3;
var hit:RaycastHit;
if (!Physics.Raycast(initialPosition, direction, hit, rayLength)) {
// handle a miss
Debug.DrawRay(initialPosition, direction.normalized * rayLength, Color.blue, 1.0f, true);
lr1.enabled = false;
lr2.enabled = false;
return;
}
impactPoint = hit.point;
guideEndPoint = impactPoint + ( -hit.normal * guideLength );
//draw rays for IDE
Debug.DrawRay(initialPosition, impactPoint - initialPosition, Color.green, 1.0f, true);
Debug.DrawRay(impactPoint, guideEndPoint - impactPoint, Color.red, 1.0f, true);
//draw lineRenderers for GameScreen
lr1.enabled = true;
lr2.enabled = true;
lr1.SetPosition(0, initialPosition);
lr1.SetPosition(1, impactPoint);
lr2.SetPosition(0, impactPoint);
lr2.SetPosition(1, guideEndPoint);
}
This isnt capping the max length of my line renderer, only the raycast - I dont want to restrict the raycast itself, just the line renderer of a maximum of 5
lineEnd = lineStart + (direction * lineLength);
will find your endpoint if:
lineStart is the starting point
direction is a unit vector defining direction
lineLength is the length you want the line to have.
Once you have the start and end points just plug them into the LineRenderer.
I already have the location of my line end: 'newDirection * rayLength' - I just want to cap it at a certain length - none of these answers are working and I'm getting really confused by the whole situation here :/
Where are you getting capLength from? If I change the rayLength in 'newDirection * rayLength' from something different from the raycast length (which is 30 right now), it goes all messed up, plus the line still changed length... I want it to always be a length of 5.
Answer by Draitch · Dec 07, 2013 at 04:46 PM
If you want to draw a line of fixed length from a known starting position and following some fixed direction then you can compute the two end points like this:
// Code snippet
var separation : Vector3 = transform.position - player.transform.position;
var tangent : Vector3 = Vector3.Normalize(separation) * lineLength;
var start : Vector3 = transform.position;
var end : Vector3 = start + tangent;
To give you a little more of a hint, I've created a Unity scene and some script code that shows just how to do this. Take a look here for details: the computation of the line you care about is all in the "TargetBall" script/