Search Unity

Question Drawing Board with Line renderer and XRITK

Discussion in 'Scripting' started by mquenumsia, Feb 21, 2024.

  1. mquenumsia

    mquenumsia

    Joined:
    Mar 7, 2023
    Posts:
    2
    Hello,
    I'm implementing a drawing board in VR, taking inspiration from this tutorial https://immersive-insiders.com/blog/oculus-hand-interaction-drawing-in-vr. I've done some modifications/optimization and came down to this for the marker:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class InkGenerator : MonoBehaviour
    6. {
    7.     // Variable to store the prefab for the ink
    8.     [SerializeField] private GameObject inkPrefab;
    9.     // Variable to store the transform of the pencil
    10.     [SerializeField] private Transform pencilTransform;
    11.     // Variable to store the transform of the paper
    12.     [SerializeField] private Transform paperTransform;
    13.     // Variable to store the offset of the pencil
    14.     [SerializeField] private Vector3 pencilOffset;
    15.     // Variable to store the parent transform for the ink objects
    16.     [SerializeField] private Transform parent;
    17.  
    18.     // Variable to store the InkTracer component
    19.     private InkTracer ink;
    20.     // Variable to keep track of whether the player is touching the whiteboard
    21.     private bool isTouching = false;
    22.     // Variable to store the newly created ink object
    23.     private GameObject newInk = null;
    24.     // Coroutine for generating ink
    25.     private Coroutine generateInkCoroutine;
    26.  
    27.     // Called when another collider enters this object's trigger zone
    28.     private void OnTriggerEnter(Collider otherObject)
    29.     {
    30.         // Check if the other collider has the tag "Whiteboard"
    31.         if (otherObject.CompareTag("Whiteboard"))
    32.         {
    33.             // Set isTouching to true
    34.             isTouching = true;
    35.             // Start the coroutine to generate ink
    36.             generateInkCoroutine = StartCoroutine(GenerateInk());
    37.         }
    38.     }
    39.  
    40.     // Called when another collider exits this object's trigger zone
    41.     private void OnTriggerExit(Collider otherObject)
    42.     {
    43.         // Check if the other collider has the tag "Whiteboard"
    44.         if (otherObject.CompareTag("Whiteboard"))
    45.         {
    46.             // Set isTouching to false
    47.             isTouching = false;
    48.             // Check if there is a new ink object
    49.             if (newInk != null)
    50.             {
    51.                 // Stop the coroutine for generating ink
    52.                 StopCoroutine(generateInkCoroutine);
    53.                 // Set newInk to null
    54.                 newInk = null;
    55.             }
    56.         }
    57.     }
    58.  
    59.     // Coroutine for generating ink
    60.     private IEnumerator GenerateInk()
    61.     {
    62.         // Continue looping while the player is touching the whiteboard
    63.         while (isTouching)
    64.         {
    65.             // Check if there is no new ink object
    66.             if (newInk == null)
    67.             {
    68.                 // Instantiate a new ink object from the prefab
    69.                 newInk = Instantiate(inkPrefab);
    70.                 // Get the InkTracer component from the new ink object
    71.                 ink = newInk.GetComponent<InkTracer>();
    72.             }
    73.  
    74.             // Check if there is a new ink object
    75.             if (newInk != null)
    76.             {
    77.                 // Calculate the position for the ink based on the pencil and paper positions, and the pencil offset
    78.                 Vector3 pos = new Vector3(pencilTransform.position.x, paperTransform.position.y, pencilTransform.position.z);
    79.                 // Update the line renderer of the ink with the calculated position
    80.                 ink.UpdateLineRenderer(pos + pencilOffset);
    81.             }
    82.  
    83.             // Wait for the next frame
    84.             yield return null;
    85.         }
    86.     }
    87. }
    88.  
    and this for the ink component that is instantiated everytime the marker collider is triggered, hence creating a line at the given position:
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using System.Linq;
    4.  
    5. [RequireComponent(typeof(LineRenderer))]
    6. public class InkTracer : MonoBehaviour
    7. {
    8.     // Variable to store the LineRenderer component
    9.     private LineRenderer lineRenderer = null;
    10.     // List to store the points of the ink stroke
    11.     private List<Vector3> points = new List<Vector3>();
    12.     // Threshold for determining if a new point should be added to the line renderer
    13.     [SerializeField] private float drawingThreshold = 0.001f;
    14.  
    15.     // Called when the object is initialized
    16.     private void Awake()
    17.     {
    18.         // Get the LineRenderer component attached to this object
    19.         lineRenderer = GetComponent<LineRenderer>();
    20.     }
    21.  
    22.     // Method to update the LineRenderer with a new position
    23.     public void UpdateLineRenderer(Vector3 newPosition)
    24.     {
    25.         // Debug.Log(newPosition);
    26.         // Check if adding a new point is required based on the drawing threshold
    27.         if (IsUpdateRequired(newPosition))
    28.         {
    29.             // Add the new position to the list of points
    30.             points.Add(newPosition);
    31.             // Set the position count of the LineRenderer to match the number of points
    32.             lineRenderer.positionCount = points.Count;
    33.             // Set the position of the last added point in the LineRenderer
    34.             lineRenderer.SetPosition(points.Count - 1, newPosition);
    35.         }
    36.     }
    37.  
    38.     // Method to determine if adding a new point is required based on the drawing threshold
    39.     private bool IsUpdateRequired(Vector3 position)
    40.     {
    41.         // Check if there are no points yet
    42.         if (points.Count == 0)
    43.             return true;
    44.         // Check if the distance between the last point and the new position is greater than the drawing threshold
    45.         return Vector3.Distance(points.Last(), position) > drawingThreshold;
    46.     }
    47. }
    Attached is my Line Renderer component setup.

    Right now, everytime i try to draw, the drawing is like squished in front of the board, instead of in front of and facing me, like when writing on a real board.
    Here is a video showing the result:

    I don't really know what is wrong here, so any help would be much appreciated. Thanks !
     

    Attached Files:

  2. Luke3671

    Luke3671

    Joined:
    Jul 6, 2014
    Posts:
    56
    Try
    InkGenerator Script:
    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3.  
    4. public class InkGenerator : MonoBehaviour
    5. {
    6.     [SerializeField] private GameObject inkPrefab; // Variable to store the prefab for the ink
    7.     [SerializeField] private Transform pencilTransform; // Variable to store the transform of the pencil
    8.     [SerializeField] private Transform paperTransform; // Variable to store the transform of the paper
    9.     [SerializeField] private Vector3 pencilOffset; // Variable to store the offset of the pencil
    10.     [SerializeField] private Transform parent; // Variable to store the parent transform for the ink objects
    11.  
    12.     private InkTracer ink; // Variable to store the InkTracer component
    13.     private bool isTouching = false; // Variable to keep track of whether the player is touching the whiteboard
    14.     private GameObject newInk = null; // Variable to store the newly created ink object
    15.     private Coroutine generateInkCoroutine; // Coroutine for generating ink
    16.  
    17.     private void OnTriggerEnter(Collider otherObject)
    18.     {
    19.         if (otherObject.CompareTag("Whiteboard"))
    20.         {
    21.             isTouching = true; // Set isTouching to true
    22.             generateInkCoroutine = StartCoroutine(GenerateInk()); // Start the coroutine to generate ink
    23.         }
    24.     }
    25.  
    26.     private void OnTriggerExit(Collider otherObject)
    27.     {
    28.         if (otherObject.CompareTag("Whiteboard"))
    29.         {
    30.             isTouching = false; // Set isTouching to false
    31.             if (newInk != null)
    32.             {
    33.                 StopCoroutine(generateInkCoroutine); // Stop the coroutine for generating ink
    34.                 newInk = null; // Set newInk to null
    35.             }
    36.         }
    37.     }
    38.  
    39.     private IEnumerator GenerateInk()
    40.     {
    41.         while (isTouching)
    42.         {
    43.             if (newInk == null)
    44.             {
    45.                 newInk = Instantiate(inkPrefab, parent); // Instantiate ink as child of parent
    46.                 ink = newInk.GetComponent<InkTracer>(); // Get the InkTracer component from the new ink object
    47.             }
    48.  
    49.             if (newInk != null)
    50.             {
    51.                 Vector3 pos = paperTransform.position + pencilTransform.forward * 0.1f; // Calculate ink position based on paper and pencil orientation
    52.                 ink.UpdateLineRenderer(pos + pencilOffset); // Update the line renderer of the ink with the calculated position
    53.             }
    54.  
    55.             yield return null;
    56.         }
    57.     }
    58. }
    59.  
    Moved the comment "// Instantiate ink as child of parent" to indicate the addition of instantiating the ink as a child of the parent object.
    • Moved the comment "// Instantiate ink as child of parent" to indicate the addition of instantiating the ink as a child of the parent object.

    • Added the comment "// Calculate ink position based on paper and pencil orientation" to clarify the calculation of the ink position based on the paper and pencil orientations

    InkTracer Script
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. [RequireComponent(typeof(LineRenderer))]
    5. public class InkTracer : MonoBehaviour
    6. {
    7.     private LineRenderer lineRenderer = null; // Variable to store the LineRenderer component
    8.     private List<Vector3> points = new List<Vector3>(); // List to store the points of the ink stroke
    9.     [SerializeField] private float drawingThreshold = 0.001f; // Threshold for determining if a new point should be added to the line renderer
    10.  
    11.     private void Awake()
    12.     {
    13.         lineRenderer = GetComponent<LineRenderer>(); // Get the LineRenderer component attached to this object
    14.     }
    15.  
    16.     public void UpdateLineRenderer(Vector3 newPosition)
    17.     {
    18.         if (IsUpdateRequired(newPosition)) // Check if adding a new point is required based on the drawing threshold
    19.         {
    20.             points.Add(newPosition); // Add the new position to the list of points
    21.             lineRenderer.positionCount = points.Count; // Set the position count of the LineRenderer to match the number of points
    22.             lineRenderer.SetPosition(points.Count - 1, newPosition); // Set the position of the last added point in the LineRenderer
    23.         }
    24.     }
    25.  
    26.     private bool IsUpdateRequired(Vector3 position)
    27.     {
    28.         if (points.Count == 0)
    29.             return true; // Check if there are no points yet
    30.         return Vector3.Distance(points[points.Count - 1], position) > drawingThreshold; // Check if the distance between the last point and the new position is greater than the drawing threshold
    31.     }
    32. }
    33.  
     
  3. mquenumsia

    mquenumsia

    Joined:
    Mar 7, 2023
    Posts:
    2
    Thanks ! I've tried your solution, but it still seems that there a miscalculation somewhere. I was thinking that i should maybe get the contact points transform when colliding on the board and use them to update the Line Renderer component... Have to give it a try but do you think it could work ? I'm open to any suggestion !