Last active
September 28, 2023 18:52
-
-
Save andrew-raphael-lukasik/3a57c586017a593b6f8ba2a5b22133ff to your computer and use it in GitHub Desktop.
world point to texture coordinate + no mesh + arbitrary rotation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// void* src: https://gist.github.com/andrew-raphael-lukasik/3a57c586017a593b6f8ba2a5b22133ff | |
using UnityEngine; | |
using UnityEngine.InputSystem; | |
public class Unity3DPaint : MonoBehaviour | |
{ | |
[SerializeField][Min(4)] int _textureWidth = 64; | |
[SerializeField][Min(4)] int _textureHeight = 64; | |
[SerializeField] Vector2 _regionWorldSize = new Vector2{ x=100 , y=100 }; | |
Texture2D _texture; | |
[SerializeField] Material _dstMaterial = null; | |
#if UNITY_EDITOR | |
void OnValidate () { if( _texture!=null && ( _texture.width!=_textureWidth || _texture.height!=_textureHeight ) ) { Dispose(); CreateNewTexture(); } } | |
void OnDrawGizmos () | |
{ | |
GetAreaWorldCorners( region:_regionWorldSize , forTransform:transform , TR:out var tr , TL:out var tl , BR:out var br , BL:out var bl ); | |
Gizmos.color = Color.red; Gizmos.DrawLine(tl,tr); | |
Gizmos.color = new Color(0,1,1,1); Gizmos.DrawLine(bl,br); | |
Gizmos.color = Color.green; Gizmos.DrawLine(bl,tl); | |
Gizmos.color = new Color(1,0,1,1); Gizmos.DrawLine(br,tr); | |
} | |
#endif | |
void OnEnable () => CreateNewTexture(); | |
void OnDisable () => Dispose(); | |
void Update () | |
{ | |
var mouse = Mouse.current; | |
if( mouse!=null && mouse.leftButton.isPressed ) | |
{ | |
Vector3 origin = transform.position; | |
Vector3 normal = transform.forward; | |
var camera = Camera.main; | |
var plane = new Plane( inNormal:normal , inPoint:origin ); | |
var ray = camera.ScreenPointToRay(Input.mousePosition); | |
if( plane.Raycast(ray,out float hitDist) ) | |
{ | |
Vector3 point = ray.origin + ray.direction * hitDist; | |
bool isPointInsideRegion = PointRegionProjection( out Vector2 coord , point:point , region:_regionWorldSize , center:origin , horizontal:-transform.right , vertical:transform.up ); | |
if( isPointInsideRegion ) | |
{ | |
Debug.DrawLine( camera.transform.position , point , Color.white , 0.1f ); | |
_texture.SetPixel( (int)( _texture.width * coord.x ) , (int)( _texture.height * coord.y ) , Color.red ); | |
_texture.Apply(); | |
} | |
else Debug.DrawLine( camera.transform.position , point , Color.black , 0.1f ); | |
} | |
} | |
} | |
void CreateNewTexture () | |
{ | |
_texture = new Texture2D( width:_textureWidth , height:_textureHeight , textureFormat:TextureFormat.ARGB32 , mipCount:3 , linear:true ); | |
_texture.filterMode = FilterMode.Point;// no smooth pixels | |
_texture.SetPixel( 0 , 0 , Color.black ); | |
_texture.SetPixel( x:_texture.width-1 , y:_texture.height-1 , Color.magenta ); | |
_texture.Apply(); | |
if( _dstMaterial!=null ) _dstMaterial.mainTexture = _texture; | |
} | |
void Dispose () => Dispose( _texture ); | |
void Dispose ( Object obj ) | |
{ | |
#if UNITY_EDITOR | |
if( Application.isPlaying ) { UnityEngine.Object.Destroy( obj ); } | |
else { UnityEngine.Object.DestroyImmediate( obj ); } | |
#else | |
UnityEngine.Object.Destroy( thisObject ); | |
#endif | |
} | |
/// <summary>Projects world point onto a region of a plane with arbitrary rotation.</summary> | |
/// <returns>True when coordinate is inside given region.</returns> | |
/// <param name="coordinates">UV-type coordinates.</param> | |
/// <param name="point">World point you want to project.</param> | |
/// <param name="region">Region absolute world space size.</param> | |
/// <param name="center">Region center (world space).</param> | |
/// <param name="horizontal">Horizontal axis (world space).</param> | |
/// <param name="vertical">Vertical axis (world space).</param> | |
public static bool PointRegionProjection ( out Vector2 coordinates , Vector3 point , Vector2 region , Vector3 center , Vector3 horizontal , Vector3 vertical ) | |
{ | |
GetAreaWorldCorners( region:region , center:center , horizontal:horizontal , vertical:vertical , TR:out var TR , TL:out var TL , BR:out var BR , BL:out var BL ); | |
Vector3 pointRelativeToBLCorner = point - BL; | |
Vector3 H = Vector3.Project( vector:pointRelativeToBLCorner , onNormal:horizontal ); | |
Vector3 V = Vector3.Project( vector:pointRelativeToBLCorner , onNormal:vertical ); | |
Vector2 regionalCoords = new Vector2{ | |
x = H.magnitude * Mathf.Sign( Vector3.Dot(H,horizontal) ) , | |
y = V.magnitude * Mathf.Sign( Vector3.Dot(V,vertical) ) | |
}; | |
coordinates = regionalCoords / region; | |
return( coordinates.x>0 && coordinates.y>0 && coordinates.x<1f && coordinates.y<1f ); | |
} | |
/// <param name="region">Region absolute world space size.</param> | |
/// <param name="center">Region center (world space).</param> | |
/// <param name="horizontal">Horizontal axis (world space).</param> | |
/// <param name="vertical">Vertical axis (world space).</param> | |
/// <param name="TR">Top-right corner (world space).</param> | |
/// <param name="TL">Top-left corner (world space).</param> | |
/// <param name="BR">Bottom-right corner (world space).</param> | |
/// <param name="BL">Bottom-left corner (world space).</param> | |
public static void GetAreaWorldCorners ( | |
Vector2 region , | |
Vector3 center , Vector3 horizontal , Vector3 vertical , | |
out Vector3 TR , out Vector3 TL , out Vector3 BR , out Vector3 BL | |
) | |
{ | |
horizontal = horizontal.normalized; | |
vertical = vertical.normalized; | |
Vector3 horizontalExtent = horizontal * region.x * 0.5f; | |
Vector3 verticalExtent = vertical * region.y * 0.5f; | |
TR = center + horizontalExtent + verticalExtent; | |
TL = center + -horizontalExtent + verticalExtent; | |
BR = center + horizontalExtent + -verticalExtent; | |
BL = center + -horizontalExtent + -verticalExtent; | |
} | |
/// <inheritdoc/> | |
/// <param name="forTransform">Transform to source <paramref name="center"/>, <paramref name="horizontal"/> and <paramref name="vertical"/> values from.</param> | |
public static void GetAreaWorldCorners ( | |
Vector2 region , | |
Transform forTransform , | |
out Vector3 TR , out Vector3 TL , out Vector3 BR , out Vector3 BL | |
) | |
{ | |
Vector3 center = forTransform.position; | |
Vector3 left = -forTransform.right; | |
Vector3 up = forTransform.up; | |
GetAreaWorldCorners( region:region , center:center , horizontal:left , vertical:up , TR:out TR , TL:out TL , BR:out BR , BL:out BL ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment