How to CastRay() for Unity.Physics.SphereCollider struct without SphereCollider.Create() factory method call - unity3d

How to CastRay() for Unity.Physics.SphereCollider struct without SphereCollider.Create() factory method call (resulting in heap allocation I presume).
Code below doesn't work and not sure why exactly:
using Physics = Unity.Physics;
bool TraceRaySphere
(
float3 spherePos ,
float sphereRadius ,
float3 rayStart ,
float3 rayEnd ,
out Physics.RaycastHit raycastHit
)
{
var ray = new Physics.RaycastInput{
Start = rayStart ,
End = rayEnd ,
Filter = Physics.CollisionFilter.Default
};
var geometry = new Physics.SphereGeometry{
Center = spherePos ,
Radius = sphereRadius
};
var sphere = new Physics.SphereCollider{
Geometry = geometry ,
Filter = Physics.CollisionFilter.Default
};
return sphere.CastRay( ray , out raycastHit );
}
This works, but uses mentioned SphereCollider.Create(geometry) factory method I want to get rid of (if that's possible):
public static bool TraceRaySphere
(
float3 spherePos ,
float sphereRadius ,
float3 rayStart ,
float3 rayEnd ,
out RaycastHit raycastHit
)
{
var ray = new RaycastInput{
Start = rayStart ,
End = rayEnd ,
Filter = CollisionFilter.Default
};
var geometry = new SphereGeometry{
Center = spherePos ,
Radius = sphereRadius
};
var sphereBlobAsset = SphereCollider.Create( geometry );
bool didHit = sphereBlobAsset.Value.CastRay( ray , out raycastHit );
sphereBlobAsset.Dispose();
return didHit;
}

In my project i use following helper method to cast any Colliders (needs unsafe code execution flag because its working with the pointer)
public static unsafe bool ColliderCast(float3 rayFrom, float3 rayTo, quaternion rotation, CollisionWorld collisionWorld, PhysicsCollider collider)
{
ColliderCastInput input = new ColliderCastInput()
{
Collider = (Collider*)collider.Value.GetUnsafePtr(),
Orientation = rotation,
Start = rayFrom,
End = rayTo
};
return collisionWorld.CastCollider(input);
}
And i also have a CollisionGeome
trySingleton class which contains this
//Cache geometries (float3 = size, float3 = center)
private IDictionary<Tuple<float3, float3>, BoxGeometry> boxGeometries;
public BoxGeometry CreateOrGetBoxGeometry(float3 size, float3 center)
{
if(this.boxGeometries == null)
{
this.boxGeometries = new Dictionary<Tuple<float3,float3>, BoxGeometry>();
}
Tuple<float3, float3> key = new Tuple<float3, float3>(size, center);
if(!this.boxGeometries.ContainsKey(key))
{
this.boxGeometries.Add(key, new BoxGeometry { Size = key.Item1, Center = key.Item2, Orientation = quaternion.identity });
}
return this.boxGeometries[key];
}
This allows me to use
BoxCollider.Create
(
CollisionGeomeotrySingleton.Instance.CreateOrGetBoxGeometry(5, 5),
CollisionFilterSingleton.Instance.CollidesWithPlayerFilter
)
You could go now one step further and store the BoxCollider also in the CollisionGeometrySingleton

SphereCollider struct contains few hidden private fields that requires Init(args) method to be called in order to set those up with proper values:
public static bool TraceRaySphere
(
float3 spherePos ,
float sphereRadius ,
float3 rayStart ,
float3 rayEnd ,
out RaycastHit raycastHit
)
{
var ray = new RaycastInput
{
Start = rayStart ,
End = rayEnd ,
Filter = CollisionFilter.Default
};
var geometry = new SphereGeometry
{
Center = spherePos ,
Radius = sphereRadius
};
var sphere = default(SphereCollider);
sphere.Init( geometry , CollisionFilter.Default , Material.Default );
return sphere.CastRay( ray , out raycastHit );
}
However
this method is private (chances are this may change).
To make Init method available you need to modify ...\com.unity.physics#0.5.0-preview.1\Unity.Physics\Collision\Colliders\Physics_SphereCollider.cs source file and make it public.

Related

Mesh is getting black on change

I have written a small code, which is mooving vertices down on mouse click. The problem is in that mesh on change is getting black (only in some places).
Here's the code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MinerScript : MonoBehaviour
{
public MeshFilter filter;
public MeshCollider col;
public GameObject Player;
public float mineSpeed = 200;
Mesh mesh;
Vector3[] vertices;
void Update()
{
filter = transform.parent.GetComponent<PlayerGravity>().mesh;
mesh = filter.GetComponent<MeshFilter>().sharedMesh;
vertices = mesh.vertices;
Ray ray = new Ray(transform.position, transform.forward * 2);
if (Physics.Raycast(ray))
{
if (Input.GetMouseButton(1))
{
int index = Mathf.RoundToInt(ClosestIndexToPoint(ray));
vertices[index] += (-Player.transform.eulerAngles) * Time.deltaTime * mineSpeed;
mesh.vertices = vertices;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
Color[] colors = new Color[mesh.vertices.Length];
colors[index] = Color.red;
mesh.SetColors(colors);
//col.sharedMesh = mesh;
}
}
}
public float ClosestIndexToPoint(Ray ray)
{
if (Physics.Raycast(ray, out RaycastHit hit))
{
Mesh m = hit.transform.GetComponent<MeshFilter>().sharedMesh;
col = hit.transform.GetComponent<MeshCollider>();
int[] tri = new int[3] {
m.triangles[hit.triangleIndex * 3 + 0],
m.triangles[hit.triangleIndex * 3 + 1],
m.triangles[hit.triangleIndex * 3 + 2],
};
float closestDistance = Vector3.Distance(m.vertices[tri[0]], hit.point);
int closestVertexIndex = tri[0];
for (int i = 0; i < tri.Length; i++)
{
float dist = Vector3.Distance(m.vertices[tri[i]], hit.point);
if (dist < closestDistance)
{
closestDistance = dist;
closestVertexIndex = tri[i];
}
}
return closestVertexIndex;
}
else
return -1;
}
I don't think the problem is in color, as i've tried to apply the teture on it.
About code:
It throws a ray, and if it hits any mesh, it is calling func "ClosestIndexToPoint". It returns value of type float. This function gets the triangle a ray hits, and then finds the closest vertecs to it. Then it just mooves it down (or the rotation of our Player object, cause a have a non - flat mesh).

How to get width difference between the canvas and a scaled image and do an efficient PingPong effect in Unity3D

I am trying to get the width difference between the canvas and a image which is scaled by CanvasScaler in order to create translation between the image and his border.
Illustration:
How get the size of the red arrow?
[EDIT 1]
The code snippet bellow give me a possible correct result
var dist = (canvasRectTransform.rect.width - image.sprite.rect.width) / 2;
But It seems to be incorrect:
public class Background : Monobehaviour
{
private float dist;
private float _percentage;
private float _currentLerpTime;`
private readonly Dictionary<LerpDirection, Func<Vector3>> _lerpDirectionActions;
public float lerpTime;
void Awake()
{
var image = GetComponent<Image>();
var canvasRectTransform = GetComponentInParent<RectTransform>();
dist = (canvasRectTransform.rect.width - image.sprite.rect.width) / 2;
_lerpDirectionActions = new Dictionary<LerpDirection, Func<Vector3>>
{
[LerpDirection.Left] = LerpToLeft,
[LerpDirection.Right] = LerpToRight
};
}
private Vector3 Lerp()
{
return Vector3.Lerp(
transform.position,
_lerpDirectionActions[lerpDirection].Invoke(), // will call LerpToRight or LerpToLeft
_percentage
);
}
private float LerpX => Lerp().x;
private Vector3 LerpToRight()
{
return new Vector3(transform.position.x - dist, transform.position.y);
}
private Vector3 LerpToLeft()
{
return new Vector3(transform.position.x + dist , transform.position.y);
}
void Update()
{
_currentLerpTime += Time.deltaTime;
_percentage = _currentLerpTime / lerpTime;
var localPositionX = tranform.position.x;
var mustGoRight = localPositionX <= 0 && lerpDirection == LerpDirection.Right;
var mustGoLeft = localPositionX >= dist && lerpDirection == LerpDirection.Left;
if (mustGoLeft || mustGoRight)
{
direction = direction.Invert(); // invert direction
Reset();
}
tranform.position = new Vector3(LerpX, tranform.position.y)
}
}
The Background script is applied to the Background GameObject.
_lerpDirectionActions[lerpDirection].Invoke()
This code above will invoke the right function for lerping on left or on right.
Illustration:
The translation change his direction but not when the canvas is on the border on the image.
The value you are searching for would be
var difference = (canvas.GetComponent<RectTransform>().rect.width - image.GetComponent<RectTransform>().rect.width) / 2f;
Your script looks quite complicated to be honest.
Why not simply put it all into one single Coroutine using Mathf.PingPong which does exactly what you are currently controlling with your direction flags and actions
PingPongs the value t, so that it is never larger than length and never smaller than 0.
The returned value will move back and forth between 0 and length.
public Canvas canvas;
public Image image;
// Time in seconds to finish the movement from one extreme to the other
public float duration = 1;
private void Start()
{
StartCoroutine (LerpForthAndBack());
}
private IEnumerator LerpForthAndBack()
{
var difference = (canvas.GetComponent<RectTransform>().rect.width - image.GetComponent<RectTransform>().rect.width) / 2f;
var maxPosition = Vector3.right * difference;
var minPosition = Vector3.left * difference;
// Hugh? :O
// -> This is actually totally fine in a Coroutine
// as long as you yield somewhere within it
while(true)
{
image.transform.position = Vector3.Lerp(minPosition, maxPosition, Mathf.PingPong(Time.time / duration, 1));
// "Pause" the routine, render the frame and
// and continue from here in the next frame
yield return null;
}
}
ofcourse you could also do the same still in Update
private Vector3 minPosition;
private Vector3 maxPosition;
private void Start()
{
var difference = (canvas.GetComponent<RectTransform>().rect.width - image.GetComponent<RectTransform>().rect.width) / 2f;
maxPosition = Vector3.right * difference;
minPosition = Vector3.left * difference;
}
private void Update()
{
image.transform.position = Vector3.Lerp(minPosition, maxPosition, Mathf.PingPong(Time.time / duration, 1));
}

Unity - How to set the color of an individual face when clicking a mesh?

Yesterday others on Stack Overflow helped me determine how to recolor a mesh triangle to red by clicking on it, it works great, the only problem is that the 3 vertices that get recolored are shared between triangles. This results in coloration that looks rather smeared. I'm really hoping there's a way to color only a single face (or normal if you will).
I've attached the following script to my mesh that uses a raycast to determine the surface coordinate and translate a green cube there. The gif below will better illustrate this problem.
Once again, any help or insight into this would be greatly appreciated. Thanks!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyRayDraw : MonoBehaviour
{
public GameObject cube;
private MeshRenderer meshRenderer;
Mesh mesh;
Vector3[] vertices;
Color[] colorArray;
private void Start()
{
mesh = transform.GetComponent<MeshFilter>().mesh;
vertices = mesh.vertices;
colorArray = new Color[vertices.Length];
for (int k = 0; k < vertices.Length; k++)
{
colorArray[k] = Color.white;
}
mesh.colors = colorArray;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit))
{
Snap(hit.point); // Moves the green cube
int[] triangles = mesh.triangles;
var vertIndex1 = triangles[hit.triangleIndex * 3 + 0];
var vertIndex2 = triangles[hit.triangleIndex * 3 + 1];
var vertIndex3 = triangles[hit.triangleIndex * 3 + 2];
colorArray[vertIndex1] = Color.red;
colorArray[vertIndex2] = Color.red;
colorArray[vertIndex3] = Color.red;
mesh.colors = colorArray;
}
else
{
Debug.Log("no hit");
}
}
}
}
As you say the issue is that the vertices are shared between triangles but coloring is always vertex based.
The idea for a solution is:
for each vertex of the hit triangle check if it is used by other triangles
if so copy its position to create a new separated vertex
update the triangle to use the newly created vertex indices
(evtl.) use RecalculateNormals to make the triangles face outside without having to care about the order of provided vertices
using System.Linq;
using UnityEngine;
public class MyRayDraw : MonoBehaviour
{
public GameObject cube;
// Better to reference those already in the Inspector
[SerializeField] private MeshFilter meshFilter;
[SerializeField] private MeshRenderer meshRenderer;
[SerializeField] private MeshCollider meshCollider;
private Mesh _mesh;
private void Awake()
{
if (!meshFilter) meshFilter = GetComponent<MeshFilter>();
if (!meshRenderer) meshRenderer = GetComponent<MeshRenderer>();
if (!meshCollider) meshCollider = GetComponent<MeshCollider>();
_mesh = meshFilter.mesh;
// create new colors array where the colors will be created
var colors = new Color[_mesh.vertices.Length];
for (var k = 0; k < colors.Length; k++)
{
colors[k] = Color.white;
}
_mesh.colors = colors;
}
private void Update()
{
if (!Input.GetMouseButtonDown(0)) return;
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out var hit))
{
Debug.Log(hit.triangleIndex);
//cube.transform.position = hit.point;
// Get current vertices, triangles and colors
var vertices = _mesh.vertices;
var triangles = _mesh.triangles;
var colors = _mesh.colors;
// Get the vert indices for this triangle
var vert1Index = triangles[hit.triangleIndex * 3 + 0];
var vert2Index = triangles[hit.triangleIndex * 3 + 1];
var vert3Index = triangles[hit.triangleIndex * 3 + 2];
// Get the positions for the vertices
var vert1Pos = vertices[vert1Index];
var vert2Pos = vertices[vert2Index];
var vert3Pos = vertices[vert3Index];
// Now for all three vertices we first check if any other triangle if using it
// by simply count how often the indices are used in the triangles list
var vert1Occurrences = 0;
var vert2Occurrences = 0;
var vert3Occurrences = 0;
foreach (var index in triangles)
{
if (index == vert1Index) vert1Occurrences++;
else if (index == vert2Index) vert2Occurrences++;
else if (index == vert3Index) vert3Occurrences++;
}
// Create copied Lists so we can dynamically add entries
var newVertices = vertices.ToList();
var newColors = colors.ToList();
// Now if a vertex is shared we need to add a new individual vertex
// and also an according entry for the color array
// and update the vertex index
// otherwise we will simply use the vertex we already have
if (vert1Occurrences > 1)
{
newVertices.Add(vert1Pos);
newColors.Add(new Color());
vert1Index = newVertices.Count - 1;
}
if (vert2Occurrences > 1)
{
newVertices.Add(vert2Pos);
newColors.Add(new Color());
vert2Index = newVertices.Count - 1;
}
if (vert3Occurrences > 1)
{
newVertices.Add(vert3Pos);
newColors.Add(new Color());
vert3Index = newVertices.Count - 1;
}
// Update the indices of the hit triangle to use the (eventually) new
// vertices instead
triangles[hit.triangleIndex * 3 + 0] = vert1Index;
triangles[hit.triangleIndex * 3 + 1] = vert2Index;
triangles[hit.triangleIndex * 3 + 2] = vert3Index;
// color these vertices
newColors[vert1Index] = Color.red;
newColors[vert2Index] = Color.red;
newColors[vert3Index] = Color.red;
// write everything back
_mesh.vertices = newVertices.ToArray();
_mesh.triangles = triangles;
_mesh.colors = newColors.ToArray();
_mesh.RecalculateNormals();
}
else
{
Debug.Log("no hit");
}
}
}
Note, however, that this works with simple coloring but might not for complex textures with UV mapping. You would have to also update the mesh.uv if using UV mapped textures.

How to draw a line over a specific duration using Vectrosity [duplicate]

I created a diagonal line renderer by attaching the following script to an empty game object. How can I extend the line at both ends for a half its length and how can I also extend the line by say 1 unit along the x-axis? Both over a certain period of time.
public class DiagonalLine : MonoBehaviour {
bool firstLineComplete = false;
LineRenderer diagLine;
public Vector3 startPoint = new Vector3 (0, 0, 0);
public Vector3 endPoint = new Vector3 (1.0f, 1.0f, 0);
public float lineDrawSpeed;
// Use this for initialization
void Start () {
diagLine = gameObject.AddComponent<LineRenderer>();
diagLine.material = new Material (Shader.Find ("Sprites/Default"));
diagLine.startColor = diagLine.endColor = Color.green;
diagLine.startWidth = diagLine.endWidth = 0.15f;
diagLine.SetPosition (0, startPoint);
diagLine.SetPosition (1, endPoint);
}
}
This is basic vector math.
You have the line with (from end to start):
Vector3 v = start - end;
and then you extend on each side by half if it:
extensionA = start + (v * 0.5f);
extensionB = end + (v * -0.5f);
If you need to extend by 1 then normalize:
Vector3 v = (start - end).normalized;
extensionA = start + v;
extensionB = end + (v * -1f);
Break your problem into pieces:
1.Extend line by x units on both sides:
This is done with the Ray class. Create a new Ray instance from the startPoint and endPoint variables then use the Ray.GetPoint function to extend the line. You have to do this on both sides to get the new extended lines.
A simple wrapper for the Ray class to simplify this:
Vector3 extendLine(Vector3 startPoint, Vector3 endPoint, ExtendDirection extendDirection, float extendDistance)
{
Ray ray = new Ray();
//Start
if (extendDirection == ExtendDirection.START_POINT)
{
ray.origin = startPoint;
ray.direction = startPoint - endPoint;
}
//End
else if (extendDirection == ExtendDirection.END_POINT)
{
ray.origin = endPoint;
ray.direction = endPoint - startPoint;
}
//Extend
Vector3 newUnityPoint = ray.GetPoint(extendDistance);
//Debug.DrawLine(ray.origin, newUnityPoint, Color.blue);
return newUnityPoint;
}
public enum ExtendDirection
{
START_POINT, END_POINT
}
Extend to the Left end
Vector3 newStartPos = extendLine(startPoint, endPoint, ExtendDirection.START_POINT, 4);
diagLine.SetPosition(0, newStartPos);
Extend to the Right end
Vector3 newEndPos = extendLine(startPoint, endPoint, ExtendDirection.END_POINT, 4);
diagLine.SetPosition(1, newEndPos);
2.For animating/moving it over time, use coroutine and Time.deltaTime. Increment a variable with Time.deltaTime every frame to then use Vector3.Lerp to lerp the from and to value.
See this function for example.
With both combined, below is a complete function to extend both lines over time:
bool isRunning = false;
IEnumerator extentLineOverTime(LineRenderer targetLineRenderer, float extendDistance, float duration)
{
//Calculate Left from extension length
Vector3 fromValLeftPos = targetLineRenderer.GetPosition(0);
//Calculate Right from extension length
Vector3 fromValRightPos = targetLineRenderer.GetPosition(1);
//Calculate Left to extension length
Vector3 newLeftPos = extendLine(fromValLeftPos, fromValRightPos, ExtendDirection.START_POINT, extendDistance);
//Calculate Right to extension length
Vector3 newRightPos = extendLine(fromValLeftPos, fromValRightPos, ExtendDirection.END_POINT, extendDistance);
//Make sure there is only one instance of this function running
if (isRunning)
{
yield break; ///exit if this is still running
}
isRunning = true;
float counter = 0;
while (counter < duration)
{
counter += Time.deltaTime;
//Move to left overtime
Vector3 tempLeftPos = Vector3.Lerp(fromValLeftPos, newLeftPos, counter / duration);
targetLineRenderer.SetPosition(0, tempLeftPos);
//Move to Right overtime
Vector3 tempRightPos = Vector3.Lerp(fromValRightPos, newRightPos, counter / duration);
targetLineRenderer.SetPosition(1, tempRightPos);
yield return null;
}
isRunning = false;
}
USAGE:
LineRenderer diagLine;
public Vector3 startPoint = new Vector3(0, 0, 0);
public Vector3 endPoint = new Vector3(1.0f, 1.0f, 0);
// Use this for initialization
void Start()
{
diagLine = gameObject.AddComponent<LineRenderer>();
diagLine.material = new Material(Shader.Find("Sprites/Default"));
diagLine.startColor = diagLine.endColor = Color.green;
diagLine.startWidth = diagLine.endWidth = 0.15f;
diagLine.SetPosition(0, startPoint);
diagLine.SetPosition(1, endPoint);
//Extend Line Over time
StartCoroutine(extentLineOverTime(diagLine, 4, 3));
}
The StartCoroutine(extentLineOverTime(diagLine, 4, 3)); will extend the line 4 units away from both sides within 3 seconds.

Unity game engine having camera follow script transform change depending on car selected script?

OVERALL GOAL: Have the camera change target to the selected car
I'm new to the unity game engine and got a bit of a problem.
So, I have a successful car selector which changes between cars and starts the match with that car. Everything there works. The only issue is that my "CarCameraScript" has a transform variable which is always 1 of the 3 cars. I want it to change dependant on the selected car.
Here is the look at the code of the CarCameraScript
#pragma strict
var car : Transform;
var distance: float = 6.4;
var height: float = 1.4;
var rotationDamping : float = 3.0;
var heightDamping: float = 2.0;
var zoomRatio : float = 0.5;
var DefaultFOV : float = 60;
private var rotationVector : Vector3;
function Start () {
}
function LateUpdate () {
var wantedAngel = rotationVector.y;
var wantedHeight = car.position.y + height;
var myAngel = transform.eulerAngles.y;
var myHeight = transform.position.y;
myAngel = Mathf.LerpAngle(myAngel,wantedAngel,rotationDamping*Time.deltaTime);
myHeight = Mathf.Lerp(myHeight,wantedHeight,heightDamping*Time.deltaTime);
var currentRotation = Quaternion.Euler(0,myAngel,0);
transform.position = car.position;
transform.position -= currentRotation*Vector3.forward*distance;
transform.position.y = myHeight;
transform.LookAt(car);
}
function FixedUpdate () {
var localVilocity = car.InverseTransformDirection(car.rigidbody.velocity);
if (localVilocity.z<-0.5) {
rotationVector.y = car.eulerAngles.y + 180;
} else {
rotationVector.y = car.eulerAngles.y;
}
var acc = car.rigidbody.velocity.magnitude;
camera.fieldOfView = DefaultFOV + acc*zoomRatio;
}
This is what it looks like on the side panel.
http://i.stack.imgur.com/lYJP7.jpg
The area that says none (transform) is the place that should be variable dependant on the currently selected car.
Now, Here is my other script being the CharacterSelectScript
#pragma strict
//this is the currently selected Player. Also the one that will be saved to PlayerPrefs
var selectedPlayer : int = 0;
function Update()
{
if (Input.GetMouseButtonUp (0)) {
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
var hit : RaycastHit;
if (Physics.Raycast (ray, hit, 100))
{
// The pink text is where you would put the name of the object you want to click on (has attached collider).
if(hit.collider.name == "Player1")
SelectedCharacter1(); //Sends this click down to a function called "SelectedCharacter1(). Which is where all of our stuff happens.
if(hit.collider.name == "Player2")
SelectedCharacter2();
if(hit.collider.name == "Player3")
SelectedCharacter3();
}
else
{
return;
}
}
}
function SelectedCharacter1() {
Debug.Log ("Character 1 SELECTED"); //Print out in the Unity console which character was selected.
selectedPlayer = 1;
PlayerPrefs.SetInt("selectedPlayer", (selectedPlayer));
}
function SelectedCharacter2() {
Debug.Log ("Character 2 SELECTED");
selectedPlayer = 2;
PlayerPrefs.SetInt("selectedPlayer", (selectedPlayer));
}
function SelectedCharacter3() {
Debug.Log ("Character 3 SELECTED");
selectedPlayer = 3;
PlayerPrefs.SetInt("selectedPlayer", (selectedPlayer));
}
How would I get it so that the SelectedPlayer changes the transform in the first script?
Any ideas?
I also have the prefab script which probably isnt important.
Also, should I join both scripts into one?
OVERALL GOAL: Have the camera change target to the selected car