Last active
February 28, 2022 18:33
-
-
Save staggartcreations/dfe566c20f56856cc066e933c53d8966 to your computer and use it in GitHub Desktop.
World-space texel sampling in Unity
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
using System.Collections; | |
using System.Collections.Generic; | |
#if UNITY_EDITOR | |
using UnityEditor; | |
#endif | |
using UnityEngine; | |
[ExecuteInEditMode] | |
public class WorldSpaceTexel : MonoBehaviour | |
{ | |
public class WorldSpaceTexelData | |
{ | |
public Vector3 position; | |
public Color color; | |
} | |
public Texture2D texture; | |
private List<WorldSpaceTexelData> texelData = new List<WorldSpaceTexelData>(); | |
[Range(8, 128)] | |
public int samples = 32; | |
[Header("Gizmos (slow!)")] | |
public bool showSpheres = false; | |
public bool showLines = true; | |
public Bounds worldBounds; | |
public void OnEnable() | |
{ | |
//World bounds, hardcoded for a centered 1x1km test plane | |
worldBounds = new Bounds(Vector3.zero, new Vector3(1000f, 0f, 1000f)); | |
RefreshTexelData(); | |
} | |
public void RefreshTexelData() | |
{ | |
if (texture == null) | |
{ | |
texelData.Clear(); | |
return; | |
} | |
//Can't use more samples than there are texels | |
samples = Mathf.Clamp(samples, 0, texture.width); | |
texelData.Clear(); | |
int i = 0; | |
#if UNITY_EDITOR | |
EditorUtility.DisplayProgressBar(this.name, "Sampling texel", 0); | |
#endif | |
//2D loop | |
for (int x = 0; x <= samples; x++) | |
{ | |
//World-position for sample point on X-axis | |
float wPosX = x * (worldBounds.size.x / samples); | |
for (int z = 0; z <= samples; z++) | |
{ | |
//World-position for sample point on Z-axis | |
float wPosZ = z * (worldBounds.size.z / samples); | |
//Create texel data | |
WorldSpaceTexelData td = new WorldSpaceTexelData() | |
{ | |
position = new Vector3(worldBounds.min.x + wPosX, 0f,worldBounds.min.z + wPosZ), | |
color = texture.GetPixel(x * (texture.width / samples), z * (texture.height / samples)) | |
}; | |
texelData.Add(td); | |
i++; | |
} | |
i++; | |
} | |
#if UNITY_EDITOR | |
EditorUtility.ClearProgressBar(); | |
#endif | |
Debug.Log("Created " + texelData.Count + " texel samples"); | |
} | |
//Get TexelData for closest matching position | |
public WorldSpaceTexelData GetCacheData(Vector3 pos) | |
{ | |
if (texelData.Count == 0) | |
{ | |
return new WorldSpaceTexelData(); | |
} | |
float distance = 999; | |
int closestIndex = 0; | |
for (int i = 0; i < texelData.Count; i++) | |
{ | |
float d = Vector3.Distance(texelData[i].position, pos); | |
//Find position with lowest distance | |
if (d < distance) | |
{ | |
distance = d; | |
closestIndex = i; | |
} | |
} | |
return texelData[closestIndex]; | |
} | |
//Transform world-space position to position relative to bounds and texture dimensions | |
public Vector2 WorldToTexelPosition(Vector3 pos) | |
{ | |
return new Vector2( | |
((pos.x - worldBounds.min.x) / worldBounds.size.x) * texture.width, | |
((pos.z - worldBounds.min.z) / worldBounds.size.z) * texture.height | |
); | |
} | |
//Sample texel color at world-space position. Slow but accurate | |
public Color GetTexelAtPosition(Vector3 wsPos) | |
{ | |
Vector2 texelCoordinates = WorldToTexelPosition(wsPos); | |
return texture.GetPixel((int)texelCoordinates.x, (int)texelCoordinates.y); | |
} | |
private void OnDrawGizmos() | |
{ | |
if (texelData == null) return; | |
Gizmos.DrawWireCube(worldBounds.center, worldBounds.size); | |
foreach (WorldSpaceTexelData td in texelData) | |
{ | |
Gizmos.color = new Color(td.color.r, td.color.g, td.color.b, 1f); | |
if (showSpheres) Gizmos.DrawSphere(td.position, (250f / samples)); | |
//Texel color as XZ direction | |
if (showLines) Gizmos.DrawLine(td.position, td.position + (new Vector3(td.color.r, 0f, td.color.g) * (1000f / samples))); | |
} | |
} | |
} |
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
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
[ExecuteInEditMode] | |
//Test class for sampling texel data | |
public class WorldSpaceTexelSampler : MonoBehaviour | |
{ | |
public WorldSpaceTexel data; | |
public bool useCachedData = true; | |
[Header("Output")] | |
public Color texel; | |
private MeshRenderer r; | |
private void OnEnable() | |
{ | |
r = this.GetComponent<MeshRenderer>(); | |
if (!data) data = GameObject.FindObjectOfType<WorldSpaceTexel>(); | |
Sample(); | |
} | |
void Update() | |
{ | |
Sample(); | |
} | |
void Sample() | |
{ | |
if (!data) return; | |
if (useCachedData) | |
{ | |
texel = data.GetCacheData(this.transform.position).color; | |
} | |
//Realtime fetching using GetPixel, slow! | |
else | |
{ | |
texel = data.GetTexelAtPosition(this.transform.position); | |
} | |
r.sharedMaterial.color = texel; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment