What's new

C# Google Cardboard Issue in Unity

az2015

Honorary Poster
Established
Joined
Mar 20, 2018
Posts
577
Solutions
1
Reaction
279
Points
243
NullReferenceException: Object reference not set to an instance of an object
VrModeController.Update () (at Assets/Samples/Google Cardboard XR Plugin for Unity/1.21.0/Hello Cardboard/Scripts/VrModeController.cs:89)
 
A NullReferenceException occurs when you try to access a member or method of an object that is null (i.e., it has not been instantiated or assigned a value). In this case, the error is happening in the Update method of the VrModeController script at line 89.

To fix this issue, you need to identify which object is null and ensure that it is properly initialized before accessing its members.

Here are a few steps you can follow to troubleshoot and resolve the NullReferenceException:

1. Check line 89 of the VrModeController script: Examine the code at that line and see which object is being accessed. Look for any variables or properties that might be null.

2. Identify the null object: Once you have identified the line causing the error, find the object that is null. It could be a GameObject, a component, or a variable that has not been assigned.

3. Initialize the object: If the object is a GameObject, make sure it is instantiated using the "new" keyword or by instantiating a prefab. If it is a component, make sure it is properly attached to a GameObject in the scene. If it is a variable, make sure it is assigned a value before being accessed.

4. Check for missing references: If the null object is a component, verify that it is properly assigned in the Unity Inspector. Look for any missing or unassigned references in the Inspector panel for the script that contains the VrModeController.

5. Debugging: Use debugging techniques to identify the exact cause of the issue. You can use breakpoints, print statements, or the Unity Debug.Log() function to check the values of variables and identify where the null reference is coming from.

By following these steps, you should be able to track down and fix the NullReferenceException in your code.
 
C#:
//-----------------------------------------------------------------------
// <copyright file="CardboardReticlePointer.cs" company="Google LLC">
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
//-----------------------------------------------------------------------

using UnityEngine;
using UnityEngine.EventSystems;

/// <summary>
/// Draws a circular reticle in front of any object that the user points at.
/// </summary>
/// <remarks>
/// Sends messages to gazed GameObject. The reticle dilates if the object has an interactive layer.
/// </remarks>
public class CardboardReticlePointer : MonoBehaviour
{
    /// <summary>
    /// Sorting order to use for the reticle's renderer.
    /// </summary>
    /// <remarks><para>
    /// Range values come from https://docs.unity3d.com/ScriptReference/Renderer-sortingOrder.html.
    /// </para><para>
    /// Default value 32767 ensures gaze reticle is always rendered on top.
    /// </para></remarks>
    [Range(-32767, 32767)]
    public int ReticleSortingOrder = 32767;

    /// <summary>
    /// Mask used to indicate interactive objects.
    /// </summary>
    public LayerMask ReticleInteractionLayerMask = 1 << _RETICLE_INTERACTION_DEFAULT_LAYER;

    /// <summary>
    /// Default layer for interactive game objects.
    /// </summary>
    private const int _RETICLE_INTERACTION_DEFAULT_LAYER = 8;

    /// <summary>
    /// The angle in degrees defined between the 2 vectors that depart from the camera and point to
    /// the extremes of the minimum inner diameter of the reticle.
    ///
    /// Being `z` the distance from the camera to the object and `d_i` the inner diameter of the
    /// reticle, this is 2*arctg(d_i/(2*z)).
    /// </summary>
    private const float _RETICLE_MIN_INNER_ANGLE = 0.0f;

    /// <summary>
    /// The angle in degrees defined between the 2 vectors that depart from the camera and point to
    /// the extremes of the minimum outer diameter of the reticle.
    ///
    /// Being `z` the distance from the camera to the object and `d_o` the outer diameter of the
    /// reticle, this is 2*arctg(d_o/(2*z)).
    /// </summary>
    private const float _RETICLE_MIN_OUTER_ANGLE = 0.5f;

    /// <summary>
    /// Angle at which to expand the reticle when intersecting with an object (in degrees).
    /// </summary>
    private const float _RETICLE_GROWTH_ANGLE = 1.5f;

    /// <summary>
    /// Minimum distance between the camera and the reticle (in meters).
    /// </summary>
    private const float _RETICLE_MIN_DISTANCE = 0.45f;

    /// <summary>
    /// Maximum distance between the camera and the reticle (in meters).
    /// </summary>
    private const float _RETICLE_MAX_DISTANCE = 20.0f;

    /// <summary>
    /// Number of segments making the reticle circle.
    /// </summary>
    private const int _RETICLE_SEGMENTS = 20;

    /// <summary>
    /// Growth speed multiplier for the reticle.
    /// </summary>
    private const float _RETICLE_GROWTH_SPEED = 8.0f;

    /// <summary>
    /// The game object the reticle is pointing at.
    /// </summary>
    private GameObject _gazedAtObject = null;

    /// <summary>
    /// The material used to render the reticle.
    /// </summary>
    private Material _reticleMaterial;

    /// <summary>
    /// The current inner angle of the reticle (in degrees).
    /// </summary>
    private float _reticleInnerAngle;

    /// <summary>
    /// The current outer angle of the reticle (in degrees).
    /// </summary>
    private float _reticleOuterAngle;

    /// <summary>
    /// The current distance of the reticle (in meters).
    /// </summary>
    private float _reticleDistanceInMeters;

    /// <summary>
    /// The current inner diameter of the reticle, before distance multiplication (in meters).
    /// </summary>
    private float _reticleInnerDiameter;

    /// <summary>
    /// The current outer diameter of the reticle, before distance multiplication (in meters).
    /// </summary>
    private float _reticleOuterDiameter;

    /// <summary>
    /// Start is called before the first frame update.
    /// </summary>
    private void Start()
    {
        Renderer rendererComponent = GetComponent<Renderer>();
        rendererComponent.sortingOrder = ReticleSortingOrder;

        _reticleMaterial = rendererComponent.material;

        CreateMesh();
    }

    /// <summary>
    /// Update is called once per frame.
    /// </summary>
    private void Update()
    {
        // Casts ray towards camera's forward direction, to detect if a GameObject is being gazed
        // at.
        RaycastHit hit;
        if (Physics.Raycast(transform.position, transform.forward, out hit, _RETICLE_MAX_DISTANCE))
        {
            // GameObject detected in front of the camera.
            if (_gazedAtObject != hit.transform.gameObject)
            {
                // New GameObject.
                _gazedAtObject?.SendMessage("OnPointerExit");
                _gazedAtObject = hit.transform.gameObject;
                _gazedAtObject.SendMessage("OnPointerEnter");
            }

            bool isInteractive = (1 << _gazedAtObject.layer & ReticleInteractionLayerMask) != 0;
            SetParams(hit.distance, isInteractive);
        }
        else
        {
            // No GameObject detected in front of the camera.
            _gazedAtObject?.SendMessage("OnPointerExit");
            _gazedAtObject = null;
            ResetParams();
        }

        // Checks for screen touches.
        if (Google.XR.Cardboard.Api.IsTriggerPressed)
        {
            _gazedAtObject?.SendMessage("OnPointerClick");
        }

        UpdateDiameters();
    }

    /// <summary>
    /// Updates the material based on the reticle properties.
    /// </summary>
    private void UpdateDiameters()
    {
        _reticleDistanceInMeters =
      Mathf.Clamp(_reticleDistanceInMeters, _RETICLE_MIN_DISTANCE, _RETICLE_MAX_DISTANCE);

        if (_reticleInnerAngle < _RETICLE_MIN_INNER_ANGLE)
        {
            _reticleInnerAngle = _RETICLE_MIN_INNER_ANGLE;
        }

        if (_reticleOuterAngle < _RETICLE_MIN_OUTER_ANGLE)
        {
            _reticleOuterAngle = _RETICLE_MIN_OUTER_ANGLE;
        }

        float inner_half_angle_radians = Mathf.Deg2Rad * _reticleInnerAngle * 0.5f;
        float outer_half_angle_radians = Mathf.Deg2Rad * _reticleOuterAngle * 0.5f;

        float inner_diameter = 2.0f * Mathf.Tan(inner_half_angle_radians);
        float outer_diameter = 2.0f * Mathf.Tan(outer_half_angle_radians);

        _reticleInnerDiameter = Mathf.Lerp(
            _reticleInnerDiameter, inner_diameter, Time.unscaledDeltaTime * _RETICLE_GROWTH_SPEED);
        _reticleOuterDiameter = Mathf.Lerp(
            _reticleOuterDiameter, outer_diameter, Time.unscaledDeltaTime * _RETICLE_GROWTH_SPEED);

        _reticleMaterial.SetFloat(
            "_InnerDiameter", _reticleInnerDiameter * _reticleDistanceInMeters);
        _reticleMaterial.SetFloat(
            "_OuterDiameter", _reticleOuterDiameter * _reticleDistanceInMeters);
        _reticleMaterial.SetFloat("_DistanceInMeters", _reticleDistanceInMeters);
    }

    /// <summary>
    /// Sets the reticle pointer's inner angle, outer angle and distance.
    /// </summary>
    /// <param name="distance">The distance to the target location.</param>
    /// <param name="interactive">Whether the pointer is pointing at an interactive object.</param>
    private void SetParams(float distance, bool interactive)
    {
        _reticleDistanceInMeters = Mathf.Clamp(distance,
                                              _RETICLE_MIN_DISTANCE,
                                              _RETICLE_MAX_DISTANCE);
        if (interactive)
        {
            _reticleInnerAngle = _RETICLE_MIN_INNER_ANGLE + _RETICLE_GROWTH_ANGLE;
            _reticleOuterAngle = _RETICLE_MIN_OUTER_ANGLE + _RETICLE_GROWTH_ANGLE;
        }
        else
        {
            _reticleInnerAngle = _RETICLE_MIN_INNER_ANGLE;
            _reticleOuterAngle = _RETICLE_MIN_OUTER_ANGLE;
        }
    }

    /// <summary>
    /// Exits the reticle pointer's target.
    /// </summary>
    private void ResetParams()
    {
        _reticleDistanceInMeters = _RETICLE_MAX_DISTANCE;
        _reticleInnerAngle = _RETICLE_MIN_INNER_ANGLE;
        _reticleOuterAngle = _RETICLE_MIN_OUTER_ANGLE;
    }

    /// <summary>
    /// Creates the mesh used to draw the reticle.
    /// </summary>
    private void CreateMesh()
    {
        Mesh mesh = new Mesh();
        gameObject.AddComponent<MeshFilter>();
        GetComponent<MeshFilter>().mesh = mesh;

        int segments_count = _RETICLE_SEGMENTS;
        int vertex_count = (segments_count + 1) * 2;

        // Vertices.
        Vector3[] vertices = new Vector3[vertex_count];

        const float kTwoPi = Mathf.PI * 2.0f;
        int vi = 0;
        for (int si = 0; si <= segments_count; ++si)
        {
            // Add two vertices for every circle segment: one at the beginning of the
            // prism, and one at the end of the prism.
            float angle = (float)si / (float)segments_count * kTwoPi;

            float x = Mathf.Sin(angle);
            float y = Mathf.Cos(angle);

            vertices[vi++] = new Vector3(x, y, 0.0f); // Outer vertex.
            vertices[vi++] = new Vector3(x, y, 1.0f); // Inner vertex.
        }

        // Triangles.
        int indices_count = (segments_count + 1) * 3 * 2;
        int[] indices = new int[indices_count];

        int vert = 0;
        int idx = 0;
        for (int si = 0; si < segments_count; ++si)
        {
            indices[idx++] = vert + 1;
            indices[idx++] = vert;
            indices[idx++] = vert + 2;

            indices[idx++] = vert + 1;
            indices[idx++] = vert + 2;
            indices[idx++] = vert + 3;

            vert += 2;
        }

        mesh.vertices = vertices;
        mesh.triangles = indices;
        mesh.RecalculateBounds();
    }
}
 
Back
Top