25-05-2021, 01:55 PM
(This post was last modified: 25-05-2021, 02:06 PM by josemendez.)
(21-05-2021, 03:45 PM)Hatchling Wrote: Could you please write a simple script that shows how it'd be used?
The following code is already functional in the development version:
Code:
using UnityEngine;
using Obi;
[RequireComponent(typeof(ObiSolver))]
public class QueryTests : MonoBehaviour
{
ObiSolver solver;
ObiNativeQueryShapeList queries;
ObiNativeAffineTransformList transforms;
ObiNativeContactShapeList results;
void Start()
{
solver = GetComponent<ObiSolver>();
queries = new ObiNativeQueryShapeList();
transforms = new ObiNativeAffineTransformList();
results = new ObiNativeContactShapeList();
queries.Add(new QueryShape()
{
type = QueryShape.QueryType.Box,
center = Vector3.zero,
size = new Vector3(2, 1, 1),
contactOffset = 0.01,
distance = 1,
filter = ObiUtils.MakeFilter(ObiUtils.CollideWithEverything, 0)
});
transforms.Add(new AffineTransform(Vector4.zero,Quaternion.identity,Vector4.one));
}
private void OnDestroy()
{
queries.Dispose();
transforms.Dispose();
results.Dispose();
}
void Update()
{
// perform query
solver.SpatialQuery(queries,transforms, results);
// draw results:
for (int i = 0; i < results.count; ++i)
{
Debug.DrawRay(solver.transform.TransformPoint(results[i].pointB),
solver.transform.TransformVector(results[i].normal * results[i].distance), Color.red);
}
}
}
For query results, I'm currently reusing the same struct used for contacts. Many of its fields are unused, so I'll write a leaner struct with only what's needed by the query.
(21-05-2021, 03:45 PM)Hatchling Wrote: Judging from what I understand so far, I'd recommend allowing a list to be provided for query results. I know you could just use a really huge array. But I understand if this could possibly mess up some sort of optimization or simplicity with regards to how the parallelization is done.
Since results are written by multiple threads, there's two main ways to go about this:
- parallel writing results into a queue, then dequeuing into an array.
- using a really large array (num queries * max hits per query) and writing the result directly into queryIndex * hitCount.
I went for the first option. Pros: no wasted memory, no missed hits. Cons: hits appear in no particular order, so you have to iterate trough them all and look at their queryIndex to correlate with the query that spawned them. You can't get the results of a specific query without iterating trough all the results, but usually you're interested in all the results (otherwise you'd make one single solver.SpatialQuery() call) so I guess this is ok?
Unity's RaycastCommands use the second option. Pros: you can access the results of a specific ray/query at queryIndex * maxHits. Cons: forces you to tradeoff memory for accuracy: either use a very large maxHits value thus allocating a huge array, or miss hits.
(21-05-2021, 03:45 PM)Hatchling Wrote: I'm guessing a raycast (similar to Physics.Raycast) would be done by enumerating through the results and:
- Discarding results that have a positive distance
- Converting the "point" result to a raycast distance using a dot product "dot(point-rayOrigin,rayDirection)" and discarding all but the smallest positive result (the closest point ahead of the ray).
- Returning the result if they weren't all discarded.
Yes, that's how you'd do it. I'm going to also add helper methods to perform single distance/overlap queries (no need to manually allocate lists for input/results) and perform single/multiple raycasts, all built on top of SpatialQuery(). No need to do this yourself.