In unity, how do you find voxel information at a given worldspace position? - unity3d

I am trying to have a gameobject in unity react with sound if another object is inside it. I want the gameobject to use the entering objects location to then see what voxel is closest and then play audio based on the voxel intensity/colour. Does anyone have any ideas? I am working with a dataset that is 512x256x512 voxels. I want it to work if the object is resized as well. Any help is much appreciated :).
The dataset I'm working with is a 3d .mhd medical scan of a body. Here is how the texture is added to the renderer on start:
for (int k = 0; k < NumberOfFrames; k++) {
string fname_ = "T" + k.ToString("D2");
Color[] colors = LoadData(Path.Combine (imageDir, fname_+".raw"));
_volumeBuffer.Add (new Texture3D (dim [0], dim [1], dim [2], TextureFormat.RGBAHalf, mipmap));
_volumeBuffer[k].SetPixels(colors);
_volumeBuffer [k].Apply ();
}
GetComponent<Renderer>().material.SetTexture("_Data", _volumeBuffer[0]);
The size of the object is defined by using the mdh header files spacing as well as voxel dimensions:
transform.localScale = new Vector3(mhdheader.spacing[0] * volScale, mhdheader.spacing[1] * volScale * dim[1] / dim[0], mhdheader.spacing[2] * volScale * dim[2] / dim[0]);
I have tried making my own function to get the index from the world by offsetting it to the beginning of the render mesh (not sure if this is right). Then, scaling it by the local scale. Then, multiplying by the amount of voxels in each dimension. However, I am not sure if my logic is right whatsoever... Here is the code I tried:
public Vector3Int GetIndexFromWorld(Vector3 worldPos)
{
Vector3 startOfTex = gameObject.GetComponent<Renderer>().bounds.min;
Vector3 localPos = transform.InverseTransformPoint(worldPos);
Vector3 localScale = gameObject.transform.localScale;
Vector3 OffsetPos = localPos - startOfTex;
Vector3 VoxelPosFloat = new Vector3(OffsetPos[0] / localScale[0], OffsetPos[1] / localScale[1], OffsetPos[2] / localScale[2]);
VoxelPosFloat = Vector3.Scale(VoxelPosFloat, new Vector3(voxelDims[0], voxelDims[1], voxelDims[2]));
Vector3Int voxelPos = Vector3Int.FloorToInt(VoxelPosFloat);
return voxelPos;
}

You can try setting up a large amount of box colliders and the OnTriggerEnter() function running on each. But a much better solution is to sort your array of voxels and then use simple math to clamp the moving objects position vector to ints and do some maths to map the vector to an index in the array. For example the vector (0,0,0) could map to voxels[0]. Then just fetch that voxels properties as you like. For a voxel application this would be a much needed faster calculation than colliders.

I figured it out I think. If anyone sees any flaw in my coding, please let me know :).
public Vector3Int GetIndexFromWorld(Vector3 worldPos)
{
Vector3 deltaBounds = rend.bounds.max - rend.bounds.min;
Vector3 OffsetPos = worldPos - rend.bounds.min;
Vector3 normPos = new Vector3(OffsetPos[0] / deltaBounds[0], OffsetPos[1] / deltaBounds[1], OffsetPos[2] / deltaBounds[2]);
Vector3 voxelPositions = new Vector3(normPos[0] * voxelDims[0], normPos[1] * voxelDims[1], normPos[2] * voxelDims[2]);
Vector3Int voxelPos = Vector3Int.FloorToInt(voxelPositions);
return voxelPos;
}

Related

How get the quaterion with rotation in x,y,z that faces gameobect to ther gameobject in unity c#

I have a Steerings system that have an align steering that aligns one object to other object.
That woks well.
So when I start to programming the face behaivour to face gameobject to other object using the Aling steering.
I want a steering that one object1 faces to other object2 contnuously that if object2 moves or stay in place the object1 rotate to face object1 this in all rotation axies.
The problem is:
I need to get the quaternion rotated in direction of vector in 3D space. That vector is the diference between position of two gameobjects in Unity.
The Face script is:
Vector3 directionToTarget = target.transform.position - ownKS.position;
//Debug.Log(directionToTarget+"ssssss");
SURROGATE_TARGET.transform.rotation =Quaternion.Euler(Utils3D.VectorToOrientation(directionToTarget));
// Align with surrogate target
return Align3D.GetSteering (ownKS, SURROGATE_TARGET, targetAngularRadius,
slowDownAngularRadius, timeToDesiredAngularSpeed);
I tried to do with Quaterion.Euler(vector.normalized). not working.
vector = vector.normalized;
// Debug.Log(vector.normalized+"v normaliyes");
Quaternion v = Quaternion.Euler(vector);
Debug.Log(v.eulerAngles);
return v;
I tried that :
where m is the vector of diference position between two objects.
The funtion VectorToOrientation(vector3 m) is:
m = m.normalized;
Debug.Log(m);
Vector3 axis = Vector3.Cross(m, new Vector3(1,1,1));
axis.Normalize();
double anglex = Math.Acos(Vector3.Dot(m, new Vector3(1,0,0)) / m.magnitude / new Vector3(1,0,0).magnitude);
double angley = Math.Acos(Vector3.Dot(m, new Vector3(0,1,0)) / m.magnitude / new Vector3(0,1,0).magnitude);
double anglez = Math.Acos(Vector3.Dot(m, new Vector3(0,0,1)) / m.magnitude / new Vector3(0,0,1).magnitude);
Debug.Log(anglex*180/Mathf.PI + "x "+angley*180/Mathf.PI+"y z"+anglez*180/Mathf.PI);
```
I don't konw if you undestand the problem?
If you have questions?? You can ask me.
If anyone can help me??
Thanks

Unity3d: how to apply a vortex like force to objects?

I would like to simulate a vortex like force to a "bunch" of objects in my scene.
How can I do in Unity ?
Thanks
If you are using the physics system, there's two parts to this. Applying the vortex force, and getting the nice swirling effect. To apply the vortex force you can just loop over the rigidbodies and apply the force. To make the swirl look like a proper vortex swirl, you need to start the objects off with a tangential velocity that you can figure out using the vector cross product.
public float VortexStrength = 1000f;
public float SwirlStrength = 5f;
void Start () {
foreach(GameObject g in RigidBodies){
//to get them nice and swirly, use the perpendicular to the direction to the vortex
Vector3 direction = Vortex.transform.position - g.transform.position;
var tangent = Vector3.Cross(direction, Vector3.up).normalized * SwirlStrength;
g.GetComponent<Rigidbody>().velocity = tangent;
}
}
void Update(){
//apply the vortex force
foreach(GameObject g in RigidBodies){
//force them toward the center
Vector3 direction = Vortex.transform.position - g.transform.position;
g.GetComponent<Rigidbody>().AddForce(direction.normalized * Time.deltaTime * VortexStrength);
}
}
Circular motion:
float angle =0;
float speed=(2*Mathf.PI)/5 //2*PI in degress is 360, so you get 5 seconds to complete a circle
float radius=5;
void Update()
{
angle += speed*Time.deltaTime; //if you want to switch direction, use -= instead of +=
x = Mathf.Cos(angle)*radius;
y = Mathf.Sin(angle)*radius;
}
where the center of your circle is the center of your vortex.
Of course:
If you want multiple objects with diferent distance from vortex's
center you have to play with your radius variable (i would add a
Random.Range(minDistance, maxDistance))
If you want diferent speeds you can randomize/change the speed.
Randomize/change your x/y if you don't want a perfect circle
Hope i was clear enought.

Unity3D - Calculating t-value position on orbit

I'm using a script that i found online that uses a kdTree to calculate the nearest point to an object on the surface of a mesh.
I have the following code in the OnDrawGizmos method that allows me to draw a circle that will orbit the surface of the object.
x = target.transform.position.x + ((Mathf.Cos(tValue)) * (radius));
z = target.transform.position.z + ((Mathf.Sin(tValue)) * (radius));
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(new Vector3(x, y, z), 0.06f);
On the the object i am orbiting the "tValue" ranges from 0 to 6.3 to do a full orbit. My problem is that i am trying to calculate the tValue in the range 0-6.3 of an object that is near the central object. I have used my kdTree system to calculate the vector3 position on the surface of the object and it lines up perfectly.
I calculate the radius used in both the above and below equation with:
Vector3 RadiusDirection = (Vector3.ProjectOnPlane(orbitingSurfaceMeshPos, planet.transform.up) - Vector3.ProjectOnPlane(planet.transform.position, planet.transform.up));
float radius = RadiusDirection.magnitude;
However, when i try to calculate the t-value, i get a completely different value. I figured i could just "reverse" the "equation" and so i've been doing:
float temp = orbiting.z - planet.transform.position.z;
temp = temp / radius;
calculatedTvalue = (Mathf.Asin(temp));
What could i be doing wrong? I have tested my "reversing equation" in an empty scene and new script and it worked fine, if i just took the result of the orbit position calculation and directly reversed it. However, it doesn't work in my game.

How to limit where a sprite can move in Unity?

I am fairly new to Unity so please bear with me I have tried looking for the answer everywhere, but have had no luck.
Basically I am using onMouseDrag to move a sprite around the background for a classroom (1366x768) that has a table. However, I want to limit where the sprite can go so that it does not end up off screen or off of the table on my background.
My sprite has the 2d box collider and rigidbody components attached (gravity is set to zero and it is at a fixed angle). I thought that by placing four 2d box colliders around the area I want to keep the sprite in it would be enough to contain it but the sprite simply goes straight through them.
I also read up about using Mathf.Clamp to restrict the area but I do not really understand how to use it from the examples I have seen.
Below is my code for moving the sprite:
using UnityEngine;
using System.Collections;
public class MovementScript : MonoBehaviour {
float x;
float y;
void Update() {
x = Input.mousePosition.x;
y = Input.mousePosition.y;
}
public void OnMouseDrag() {
transform.position = Camera.main.ScreenToWorldPoint (new Vector3 (x, y, 1.0f));
}
}
Any help would be greatly appreciated!
Moving an object using its transform is not the same as moving it.
When you use the transform, the object doesn't "move", it teleports every Update by a small amount. Unfortunately, the Rigidbody can't detect this change in position as movement and thus does not react with any colliders. Regardless, that's probably the more complicated way to do this. Using Clamp is definitely easier.
Clamp is a pretty straightforward function. it takes three args: a value, a min, and a max. If the value is less than min or greater than max, it returns that boundary. Otherwise, it returns the value itself.
For instance,
Mathf.Clamp(5, 1, 3); //returns 3
Mathf.Clamp(2, 1, 3); //returns 2
Mathf.Clamp(-2, 1, 3); //returns 1
This is simply a convenience function for something like this:
if(val > max) {
return max;
} else if(val < min) {
return min;
} else {
return val;
}
So using Clamp, you can restrict the values of your x and y coordinates:
//to avoid confusion, I'm referring to your x and y variables
//as inputX and inputY. they represent the mouse position.
public void OnMouseDrag() {
Vector3 pos = Vector3.zero;
pos.x = Mathf.Clamp(inputX, minX, maxX);
pos.y = Mathf.Clamp(inputY, minY, maxY);
pos.z = 1.0;
transform.position = Camera.main.ScreenToWorldPoint (pos);
}
Mathf.Clamp will keep the X and Y coordinates of your Transform within the range (minX, maxX) and (minY, maxY) respectively. You can create these variables as inspector variables so you can change them on the fly.

Instantiate gameobject between 2 objects in unity 3d

I have 2 objects. It will be in various direction and distance.
How can i instantiate objects between them with a specific distance.
var centerLocation : Vector3 = Vector3.Lerp(object2.transform.position - object1.transform.position, 0.5);
Vector3.Lerp will determine the Vector3 location between 2 Vector3s at a specified percentage. 0.5 = 50%.
My suggestion would be to calculate the vector between the two objects, like this
Vector3 objectLine = (object2.transform.position - object1.transform.position);
Store the magnitude of that vector
float distance = objectLine.magnitude;
Then, normalise the vector;
objectLine = objectLine.normalized;
Iterate through the line, instanciating the object you want to create a specific distances
Vector3 creationPoint = object1.transform.position;
float creationPointDistance = (object1.transform.position -
object1.transform.position);
while(creationPointDistance < distance)
{
creationPoint += objectLine * NEW_OBJECT_DISTANCE;
creationPointDistance = (object1.transform.position -
object1.transform.position);
if(creationPointDistance < distance)
{
objects.Add((GameObject)Instanciate(newObject, creationPoint,
new Vector3(0.0f,0.0f,0.0f)));
}
}
What that will do is set the initial point to be object1's position. It will then move a set distance along the vector between object 1 and object 2, check it's within the two objects, and if it is, instanciate the object, storing it in a list of gameobjects.
That hopefully should do it. I don't have Unity (or any IDE) in front of me to check the syntax.