Split mesh artifacts into material and texture artifacts

This commit is contained in:
2026-04-02 19:36:16 +08:00
parent b2d0570b1b
commit e30f5d5ffa
12 changed files with 939 additions and 135 deletions

View File

@@ -52,6 +52,15 @@ void RemoveTextureBindingByName(
}
}
void EnsureTextureProperty(Containers::HashMap<Containers::String, MaterialProperty>& properties,
const Containers::String& name) {
MaterialProperty prop;
prop.name = name;
prop.type = MaterialPropertyType::Texture;
prop.refCount = 1;
properties.Insert(name, prop);
}
void WritePackedMaterialProperty(Core::uint8* destination, const MaterialProperty& property) {
std::memset(destination, 0, kMaterialConstantSlotSize);
@@ -271,15 +280,13 @@ void Material::SetBool(const Containers::String& name, bool value) {
}
void Material::SetTexture(const Containers::String& name, const ResourceHandle<Texture>& texture) {
MaterialProperty prop;
prop.name = name;
prop.type = MaterialPropertyType::Texture;
prop.refCount = 1;
m_properties.Insert(name, prop);
EnsureTextureProperty(m_properties, name);
for (auto& binding : m_textureBindings) {
if (binding.name == name) {
binding.texture = texture;
binding.texturePath = texture.Get() != nullptr ? texture->GetPath() : Containers::String();
binding.pendingLoad.reset();
MarkChanged(false);
return;
}
@@ -289,6 +296,33 @@ void Material::SetTexture(const Containers::String& name, const ResourceHandle<T
binding.name = name;
binding.slot = static_cast<Core::uint32>(m_textureBindings.Size());
binding.texture = texture;
binding.texturePath = texture.Get() != nullptr ? texture->GetPath() : Containers::String();
m_textureBindings.PushBack(binding);
MarkChanged(false);
}
void Material::SetTexturePath(const Containers::String& name, const Containers::String& texturePath) {
if (texturePath.Empty()) {
RemoveProperty(name);
return;
}
EnsureTextureProperty(m_properties, name);
for (auto& binding : m_textureBindings) {
if (binding.name == name) {
binding.texture.Reset();
binding.texturePath = texturePath;
binding.pendingLoad.reset();
MarkChanged(false);
return;
}
}
MaterialTextureBinding binding;
binding.name = name;
binding.slot = static_cast<Core::uint32>(m_textureBindings.Size());
binding.texturePath = texturePath;
m_textureBindings.PushBack(binding);
MarkChanged(false);
}
@@ -343,8 +377,16 @@ bool Material::GetBool(const Containers::String& name) const {
}
ResourceHandle<Texture> Material::GetTexture(const Containers::String& name) const {
for (const auto& binding : m_textureBindings) {
Material* material = const_cast<Material*>(this);
material->ResolvePendingTextureBindings();
for (Core::uint32 bindingIndex = 0; bindingIndex < material->m_textureBindings.Size(); ++bindingIndex) {
MaterialTextureBinding& binding = material->m_textureBindings[bindingIndex];
if (binding.name == name) {
if (binding.texture.Get() == nullptr &&
binding.pendingLoad == nullptr &&
!binding.texturePath.Empty()) {
material->BeginAsyncTextureLoad(bindingIndex);
}
return binding.texture;
}
}
@@ -355,8 +397,24 @@ Containers::String Material::GetTextureBindingName(Core::uint32 index) const {
return index < m_textureBindings.Size() ? m_textureBindings[index].name : Containers::String();
}
Containers::String Material::GetTextureBindingPath(Core::uint32 index) const {
return index < m_textureBindings.Size() ? m_textureBindings[index].texturePath : Containers::String();
}
ResourceHandle<Texture> Material::GetTextureBindingTexture(Core::uint32 index) const {
return index < m_textureBindings.Size() ? m_textureBindings[index].texture : ResourceHandle<Texture>();
Material* material = const_cast<Material*>(this);
material->ResolvePendingTextureBinding(index);
if (index < material->m_textureBindings.Size()) {
MaterialTextureBinding& binding = material->m_textureBindings[index];
if (binding.texture.Get() == nullptr &&
binding.pendingLoad == nullptr &&
!binding.texturePath.Empty()) {
material->BeginAsyncTextureLoad(index);
}
return binding.texture;
}
return ResourceHandle<Texture>();
}
std::vector<MaterialProperty> Material::GetProperties() const {
@@ -404,6 +462,59 @@ void Material::RecalculateMemorySize() {
UpdateMemorySize();
}
void Material::BeginAsyncTextureLoad(Core::uint32 index) {
if (index >= m_textureBindings.Size()) {
return;
}
MaterialTextureBinding& binding = m_textureBindings[index];
if (binding.texture.Get() != nullptr || binding.texturePath.Empty() || binding.pendingLoad != nullptr) {
return;
}
binding.pendingLoad = std::make_shared<PendingTextureLoadState>();
std::weak_ptr<PendingTextureLoadState> weakState = binding.pendingLoad;
const Containers::String texturePath = binding.texturePath;
ResourceManager::Get().LoadAsync(
texturePath,
ResourceType::Texture,
[weakState](LoadResult result) {
if (std::shared_ptr<PendingTextureLoadState> state = weakState.lock()) {
state->resource = result.resource;
state->errorMessage = result.errorMessage;
state->completed = true;
}
});
}
void Material::ResolvePendingTextureBinding(Core::uint32 index) {
if (index >= m_textureBindings.Size()) {
return;
}
MaterialTextureBinding& binding = m_textureBindings[index];
if (!binding.pendingLoad || !binding.pendingLoad->completed) {
return;
}
std::shared_ptr<PendingTextureLoadState> completedLoad = std::move(binding.pendingLoad);
binding.pendingLoad.reset();
if (completedLoad->resource == nullptr) {
return;
}
binding.texture = ResourceHandle<Texture>(static_cast<Texture*>(completedLoad->resource));
if (binding.texture.Get() != nullptr) {
binding.texturePath = binding.texture->GetPath();
}
}
void Material::ResolvePendingTextureBindings() {
for (Core::uint32 bindingIndex = 0; bindingIndex < m_textureBindings.Size(); ++bindingIndex) {
ResolvePendingTextureBinding(bindingIndex);
}
}
bool Material::HasProperty(const Containers::String& name) const {
return m_properties.Contains(name);
}
@@ -457,6 +568,7 @@ void Material::UpdateMemorySize() {
for (const auto& binding : m_textureBindings) {
m_memorySize += binding.name.Length();
m_memorySize += binding.texturePath.Length();
}
}