#include "behavior.h" #include #include #include #include #include #include #include #include #include "../light/behavior.h" #include "../scene/behavior.h" UF_BEHAVIOR_REGISTER_CPP(ext::BakingBehavior) UF_BEHAVIOR_TRAITS_CPP(ext::BakingBehavior, ticks = true, renders = false, multithread = false) #define this (&self) void ext::BakingBehavior::initialize( uf::Object& self ) { #if UF_USE_VULKAN this->addHook( "entity:PostInitialization.%UID%", [&]( ext::json::Value& ){ auto& metadataJson = this->getComponent(); auto& metadata = this->getComponent(); auto& scene = uf::scene::getCurrentScene(); auto& sceneMetadata = scene.getComponent(); auto& controller = scene.getController(); auto& controllerTransform = controller.getComponent>(); metadata.output = this->grabURI( metadataJson["baking"]["output"].as(), metadataJson["baking"]["root"].as() ); metadata.renderModeName = "B:" + std::to_string((int) this->getUid()); metadata.trigger.mode = metadataJson["baking"]["trigger"]["mode"].as(); metadata.trigger.value = metadataJson["baking"]["trigger"]["value"].as(); if ( metadataJson["baking"]["resolution"].is() ) metadata.size = { metadataJson["baking"]["resolution"].as(), metadataJson["baking"]["resolution"].as() }; metadata.max.lights = metadataJson["baking"]["lights"].as(metadata.max.lights); metadata.max.shadows = metadataJson["baking"]["shadows"].as(metadata.max.shadows); metadata.cull = metadataJson["baking"]["cull"].as(); metadata.previous.max = sceneMetadata.shadow.max; metadata.previous.update = sceneMetadata.shadow.update; sceneMetadata.shadow.max = 1024; sceneMetadata.shadow.update = 1024; UF_MSG_DEBUG("Temporarily altering shadow limits..."); auto& renderMode = this->getComponent(); uf::renderer::addRenderMode( &renderMode, metadata.renderModeName ); renderMode.execute = false; renderMode.metadata.type = "single"; renderMode.metadata.pipeline = "baking"; renderMode.metadata.samples = 1; renderMode.metadata.json["descriptor"]["cull mode"] = "none"; renderMode.width = metadata.size.x; renderMode.height = metadata.size.y; renderMode.blitter.process = false; UF_MSG_DEBUG("Binding..."); uf::stl::vector textures2D; uf::stl::vector texturesCube; // bind scene textures for ( auto& key : uf::graph::storage.texture2Ds.keys ) textures2D.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[key] ); // bind shadow maps for ( auto& texture : uf::graph::storage.shadow2Ds ) textures2D.emplace_back().aliasTexture(texture); for ( auto& texture : uf::graph::storage.shadowCubes ) texturesCube.emplace_back().aliasTexture(texture); scene.process([&]( uf::Entity* entity ) { if ( !entity->hasComponent() ) return; auto& graphic = entity->getComponent(); { graphic.material.metadata.autoInitializeUniforms = false; uf::stl::string vertexShaderFilename = uf::io::resolveURI("/graph/baking/bake.vert.spv"); uf::stl::string fragmentShaderFilename = uf::io::resolveURI("/graph/baking/bake.frag.spv"); graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX, "baking"); graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "baking"); graphic.material.metadata.autoInitializeUniforms = true; } { uint32_t maxPasses = 6; auto& shader = graphic.material.getShader("vertex", "baking"); uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; for ( auto pair : shader.metadata.definitions.specializationConstants ) { auto& sc = pair.second; if ( sc.name == "PASSES" ) sc.value.ui = (specializationConstants[sc.index] = maxPasses); } // uf::renderer::Buffer* indirect = NULL; // for ( auto& buffer : graphic.buffers ) if ( !indirect && buffer.usage & uf::renderer::enums::Buffer::INDIRECT ) indirect = &buffer; // shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera ); // shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.drawCommands ); shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance ); shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.joint ); } { uint32_t maxTextures = textures2D.size(); uint32_t maxCubemaps = texturesCube.size(); auto& shader = graphic.material.getShader("fragment", "baking"); uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; for ( auto pair : shader.metadata.definitions.specializationConstants ) { auto& sc = pair.second; if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures); else if ( sc.name == "CUBEMAPS" ) sc.value.ui = (specializationConstants[sc.index] = maxCubemaps); } for ( auto pair : shader.metadata.definitions.textures ) { auto& tx = pair.second; for ( auto& layout : shader.descriptorSetLayoutBindings ) { if ( layout.binding != tx.binding ) continue; if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures; else if ( tx.name == "samplerCubemaps" ) layout.descriptorCount = maxCubemaps; } } shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance ); shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.material ); shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.texture ); shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.light ); for ( auto& t : textures2D ) shader.textures.emplace_back().aliasTexture( t ); for ( auto& t : texturesCube ) shader.textures.emplace_back().aliasTexture( t ); } }); UF_MSG_DEBUG("Finished initialiation."); }); this->queueHook( "entity:PostInitialization.%UID%", ext::json::null(), 1 ); #endif } void ext::BakingBehavior::tick( uf::Object& self ) { #if 1 #if UF_USE_VULKAN if ( !this->hasComponent() ) return; auto& metadata = this->getComponent(); auto& renderMode = this->getComponent(); if ( renderMode.executed && !metadata.initialized.renderMode ) goto PREPARE; else if ( renderMode.executed && !metadata.initialized.map ) { TIMER(1.0, (metadata.trigger.mode == "rendered" || (metadata.trigger.mode == "key" && uf::Window::isKeyPressed(metadata.trigger.value))) && ) { goto SAVE; } } return; PREPARE: { UF_MSG_DEBUG("Preparing graphics to bake..."); metadata.initialized.renderMode = true; renderMode.execute = true; renderMode.setTarget(""); uf::renderer::states::rebuild = true; UF_MSG_DEBUG("Graphic configured, ready to bake"); return; } SAVE: { #if 1 renderMode.execute = false; UF_MSG_DEBUG("Baking..."); auto image = renderMode.screenshot(); uf::stl::string filename = metadata.output; bool status = image.save(filename); UF_MSG_DEBUG("Writing to " << filename << ": " << status); UF_MSG_DEBUG("Baked."); metadata.initialized.map = true; auto& scene = uf::scene::getCurrentScene(); auto& sceneMetadata = scene.getComponent(); sceneMetadata.shadow.max = metadata.previous.max; sceneMetadata.shadow.update = metadata.previous.update; UF_MSG_DEBUG("Reverted shadow limits"); uf::Serializer payload; payload["uid"] = this->getUid(); uf::scene::getCurrentScene().queueHook("system:Destroy", payload); #endif return; } #endif #endif } void ext::BakingBehavior::render( uf::Object& self ){} void ext::BakingBehavior::destroy( uf::Object& self ){ if ( this->hasComponent() ) { auto& renderMode = this->getComponent(); uf::renderer::removeRenderMode( &renderMode, false ); // this->deleteComponent(); } #if 0 if ( this->hasComponent() ) { auto& graph = this->getComponent(); uf::graph::destroy( graph ); } #endif } void ext::BakingBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ) {} void ext::BakingBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer& serializer ) {} #undef this