Forum Discussion
nigrin
13 years agoExplorer
[TIP] Detecting where the player looks at
Hi guys,
we came across this for our vrjam game "Sorcerer's Wrath", where the player fights things by just looking at them.
Here is a quick blog post how we did this, I have not seen this specific approach in the wild and thought it might be worth sharing. Happy to discuss pro's and con's.
we came across this for our vrjam game "Sorcerer's Wrath", where the player fights things by just looking at them.
Here is a quick blog post how we did this, I have not seen this specific approach in the wild and thought it might be worth sharing. Happy to discuss pro's and con's.
18 Replies
Replies have been turned off for this discussion
- CaineHonored GuestThanks for writing that up :)
- marky1124ExplorerHi Nigrin,
Thanks for sharing that. I tackled the same problem and decided to use the Physics.Raycast() approach. Your approach may be much faster I don't know, I've heard raycasting is slow, but in my situation it didn't matter and I've not seen any speed impact.
I'm pretty new to Unity so my approach is probably poor but I thought I'd share it (written in C#) :-
public class PlayerLookingAt : MonoBehaviour {
Transform cameraTransform = null;
void Awake() {
cameraTransform = GameObject.FindWithTag("MainCamera").transform;
}
void Update() {
float length = 10.0f;
RaycastHit hit;
Vector3 rayDirection = cameraTransform.TransformDirection(Vector3.forward);
Vector3 rayStart = cameraTransform.position + rayDirection; // Start the ray away from the player to avoid hitting itself
Debug.DrawRay(rayStart, rayDirection * length, Color.green);
if (Physics.Raycast(rayStart, rayDirection, out hit, length)) {
if (hit.collider.tag == "Tower") {
// Do stuff
}
}
}
}
That's the guts of the code. I've tagged the OVR camera controller as 'MainCamera' and put a collider with isTrigger ticked on the objects I want to know if the player is looking at.
I hope that helps someone,
Cheers,
Mark - DarkJamesHonored GuestAnother technique is to use dot product between to Vector3's. I found the information on it here http://forum.unity3d.com/threads/173707-Using-Vector3-Dot-for-Direction-Facing-Calculation
I found that 0.72f < x <= 1 seemed to fit the Oculus field of vision to determine if it was in view or not. That was with the B cups, I believe the other cups would change the number you needed to use. - jamesjExplorer
"marky1124" wrote:
Hi Nigrin,
Thanks for sharing that. I tackled the same problem and decided to use the Physics.Raycast() approach. Your approach may be much faster I don't know, I've heard raycasting is slow, but in my situation it didn't matter and I've not seen any speed impact.
I'm pretty new to Unity so my approach is probably poor but I thought I'd share it (written in C#) :-
public class PlayerLookingAt : MonoBehaviour {
Transform cameraTransform = null;
void Awake() {
cameraTransform = GameObject.FindWithTag("MainCamera").transform;
}
void Update() {
float length = 10.0f;
RaycastHit hit;
Vector3 rayDirection = cameraTransform.TransformDirection(Vector3.forward);
Vector3 rayStart = cameraTransform.position + rayDirection; // Start the ray away from the player to avoid hitting itself
Debug.DrawRay(rayStart, rayDirection * length, Color.green);
if (Physics.Raycast(rayStart, rayDirection, out hit, length)) {
if (hit.collider.tag == "Tower") {
// Do stuff
}
}
}
}
That's the guts of the code. I've tagged the OVR camera controller as 'MainCamera' and put a collider with isTrigger ticked on the objects I want to know if the player is looking at.
I hope that helps someone,
Cheers,
Mark
Thanks for this, I ported it to JS and works like a charm. - vajra3dHonored GuestThanks for sharing this Mark... do you know if it casts a ray to the actual center of the view or is it slightly offset due to the OVR camera offset? I can't remember if I tried using Vector3.forward when I tackled this problem but this is what I ended up doing in order to compensate for the OVR's camera offset:
var rayLength = 5.0;
function Update () {
var ray : Ray = camera.main.ViewportPointToRay (Vector3(0.59,0.5,0));
var hit : RaycastHit;
Debug.DrawRay (ray.origin, ray.direction * rayLength, Color.red);
if (Physics.Raycast (ray, hit, rayLength)) {
if(hit.collider.tag == "whateverObjectYouWant") {
//Do Something...
}
}
.. by adding .09 to the x it counters the offset and casts the ray to the center of the screen view. It works but I'm always interested in a better solution so I might have to give this a try and see if it works for me. Thanks! - ssshakeHonored GuestGot a question about this type of stuff. How do you add a requirement that a "button" on screen must be looked at for x seconds? I want to add input like we see in many rift games like titans of space. But have no idea what to look for.
- MikeFTrusteei'd create a timer that begins counting up when the player has a button in sight, if the raycast leaves the button before the set amount of time required to look at it then the timer resets. If the timer exceeds the time required then it becomes active
- AnonymousIn the Unity tutorials, they use raycasting instead of a collider like Nigrin suggested.
I think (and may be wrong) that the problem of the collider is that you can "look" at something through walls. Let's say you look forward, at a wall, and right behind this wall, an enemy enters the collider : theonColliderEnter(collider other){if(other == enemy){somecode();}}
is true, even if you don't see the enemy, and somecode will be executed.
With the raycast, you can put something like :raycasthit = hit ;
Physics.Raycast(transform.position, Vector3.forward, out hit);
if(hit == enemy){somecode();}
in your code and it will take the first thing the raycast hits. So, if it's a wall, the condition is false even if your raycast hits an enemy behind the wall.
I personally use linecast instead of raycast if possible, because I had less problems with it, and because I think that it's faster (not having to calculate the ray to the infinite), but maybe am I wrong on this. The best way I found to do what we intend to do is to combine both approaches : use a box collider to see if there is an enemy in front of you (or near you), even if it's behind a wall, and if there is one, cast a raycast (or linecast) to see if there is something between you and the enemy. This way, you can avoid the "enemy behind wall" problem, and you don't use constantly raycasts / linecasts, and that should be better for the performance of the game. - GeekOffGridHonored Guest
"nigrin" wrote:
Hi guys,
we came across this for our vrjam game "Sorcerer's Wrath", where the player fights things by just looking at them.
Here is a quick blog post how we did this, I have not seen this specific approach in the wild and thought it might be worth sharing. Happy to discuss pro's and con's.
Commenting out a.x fixed a huge issue for me - thanks! - sh0v0rProtegeLunar Flight uses ray casts for the cockpit interaction. I placed and object between the eyes which is a child of the Right Camera as this is the camera that all other cameras reference for orientation information. I use it's forward vector for the raycast direction and cast just a bit further than the depth of the cockpit.
Everything the player can interact with has a collider and an object that contains all it's information. When the ray cast hits one of them it then gets the info object to know what icon or string to display and it's interaction method. The raycast is also only done every 100ms.
Quick Links
- Horizon Developer Support
- Quest User Forums
- Troubleshooting Forum for problems with a game or app
- Quest Support for problems with your device
Other Meta Support
Related Content
- 3 years ago
- 7 months ago
- 5 months ago