Getting positions of a line renderer on moving and rotating a line - unity3d

I have a line with line renderer attached to it . The user can move the line and rotate it. How do I go about getting the new positions of the line renderer which has been moved or rotated? since the coordinates of vertices of line renderer do not change , only the positions and the rotation of the line object as a whole changes .
The positions in the bottom part of image do not change on moving or rotating it. These positions are returned by the getpositions() method which is not useful in my case.

The LineRenderer in unity takes a list of points (stored as Vector3s) and draws a line through them. It does this in one of two ways.
Local Space: (Default) All points are positioned relative to
transform. So if your GameObject moves or rotates, the line would
also move and rotate.
World Space: (You would need to check the Use World Space
Checkbox) The line will be rendered in a fixed position in the
world that exactly matched the Positions in the list. If the
gameObject moves or rotates, the line would be unchanged
So what you really want to know is
"How do I get the world space position of a local space point in my line?"
This common use case is addressed by methods on a gameObjects transform
Transform.TransformPoint
It takes a local space point (which is how the data is stored in the line renderer by default) and transforms it to world space.
An Example:
using UnityEngine;
using System.Collections;
public class LineRendererToWorldSpace : MonoBehaviour
{
private LineRenderer lr;
void Start()
{
lr = GetComponent<LineRenderer>();
// Set some positions in the line renderer which are interpreted as local space
// These are what you would see in the inspector in Unity's UI
Vector3[] positions = new Vector3[3];
positions[0] = new Vector3(-2.0f, -2.0f, 0.0f);
positions[1] = new Vector3(0.0f, 2.0f, 0.0f);
positions[2] = new Vector3(2.0f, -2.0f, 0.0f);
lr.positionCount = positions.Length;
lr.SetPositions(positions);
}
Vector3[] GetLinePointsInWorldSpace()
{
Vector3[] positions;
//Get the positions which are shown in the inspector
var numberOfPositions = lr.GetPositions(positions);
//Iterate through all points, and transform them to world space
for(var i = 0; i < numberOfPositions; i += 1)
{
positions[i] = transform.TransformPoint(positions[i]);
}
//the points returned are in world space
return positions;
}
}
This code is just for demonstration purposes, as I am not exactly sure of the use case.
Also, my links are to 2018.2 which is a very recent version of unity, however the logic and methods used should be quite similar going back.

Related

How to create Reflecting linerenderer with raycast?

In Unity I have created cube and player. The player has LineRenderer component.The line hits the cube and stops. This is following code in player.
_lineRenderer.SetPosition(0,transform.position);
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit))
{
if (hit.collider)
{
_lineRenderer.SetPosition(1,hit.point);
/* if(hit.collider){
Vector3 pos = Vector3.Reflect (hit.point - transform.position, hit.normal);
_lineRenderer.SetPosition(2,pos);
//lineRenderer.SetPosition(3, pos);
}*/
}
}
This works fine. But how can I reflect the line after hitting cube. As you can see in my code's comment I tried to reflect with Vector3.Reflect.But it did not work.If I run it shows me an error likeLineRenderer.SetPosition index out of bounds How can I reflect line like in this image
Per comments, your initial problem is not setting the correct number of points for the LineRenderer to use:
if (hit.collider)
{
_lineRenderer.positionCount = 3;
_lineRenderer.SetPosition(1,hit.point);
// etc
}
else
_lineRenderer.positionCount = 2; // No bounced ray
Also, Reflect returns a direction vector, but you're trying to use it as a position:
_lineRenderer.SetPosition(2,pos);
You need to apply the direction to an existing starting point. Do this:
_lineRenderer.SetPosition(2, hit.point + pos);
The error tells you that your LineRenderer does not provide enough space for setting a third point.
Unity's LineRenderer.SetPosition(...) does not manage the number of actually available points in a LineRenderer for you. You have to configure this manually before setting the points.
If you want a LineRenderer built from 3 points (player, reflection point, end of reflected ray) just use:
_lineRenderer.positionCount = 3; // tells the renderer it consists of 3 points
_lineRenderer.SetPosition(0, yourFirstPosition);
_lineRenderer.SetPosition(1, yourSecondPosition);
_lineRenderer.SetPosition(2, yourThirdPosition);

Snapping UI sprite in Unity?

IMAGE
Is there any way to snap UI sprite vertex? Holding "V" does not work in this case.
Checking Unity's Documentation is good start when you run into an issue. I checked the documentation, which can be found here: Modifying Sprite Vertices via Script.
Reading the documentation you can grab a Sprites Vertices using a Vector2 Array.
//Fetch the Sprite and vertices from the SpriteRenderer
Sprite sprite = m_SpriteRenderer.sprite;
Vector2[] spriteVertices = sprite.vertices;
You can draw using the vertices by following this and viewing them in scene view
// Show the sprite triangles
void DrawDebug()
{
Sprite sprite = m_SpriteRenderer.sprite;
ushort[] triangles = sprite.triangles;
Vector2[] vertices = sprite.vertices;
int a, b, c;
// draw the triangles using grabbed vertices
for (int i = 0; i < triangles.Length; i = i + 3)
{
a = triangles[i];
b = triangles[i + 1];
c = triangles[i + 2];
//To see these you must view the game in the Scene tab while in Play mode
Debug.DrawLine(vertices[a], vertices[b], Color.red, 100.0f);
Debug.DrawLine(vertices[b], vertices[c], Color.red, 100.0f);
Debug.DrawLine(vertices[c], vertices[a], Color.red, 100.0f);
}
}
Snapping the vertices together through the use of scripting, however, does seem overly complicated depending on what these are for. Given this, it would be useful to know why you want to do this? If these sprites are static and unmoving or only used for a short period it may be much easier to manually align them in the Scene view.
Another method could be to use ProGrid, which is a Unity Package that allows you to turn on snapping in your scene and is very useful for aligning gameobjects; this also allows the amount of snapping to be changed.
Find it by going to Window -> Package Manager. Note that you may need to turn on preview packages to find it.

Unity C#: Line renderer from Gameobject (3D) to Canvas (Screen Space - Camera) [duplicate]

I have an image UI in a canvas with Screen Space - Camera render mode. What I like to do is move my LineRenderer to the image vertical position by looping through all the LineRenderer positions and changing its y axis. My problem is I cant get the correct position of the image that the LineRenderer can understand. I've tried using ViewportToWorldPoint and ScreenToWorldPoint but its not the same position.
Vector3 val = Camera.main.ViewportToWorldPoint(new Vector3(image.transform.position.x, image.transform.position.y, Camera.main.nearClipPlane));
for (int i = 0; i < newListOfPoints.Count; i++)
{
line.SetPosition(i, new Vector3(newListOfPoints[i].x, val.y, newListOfPoints[i].z));
}
Screenshot result using Vector3 val = Camera.main.ScreenToWorldPoint(new Vector3(image.transform.localPosition.x, image.transform.localPosition.y, -10));
The green LineRenderer is the result of changing the y position. It should be at the bottom of the square image.
Wow, this was annoying and complicated.
Here's the code I ended up with. The code in your question is the bottom half of the Update() function. The only thing I changed is what was passed into the ScreenToWorldPoint() method. That value is calculated in the upper half of the Update() function.
The RectTransformToScreenSpace() function was adapted from this Unity Answer post1 about getting the screen space coordinates of a RectTransform (which is exactly what we want in order to convert from screen space coordinates back into world space!) The only difference is that I was getting inverse Y values, so I changed from Screen.height - transform.position.y to just transform.position.y which did the trick perfectly.
After that it was just a matter of grabbing that rectangle's lower left corner, making it a Vector3 instead of a Vector2, and passing it back into ScreenToWorldPoint(). The only trick there was because of the perspective camera, I needed to know how far away the line was from the camera originally in order to maintain that same distance (otherwise the line moves up and down the screen faster than the image). For an orthographic camera, this value can be anything.
void Update () {
//the new bits:
float dist = (Camera.main.transform.position - newListOfPoints[0]).magnitude;
Rect r = RectTransformToScreenSpace((RectTransform)image.transform);
Vector3 v3 = new Vector3(r.xMin, r.yMin, dist);
//more or less original code:
Vector3 val = Camera.main.ScreenToWorldPoint(v3);
for(int i = 0; i < newListOfPoints.Count; i++) {
line.SetPosition(i, new Vector3(newListOfPoints[i].x, val.y, newListOfPoints[i].z));
}
}
//helper function:
public static Rect RectTransformToScreenSpace(RectTransform transform) {
Vector2 size = Vector2.Scale(transform.rect.size, transform.lossyScale);
Rect rect = new Rect(transform.position.x, transform.position.y, size.x, size.y);
rect.x -= (transform.pivot.x * size.x);
rect.y -= ((1.0f - transform.pivot.y) * size.y);
return rect;
}
1And finding that post from a generalized search on "how do I get the screen coordinates of a UI object" was not easy. A bunch of other posts came up and had some code, but none of it did what I wanted (including converting screen space coordinates back into world space coordinates of the UI object which was stupid easy and not reversibe, thanks RectTransformUtility!)

Best way to use Farseer/Box2D's DebugDraw in Unity3D?

Box2D/Farseer 2D physics has a useful component which draws a simple representation of the physics world using primitives (lines, polygons, fills, colors). Here's an example:
What's the best way to accomplish this in Unity3D? Is there a simple way to render polygons with fill, lines, points, etc.? If so, I could implement the interface of DebugDraw with Unity's API, but I'm having trouble finding how to implement primitive rendering like this with Unity.
I understand it'll be in 3D space, but I'll just zero-out one axis and use it basically as 2D.
In case you mean actually a debug box just displayed in the SceneView not in the GameView you can use Gizmos.DrawWireCube
void OnDrawGizmos()
{
//store original gizmo color
var color = Gizmos.color;
// store original matrix
var matrix = Gizmos.matrix;
// set gizmo to local space
Gizmos.matrix = transform.localToWorldMatrix;
// Draw a yellow cube at the transform position
Gizmos.color = Color.yellow;
// here set the scale e.g. for a "almost" 2d box simply use a very small z value
Gizmos.DrawWireCube(transform.position, new Vector3(0.5f, 0.2f, 0.001f));
// restor matrix
Gizmos.matrix = matrix;
// restore color
Gizmos.color = color;
}
you can use OnDrawGizmosSelected to show the Gizmo only if the GameObject is selected
you could also extend this by getting the box size over the inspector
[SerializeField] private Vector3 _boxScale;
and using
Gizmos.DrawWireCube(transform.position, _boxScale);

How to calculate number of sprites to spawn across the device's screen height?

In my Unity2D project, I am trying to spawn my sprite on top of each other and across the entire height of the device's screen. For example to give an idea, think of a box on top of each other across the entire device's screen height. In my case, I'm spawning arrow sprites instead of boxes
I already got the sprites spawning on top of each other successfully. My problem now is how to calculate how many sprites to spawn to make sure it spreads across the screen's height.
I currently have this snippet of code:
public void SpawnInitialArrows()
{
// get the size of our sprite first
Vector3 arrowSizeInWorld = dummyArrow.GetComponent<Renderer>().bounds.size;
// get screen.height in world coords
float screenHeightInWorld = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0)).y;
// get the bottom edge of the screen in world coords
Vector3 bottomEdgeInWorld = Camera.main.ScreenToWorldPoint(new Vector3(0,0,0));
// calculate how many arrows to spawn based on screen.height/arrow.size.y
int numberOfArrowsToSpawn = (int)screenHeightInWorld / (int)arrowSizeInWorld.y;
// create a vector3 to store the position of the previous arrow
Vector3 lastArrowPos = Vector3.zero;
for(int i = 0; i < numberOfArrowsToSpawn; ++i)
{
GameObject newArrow = this.SpawnArrow();
// if this is the first arrow in the list, spawn at the bottom of the screen
if(LevelManager.current.arrowList.Count == 0)
{
// we only handle the y position because we're stacking them on top of each other!
newArrow.transform.position = new Vector3(newArrow.transform.position.x,
bottomEdgeInWorld.y + arrowSizeInWorld.y/2,
newArrow.transform.position.z);
}
else
{
// else, spawn on top of the previous arrow
newArrow.transform.position = new Vector3(newArrow.transform.position.x,
lastArrowPos.y + arrowSizeInWorld.y,
newArrow.transform.position.z);
}
// save the position of this arrow so that we know where to spawn the next arrow!
lastArrowPos = new Vector3(newArrow.transform.position.x,
newArrow.transform.position.y,
newArrow.transform.position.z);
LevelManager.current.arrowList.Add(newArrow);
}
}
The problem with my current code is that it doesn't spawn the correct number of sprites to cover the entire height of the device's screen. It only spawns my arrow sprites approximately up to the middle of the screen. What I want is for it to be able to spawn up to the top edge of the screen.
Anyone know where the calculation went wrong? and how to make the current code cleaner?
If sprites are rendered via camera mode in perspective and the sprites appear to have varying sizes when displayed on the screen (sprites farther away from the camera are smaller than sprites that are closer to the camera) then a new way to calculate the numberOfArrowsToSpawn value is needed.
You could try adding sprites with a while loop, instead of using a for loop, just continue creating sprites until the calculated world position for the sprite will no longer be visible to the camera. Check to see if a point will be visible in camera by using the technique Jessy provides in this link:
http://forum.unity3d.com/threads/point-in-camera-view.72523/
I think your screenHeightInWorld is really a screenTopInWorld, a point can be anywhere in the space.
You need the relative screen height in world coordinate.
Which is actially the half of the camera frustum size if you use ortographic projection, as you think of it.
float screenHeightInWorld = Camera.main.orthographicSize / 2.0f;
I did not read the rest, but is probably fine, up to you how you implement this.
I'd simply create an arrow method, something like bool SpawnArrowAboveIfFits(), which can call itself iteratively on the new instances.