Search code examples
c#androidunity-game-enginegoogle-cardboardvirtual-reality

Change Material of a Sphere on Focus for VR 360 Degree Image App in Unity3d


I am creating an app for google-cardboard, App like 360 degree image. I created a sphere and I made 62 material with different 360 degree image. I created 2 button, next and previous, when i focus on next button its changing to next material as i want. but when i focus on previous button, its changing to last material which i dont want. What I want is just previous material.

Here is my code. See and tell me what I am doing wrong. Thanks.

using UnityEngine;
using System.Collections;

public class next : MonoBehaviour {

    public CardboardHead head;
    public Material[] myMaterials = new Material[60];
    int maxMaterials;
    int arrayPos = 0;
    public GameObject Sphere;
    public int timeToCompleteLoading = 3;
    bool wait = false;

    void Start ()
    {
        head = Camera.main.GetComponent<StereoController> ().Head;
        maxMaterials = myMaterials.Length-1;

    }

    public void ToggleVRMode() 
    {
        Cardboard.SDK.VRModeEnabled = !Cardboard.SDK.VRModeEnabled;
    }

    IEnumerator RadialProgress(float time)
    {
        wait = true;
        yield return new WaitForSeconds(time);

        float rate = 1 / time;
        float i = 0;
        while (i < 1)
        {
            i += Time.deltaTime * rate;
            gameObject.renderer.material.SetFloat("_Progress", i);

        }
        wait = false;
    }

    void updateMaterials(){
        if (collider.gameObject.tag == "next") {
            if (arrayPos == maxMaterials){
                arrayPos = 0;
            }else{

                arrayPos++;
                Sphere.renderer.material = myMaterials [arrayPos];
            }
        }
         if (collider.gameObject.tag == "previous") {
            if (arrayPos == 0){
                arrayPos = maxMaterials;
            }else{
                arrayPos--;
                Sphere.renderer.material = myMaterials [arrayPos];

            }
        }


    }


    void Update ()
    {
        RaycastHit hit;
        Collider collider = GetComponent<Collider> ();

        if (collider) {

            bool isLookAt = collider.Raycast (head.Gaze, out hit, Mathf.Infinity);
            if (isLookAt == true) {
                if(wait == false){
                    StartCoroutine (RadialProgress (timeToCompleteLoading));

                    updateMaterials();
                }
            }
        }
    }
}

Solution

  • There is something wrong in what you describe. There is 60 materials, so maxMaterial should be 59 (0 to 59 is 60 spots). But you say it shows 61 and 60 and that should be out of bounds. Also, since maxMaterial is 59 (60 -1), when your index is 60 or 61, your if statement does not do.

    You could review like so:

     void updateMaterials(){
        if (collider.gameObject.tag == "next") {
            if (++arrayPos == myMaterials.Length){
                arrayPos = 0;
            }
        }
        else if (collider.gameObject.tag == "previous") {
            if (--arrayPos < 0){
                arrayPos = myMaterials.Length - 1;
            }
        }
        Sphere.renderer.material = myMaterials [arrayPos];
    }
    

    P.S.: As I mentioned in a comment, your while loop in the coroutine will not do any delayed process:

        while (i < 1)
        {
            i += Time.deltaTime * rate;
            gameObject.renderer.material.SetFloat("_Progress", i);
        }
    

    The while loop runs within a single frame.

        while (i < 1)
        {
            i += Time.deltaTime * rate;
            gameObject.renderer.material.SetFloat("_Progress", i);
            yield return null;
        }
    

    Now the while loop runs over several frames.