Unity3D Raycasting with Oculus Rift Integration / Measuring the distance - unity3d

I want to measure the distance between two points in Unity3D Game Engine using the Oculus Rift. The points are targeted by the user by looking at point A, pressing alpha1 on the keyboard and B, pressing alpha2 on the keyboard. I got this far:
#pragma strict
private var measuring = false;
private var startPoint : Vector3;
private var dist;
function Update() {
var hit : RaycastHit;
if (Input.GetKeyDown(KeyCode.Alpha1)) {
dist = 0.0f;
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), hit)) {
// if (Physics.Raycast(transform.position, transform.forward, hit, 10)) {
measuring = true;
startPoint = hit.point;
}
}
if (measuring && Input.GetKeyDown(KeyCode.Alpha2)) {
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), hit)) {
// if (Physics.Raycast(transform.position, transform.forward, hit, 10)) {
dist = Vector3.Distance(startPoint, hit.point);
}
}
}
function OnGUI() {
if (measuring) {
GUI.Label(Rect(50,50,180,50), "Distance: " + dist.ToString());
}
}
My problem is, that this code only works with the standard main camera object, but I want to use the Oculus integrated OVRCameraRig. I get the following exception message:
NullReferenceException: Object reference not set to an instance of an object
MeasureInGame.Update () (at Assets/MeasureInGame.js:11)
I found a solution on this site: https://kaharri.com/unity-gaming-shootingaiming-part3-oculus/ I created a ShotSpawner object as a child of OVRCameraRig (this should act like a gun in front of the camera) and changed the Raycast to
Physics.Raycast(transform.position, transform.forward, hit, 10)
to get the users view. But it also doesn't seem to work.
How can I get the aiming done with the Oculus a Main Camera. And is it correct that I strictly need to have a collider on my objects to be measured or is there a solution without collider?
Greetings

First of all - are you really using the mouse with Oculus? Of course you can, but the standard way is to look at the selected object (cursor is in the center of viewport). Cast the ray from the "middle" eye in the oculus integration - it's the object that is the parent to the left and right eyes. Use this ray instead of the one from Camera.main.ScreenPointToRay:
// add a reference to the middleEyeGameobject
// in your class and link it in the inspector
var ray=new Ray(middleEyeGameobject.transform.position, middleEyeGameobject.transform.forward);
Also, you don't have to specify the distance with hit raycast (remove the fourth parameter to Physics.Raycast).
And for the additional question yes, everything has to have a collider with Physics.Raycast. And yes, there are other ways to do this, but the built in ones (2) still require colliders (or similar), although they can be virtual, not attached to objects.
It's best to use colliders, perhaps on their own layer.

The NullReferenceException you are getting is because you are using Camera.main.ScreenPointToRay(Input.mousePosition) , camera.main uses the MainCamera tag which is not set for your OVRCameraRig. You can set tag of this camera as mainCamera if OVRCameraRig is supposed to be your mainCamera or otherwise you can take reference of this camera (OVRCameraRig) and use cameraRef.ScreenPointToRay(Input.mousePosition). :)

Related

2D Object Not Detecting When Hit by Raycast

I'm creating a top down 2D game, where the player has to break down trees. I made it so the player casts a ray toward the mouse, and when the ray hits a tree, it should lower the tree's health. I don't get any errors when I run the game or click, but it seems like the tree isn't detecting the hits.
void Update()
{
...
if (Input.GetMouseButtonDown(0))
{
RaycastHit2D hit = Physics2D.Raycast(playerRb.transform.position, mousePosition - playerRb.transform.position, 2.0f);
if (hit.collider != null)
{
if (hit.collider == GameObject.FindWithTag("Tree"))
{
hit.collider.GetComponent<TreeScript>().treeHealth--;
}
}
}
}
Still pretty new to coding and I'm teaching myself, so please make your answer easy to understand to help me learn.
Input.mousePosition is equal to the pixel your mouse is on. This is very different than the location your mouse is pointing at in the scene. To explain further, Input.mousePosition is where the mouse is. Think about it. If the camera was facing up, the mouse positon would be the same, but where they are clicking is different.
Instead of using Input.mousePosition, You should pass this into a function called Ray Camera.ScreenPointToRay();
You just input the mouse position and then use this new ray to do the raycast.
ANOTHER EXTREMELY IMPORTANT THING 1: Do not use Camera.main in Update(), as it uses a GetComponet call, which can cause perormance decreases. Store a reference of it in your script and use that.
Extremely important thing 2: I notice you are using GetComponent to change the tree's health. This is fine, but do not use GetComponent if you don't have to.
Like this:
Camera cam;
void Start()
{
cam = Camera.main; //it is fine to use this in start,
//because it is only being called once.
}
void Update()
{
...
if (Input.GetMouseButtonDown(0))
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(ray);
...
}
}
You need to convert your mouse position from screen point to world point with Z value same as the other 2D objects.
Vector3 Worldpos=Camera.main.ScreenToWorldPoint(mousePos);
Also use a Debug.DrawRay to check the Raycast
Debug.DrawRay(ray.origin, ray.direction*10000f,Color.red);
Source

Unity / Mirror - Is there a way to keep my camera independent from the player object's prefab after start?

I'm currently trying to create a multiplayer game using mirror!
So far I've been successful in creating a lobby and set up a simple character model with a player locomotion script I've taken and learnt inside out from Sebastian Graves on YouTube (you may know him as the dark souls III tutorial guy)
This player locomotion script uses unity's package 'Input System' and is also dependent on using the camera's .forward and .right directions to determine where the player moves and rotates instead of using forces on the rigidbody. This means you actually need the camera free in the scene and unparented from the player.
Here is my HandleRotation() function for rotating my character (not the camera's rotation function):
private void HandleRotation()
{
// target direction is the way we want our player to rotate and move // setting it to 0
Vector3 targetDirection = Vector3.zero;
targetDirection = cameraManager.cameraTransform.forward * inputHandler.verticalInput;
targetDirection += cameraManager.cameraTransform.right * inputHandler.horizontalInput;
targetDirection.Normalize();
targetDirection.y = 0;
if (targetDirection == Vector3.zero)
{
// keep our rotation facing the way we stopped
targetDirection = transform.forward;
}
// Quaternion's are used to calculate rotations
// Look towards our target direction
Quaternion targetRotation = Quaternion.LookRotation(targetDirection);
// Slerp = rotation between current rotation and target rotation by the speed you want to rotate * constant time regardless of framerates
Quaternion playerRotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
transform.rotation = playerRotation;
}
It's also worth mentioning I'm not using cinemachine however I'm open to learning cinemachine as it may be beneficial in the future.
However, from what I've learnt and managed to find about mirror is that you have to parent the Main Camera under your player object's prefab so that when multiple people load in, multiple camera's are created. This has to happen on a Start() function or similar like OnStartLocalPlayer().
public override void OnStartLocalPlayer()
{
if (mainCam != null)
{
// configure and make camera a child of player
mainCam.orthographic = false;
mainCam.transform.SetParent(cameraPivotTransform);
mainCam.transform.localPosition = new Vector3(0f, 0f, -3f);
mainCam.transform.localEulerAngles = new Vector3(0f, 0f, 0f);
cameraTransform = GetComponentInChildren<Camera>().transform;
defaultPosition = cameraTransform.localPosition.z;
}
}
But of course, that means that the camera is no longer independent to the player and so what ends up happening is the camera rotates when the player rotates.
E.g. if I'm in game and looking to the right of my player model and then press 'w' to walk in the direction the camera is facing, my camera will spin with the player keeping the same rotation while my player spins in order to try and walk in the direction the camera is facing.
What my question here would be: Is there a way to create a system using mirror that doesn't require the camera to be parented to the player object prefab on start, and INSTEAD works by keeping it independent in the scene?
(I understand that using forces on a rigidbody is another method of creating a player locomotion script however I would like to avoid that if possible)
If anybody can help that would be greatly appreciated, Thank You! =]
With the constraint of your camera being attached to the player you will have to adapt the camera logic. What you can do is instantiate a proxy transform for the camera and copy that transforms properties to your camera, globally, every frame. The parent constraint component might do this for you. Then do all your transformations on that proxy.
Camera script with instantiation:
Transform proxy;
void Start(){
proxy = (new GameObject()).transform;
}
void Update(){
//transformations on proxy
transform.position = proxy.position;
transform.rotation = proxy.rotation;
}

Unity and Oculus Raycast from Motion Controller Only working at Guardian Border

I have coded up a simple raycast script that is attached to the hand of an Oculus Motion Controller. The idea is - the controller acts like a vacuum, it sucks up the prefabbed objects called "Eosinophil2(Clone)".
On a few tests outside of the motion controller this works.
The trouble I am experiencing is when I place the Raycast script into the motion controller. It only appear to work as anticipated when I am beside the Guardian Border.
I have turned on and off the border to see if that solved anything but it did not.
I've checked that the line raycast line goes in the right direction - and it is.
Any ideas?
void FixedUpdate()
{
// OVRInput.SetControllerVibration(.3f, 0.3f, OVRInput.Controller.RTouch);
var up = transform.TransformDirection(Vector3.forward);
//note the use of var as the type. This is because in c# you
// can have lamda functions which open up the use of untyped variables
//these variables can only live INSIDE a function.
RaycastHit hit;
Debug.DrawRay(transform.position, up * 20, Color.green,1);
if (Physics.Raycast(transform.position, up, out hit, 20))
{
if (hit.collider.gameObject.name == "Eosinophil2(Clone)")
{
OVRInput.SetControllerVibration(.3f, 0.3f, OVRInput.Controller.RTouch);
hit.collider.gameObject.transform.position = Vector3.MoveTowards(hit.collider.gameObject.transform.position, transform.position, 20 * Time.deltaTime);
}
else
{
//OVRInput.SetControllerVibration(0, 0, OVRInput.Controller.RTouch);
}
}
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.transform.name == "Eosinophil2(Clone)")
{
this.gameObject.GetComponent<AudioSource>().Play(0);
Debug.Log("works");
Destroy(other.gameObject);
Debug.Log("HIT ONE!");
hitRate++;
}
}`enter code here`
Moral of the story - build your scene from scratch.
Use the OVRCameraRig prefab in said build scene.
Using prebuilt scenes from Oculus can be detrimental to ones health, time and code.
I hope this helps someone someday.

Unity - Walk around a cube

I have an issue with trying to get an 'object(character)' to walk around a cube (all sides) within Unity. Ive attached an image and video showing what i am trying to achieve. Im trying to show you visually rather than trying to explain. As the character drops over the edge it rotates 90 degrees and then the stands up like gravity has switched. Then the character can jump walk etc.
This is an example of someone else that posted a video showing exactly what im trying to achieve
I have looked through the forums and cant find what im after. i have tried to attach a diagram but the site wont let me. Any advice would be greatly appreciated!
Regards
Nick
You have a couple of options that I can think of.
One is to trigger the gravity change when the character exits one face of the cube to go to another. To achieve this you would have trigger zones on each edge and face and use a [Bob went from Face A to Edge ANorth -> Switch Gravity to go in X direction].
This would work for situations where the gravity switch must affect other objects too but be advantageous to your player (walking off the side makes an enemy fall off and die - for example.)
However, if you want all entities to stick to their relative sides then we need to make custom gravity! To do this is easier than you might think as gravity is simply a downward accelleration of 9.8. So turn off the engines native gravity and create a "personal gravity" component:
private Vector3 surfaceNormal;
private Vector3 personalNormal;
private float personalGravity = 9.8f;
private float normalSwitchRange = 5.0f;
public void Start()
{
personalNormal = transform.up; // Start with "normal" normal
rigidbody.freezeRotation = true; // turn off physics rotation
}
public void FixedUpdate()
{
// Apply force taking into account character normal as personal gravity:
rigidbody.AddForce(-personalGravity * rigidbody.mass * personalNormal);
}
Rotating your character and changing his normal is then up to you to suit your situation or game mechanic, whether you do that by raycasting if you're standing on a surface to detect when to change it or only want gravity to change when you hit a powerup or similar - experiment and see what works. Comment more if you have questions!
EDIT:
As an addition to the video you linked. You can keep a state variable on the jump state and raycast in each axis direction to check which face is nearest in the case of just rolling off.
public void Update()
{
// we don't update personal normals in the case of jumping
if(!jumping)
{
UpdatePersonalNormal();
}
}
public void UpdatePersonalNormal()
{
RaycastHit hit; //hit register
// list of valid normals to check (all 6 axis)
Ray[] rays =
{
Vector3.up, Vector3.down,
Vector3.left, Vector3.right,
Vector3.forward, Vector3.backward
};
//for each valid normal...
foreach(Ray rayDirection in rays)
{
//check if we are near a cube face...
if(Physics.Raycast(rayDirection , hit, normalSwitchRange)
{
personalNormal = hit.Normal; //set personal normal ...
return; // and return as we are done
}
}
}
Please keep in mind that the above is completely hand written and not tested but play with it and this pseudo start should give you a good idea of what to do.

How to Make Raycast Effect Named GameObject Only

In my current(Unity 3.3 IOS)project I have a character walking across a bridge. If the character falls off
the bridge he is to fall into a fiery river and explode. The problem is when he's on the bridge the Raycast reads the rigidbody on the bridge and he immediately explodes. If I reposition him in the scene window to an open air position, the gravity causes him to fall into the river and explode as planned. I added the following line of code to designate only destroy if the raycast hits the "plane". It doesn't work.
if(hit.collider.gameObject.name == "plane");
The character does not get destroyed on the bridge or when he hits the plane/fiery river.
There are several bridges and buildings he will be walking into, so I only want him to be destroyed/explode if the raycast hits the plane.
Can anyone tell me why my code isn't working or how to correct it?
Here is my complete Raycast code.
var explosion : Transform;
var point : Vector3;
var explosionRotation : Quaternion;
function Update()
{
var hit :RaycastHit;
var dwn = transform.TransformDirection(Vector3.down);
if (Physics.Raycast(this.transform.position,dwn,hit,3))
if (hit.collider.gameObject.name == "plane")
{
point = hit.point;
explosionRotation = Quaternion.FromToRotation(Vector3.up, hit.normal);
Explode();
}
}
function Explode()
{
Destroy(this.gameObject);
var instanExplosion = Instantiate(explosion, point, explosionRotation);
}
Can you share your scene with the basic objects that are involved?
There are some problems that might occur.
The bridge might be named "plane", too
The ray is too long
Have you considered using layers? It sound like you use that ray only for falling/dying purpose for the character. You might want to add your plane to a separate layer and let the ray only check against that layer.