Implemented getResourceBindings methods to recursively collect resource bindings from nodes and resource-to-resource connections. Replaced many KRNode::preStream() overrides with a generic handler in KRNode::preStream() that walks the resource binding tree.

This commit is contained in:
2025-11-17 19:40:51 -08:00
parent b146886691
commit 9b20d1ef1d
19 changed files with 307 additions and 157 deletions

View File

@@ -76,3 +76,8 @@ void KRResource::requestResidency(uint32_t usage, float lodCoverage)
{
}
void KRResource::getResourceBindings(std::list<KRResourceBinding*>& bindings)
{
}

View File

@@ -38,6 +38,7 @@
class KRBundle;
class KRScene;
class KRMesh;
class KRResourceBinding;
class KRResource : public KRContextObject
{
public:
@@ -52,6 +53,8 @@ public:
// to directly balance memory from KRResourceRequest's
virtual void requestResidency(uint32_t usage, float lodCoverage);
virtual void getResourceBindings(std::list<KRResourceBinding*>& bindings);
virtual ~KRResource();
static KRMesh* LoadObj(KRContext& context, const std::string& path);

View File

@@ -235,14 +235,16 @@ bool KRMaterial::isTransparent()
return m_tr < 1.0 || m_alpha_mode == KRMATERIAL_ALPHA_MODE_BLENDONESIDE || m_alpha_mode == KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE;
}
void KRMaterial::preStream(std::list<KRResourceRequest>& resourceRequests, float lodCoverage)
void KRMaterial::getResourceBindings(std::list<KRResourceBinding*>& bindings)
{
m_ambientMap.submitRequest(&getContext(), resourceRequests, lodCoverage);
m_diffuseMap.submitRequest(&getContext(), resourceRequests, lodCoverage);
m_normalMap.submitRequest(&getContext(), resourceRequests, lodCoverage);
m_specularMap.submitRequest(&getContext(), resourceRequests, lodCoverage);
m_reflectionMap.submitRequest(&getContext(), resourceRequests, lodCoverage);
m_reflectionCube.submitRequest(&getContext(), resourceRequests, lodCoverage);
KRResource::getResourceBindings(bindings);
bindings.push_back(&m_ambientMap);
bindings.push_back(&m_diffuseMap);
bindings.push_back(&m_normalMap);
bindings.push_back(&m_specularMap);
bindings.push_back(&m_reflectionMap);
bindings.push_back(&m_reflectionCube);
}
kraken_stream_level KRMaterial::getStreamLevel()

View File

@@ -96,7 +96,8 @@ public:
bool needsVertexTangents();
kraken_stream_level getStreamLevel();
void preStream(std::list<KRResourceRequest>& resourceRequests, float lodCoverage);
virtual void getResourceBindings(std::list<KRResourceBinding*>& bindings) override;
private:
std::string m_name;

View File

@@ -0,0 +1,65 @@
//
// KRMaterialBinding.cpp
// Kraken Engine
//
// Copyright 2025 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
#include "KREngine-common.h"
#include "KRContext.h"
#include "KRMaterial.h"
#include "KRMaterialBinding.h"
KRMaterialBinding::KRMaterialBinding()
: KRResourceBinding(0)
{
}
KRMaterialBinding::KRMaterialBinding(const std::string& name)
: KRResourceBinding(name, 0)
{
}
KRMaterial* KRMaterialBinding::get()
{
return static_cast<KRMaterial*>(m_resource);
}
bool KRMaterialBinding::bind(KRContext* context)
{
if (m_name.size() == 0) {
return true;
}
if (m_resource != nullptr) {
return true;
}
m_resource = context->getMaterialManager()->getMaterial(m_name.c_str());
return (m_resource != nullptr);
}

View File

@@ -0,0 +1,48 @@
//
// KRMaterialBinding.h
// Kraken Engine
//
// Copyright 2025 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
#pragma once
#include "KREngine-common.h"
#include "resources/KRResourceBinding.h"
class KRMaterial;
class KRMaterialBinding : public KRResourceBinding
{
public:
KRMaterialBinding();
KRMaterialBinding(const std::string& name);
KRMaterial* get();
bool bind(KRContext* context) override final;
private:
};

View File

@@ -164,26 +164,7 @@ void KRMesh::getMaterials()
for (std::vector<KRMesh::Submesh>::iterator itr = m_submeshes.begin(); itr != m_submeshes.end(); itr++) {
const char* szMaterialName = (*itr).szMaterialName;
KRMaterial* pMaterial = nullptr;
if (*szMaterialName != '\0') {
pMaterial = getContext().getMaterialManager()->getMaterial(szMaterialName);
}
m_materials.push_back(pMaterial);
if (pMaterial) {
m_uniqueMaterials.insert(pMaterial);
} else if (*szMaterialName != '\0') {
KRContext::Log(KRContext::LOG_LEVEL_WARNING, "Missing material: %s", szMaterialName);
m_materials.clear();
return;
}
}
m_hasTransparency = false;
for (std::set<KRMaterial*>::iterator mat_itr = m_uniqueMaterials.begin(); mat_itr != m_uniqueMaterials.end(); mat_itr++) {
if ((*mat_itr)->isTransparent()) {
m_hasTransparency = true;
break;
}
m_materials.push_back(KRMaterialBinding(szMaterialName));
}
}
@@ -198,13 +179,26 @@ void KRMesh::requestResidency(uint32_t usage, float lodCoverage)
}
}
void KRMesh::preStream(std::list<KRResourceRequest>& resourceRequests, float lodCoverage)
void KRMesh::preStream()
{
getSubmeshes();
getMaterials();
for (std::set<KRMaterial*>::iterator mat_itr = m_uniqueMaterials.begin(); mat_itr != m_uniqueMaterials.end(); mat_itr++) {
(*mat_itr)->preStream(resourceRequests, lodCoverage);
m_hasTransparency = false;
for(KRMaterialBinding& material : m_materials) {
if (material.isBound() && material.get()->isTransparent()) {
m_hasTransparency = true;
break;
}
}
}
void KRMesh::getResourceBindings(std::list<KRResourceBinding*>& bindings)
{
KRResource::getResourceBindings(bindings);
for (KRResourceBinding& binding : m_materials) {
bindings.push_back(&binding);
}
}
@@ -214,8 +208,10 @@ kraken_stream_level KRMesh::getStreamLevel()
getSubmeshes();
getMaterials();
for (std::set<KRMaterial*>::iterator mat_itr = m_uniqueMaterials.begin(); mat_itr != m_uniqueMaterials.end(); mat_itr++) {
stream_level = KRMIN(stream_level, (*mat_itr)->getStreamLevel());
for (KRMaterialBinding& material : m_materials) {
if (material.isBound()) {
stream_level = KRMIN(stream_level, material.get()->getStreamLevel());
}
}
bool all_vbo_data_loaded = true;
bool vbo_data_loaded = false;
@@ -251,46 +247,42 @@ void KRMesh::render(KRNode::RenderInfo& ri, const std::string& object_name, cons
int cSubmeshes = (int)m_submeshes.size();
if (ri.renderPass->getType() == RenderPassType::RENDER_PASS_SHADOWMAP) {
for (int iSubmesh = 0; iSubmesh < cSubmeshes; iSubmesh++) {
KRMaterial* pMaterial = m_materials[iSubmesh];
KRMaterial* pMaterial = m_materials[iSubmesh].get();
if (pMaterial && !pMaterial->isTransparent()) {
// Exclude transparent and semi-transparent meshes from shadow maps
renderSubmesh(ri.commandBuffer, iSubmesh, ri.renderPass, object_name, pMaterial->getName(), lod_coverage);
}
}
} else {
// Apply submeshes in per-material batches to reduce number of state changes
for (std::set<KRMaterial*>::iterator mat_itr = m_uniqueMaterials.begin(); mat_itr != m_uniqueMaterials.end(); mat_itr++) {
for (int iSubmesh = 0; iSubmesh < cSubmeshes; iSubmesh++) {
KRMaterial* pMaterial = m_materials[iSubmesh];
for (int iSubmesh = 0; iSubmesh < cSubmeshes; iSubmesh++) {
KRMaterial* pMaterial = m_materials[iSubmesh].get();
if (pMaterial != NULL && pMaterial == (*mat_itr)) {
if ((!pMaterial->isTransparent() && ri.renderPass->getType() != RenderPassType::RENDER_PASS_FORWARD_TRANSPARENT) || (pMaterial->isTransparent() && ri.renderPass->getType() == RenderPassType::RENDER_PASS_FORWARD_TRANSPARENT)) {
std::vector<Matrix4> bone_bind_poses;
for (int i = 0; i < (int)bones.size(); i++) {
bone_bind_poses.push_back(getBoneBindPose(i));
}
if (pMaterial) {
if ((!pMaterial->isTransparent() && ri.renderPass->getType() != RenderPassType::RENDER_PASS_FORWARD_TRANSPARENT) || (pMaterial->isTransparent() && ri.renderPass->getType() == RenderPassType::RENDER_PASS_FORWARD_TRANSPARENT)) {
std::vector<Matrix4> bone_bind_poses;
for (int i = 0; i < (int)bones.size(); i++) {
bone_bind_poses.push_back(getBoneBindPose(i));
}
switch (pMaterial->getAlphaMode()) {
case KRMaterial::KRMATERIAL_ALPHA_MODE_OPAQUE: // Non-transparent materials
case KRMaterial::KRMATERIAL_ALPHA_MODE_TEST: // Alpha in diffuse texture is interpreted as punch-through when < 0.5
pMaterial->bind(ri, getModelFormat(), getVertexAttributes(), CullMode::kCullBack, bones, bone_bind_poses, matModel, pLightMap, lod_coverage);
renderSubmesh(ri.commandBuffer, iSubmesh, ri.renderPass, object_name, pMaterial->getName(), lod_coverage);
break;
case KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDONESIDE: // Blended alpha with backface culling
pMaterial->bind(ri, getModelFormat(), getVertexAttributes(), CullMode::kCullBack, bones, bone_bind_poses, matModel, pLightMap, lod_coverage);
renderSubmesh(ri.commandBuffer, iSubmesh, ri.renderPass, object_name, pMaterial->getName(), lod_coverage);
break;
case KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE: // Blended alpha rendered in two passes. First pass renders backfaces; second pass renders frontfaces.
// Render back faces first
pMaterial->bind(ri, getModelFormat(), getVertexAttributes(), CullMode::kCullFront, bones, bone_bind_poses, matModel, pLightMap, lod_coverage);
renderSubmesh(ri.commandBuffer, iSubmesh, ri.renderPass, object_name, pMaterial->getName(), lod_coverage);
switch (pMaterial->getAlphaMode()) {
case KRMaterial::KRMATERIAL_ALPHA_MODE_OPAQUE: // Non-transparent materials
case KRMaterial::KRMATERIAL_ALPHA_MODE_TEST: // Alpha in diffuse texture is interpreted as punch-through when < 0.5
pMaterial->bind(ri, getModelFormat(), getVertexAttributes(), CullMode::kCullBack, bones, bone_bind_poses, matModel, pLightMap, lod_coverage);
renderSubmesh(ri.commandBuffer, iSubmesh, ri.renderPass, object_name, pMaterial->getName(), lod_coverage);
break;
case KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDONESIDE: // Blended alpha with backface culling
pMaterial->bind(ri, getModelFormat(), getVertexAttributes(), CullMode::kCullBack, bones, bone_bind_poses, matModel, pLightMap, lod_coverage);
renderSubmesh(ri.commandBuffer, iSubmesh, ri.renderPass, object_name, pMaterial->getName(), lod_coverage);
break;
case KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE: // Blended alpha rendered in two passes. First pass renders backfaces; second pass renders frontfaces.
// Render back faces first
pMaterial->bind(ri, getModelFormat(), getVertexAttributes(), CullMode::kCullFront, bones, bone_bind_poses, matModel, pLightMap, lod_coverage);
renderSubmesh(ri.commandBuffer, iSubmesh, ri.renderPass, object_name, pMaterial->getName(), lod_coverage);
// Render front faces second
pMaterial->bind(ri, getModelFormat(), getVertexAttributes(), CullMode::kCullBack, bones, bone_bind_poses, matModel, pLightMap, lod_coverage);
renderSubmesh(ri.commandBuffer, iSubmesh, ri.renderPass, object_name, pMaterial->getName(), lod_coverage);
break;
}
// Render front faces second
pMaterial->bind(ri, getModelFormat(), getVertexAttributes(), CullMode::kCullBack, bones, bone_bind_poses, matModel, pLightMap, lod_coverage);
renderSubmesh(ri.commandBuffer, iSubmesh, ri.renderPass, object_name, pMaterial->getName(), lod_coverage);
break;
}
}
}

View File

@@ -36,6 +36,7 @@
#include "KRContext.h"
#include "nodes/KRBone.h"
#include "KRMeshManager.h"
#include "resources/material/KRMaterialBinding.h"
#include "KREngine-common.h"
@@ -75,7 +76,8 @@ public:
virtual ~KRMesh();
kraken_stream_level getStreamLevel();
void preStream(std::list<KRResourceRequest>& resourceRequests, float lodCoverage);
virtual void getResourceBindings(std::list<KRResourceBinding*>& bindings) override;
void preStream();
void requestResidency(uint32_t usage, float lodCoverage) final;
bool hasTransparency();
@@ -251,7 +253,7 @@ private:
static bool sphereCast(const hydra::Matrix4& model_to_world, const hydra::Vector3& v0, const hydra::Vector3& v1, float radius, const hydra::Triangle3& tri, hydra::HitInfo& hitinfo);
int m_lodCoverage; // This LOD level is activated when the bounding box of the model will cover less than this percent of the screen (100 = highest detail model)
vector<KRMaterial*> m_materials;
vector<KRMaterialBinding> m_materials;
set<KRMaterial*> m_uniqueMaterials;
bool m_hasTransparency;