Hello,
I’m implementing a drawing board in VR, taking inspiration from this tutorial Oculus Hand Interaction: Drawing in VR. I’ve done some modifications/optimization and came down to this for the marker:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InkGenerator : MonoBehaviour
{
// Variable to store the prefab for the ink
[SerializeField] private GameObject inkPrefab;
// Variable to store the transform of the pencil
[SerializeField] private Transform pencilTransform;
// Variable to store the transform of the paper
[SerializeField] private Transform paperTransform;
// Variable to store the offset of the pencil
[SerializeField] private Vector3 pencilOffset;
// Variable to store the parent transform for the ink objects
[SerializeField] private Transform parent;
// Variable to store the InkTracer component
private InkTracer ink;
// Variable to keep track of whether the player is touching the whiteboard
private bool isTouching = false;
// Variable to store the newly created ink object
private GameObject newInk = null;
// Coroutine for generating ink
private Coroutine generateInkCoroutine;
// Called when another collider enters this object's trigger zone
private void OnTriggerEnter(Collider otherObject)
{
// Check if the other collider has the tag "Whiteboard"
if (otherObject.CompareTag("Whiteboard"))
{
// Set isTouching to true
isTouching = true;
// Start the coroutine to generate ink
generateInkCoroutine = StartCoroutine(GenerateInk());
}
}
// Called when another collider exits this object's trigger zone
private void OnTriggerExit(Collider otherObject)
{
// Check if the other collider has the tag "Whiteboard"
if (otherObject.CompareTag("Whiteboard"))
{
// Set isTouching to false
isTouching = false;
// Check if there is a new ink object
if (newInk != null)
{
// Stop the coroutine for generating ink
StopCoroutine(generateInkCoroutine);
// Set newInk to null
newInk = null;
}
}
}
// Coroutine for generating ink
private IEnumerator GenerateInk()
{
// Continue looping while the player is touching the whiteboard
while (isTouching)
{
// Check if there is no new ink object
if (newInk == null)
{
// Instantiate a new ink object from the prefab
newInk = Instantiate(inkPrefab);
// Get the InkTracer component from the new ink object
ink = newInk.GetComponent<InkTracer>();
}
// Check if there is a new ink object
if (newInk != null)
{
// Calculate the position for the ink based on the pencil and paper positions, and the pencil offset
Vector3 pos = new Vector3(pencilTransform.position.x, paperTransform.position.y, pencilTransform.position.z);
// Update the line renderer of the ink with the calculated position
ink.UpdateLineRenderer(pos + pencilOffset);
}
// Wait for the next frame
yield return null;
}
}
}
and this for the ink component that is instantiated everytime the marker collider is triggered, hence creating a line at the given position:
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
[RequireComponent(typeof(LineRenderer))]
public class InkTracer : MonoBehaviour
{
// Variable to store the LineRenderer component
private LineRenderer lineRenderer = null;
// List to store the points of the ink stroke
private List<Vector3> points = new List<Vector3>();
// Threshold for determining if a new point should be added to the line renderer
[SerializeField] private float drawingThreshold = 0.001f;
// Called when the object is initialized
private void Awake()
{
// Get the LineRenderer component attached to this object
lineRenderer = GetComponent<LineRenderer>();
}
// Method to update the LineRenderer with a new position
public void UpdateLineRenderer(Vector3 newPosition)
{
// Debug.Log(newPosition);
// Check if adding a new point is required based on the drawing threshold
if (IsUpdateRequired(newPosition))
{
// Add the new position to the list of points
points.Add(newPosition);
// Set the position count of the LineRenderer to match the number of points
lineRenderer.positionCount = points.Count;
// Set the position of the last added point in the LineRenderer
lineRenderer.SetPosition(points.Count - 1, newPosition);
}
}
// Method to determine if adding a new point is required based on the drawing threshold
private bool IsUpdateRequired(Vector3 position)
{
// Check if there are no points yet
if (points.Count == 0)
return true;
// Check if the distance between the last point and the new position is greater than the drawing threshold
return Vector3.Distance(points.Last(), position) > drawingThreshold;
}
}
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 !
```csharp
**using System.Collections;
using UnityEngine;
public class InkGenerator : MonoBehaviour
{
[SerializeField] private GameObject inkPrefab; // Variable to store the prefab for the ink
[SerializeField] private Transform pencilTransform; // Variable to store the transform of the pencil
[SerializeField] private Transform paperTransform; // Variable to store the transform of the paper
[SerializeField] private Vector3 pencilOffset; // Variable to store the offset of the pencil
[SerializeField] private Transform parent; // Variable to store the parent transform for the ink objects
private InkTracer ink; // Variable to store the InkTracer component
private bool isTouching = false; // Variable to keep track of whether the player is touching the whiteboard
private GameObject newInk = null; // Variable to store the newly created ink object
private Coroutine generateInkCoroutine; // Coroutine for generating ink
private void OnTriggerEnter(Collider otherObject)
{
if (otherObject.CompareTag("Whiteboard"))
{
isTouching = true; // Set isTouching to true
generateInkCoroutine = StartCoroutine(GenerateInk()); // Start the coroutine to generate ink
}
}
private void OnTriggerExit(Collider otherObject)
{
if (otherObject.CompareTag("Whiteboard"))
{
isTouching = false; // Set isTouching to false
if (newInk != null)
{
StopCoroutine(generateInkCoroutine); // Stop the coroutine for generating ink
newInk = null; // Set newInk to null
}
}
}
private IEnumerator GenerateInk()
{
while (isTouching)
{
if (newInk == null)
{
newInk = Instantiate(inkPrefab, parent); // Instantiate ink as child of parent
ink = newInk.GetComponent<InkTracer>(); // Get the InkTracer component from the new ink object
}
if (newInk != null)
{
Vector3 pos = paperTransform.position + pencilTransform.forward * 0.1f; // Calculate ink position based on paper and pencil orientation
ink.UpdateLineRenderer(pos + pencilOffset); // Update the line renderer of the ink with the calculated position
}
yield return null;
}
}
}** ``` 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
```csharp
**using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(LineRenderer))]
public class InkTracer : MonoBehaviour
{
private LineRenderer lineRenderer = null; // Variable to store the LineRenderer component
private List points = new List(); // List to store the points of the ink stroke
[SerializeField] private float drawingThreshold = 0.001f; // Threshold for determining if a new point should be added to the line renderer
private void Awake()
{
lineRenderer = GetComponent<LineRenderer>(); // Get the LineRenderer component attached to this object
}
public void UpdateLineRenderer(Vector3 newPosition)
{
if (IsUpdateRequired(newPosition)) // Check if adding a new point is required based on the drawing threshold
{
points.Add(newPosition); // Add the new position to the list of points
lineRenderer.positionCount = points.Count; // Set the position count of the LineRenderer to match the number of points
lineRenderer.SetPosition(points.Count - 1, newPosition); // Set the position of the last added point in the LineRenderer
}
}
private bool IsUpdateRequired(Vector3 position)
{
if (points.Count == 0)
return true; // Check if there are no points yet
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
}
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 !