How to display a text on Line in Unity? - unity3d

I have created small iOS Unity app that draws a line between 2 points. I am getting the distance as well showing in a TextMeshPro. Now I want to render this text on the line except showing it on somewhere else on the screen. This is how I draw the line and shows the distance.
GameObject start = points[0];
GameObject end = points[1];
measureLine.SetPosition(0, start.transform.position);
measureLine.SetPosition(1, end.transform.position);
var measurement = Vector3.Distance(start.transform.position, end.transform.position) * measurementFactor;
distanceText.transform.position = end.transform.position + offsetMeasurement;
var hasHit = Physics.Raycast(ray,out hit, float.PositiveInfinity,layersToInclude);
distanceText.transform.rotation = Quaternion.FromToRotation(Vector3.up, hit.normal);
distanceText.text = $"Distance: {measurement.ToString("F2")}cm";
But I want to render this distanceText on the line just like in the below picture.
In my case it just shows at the end point which also perpendicular to the line. How can I do that? Please help me. Thank you very much.
UPDATE
My current result is like this

Related

how to move a line Shape object

Using EaselJS 1.0 I want to move a line. I can get this to work setting the x and y by incrementing and decrementing, but not by setting x and y directly to numbers. IOW - line.x++; works, but line.x = 300; does not work. The code editor here seems cranky, so in case I fail inserting code see two versions running online here:
http://www.clarksoncs.com/Gettysburg/testMovingLineAlt.html
http://www.clarksoncs.com/Gettysburg/testMovingLine.html
In the init function:
createjs.Ticker.addEventListener("tick", stage);
createjs.Ticker.addEventListener("tick", handleTick);
stage = new createjs.Stage("canvasOne");
line.graphics.setStrokeStyle(3);
line.graphics.beginStroke(color);
line.graphics.moveTo(300, 400);
line.graphics.lineTo(startX, startY);
line.graphics.endStroke();
stage.addChild(line);
stage.update();
in the tick event:
//Run these two lines: Expected = line moves right and up. Actual = line moves right and up AND GETS LONGER.
line.x++;
line.y--;
/*
Run these two lines: Expected = line appears centered at 600,600. Actual = line is not visible. Check debugger, x and y are set to 600.
line.x = 600;
line.y = 600;
*/
stage.update();
I think the problem here might be that you are confusing the graphics coordinates with the line's position.
The line you are making is at [0,0]. Its registration point has not moved. You are then drawing the line from the internal coordinates of [300,400] to wherever your startX and startY are. The line position doesn't change because of the internal graphics coordinates.
My guess is that when you set the line to x=600, it is not visible because your graphics are now off-stage. The line position will be 600, but the line graphics start at 300 on top of that.
Here is a quick fiddle
https://jsfiddle.net/b01tsw42/1/
var line = new createjs.Shape();
line.graphics.setStrokeStyle(3);
line.graphics.beginStroke("#ff0000");
line.graphics.moveTo(0, 0);
line.graphics.lineTo(300, 400);
line.graphics.endStroke();
stage.addChild(line);
stage.x = 300; // sets the graphic container to x=300
I hope that helps!
Thanks! I think the easiest way to move a line shape is probably to put the line in a bitmap, and move the bitmap.

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

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.

Orientations Offset

I am using the MVN-Unity plug-in to access Xsens motion capture data and animate a Unity character in real-time. The character in white and green and yellow is a Unity skeleton that is animated based on Xsens motion data.
I am now trying to animate a different (non-Unity) character using Xsens (the other character that looks like a human) so similar to what the plug-in does, the motion data (positions & orientations) are being mapped to his joints/bones.
But as you can see below, something is wrong with orientations...
I think the reason might be that the rotations from MVN are not properly offset. As you can see in the next two pictures, the MVN hips have the x-axis (red) pointing to the puppet's backside, whereas for the guy's hips, the x-axis points to the right of him.
It might also be that the plug-in is using global rotations somewhere where it should use local rotations. That this must be the case can be demonstrated when I rotate the guy around before I start the Unity app; i.e. select the guy's root game object and try setting the y-rotation to 0/90/180/270 before pressing play, and compare the results: every time the distortions are different.
I don't know how to properly fix this. The code snippet that updates the Unity model (mapped to the MVN puppet or the guy) is as follows. I took this from the plug-in scripts:
private void updateModel(Transform[] pose, Transform[] model)
{
// Re-set the target, then set it up based on the segments.
Vector3 pelvisPos = new Vector3();
Vector3 lastPos = target.position;
target.position = Vector3.zero;
// Map only 23 joints.
for (int i = 0; i < 23; i++)
{
switch (i)
{
// Position only on y axis, and leave x and z to the body. Apply the 'global' position & orientation to the pelvis.
case (int)XsAnimationSegment.Pelvis:
pelvisPos = pose[i].position * scale;
model[i].position = new Vector3( model[i].position.x, pelvisPos.y, model[i].position.z );
model[i].rotation = pose[i].rotation * modelRotTP[i];
break;
// Update only the 'orientation' for the rest of the segments.
default:
if ( model[i] != null )
{
model[i].rotation = pose[i].rotation * modelRotTP[i];
}
break;
}
}
// Apply root motion if the flag is enabled; i.e. true.
if (applyRootMotion)
{
// Only update x and z, since pelvis is already modified by y previously.
target.position = new Vector3(pelvisPos.x + pelvisPosTP.x, lastPos.y, pelvisPos.z + pelvisPosTP.z);
}
// Set the final rotation of the full body, but only position it to face similar as the pelvis.
Quaternion q = Quaternion.Inverse(modelRotTP[(int)XsAnimationSegment.Pelvis]) * model[(int)XsAnimationSegment.Pelvis].rotation;
target.rotation = new Quaternion(target.rotation.x, q.y, target.rotation.z, target.rotation.w);
}
I sort of understand what the code does, but I don't know how to fix this problem. Most probably to do with the axes being different? I would appreciate any help...
You can modify XsLiveAnimator.cs script in the line: 496
with that
model[segmentOrder[i]].transform.rotation = orientations[segmentOrder[i]];
model[segmentOrder[i]].transform.Rotate(rotOffset, Space.World);
rotOffset is a Vector3 of your rotation

Vectrosity: Make a dashed line appear to rotate with the same speed across resolutions

I am using Vectrosity to draw some shapes and I have come across a problem I'm unable to solve. This is not an issue with Vectrosity, but rather a hole in my knowledge. I hope someone here can help me get this right! :)
The red bar in the image is moving around the circle using a script that in short looks like this:
// Make the red bar move around the dashed circle
float dist = 0;
void Update()
{
if (dist > 1)
dist = dist - 1;
dist += Time.deltaTime * (Mathf.Abs(speed) / 8);
Vector3 point = line.GetPoint3D01(dist);
redbar.localPosition = pos;
}
So far so good - this works exactly like I want it to.
The issue I am having is with the dashed line itself. I need it to move with the same speed as the red bar. I can make it work by setting a fixed value for the speed for a given resolution, but as soon as the screen resolution changes, the dashed line no longer move with the same speed as the red bar.
I have tried to figure out a formula that sets the textureOffset dynamically - without any success. The dashed line is "moved" by changing the textureOffset like this:
// Make dashed line appear to rotate
void Update()
{
dashedline.textureOffset = -Time.time * (speed * 4.8f) % 1f;
}
How can I make the dashed line appear to rotate with the exact same speed as the red bar across all screen resolutions?
Thank you!

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.