How to cycle more then one video inside the sphere for VR view ? [duplicate] - unity3d

I want to play a stereo 360 degree video in virtual reality in Unity on an Android. So far I have been doing some research and I have two cameras for the right and left eye with each a sphere around them. I also need a custom shader to make the image render on the inside of the sphere. I have the upper half of the image showing on one sphere by setting the y-tiling to 0.5 and the lower half shows on the other sphere with y-tiling 0.5 and y-offset 0.5. With this I can show a 3D 360 degree image already correct. The whole idea is from this tutorial.
Now for video, I need control over the Video speed so it turned out I need the VideoPlayer from the new Unity 5.6 beta. Now my setup so far would require the Video Player to play the video on both spheres with one sphere playing the upper part (one eye) and the other video playing the lower part (other eye).
Here is my problem: I don't know how to get the video Player to play the same video on two different materials (since they have different tiling values). Is there a way to do that?
I got a hint that I could use the same material and achieve the tiling effect via UV, but I don't know how that works and I haven't even got the video player to play the video on two objects using the same material on both of them. I have a screenshot of that here. The Right sphere just has the material videoMaterial. No tiling since I'd have to do that via UV.
Which way to go and how to do it? Am I on the right way here?

Am I on the right way here?
Almost but you are currently using Renderer and Material instead of RenderTexture and Material.
Which way to go and how to do it?
You need to use RenderTexture for this. Basically, you render the Video to RenderTexture then you assign that Texture to the material of both Spheres.
1.Create a RenderTexture and assign it to the VideoPlayer.
2.Create two materials for the spheres.
3.Set VideoPlayer.renderMode to VideoRenderMode.RenderTexture;
4.Set the Texture of both Spheres to the Texture from the RenderTexture
5.Prepare and Play Video.
The code below is doing that exact thing. It should work out of the box. The only thing you need to do is to modify the tiling and offset of each material to your needs.
You should also comment out:
leftSphere = createSphere("LeftEye", new Vector3(-5f, 0f, 0f), new Vector3(4f, 4f, 4f));
rightSphere = createSphere("RightEye", new Vector3(5f, 0f, 0f), new Vector3(4f, 4f, 4f));
then use a Sphere imported from any 3D application. That line of code is only there for testing purposes and it's not a good idea to play video with Unity's sphere because the spheres don't have enough details to make the video smooth.
using UnityEngine;
using UnityEngine.Video;
public class StereoscopicVideoPlayer : MonoBehaviour
{
RenderTexture renderTexture;
Material leftSphereMat;
Material rightSphereMat;
public GameObject leftSphere;
public GameObject rightSphere;
private VideoPlayer videoPlayer;
//Audio
private AudioSource audioSource;
void Start()
{
//Create Render Texture
renderTexture = createRenderTexture();
//Create Left and Right Sphere Materials
leftSphereMat = createMaterial();
rightSphereMat = createMaterial();
//Create the Left and Right Sphere Spheres
leftSphere = createSphere("LeftEye", new Vector3(-5f, 0f, 0f), new Vector3(4f, 4f, 4f));
rightSphere = createSphere("RightEye", new Vector3(5f, 0f, 0f), new Vector3(4f, 4f, 4f));
//Assign material to the Spheres
leftSphere.GetComponent<MeshRenderer>().material = leftSphereMat;
rightSphere.GetComponent<MeshRenderer>().material = rightSphereMat;
//Add VideoPlayer to the GameObject
videoPlayer = gameObject.AddComponent<VideoPlayer>();
//Add AudioSource
audioSource = gameObject.AddComponent<AudioSource>();
//Disable Play on Awake for both Video and Audio
videoPlayer.playOnAwake = false;
audioSource.playOnAwake = false;
// We want to play from url
videoPlayer.source = VideoSource.Url;
videoPlayer.url = "http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4";
//Set Audio Output to AudioSource
videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
//Assign the Audio from Video to AudioSource to be played
videoPlayer.EnableAudioTrack(0, true);
videoPlayer.SetTargetAudioSource(0, audioSource);
//Set the mode of output to be RenderTexture
videoPlayer.renderMode = VideoRenderMode.RenderTexture;
//Set the RenderTexture to store the images to
videoPlayer.targetTexture = renderTexture;
//Set the Texture of both Spheres to the Texture from the RenderTexture
assignTextureToSphere();
//Prepare Video to prevent Buffering
videoPlayer.Prepare();
//Subscribe to prepareCompleted event
videoPlayer.prepareCompleted += OnVideoPrepared;
}
RenderTexture createRenderTexture()
{
RenderTexture rd = new RenderTexture(1024, 1024, 16, RenderTextureFormat.ARGB32);
rd.Create();
return rd;
}
Material createMaterial()
{
return new Material(Shader.Find("Specular"));
}
void assignTextureToSphere()
{
//Set the Texture of both Spheres to the Texture from the RenderTexture
leftSphereMat.mainTexture = renderTexture;
rightSphereMat.mainTexture = renderTexture;
}
GameObject createSphere(string name, Vector3 spherePos, Vector3 sphereScale)
{
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = spherePos;
sphere.transform.localScale = sphereScale;
sphere.name = name;
return sphere;
}
void OnVideoPrepared(VideoPlayer source)
{
Debug.Log("Done Preparing Video");
//Play Video
videoPlayer.Play();
//Play Sound
audioSource.Play();
//Change Play Speed
if (videoPlayer.canSetPlaybackSpeed)
{
videoPlayer.playbackSpeed = 1f;
}
}
}
There is also Unity tutorial on how to do this with a special shader but this does not work for me and some other people. I suggest you use the method above until VR support is added to the VideoPlayer API.

Related

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;
}

Camera Shake Effect When Camera Following Player

I was working on a 3d game where the camera is continuously following the player object.
Now when a bomb hits the player object I want to play camera shake with blast particle effect.
I have coded this for camera shake:
public IEnumerator PlayCameraShakeAnimation(float duration, float magnitude)
{
Vector3 originalPosition = transform.localPosition;
float elapsedTime = 0f;
while(elapsedTime < duration)
{
float x = Random.Range(-1f, 1f) * magnitude;
float y = Random.Range(-1f, 1f) * magnitude;
transform.localPosition = new Vector3(x, y,originalPosition.z);
elapsedTime += Time.deltaTime;
yield return null;
}
transform.localPosition = originalPosition;
}
Camera Follow is the normal script I have written to follow the player.
Because of Camera Follow script is running, camera shake effect we can't able to show in the screen.
If I turn off Camera Follow script then we can able to see clearly camera shaking otherwise not.
If I turn off Camera Follow script for a small amount of time then I am losing smoothness in following of player because the player position gets updated after the blast. So when I start back following the player, it will get a high jerk in a movement to reach a target position.
Also, the Camera is following the player in position and rotation in both fields. Now provide me some suggestions to achieve the Camera Shake effect while following the player.
This is actually quite simple:
Separate it into two GameObjects:
parentObject
|--Camera
parentObject follows player.
Camera does the shaking in localPosition &rightarrow; relative to parentObject
Result: While parentObject follows the player the Camera is automatically moved along with it. No need to turn anything on and of ;)

Unity3D follow Sphere player camera rotation

Hi I'm trying to get my camera to follow my player (Sphere) when ever it moves around. I have got the camera to follow the player, but when the sphere spins, so do the camera. That is not what i'm looking for. I need the camera to stay put on the sphere and rotate when I turn. This is my code so far:
EDIT: What I'm looking for is something like you see in the vid. where the camera rotate when the sphere is turning, so it's behind it all the time. https://www.youtube.com/watch?v=jPAgPQi1l0c
using UnityEngine;
using System.Collections;
public class TransformFollower : MonoBehaviour
{
[SerializeField]
private Transform target;
[SerializeField]
private Vector3 offsetPosition;
[SerializeField]
private Space offsetPositionSpace = Space.Self;
[SerializeField]
private bool lookAt = true;
private void Start()
{
offsetPosition = new Vector3(-3, -2, 0);
}
private void Update()
{
Refresh();
}
public void Refresh()
{
if (target == null)
{
Debug.LogWarning("Missing target ref !", this);
return;
}
// compute position
if (offsetPositionSpace == Space.Self)
{
transform.position = target.TransformPoint(offsetPosition);
}
else
{
transform.position = target.position + offsetPosition;
}
// compute rotation
if (lookAt)
{
transform.LookAt(target);
}
else
{
transform.rotation = target.rotation;
}
}
}
You should implement the following logic:
Create an empty gameObject:Character, where it will have as childs: Camera, Sphere
when you move, you simply transform the Character, so the Camera and the Sphere transform in the exact same way.
Now, when you want to rotate only the Sphere, but not the camera, just apply your rotation(or anything else), only in the sphere.
To do so, in your script you can pass the Character and the Sphere.
So moving transformations will be applied in on the Character and any custom move, only in the sphere.
Nik
Did you write this code yourself?
It simply seems that if lookat is true, it will do what you want. If it is false, if will do what you describe.
Just look in the editor and check the 'look at' box.
If you never want to use it you can remove it from the code by removing the lookat variable and replacing
// compute rotation
if (lookAt)
{
transform.LookAt(target);
}
else
{
transform.rotation = target.rotation;
}
by
// compute rotation
transform.LookAt(target);
EDIT more explanation:
In your code, you have two options: lookat and offsetPositionSpace.
Basically, offsetPositionSpace can be two values:
Self -> The camera will always be behind the player (if you rotate the player, it moves to stay behind
World -> The camera will always imitate the player's moves (If the player rotates, the camera won't move
LookAt can also have two values
true -> the camera looks at the player, always
false -> the camera imitate the players rotation (if the player rotates, the camera does the same and stops looking at the player)

Unity - move 3d object in an AR scene

I have an AR scene that has one AR camera, an image target and 3d object below as.
I create an .cs file and attach to ARCamera. I want to move AR object to mouse click position. I tried many codes for this. But I couldn't success it.
I know that Input.mouseposition returns screen position. I convert to ScreenToWorldPosition and put 3d object on this position. 3d object is moved, but not mouse click position. I don't know where it is moved.
How can I move to mouse click position? My code is here :
Camera cam;
Vector3 target = new Vector3(0.0f, 10f,0.5f);
// Use this for initialization
void Start () {
if (cam == null)
cam = Camera.main;
}
void Update()
{
if (Input.GetMouseButtonDown(0)) {
Debug.Log("MouseDown");
Vector3 mousePos = Input.mousePosition;
mousePos = cam.ScreenToWorldPoint(mousePos);
GameObject.Find("Car1").gameObject.transform.position = mousePos;
}
}
EDIT 1
If I add a plane to scene, I can move to the position of mouse click only on the plane. The code is taken from here. But the plane prevents to show AR camera view. The screenshot is below:
Instead of playing with ScreenToWorldPoint, you should use a raycast against a plane, see this answer: https://stackoverflow.com/a/29754194/785171.
The plane should be attached to your AR marker.
ScreenToWorldPoint takes a Vector3, mousePosition is basically a Vector2 (with a 0 z-axis value). You need to set the mousePosition.z value to something for it to be placed in a viewable position. Example:
Vector3 mousePos = Input.mousePosition;
mousePos = cam.ScreenToWorldPoint(mousePos);
mousePos.z = 10;
GameObject.Find("Car1").gameObject.transform.position = mousePos;
This would set the position to 10 units away from the camera.

How to drag a cube in orthographic camera in Unity 3d?

I am trying to create a isometric game like clash of clans. I created a Terrain and I set my camera position to (0,300,-10) and Rotation to (40,45,0) and Perspective to Orthographic. I am using below code to drag a cube but when i drag the cube at some position cube is not able to visible or only some portion of cube is visible. It seems like position (X,Y,Z) all three are changing using below code. But i want to drag cube just like any top down game like Clash of Clans. Please help me to resolve my issue.
void OnMouseDrag ()
{
Vector3 mousePosition = new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 0);
Vector3 objPosition = Camera.main.ScreenToWorldPoint (mousePosition);
this.target.transform.position = objPosition;
}
You need raycasting to solve it. Try this-
void OnMouseDrag ()
{
RaycastHit hitInfo;
bool hit = Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hitInfo, Mathf.Infinity, 1 << LayerMask.NameToLayer ("ground"));
if(hit){
this.target.transform.position = hitInfo.point;
}
}
You can use your existing ground or surface or on whatever your object will move, change the layer name to ground. Be aware that the ground must have a collider.