Get Voxel Intensities by location

I’m wondering if it’s possible to get the voxel value at a given position? Here is the code used to fill the voxels:

for (int k = 0; k < NumberOfFrames; k++) {
			string fname_ = "T" + k.ToString("D2");
			Color[] colors = LoadData(Path.Combine (imageDir, fname_+".raw"));
			_volumeBuffer.Add (new Texture3D (dim [0], dim [1], dim [2], TextureFormat.RGBAHalf, mipmap));

			_volumeBuffer[k].SetPixels(colors);
			_volumeBuffer [k].Apply ();
		}

        GetComponent<Renderer>().material.SetTexture("_Data", _volumeBuffer[0]);

Does anybody know how to get a value at a given position in space??

Thanks!

Took me a little bit, but I’ve figured it out I think. If there is a flaw in my coding, please let me know :slight_smile:

public Vector3Int GetIndexFromWorld(Vector3 worldPos)
    {
        Vector3 deltaBounds = rend.bounds.max - rend.bounds.min;
        Vector3 OffsetPos = worldPos - rend.bounds.min;
        Vector3 normPos = new Vector3(OffsetPos[0] / deltaBounds[0], OffsetPos[1] / deltaBounds[1], OffsetPos[2] / deltaBounds[2]);

        Vector3 voxelPositions = new Vector3(normPos[0] * voxelDims[0], normPos[1] * voxelDims[1], normPos[2] * voxelDims[2]);

        Vector3Int voxelPos = Vector3Int.FloorToInt(voxelPositions);
        return voxelPos;
    }

Since you’re using transform.InverseTransformPoint() to transform a point from world to local space, the most straightforward way to position voxels “physically” is to place them at their absolute positions relative to the GameObject (i.e. (0, 0, 0), (15, 98, 17), etc.) so that their positions can inherently be used as-is when converted to 3-dimensional array indices. (Note that this may also call for Mathf.RoundToInt() or Mathf.FloorToInt() usage, depending on how coordinates are used and whether anything like 0.5 offsets would be applied to positions to “center” the voxels)

If any repositioning or scaling is also applied to the voxels at the construction level (ideally, rotation should be a Transform-only modification), then a given block of voxel data would also need its own scaling factor(s) and position offset data.

// Reformatting your function as an example
public Vector3Int GetIndexFromWorld(Vector3 worldPos)
{
	Vector3 localPos = transform.InverseTransformPoint(worldPos);
	
	// If further scaling needs to be done:
	// Where scaleFactor is voxels-per-unit...
	// Scale is a Vector3
	localPos = Vector3.Scale(localPos, scaleFactor);
	// Scale is a float/int
	localPos *= scaleFactor;
	
	// voxelOffset would be a factor when the voxel-grid doesn't begin
	// at (0, 0, 0) of its containing GameObject/Mesh
	Vector3Int voxelPos = Vector3Int.FloorToInt(localPos + voxelOffset);
	
	// Using FloorToInt() on the assumption that there IS NOT an additional
	// 0.5-voxel offset baked in that's not part of the main offset
	// If there was, RoundToInt() would be the better choice here
	
	return voxelPos;
}

All in all, the kinds of modifications that need to be applied are really just based on whether (and how) you want to pack additional data in. If you performed ALL transformations to the voxel data using the GameObject's Transform data instead, your function would look more like this:

public Vector3Int GetIndexFromWorld(Vector3 worldPos)
{
	Vector3 localPos = transform.InverseTransformPoint(worldPos);
	Vector3Int voxelPos = Vector3Int.FloorToInt(localPos);
	return voxelPos;
}