When calling RemoveInstance(index)
on a UInstancedStaticMeshComponent
- the instance is properly removed, however the values provided via SetCustomDataValue(...)
are not properly updated as well.
Question:
Is there something else I need to do to update existing instance custom data after I remove instances or is this a bug in 4.25 (which introduced `SetCustomDataValue(...)`)?Background:
The use case is that I have a variable number of instances (10K - 500K), each with a custom data value (set of 3 floats) which I use in the material for the ISM (and I have set the material to be used with ISM). Periodically I receive new data which I then use to update the existing ISM instances (transforms, custom data) and either add new ISM instances or remove extra ISM instances that are no longer needed. When updating existing instances or adding new instances everything works fine. However, when I call RemoveInstance(index)
to remove instances I no longer need, the remaining instances have their custom data corrupted.
Example:
Bad Data (when I re-use instances and have to call `RemoveInstance`):
Good Data (when either the number of instances stabilize or when I don't re-use instances):
Here is the code I’m using to perform the update of the ISM:
if (onlyNewVoxels) {
// if we want to remove all instances
voxelMesh->ClearInstances();
}
FTransform t;
FVector scale{ voxelSize, voxelSize, voxelSize };
bool teleportUpdate = true;
bool setRenderStateDirty = true;
bool transformIsWorldSpace = true;
// update the instances here
size_t index = 0;
if (!onlyNewVoxels) {
UE_LOG(LogTemp, Log, TEXT("Updating %d existing instances"), voxelMesh->GetInstanceCount());
// update voxels we already have
for (; index < voxelMesh->GetInstanceCount(); index++) {
// break if we have more voxels than we currently have meshes
if (index >= numVoxels) break;
// set the transform
t.SetTranslationAndScale3D(voxelLocations[index], scale);
voxelMesh->UpdateInstanceTransform(index, t,
transformIsWorldSpace,
setRenderStateDirty,
teleportUpdate);
if (showVoxelColor) {
// set the color
auto color = voxelColors[index];
voxelMesh->SetCustomDataValue(index, 0, color.R, setRenderStateDirty);
voxelMesh->SetCustomDataValue(index, 1, color.G, setRenderStateDirty);
voxelMesh->SetCustomDataValue(index, 2, color.B, setRenderStateDirty);
}
}
}
// add new voxels if we have more than we have meshes
UE_LOG(LogTemp, Log, TEXT("Adding %d new instances"), numVoxels - index);
for (; index < numVoxels; index++) {
// create the new mesh instance
t.SetTranslationAndScale3D(voxelLocations[index], scale);
voxelMesh->AddInstanceWorldSpace(t);
if (showVoxelColor) {
// set the color
auto color = voxelColors[index];
voxelMesh->SetCustomDataValue(index, 0, color.R, setRenderStateDirty);
voxelMesh->SetCustomDataValue(index, 1, color.G, setRenderStateDirty);
voxelMesh->SetCustomDataValue(index, 2, color.B, setRenderStateDirty);
}
}
// remove voxels we don't need anymore
UE_LOG(LogTemp, Log, TEXT("Removing %d unneeded instances"), voxelMesh->GetInstanceCount() - index);
for (size_t i=voxelMesh->GetInstanceCount()-1; i > index ; i--) {
voxelMesh->RemoveInstance(i);
}
// now mark the render state as dirty!
voxelMesh->MarkRenderStateDirty();