ValveSoftware / steam-audio

Steam Audio
https://valvesoftware.github.io/steam-audio/
Apache License 2.0
2.2k stars 152 forks source link

Custom Scene - tracing clarification #319

Closed garrynewman closed 3 months ago

garrynewman commented 3 months ago

Hey guys, seeking some clarification on custom scene tracing and what we should be doing.

typedef void (IPLCALL *IPLClosestHitCallback)(const IPLRay* ray, IPLfloat32 minDistance, IPLfloat32 maxDistance, IPLHit* hit, void* userData);
typedef void (IPLCALL *IPLAnyHitCallback)(const IPLRay* ray, IPLfloat32 minDistance, IPLfloat32 maxDistance, IPLuint8* occluded, void* userData);

MaxDistance <= 0

Sometimes MaxDistance is zero, or less than zero in IPLAnyHitCallback. I noticed that if we don't return 1 for occluded in this instance the reflection bounces seem to echo forever. Should we be returning 1? Are we doing anything else wrong?

MinDistance

What should we be doing with minDistance and MaxDistance?

start = origin + minDistance * direction;
end = origin + MaxDistance * direction;

or

start = origin + minDistance * direction;
end = origin + (minDistance +maxDistance) * direction;

IPLHit.distance

When tracing with IPLClosestHitCallback, how should the hit distance be calculated?

Is it

distance = length(hitpoint - origin); 

or

distance = length(hitpoint - (origin + direction * minDistance )); 

No Hits

If there's no hits with IPLClosestHitCallback, should we be clearing the IPLHit, or just returning and ignoring it?

maxNumRays

When setting simulationSettings.maxNumRays to some huge number, like 32000, and then sharedInputs.numRays to some configurable, manageable value, like 128.. the spread of the rays aren't distributed uniformly. They will only emit from the left for example.

Is this right? Should these numbers always be the same?

lakulish commented 3 months ago

@garrynewman These are great questions!

garrynewman commented 3 months ago

So with maxNumRays, I can definitely see how this would happen from the code. In ReflectionSimulator's constructor it creates mListenerSamples based on maxNumRays, but then in ReflectionSimulator::simulate it's only sampling the first numRays of them, instead of some distributed sample.

With maxDistance, here's a stacktrace where it was 0

>   Sandbox.Engine.dll!Sandbox.Audio.SteamAudio.AnyHit(IPLRay* ray, float minDistance, float maxDistance, byte* occluded, void* userData) Line 202  C#
    [External Code] 
    phonon.dll!ipl::CustomScene::anyHit(const ipl::Ray & ray, float minDistance, float maxDistance) Line 48 C++
    phonon.dll!ipl::IScene::isOccluded(const ipl::Vector3<float> & from, const ipl::Vector3<float> & to) Line 33    C++
    [Inline Frame] phonon.dll!ipl::DirectSimulator::volumetricOcclusion(const ipl::IScene & sourcePosition, const ipl::Vector3<float> & numSamples, const ipl::Vector3<float> &) Line 168   C++
    phonon.dll!ipl::DirectSimulator::simulate(const ipl::IScene * scene, ipl::DirectSimulationFlags flags, const ipl::CoordinateSpace3<float> & source, const ipl::CoordinateSpace3<float> & listener, const ipl::DistanceAttenuationModel & distanceAttenuationModel, const ipl::AirAbsorptionModel & airAbsorptionModel, const ipl::Directivity & directivity, ipl::OcclusionType occlusionType, float occlusionRadius, int numOcclusionSamples, int numTransmissionRays, ipl::DirectSoundPath & directSoundPath) Line 102    C++
    [Inline Frame] phonon.dll!ipl::SimulationManager::simulateDirect(ipl::SimulationData & source) Line 171 C++
    [Inline Frame] phonon.dll!ipl::SimulationManager::simulateDirect() Line 165 C++
    phonon.dll!api::CSimulator::runDirect() Line 180    C++
    engine2.dll!CSteamAudio::SimulateDirect(IPhysicsWorld * physics, const CTransform & listener) Line 188  C++
    engine2.dll!Exports::CSteamAudio_SimulateDirect(void * self, IPhysicsWorld * world, CTransformUnaligned listener) Line 7376 C++

And here's one where it equals -1

>   Sandbox.Engine.dll!Sandbox.Audio.SteamAudio.AnyHit(IPLRay* ray, float minDistance, float maxDistance, byte* occluded, void* userData) Line 205  C#
    Sandbox.Engine.dll!Sandbox.Audio.SteamAudio.batchedAnyHitCallback.AnonymousMethod__0(int[] group) Line 257  C#
    [External Code] 
    Sandbox.Engine.dll!Sandbox.Audio.SteamAudio.batchedAnyHitCallback(int numRays, IPLRay* rays, float* minDistances, float* maxDistances, byte* occluded, void* userData) Line 253 C#
    [External Code] 
    phonon.dll!ipl::CustomScene::anyHits(int numRays, const ipl::Ray * rays, const float * minDistances, const float * maxDistances, bool * occluded) Line 87   C++
    phonon.dll!ipl::BatchedReflectionSimulator::shade(const ipl::IScene & scene, int sourceIndex, int scalar, float start, int end, int threadId, int) Line 992 C++
    phonon.dll!ipl::BatchedReflectionSimulator::simulateJob(const ipl::IScene & scene, int start, int end, int threadId, std::atomic<bool> & cancel) Line 815   C++
    [External Code] 
    [Inline Frame] phonon.dll!std::_Func_class<void,int,std::atomic<bool> &>::operator()(int <_Args_0>, std::atomic<bool> &) Line 869   C++
    [Inline Frame] phonon.dll!ipl::Job::process(int) Line 42    C++
    [Inline Frame] phonon.dll!ipl::JobGraph::processNextJob(int) Line 68    C++
    phonon.dll!ipl::ThreadPool::threadFunc(int threadId) Line 84    C++
    [External Code] 
    [Inline Frame] phonon.dll!invoke_thread_procedure(unsigned int(*)(void *) context, void * const) Line 91    C++
    phonon.dll!thread_start<unsigned int (__cdecl*)(void * __ptr64)>(void * const parameter) Line 115   C++

I do kind of worry that the plain simulators aren't ever gonna be as well trodden as the embree path, so I'm gonna look at the feasibility of using that instead, since I guess it would mean I could just put simulator tracing on a thread and forget about it.

lakulish commented 3 months ago

Ah, the BatchedReflectionSimulator sets maxDistance to -1 to indicate that the ray should not be traced. I will update the docs to indicate that if maxDistance <= minDistance, the ray shouldn't be traced. Thanks!