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:
@@ -76,3 +76,8 @@ void KRResource::requestResidency(uint32_t usage, float lodCoverage)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void KRResource::getResourceBindings(std::list<KRResourceBinding*>& bindings)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
65
kraken/resources/material/KRMaterialBinding.cpp
Normal file
65
kraken/resources/material/KRMaterialBinding.cpp
Normal 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);
|
||||
}
|
||||
48
kraken/resources/material/KRMaterialBinding.h
Normal file
48
kraken/resources/material/KRMaterialBinding.h
Normal 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:
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user