Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
bab8eb2
Initial picking work
ccpisheden Sep 8, 2026
76bca31
Merge branch 'main' into picking
ccpisheden Sep 8, 2026
8d10608
Fixed picking with the instancing and debug renderer changes.
ccpisheden Sep 8, 2026
1e9deb3
Mac async picking stuff
ccpisheden Sep 11, 2026
010537d
Mac compilation warning fixes
ccpisheden Sep 11, 2026
94f9000
Metal compilation error fixes
ccpisheden Sep 11, 2026
a37840a
Revert "Fixed picking with the instancing and debug renderer changes."
ccpisheden Sep 14, 2026
12f72ae
Revert "Fixed picking with the instancing and debug renderer changes."
ccpisheden Sep 14, 2026
1d78385
Reapply "Fixed picking with the instancing and debug renderer changes."
ccpisheden Sep 14, 2026
56277d0
Reapply "Fixed picking with the instancing and debug renderer changes."
ccpisheden Sep 14, 2026
48f8409
Commented out debug code.
ccpisheden Sep 21, 2026
b404bc5
Cleanup.
ccpisheden Sep 21, 2026
c342629
Fixed picking unmapping not being correct.
ccpisheden Sep 23, 2026
8cf68be
Removed Readback initialize functions, added null checks, fixed Pytho…
ccpisheden Sep 23, 2026
b3d1143
Fixed Mac picking.
ccpisheden Sep 23, 2026
792366f
Clang formatting fixes for picking.
ccpisheden Sep 23, 2026
c92c202
Merge branch 'main' into picking
ccpisheden Sep 23, 2026
1b95ad2
Removed picking log spam.
ccpisheden Sep 23, 2026
4360bfe
Fixed picking issues from PR feedback
ccpisheden Sep 28, 2026
51e9ecf
Additional fix for readback Destroy() function.
ccpisheden Sep 29, 2026
f8f4897
Fixed instanced picking issues.
ccpisheden Sep 29, 2026
f82bc31
Fixed warning in instanced picking fix.
ccpisheden Sep 29, 2026
a3c826c
Merge branch 'main' into picking
ccpisheden Sep 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 27 additions & 51 deletions trinity/Eve/EveInstancedMeshManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ size_t EveInstancedMeshManager::GetShadowBatches( const TriFrustum& cameraFrustu
return GetBatches( batches );
}

void EveInstancedMeshManager::GetPickingBatches( EvePendingPickingReadback& readback, const TriFrustum& viewFrustum, const TriFrustum& pickingFrustum, float invLodFactor, uint32_t objectIdOffset, const std::vector<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches )
void EveInstancedMeshManager::GetPickingBatches( EvePendingPickingReadback& readback, const TriFrustum& viewFrustum, const TriFrustum& pickingFrustum, float invLodFactor, const std::vector<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches )
{
InstanceFlags filter;
for( auto& pair : batches )
Expand All @@ -703,41 +703,9 @@ void EveInstancedMeshManager::GetPickingBatches( EvePendingPickingReadback& read
}
PerformFrustumCulling( viewFrustum, pickingFrustum, invLodFactor, filter );

GetPickingBatches( readback, objectIdOffset, batches );
GetPickingBatches( readback, batches );
}

std::pair<IRootPtr, uint32_t> EveInstancedMeshManager::GetPickedObject( uint32_t objectId, uint32_t areaId )
{
for( auto& [mesh, meshInfo] : m_meshInstances )
{
for( auto& group : meshInfo.meshGroups )
{
if( group.pickingObjectId == 0xffffffff )
{
continue;
}
if( group.pickingObjectId > objectId || group.pickingObjectId + meshInfo.lodIndices.size() <= objectId )
{
continue;
}
if( m_sphereGroups[group.sphereGroupIndex].lastTestResult == TriFrustumTestResult::Outside )
{
continue;
}
BinVisibleInstances( mesh, meshInfo, group );
auto& lod = meshInfo.lodIndices[objectId - group.pickingObjectId];
uint32_t instanceId = 0;
if( areaId < lod.size() )
{
instanceId = uint32_t( mesh.isDynamic ? static_cast<const DynamicPerInstanceData*>( lod[areaId].first ) - group.dynamicInstances : static_cast<const StaticPerInstanceData*>( lod[areaId].first ) - group.staticInstances );
}
return { group.owner, instanceId | ( group.ownerIndex << 16 ) };
}
}
return { nullptr, 0 };
}


void EveInstancedMeshManager::BinVisibleInstances( const std::initializer_list<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches )
{
TRINITY_STATS_ZONE( __FUNCTION__ );
Expand All @@ -761,22 +729,18 @@ void EveInstancedMeshManager::BinVisibleInstances( const std::initializer_list<s
}


void EveInstancedMeshManager::GetPickingBatches( EvePendingPickingReadback& readback, uint32_t objectIdOffset, const std::vector<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches )
void EveInstancedMeshManager::GetPickingBatches( EvePendingPickingReadback& readback, const std::vector<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches )
{
TRINITY_STATS_ZONE( __FUNCTION__ );


std::vector<std::pair<IRootPtr, uint32_t>>& traceback = readback.m_instancedTraceback;
std::vector<IRootPtr>& blueObjects = readback.m_blueObjects;

for( auto& [mesh, meshInfo] : m_meshInstances )
{
auto accumulator = FindBatchAccumulator( batches, mesh.batchType );
if( !accumulator )
{
for( auto& group : meshInfo.meshGroups )
{
group.pickingObjectId = 0xffffffff;
}
continue;
}
for( auto& group : meshInfo.meshGroups )
Expand All @@ -799,12 +763,9 @@ void EveInstancedMeshManager::GetPickingBatches( EvePendingPickingReadback& read
}
if( !hasVisibleInstances )
{
group.pickingObjectId = 0xffffffff;
continue;
}

group.pickingObjectId = objectIdOffset;

for( uint32_t lod = 0; lod < static_cast<uint32_t>( meshInfo.lodIndices.size() ); ++lod )
{
if( meshInfo.lodIndices[lod].empty() )
Expand Down Expand Up @@ -835,14 +796,12 @@ void EveInstancedMeshManager::GetPickingBatches( EvePendingPickingReadback& read
allocation.offset / stride );

auto perObjectData = accumulator->Allocate<PickingPerObjectData>();
perObjectData->SetUserData( objectIdOffset + lod );
perObjectData->SetPickingPointer( (uint64_t)group.owner->GetRootObject() );
blueObjects.push_back( group.owner->GetRootObject() );
batch.SetPerObjectData( perObjectData );

accumulator->Commit( batch );

traceback.push_back( { group.owner, group.ownerIndex } );
}
objectIdOffset += static_cast<uint32_t>( meshInfo.lodIndices.size() );
}
}
m_staticInstanceBuffer.DoneCopying();
Expand Down Expand Up @@ -943,17 +902,34 @@ void EveInstancedMeshManager::UploadLodData( const MeshKey& mesh, MeshData& mesh
{
for( auto [instance, perObjectDataIndex] : meshInfo.lodIndices[lod] )
{
memcpy( allocation.data, instance, sizeof( DynamicPerInstanceBufferElement ) );
reinterpret_cast<DynamicPerInstanceBufferElement*>( allocation.data )->perObjectDataIndex = perObjectDataIndex;
const DynamicPerInstanceData* instanceData = reinterpret_cast<const DynamicPerInstanceData*>( instance );
DynamicPerInstanceBufferElement* bufferElement = reinterpret_cast<DynamicPerInstanceBufferElement*>( allocation.data );

bufferElement->worldTransform = instanceData->worldTransform;
bufferElement->prevWorldTransform = instanceData->prevWorldTransform;

bufferElement->perObjectDataIndex = perObjectDataIndex;

bufferElement->pickingMeshIndex = instanceData->pickingMeshIndex;
bufferElement->pickingInstanceIndex = instanceData->pickingInstanceIndex;

allocation.data += sizeof( DynamicPerInstanceBufferElement );
}
}
else
{
for( auto [instance, perObjectDataIndex] : meshInfo.lodIndices[lod] )
{
memcpy( allocation.data, instance, sizeof( StaticPerInstanceBufferElement ) );
reinterpret_cast<StaticPerInstanceBufferElement*>( allocation.data )->perObjectDataIndex = perObjectDataIndex;
const StaticPerInstanceData* instanceData = reinterpret_cast<const StaticPerInstanceData*>( instance );
StaticPerInstanceBufferElement* bufferElement = reinterpret_cast<StaticPerInstanceBufferElement*>( allocation.data );

bufferElement->worldTransform = instanceData->worldTransform;

bufferElement->perObjectDataIndex = perObjectDataIndex;

bufferElement->pickingMeshIndex = instanceData->pickingMeshIndex;
bufferElement->pickingInstanceIndex = instanceData->pickingInstanceIndex;

allocation.data += sizeof( StaticPerInstanceBufferElement );
}
}
Expand Down
13 changes: 10 additions & 3 deletions trinity/Eve/EveInstancedMeshManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ class EveInstancedMeshManager
Float4x3 worldTransform;
Float4x3 prevWorldTransform;
uint32_t sphereIndex = 0;
uint32_t pickingMeshIndex = 0;
uint32_t pickingInstanceIndex = 0;
};

struct StaticPerInstanceData
{
Float4x3 worldTransform;
uint32_t sphereIndex = 0;
uint32_t pickingMeshIndex = 0;
uint32_t pickingInstanceIndex = 0;
};

template <typename T>
Expand Down Expand Up @@ -91,7 +95,7 @@ class EveInstancedMeshManager
void CollectMeshes( EveComponentRegistry& registry );
size_t GetBatches( const TriFrustum& frustum, float invLodFactor, const std::initializer_list<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches, Tr2RenderReason reason = TR2RENDERREASON_NORMAL );
size_t GetShadowBatches( const TriFrustum& frustum, const IEveShadowFrustum& shadowFrustum, float invLodFactor, const std::initializer_list<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches, Tr2RenderReason reason = TR2RENDERREASON_NORMAL );
void GetPickingBatches( EvePendingPickingReadback& readback, const TriFrustum& viewFrustum, const TriFrustum& pickingFrustum, float invLodFactor, uint32_t objectIdOffset, const std::vector<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches );
void GetPickingBatches( EvePendingPickingReadback& readback, const TriFrustum& viewFrustum, const TriFrustum& pickingFrustum, float invLodFactor, const std::vector<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches );
std::pair<IRootPtr, uint32_t> GetPickedObject( uint32_t objectId, uint32_t areaId );
void ReportUsedScreenSizes() const;

Expand Down Expand Up @@ -144,13 +148,17 @@ class EveInstancedMeshManager
{
Float4x3 worldTransform;
uint32_t perObjectDataIndex = 0;
uint32_t pickingMeshIndex = 0;
uint32_t pickingInstanceIndex = 0;
};

struct DynamicPerInstanceBufferElement
{
Float4x3 worldTransform;
Float4x3 prevWorldTransform;
uint32_t perObjectDataIndex = 0;
uint32_t pickingMeshIndex = 0;
uint32_t pickingInstanceIndex = 0;
};

struct MeshKey
Expand Down Expand Up @@ -188,7 +196,6 @@ class EveInstancedMeshManager
uint32_t perObjectDataIndex = 0;
uint32_t ownerIndex = 0;
IRootPtr owner; // Used for picking
uint32_t pickingObjectId = 0;
};

class InstanceBuffer
Expand Down Expand Up @@ -264,7 +271,7 @@ class EveInstancedMeshManager
void BinVisibleInstances( const std::initializer_list<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches );

size_t GetBatches( const std::initializer_list<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches );
void GetPickingBatches( EvePendingPickingReadback& readback, uint32_t objectIdOffset, const std::vector<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches );
void GetPickingBatches( EvePendingPickingReadback& readback, const std::vector<std::pair<TriBatchType, ITriRenderBatchAccumulator&>>& batches );
static uint32_t GetMeshLod( const MeshData& meshInfo, float screenSize );
void UploadLodData( const MeshKey& mesh, MeshData& meshInfo, uint32_t lod, InstanceBuffer::Allocation& allocation );
InstanceBuffer::Allocation AllocateInstanceData( uint32_t count, bool isDynamic );
Expand Down
66 changes: 15 additions & 51 deletions trinity/Eve/EvePicking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,78 +9,42 @@

EvePendingPickingReadback::EvePendingPickingReadback( uint32_t pickedX, uint32_t pickedY ) :
m_pickedX( pickedX ),
m_pickedY( pickedY ),
m_debugPickBuffer( NULL, ImageIO::PIXEL_FORMAT_R32G32B32A32_FLOAT ),
m_debugPickData( nullptr ),
m_mainPickBuffer( NULL, ImageIO::PIXEL_FORMAT_B8G8R8A8_UNORM ),
m_mainPickData( nullptr )
m_pickedY( pickedY )
{
}

// ------------------------------------------------------------------------------------------------------
void EvePendingPickingReadback::ReleaseResources( TriStorage s )
{
m_debugPickData = nullptr;
m_mainPickData = nullptr;
}

// ------------------------------------------------------------------------------------------------------
bool EvePendingPickingReadback::OnPrepareResources()
{
return true;
}


void EvePendingPickingReadback::MapDebug( bool synchronize, Tr2RenderContext& renderContext )
{
uint32_t pitch;
m_debugPickBuffer.MapForReading( synchronize, m_debugPickData, pitch, renderContext );
}


void EvePendingPickingReadback::MapMain( bool synchronize, Tr2RenderContext& renderContext )
{
uint32_t pitch;
m_mainPickBuffer.MapForReading( synchronize, m_mainPickData, pitch, renderContext );
}


void EvePendingPickingReadback::Unmap( Tr2RenderContext& renderContext )
{
if( m_debugPickData )
{
m_debugPickBuffer.UnmapForReading( renderContext );
}
if( m_mainPickData )
{
m_mainPickBuffer.UnmapForReading( renderContext );
}
}

EvePickingContext::EvePickingContext( IRoot* lockobj ) :
m_lastPickedX( 0 ),
m_lastPickedY( 0 ),
m_lastPickedObject( NULL ),
m_lastPickedArea( 0 )
m_lastPickedExtraData1( 0 ),
m_lastPickedExtraData2( 0 )
{
}



void EvePickingContext::UpdateResult( uint32_t x, uint32_t y, IRootPtr object, uint32_t area )
void EvePickingContext::UpdateResult( uint32_t x, uint32_t y, IRootPtr object, uint32_t extraData1, uint32_t extraData2 )
{
m_lastPickedX = x;
m_lastPickedY = y;
m_lastPickedObject = object;
m_lastPickedArea = area;
m_lastPickedExtraData1 = extraData1;
m_lastPickedExtraData2 = extraData2;
}

IRoot* EvePickingContext::GetObject()
IRootPtr EvePickingContext::GetObject() const
{
return m_lastPickedObject;
}

uint32_t EvePickingContext::GetArea()
uint32_t EvePickingContext::GetExtraData1() const
{
return m_lastPickedExtraData1;
}


uint32_t EvePickingContext::GetExtraData2() const
{
return m_lastPickedArea;
return m_lastPickedExtraData2;
}
38 changes: 9 additions & 29 deletions trinity/Eve/EvePicking.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,17 @@



class EvePendingPickingReadback : public Tr2DeviceResource
class EvePendingPickingReadback
{
public:
EvePendingPickingReadback( uint32_t pickedX, uint32_t pickedY );

void MapDebug( bool synchronize, Tr2RenderContext& renderContext );
void MapMain( bool synchronize, Tr2RenderContext& renderContext );
void Unmap( Tr2RenderContext& renderContext );

uint32_t m_pickedX;
uint32_t m_pickedY;
uint64_t m_frameIndex;



std::vector<Tr2DebugObjectReference> m_debugLineObjects;
std::vector<Tr2DebugObjectReference> m_debugTriangleObjects;
Tr2PickBuffer m_debugPickBuffer;
const void* m_debugPickData;

std::vector<std::pair<ITr2PickablePtr, ITr2Renderable*>> m_collisionSet;
std::vector<IRootPtr> m_blueObjects;

std::vector<std::pair<IRootPtr, uint32_t>> m_instancedTraceback;
Tr2PickBuffer m_mainPickBuffer;
const void* m_mainPickData;


/////////////////////////////////////////////////////////////
// ITriDeviceResource
void ReleaseResources( TriStorage s ) override;

private:
bool OnPrepareResources() override;
Tr2ReadbackAL m_readback;
};


Expand All @@ -55,18 +33,20 @@ BLUE_CLASS( EvePickingContext ) :

EvePickingContext( IRoot* lockobj = NULL );

void UpdateResult( uint32_t x, uint32_t y, IRootPtr object, uint32_t area );
void UpdateResult( uint32_t x, uint32_t y, IRootPtr object, uint32_t extraData1, uint32_t extraData2 );

IRoot* GetObject();
uint32_t GetArea();
IRootPtr GetObject() const;
uint32_t GetExtraData1() const;
uint32_t GetExtraData2() const;

std::vector<std::unique_ptr<EvePendingPickingReadback>> m_readbacks;

private:
uint32_t m_lastPickedX;
uint32_t m_lastPickedY;
IRootPtr m_lastPickedObject;
uint32_t m_lastPickedArea;
uint32_t m_lastPickedExtraData1;
uint32_t m_lastPickedExtraData2;

friend class EveSpaceScene;
};
Expand Down
Loading
Loading