Hello again. I have made some progress with the conversion from face-vertex-indices to point-indices.
I multiplied the QFaceIndex by 3 in wp.mesh_get_index() and took the new result value OutputPointIndex[tid] to wp.mesh_get_point(). However, the result outputted from wp.mesh_get_point() still points to a wrong location.
As a test, I created a linear comparison kernel LinearCompVert to compare InputCoordinate to each mesh point and find the closest mesh point’s index.
That’s when I noticed that the result OutputPointIndex[tid] outputted from wp.mesh_get_index() contains point-indices that matches the result from LinearCompVert.
Turns out I got the correct point-indices after multiplying QFaceIndex by 3 in wp.mesh_get_index(), but then wp.mesh_get_point() gave me a wrong location even with the correct point-indices. (Reason why remains unknown to me, but at this point the wp.mesh_get_point() function is no longer of use.)
By putting the new point-indices into InputMeshPoint, I managed to get 3 positions convincingly close to each InputCoordinate.
The 3 positions in each InputCoordinate contains one that is verified to be the closest point possible, using LinearCompVert.
At this point, the number of points to compare is small enough, I decided to use numpy.argmin() to find the closest point’s index out of the 3 positions.
Since the point dataset is constructed to correspond with the mesh point, I can extract the dataset value of the closest points using the same indices I just found.
With that, the program achieved its purpose. I can continue writing the script to extract the point dataset value using the stored assigned index in each InputCoordinates prim for each tick, and run the Query Kernel again whenever there’s a change to the position of InputCoordinates.
I’ll post the cleaned-up code here as reference for anyone that comes across the same problem:
import warp as wp
import numpy as np
import math
import logging
from pxr import Usd, Sdf, Gf
import omni.usd
from typing import Union
# Main Query Kernel
@wp.kernel
def PlayerFunction( InputIdentifier: wp.uint64,
InputCoordinates: wp.array(dtype=wp.vec3),
InputMeshPoints: wp.array(dtype=wp.vec3),
QueryPointIndex: wp.array(dtype=int, ndim=2),
QueryPointPos: wp.array(dtype=wp.vec3, ndim=2),
QueryPointDist: wp.array(dtype=wp.float32, ndim=2)):
tid = wp.tid()
QCoord = InputCoordinates[tid]
QFaceIndex = wp.int(0)
QUCoord = wp.float(0)
QVCoord = wp.float(0)
Result = wp.mesh_query_point_no_sign(InputIdentifier, QCoord, wp.float32(50), QFaceIndex, QUCoord, QVCoord)
if(Result):
QueryPointIndex[tid][0] = wp.mesh_get_index(InputIdentifier, QFaceIndex*3)
QueryPointIndex[tid][1] = wp.mesh_get_index(InputIdentifier, QFaceIndex*3 + 1)
QueryPointIndex[tid][2] = wp.mesh_get_index(InputIdentifier, QFaceIndex*3 + 2)
QueryPointPos[tid][0] = InputMeshPoints[QueryPointIndex[tid][0]]
QueryPointPos[tid][1] = InputMeshPoints[QueryPointIndex[tid][1]]
QueryPointPos[tid][2] = InputMeshPoints[QueryPointIndex[tid][2]]
QueryPointDist[tid][0] = wp.length(QueryPointPos[tid][0] - QCoord)
QueryPointDist[tid][1] = wp.length(QueryPointPos[tid][1] - QCoord)
QueryPointDist[tid][2] = wp.length(QueryPointPos[tid][2] - QCoord)
else:
QueryPointIndex[tid][0] = -1
QueryPointIndex[tid][1] = -1
QueryPointIndex[tid][2] = -1
# Initialization, warp mesh generation and getting arrow prim
def GenerateWarpMesh(func_InputPoints, func_InputIndices):
WarpPoints = wp.array(func_InputPoints, dtype=wp.vec3f)
WarpIndices = wp.array(func_InputIndices, dtype=wp.int32).flatten()
return wp.Mesh(WarpPoints, WarpIndices)
def GetArrowGroup(func_InputArrowGroupParent):
CurrentStage = omni.usd.get_context().get_stage()
InputArrowGroupPrim = CurrentStage.GetPrimAtPath(func_InputArrowGroupParent)
return InputArrowGroupPrim.GetAllChildren()
def GetArrowCoord(func_InputArrowGroup):
func_ArrowCoords = []
for i, InputArrowGroupIndex in enumerate(func_InputArrowGroup):
func_ArrowCoords.append(InputArrowGroupIndex.GetAttribute("xformOp:translate").Get())
return func_ArrowCoords
# ----------
# Some other functions...
# ----------
def compute(db: og.Database):
logger = logging.getLogger(__name__)
InputGeomPoints = db.inputs.InputMeshPoints
InputArrowGroup = GetArrowGroup(db.inputs.InputArrowGroupParent)
ArrowCoords = GetArrowCoord(InputArrowGroup)
WarpMesh = GenerateWarpMesh(db.inputs.InputMeshPoints, db.inputs.InputMeshIndices)
logger.info("compute: Warp Mesh generated")
WarpMeshID = WarpMesh.id
WarpCoords = wp.array(ArrowCoords, dtype=wp.vec3)
WarpMeshPoint = wp.array(db.inputs.InputMeshPoints, dtype=wp.vec3)
WarpPointIndex = wp.zeros(shape=(len(WarpCoords), 3), dtype=int)
WarpPointPos = wp.array(shape=(len(WarpCoords), 3), dtype=wp.vec3)
WarpPointDist = wp.array(shape=(len(WarpCoords), 3), dtype=wp.float32)
# launch kernel
wp.launch(kernel=PlayerFunction,
dim=len(WarpCoords),
inputs=[WarpMeshID, WarpCoords, WarpMeshPoint, WarpPointIndex, WarpPointPos, WarpPointDist])
logger.info("compute, warp result.")
for i in range(len(ArrowCoords)):
logger.info("Arrow " + str(i) + " at " + str(ArrowCoords[i]))
for j in range(3):
logger.info("Point Index: " + str(WarpPointIndex.numpy()[i][j]) + ". Distance " + str(WarpPointDist.numpy()[i][j]) + " at " + str(db.inputs.InputMeshPoints[WarpPointIndex.numpy()[i][j]]))
logger.info("----------")
ClosestPointIndex = []
ClosestPointPos = []
logger.info("ClosestIndex: ")
for i in range(len(WarpPointDist)):
func_DistClosestIndex = np.argmin(WarpPointDist.numpy()[i])
func_AssignedIndex = WarpPointIndex.numpy()[i][func_DistClosestIndex]
ClosestPointIndex.append(func_AssignedIndex)
ClosestPointPos.append(db.inputs.InputMeshPoints[func_AssignedIndex])
logger.info("Arrow " + str(i) + " at position " + str(ArrowCoords[i]))
logger.info(str(ClosestPointIndex[i]) + " at position" + str(ClosestPointPos[i]))
logger.info("----------")
And the Linear Comparison test kernel, in case you’re also looking for fool-proof method of finding the closest mesh point:
@wp.kernel
def LinearCompVert( InputIdentifier: wp.uint64,
InputCoordinates: wp.array(dtype=wp.vec3),
InputPointCoordinates: wp.array(dtype=wp.vec3),
OutputDistance: wp.array(dtype=wp.float32, ndim=2)):
tidArrow, tidPoint = wp.tid()
OutputDistance[tidArrow, tidPoint] = wp.length(InputPointCoordinates[tidPoint] - InputCoordinates[tidArrow])
# Paste the code below in compute
LCV_WarpInputMeshPoint = wp.array(db.inputs.InputMeshPoints, dtype=wp.vec3)
LCV_WarpOutputDistance = wp.zeros(shape=(len(ArrowCoords), len(LCV_WarpInputMeshPoint)), dtype=wp.float32)
LCV_WarpOutputDistance.fill_(9999.9)
wp.launch(kernel=LinearCompVert,
dim=(len(ArrowCoords), len(LCV_WarpInputMeshPoint)),
inputs=[WarpMeshID, WarpCoords, LCV_WarpInputMeshPoint, LCV_WarpOutputDistance],
device="cuda")
LCV_ClosestDistance = []
LCV_ClosestIndex = []
LCV_ClosestPointPosition = []
logger.info("compute, LinearCompVert")
for Index in LCV_WarpOutputDistance.numpy():
LCV_ClosestDistance.append(min(Index))
func_Index = np.argmin(Index)
LCV_ClosestIndex.append(func_Index)
LCV_ClosestPointPosition.append(db.inputs.InputMeshPoints[func_Index])
for i, ArrowIndex in enumerate(ArrowCoords):
logger.info("Arrow " + str(i) + " at " + str(np.round(WarpCoords.numpy()[i], 2)))
logger.info("Index: " + str(LCV_ClosestIndex[i]) + ", Distance " + str(LCV_ClosestDistance[i]) + " at position " + str(np.round(LCV_ClosestPointPosition[i], 2)))
logger.info("----------")
There are many improvements that can be made, such as interpolation between mesh points and their corresponding point dataset value, or that I haven’t yet implemented passing WarpMesh from setup() to compute(), or for some reason wp.argmin(QueryPointDist[tid]) in the kernel shows an error saying "array has no attribute ‘name’ ". But I can do that later and update here; or create a new topic in the forum. Of course I’m still open for any new insights.
Much appreciated for the help.