- Home /
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!
Answer by bigvalthoss · Feb 24, 2021 at 08:58 PM
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 :)
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;
}
@$$anonymous$$o-Khaon I have a dataset that is 512 x 256 x 512. It can be resized, is there any way you could think to find the voxel index from a world position (if it is inside the object).
@whydoidoit Do you have any input on this question?
Answer by Eno-Khaon · Feb 28, 2021 at 08:23 PM
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;
}
Thank you very much for the answer, I think your way would probably work. however, I am having trouble co$$anonymous$$g up with finding the scaling factor and the offset. Would you be able to help me out with that? dim[0-2] are the dimensions of the dataset. The current one I'm using is 512 x 256 x 512.
Here is how the local scale is defined:
this.transform.localScale = new Vector3(mhdheader.spacing[0] volScale, mhdheader.spacing[1] volScale dim[1] / dim[0], mhdheader.spacing[2] volScale * dim[2] / dim[0]);
Would I just create my offset by doing:
Vector3 localPos = transform.InverseTransformPoint(worldPos);
Vector3 localScale = gameObject.transform.localScale;
Vector3 OffsetPos = localPos + localScale / 2;
And then I need to find what to scale it by, which is causing me a little grief as well...
In general, the scaling factor and offset don't really need to be tracked using a dual system. While you could have something like...
Vector3 scale = transform.localScale * myScale;
Vector3 offset = localPos + Vector3.Scale(scale, myOffset);
... that's actually not very valuable to have a mishmash of your own script's values *AND* Transform attributes.
However, that's why I offer the suggestion of perfor$$anonymous$$g all transformations using just the Transform data of the containing GameObject. That way, voxel[0,0,0] would be located at the local (0, 0, 0) of the Transform. Then, if you want, say, 5 voxels per unit/meter/etc., you'd just have something like:
transform.localScale = Vector3.one / 5.0f;
By contrast, if you wanted to ignore the GameObject's Transform data entirely (which a Renderer wouldn't love, in terms of position relative to object origin), then you'd want to place the GameObject at Vector3.zero position, Quaternion.identity rotation, and Vector3.one scale.
That really would defeat the purpose of having Transform data to begin with, though, and would actually be a hindrance (at best).
Basically, if you just store values for your scale, position, and rotation, then apply those to the Transform, that's all you need to do. The rest just depends on how you want to store that data for use.
// voxel grid position is stored as world position
transform.position = voxelGridWorldPos;
// alternate: voxel grid position is stored in small integer form
// Vector3 voxelGridSize: (512x512x256)
// Vector3Int voxelGridPos: (i.e. (5, -2, 0))
transform.position = Vector3.Scale(voxelGridSize * voxelScale, voxelGridPos);
// voxel grid position is stored as Quaternion
transform.rotation = voxelGridRot;
// alternate: rotation is stored as XYZ Euler values
transform.rotation = Quaternion.Euler(vgrX, vgrY, vgrZ);
// voxel grid scale is a single value for uniform scaling
transform.localScale = Vector3.one * voxelScale;
// alternate: voxel grid scale is stored directly as a Vector3
transform.localScale = voxelScaleVector3;
// alternate: scale is stored as 3 axis scalars
transform.localScale = new Vector3(scaleX, scaleY, scaleZ);
// alternate: scale is stored as voxels-per-unit (Vector3 example)
transform.localScale = new Vector3(1f / vpu.x, 1f / vpu.y, 1f / vpu.z);
Would it be at all possible to like call over google meet about this? I don't think I entirely follow... It would help a lot