Files
Seele/src/Engine/Material/Material.cpp
T

203 lines
7.5 KiB
C++
Raw Normal View History

2023-01-21 18:43:21 +01:00
#include "Material.h"
2024-04-15 13:48:34 +02:00
#include "Graphics/Enums.h"
2023-01-29 18:58:59 +01:00
#include "Graphics/Graphics.h"
2023-11-15 17:42:57 +01:00
#include "Graphics/Shader.h"
2024-06-09 12:20:04 +02:00
#include "MaterialInstance.h"
#include "Serialization/Serialization.h"
#include "Window/WindowManager.h"
2024-01-16 19:24:49 +01:00
#include <fstream>
2023-01-21 18:43:21 +01:00
using namespace Seele;
2024-06-18 19:19:05 +02:00
Array<Gfx::PTexture2D> Material::textures;
Array<Gfx::PSampler> Material::samplers;
Gfx::OShaderBuffer Material::floatBuffer;
Array<float> Material::floatData;
Gfx::ODescriptorLayout Material::layout;
Gfx::PDescriptorSet Material::set;
2024-05-09 08:41:46 +02:00
std::atomic_uint64_t Material::materialIdCounter = 0;
Array<PMaterial> Material::materials;
2024-06-09 12:20:04 +02:00
Material::Material() {}
2023-01-21 18:43:21 +01:00
2024-06-20 21:57:26 +02:00
Material::Material(Gfx::PGraphics graphics, uint32 numTextures, uint32 numSamplers, uint32 numFloats, bool twoSided, float opacity,
std::string materialName, Array<OShaderExpression> expressions, Array<std::string> parameter, MaterialNode brdf)
2024-08-28 17:54:14 +02:00
: graphics(graphics), numTextures(numTextures), numSamplers(numSamplers), numFloats(numFloats), instanceId(0), materialId(materialIdCounter++),
materialName(materialName), twoSided(twoSided), opacity(opacity), codeExpressions(std::move(expressions)),
parameters(std::move(parameter)), brdf(std::move(brdf)) {
2024-06-18 19:19:05 +02:00
if (layout == nullptr) {
init(graphics);
}
2024-05-09 08:41:46 +02:00
materials.add(this);
2023-01-21 18:43:21 +01:00
}
2024-06-09 12:20:04 +02:00
Material::~Material() {}
2024-06-18 19:19:05 +02:00
void Material::init(Gfx::PGraphics graphics) {
2024-09-27 15:57:37 +02:00
layout = graphics->createDescriptorLayout("pResources");
2024-06-18 19:19:05 +02:00
layout->addDescriptorBinding(Gfx::DescriptorBinding{
2025-02-28 16:56:51 +09:00
.name = "textures",
2024-06-18 19:19:05 +02:00
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
2024-08-28 17:54:14 +02:00
.descriptorCount = 512,
2024-06-19 10:44:11 +02:00
.bindingFlags = Gfx::SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT,
2024-07-15 17:55:22 +02:00
.shaderStages = Gfx::SE_SHADER_STAGE_FRAGMENT_BIT | Gfx::SE_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
2025-02-28 16:56:51 +09:00
.access = Gfx::SE_DESCRIPTOR_ACCESS_SAMPLE_BIT,
2024-06-18 19:19:05 +02:00
});
layout->addDescriptorBinding(Gfx::DescriptorBinding{
2025-02-28 16:56:51 +09:00
.name = "samplers",
2024-06-18 19:19:05 +02:00
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER,
2024-08-28 17:54:14 +02:00
.descriptorCount = 512,
2024-06-19 10:44:11 +02:00
.bindingFlags = Gfx::SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT,
2024-07-15 17:55:22 +02:00
.shaderStages = Gfx::SE_SHADER_STAGE_FRAGMENT_BIT | Gfx::SE_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
2024-06-18 19:19:05 +02:00
});
2024-09-27 15:57:37 +02:00
layout->addDescriptorBinding(Gfx::DescriptorBinding{
2025-02-28 16:56:51 +09:00
.name = "floats",
2024-09-27 15:57:37 +02:00
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.bindingFlags = Gfx::SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT,
.shaderStages = Gfx::SE_SHADER_STAGE_FRAGMENT_BIT | Gfx::SE_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
});
2024-06-18 19:19:05 +02:00
layout->create();
floatBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.name = "MaterialFloatBuffer",
});
}
2024-07-18 11:45:56 +02:00
void Material::destroy() {
floatBuffer = nullptr;
set = nullptr;
layout = nullptr;
}
2024-06-18 19:19:05 +02:00
void Material::updateDescriptor() {
floatBuffer->rotateBuffer(floatData.size() * sizeof(float));
floatBuffer->updateContents(0, floatData.size() * sizeof(float), floatData.data());
2024-06-18 19:19:05 +02:00
floatBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT,
Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
layout->reset();
set = layout->allocateDescriptorSet();
2024-06-20 21:57:26 +02:00
for (uint32 i = 0; i < textures.size(); ++i) {
if (textures[i] != nullptr) {
2025-02-28 16:56:51 +09:00
set->updateTexture("textures", i, textures[i]);
2024-06-20 21:57:26 +02:00
}
2024-06-18 19:19:05 +02:00
}
2024-06-20 21:57:26 +02:00
for (uint32 i = 0; i < samplers.size(); ++i) {
if (samplers[i] != nullptr) {
2025-02-28 16:56:51 +09:00
set->updateSampler("samplers", i, samplers[i]);
2024-06-20 21:57:26 +02:00
}
2024-06-18 19:19:05 +02:00
}
2025-02-28 16:56:51 +09:00
set->updateBuffer("floats", 0, floatBuffer);
2024-06-18 19:19:05 +02:00
set->writeChanges();
}
void Material::updateTexture(uint32 index, Gfx::PTexture2D texture) { textures[index] = texture; }
void Material::updateSampler(uint32 index, Gfx::PSampler sampler) { samplers[index] = sampler; }
void Material::updateFloatData(uint32 offset, uint32 numFloats, float* data) {
std::memcpy(floatData.data() + offset, data, numFloats * sizeof(float));
}
uint32 Material::addTextures(uint32 numTextures) {
2025-03-20 20:15:38 +01:00
uint32 textureOffset = (uint32)textures.size();
2024-06-18 19:19:05 +02:00
textures.resize(textures.size() + numTextures);
2024-08-28 17:54:14 +02:00
assert(textures.size() < 512);
2024-06-18 19:19:05 +02:00
return textureOffset;
}
uint32 Material::addSamplers(uint32 numSamplers) {
2025-03-20 20:15:38 +01:00
uint32 samplerOffset = (uint32)samplers.size();
2024-06-18 19:19:05 +02:00
samplers.resize(samplers.size() + numSamplers);
2024-08-28 17:54:14 +02:00
assert(textures.size() < 512);
2024-06-18 19:19:05 +02:00
return samplerOffset;
}
uint32 Material::addFloats(uint32 numFloats) {
2025-03-20 20:15:38 +01:00
uint32 floatOffset = (uint32)floatData.size();
2024-06-18 19:19:05 +02:00
floatData.resize(floatData.size() + numFloats);
return floatOffset;
}
2024-06-09 12:20:04 +02:00
OMaterialInstance Material::instantiate() {
2024-06-18 19:19:05 +02:00
return new MaterialInstance(instanceId++, graphics, codeExpressions, parameters, numTextures, numSamplers, numFloats);
2023-01-21 18:43:21 +01:00
}
2024-06-20 21:57:26 +02:00
bool Material::isTwoSided() const { return twoSided; }
bool Material::hasTransparency() const { return opacity != 1.0f; }
float Material::getOpacity() const { return opacity; }
2023-01-21 18:43:21 +01:00
2024-06-09 12:20:04 +02:00
void Material::save(ArchiveBuffer& buffer) const {
2024-06-18 19:19:05 +02:00
Serialization::save(buffer, numTextures);
Serialization::save(buffer, numSamplers);
Serialization::save(buffer, numFloats);
2024-06-20 21:57:26 +02:00
Serialization::save(buffer, twoSided);
Serialization::save(buffer, opacity);
2023-11-01 13:38:49 +01:00
Serialization::save(buffer, instanceId);
2023-04-09 16:39:53 +02:00
Serialization::save(buffer, materialName);
2023-07-13 21:01:20 +02:00
Serialization::save(buffer, codeExpressions);
2023-11-01 13:38:49 +01:00
Serialization::save(buffer, parameters);
2023-07-13 21:01:20 +02:00
Serialization::save(buffer, brdf);
2023-02-13 14:56:13 +01:00
}
2024-06-09 12:20:04 +02:00
void Material::load(ArchiveBuffer& buffer) {
2023-02-13 14:56:13 +01:00
graphics = buffer.getGraphics();
2024-06-20 21:57:26 +02:00
if (layout == nullptr) {
2024-06-18 19:19:05 +02:00
init(graphics);
}
Serialization::load(buffer, numTextures);
Serialization::load(buffer, numSamplers);
Serialization::load(buffer, numFloats);
2024-06-20 21:57:26 +02:00
Serialization::load(buffer, twoSided);
Serialization::load(buffer, opacity);
2023-11-01 13:38:49 +01:00
Serialization::load(buffer, instanceId);
2023-02-13 14:56:13 +01:00
Serialization::load(buffer, materialName);
2023-11-01 13:38:49 +01:00
Serialization::load(buffer, codeExpressions);
Serialization::load(buffer, parameters);
Serialization::load(buffer, brdf);
2024-05-12 19:36:32 +02:00
materialId = materialIdCounter++;
2023-01-21 18:43:21 +01:00
}
2024-06-09 12:20:04 +02:00
void Material::compile() {
std::ofstream codeStream("./shaders/generated/" + materialName + ".slang");
2023-02-24 22:09:07 +01:00
codeStream << "import MaterialParameter;\n";
2024-06-18 19:19:05 +02:00
codeStream << "import Material;\n";
codeStream << "import LightEnv;\n";
codeStream << "struct Material : IMaterial{\n";
2023-02-24 22:09:07 +01:00
codeStream << "\ttypedef " << brdf.profile << " BRDF;\n";
2024-06-18 19:19:05 +02:00
codeStream << "\tstatic " << brdf.profile << " prepare(MaterialParameter input) {\n";
2023-02-24 22:09:07 +01:00
codeStream << "\t\t" << brdf.profile << " result;\n";
2023-11-05 10:36:01 +01:00
Map<std::string, std::string> varState;
2023-11-11 22:39:17 +01:00
// initialize variable state
2024-06-09 12:20:04 +02:00
for (const auto& expr : codeExpressions) {
2023-11-17 22:31:26 +01:00
codeStream << "\t\t" << expr->evaluate(varState);
2023-02-24 22:09:07 +01:00
}
2024-06-09 12:20:04 +02:00
for (const auto& [name, exp] : brdf.variables) {
2023-11-17 22:31:26 +01:00
codeStream << "\t\tresult." << name << " = " << varState[exp] << ";" << std::endl;
2023-02-24 22:09:07 +01:00
}
2025-01-30 23:25:41 +01:00
codeStream << "\t\tresult.transformNormal(input.tangentToWorld);" << std::endl;
2023-02-24 22:09:07 +01:00
codeStream << "\t\treturn result;\n";
codeStream << "\t}\n";
codeStream << "};\n";
2023-11-05 10:36:01 +01:00
graphics->getShaderCompiler()->registerMaterial(this);
2023-02-24 22:09:07 +01:00
}
2024-08-07 21:19:33 +02:00
uint64 Material::getCPUSize() const {
uint64 result = sizeof(Material);
for (size_t i = 0; i < parameters.size(); ++i) {
result += parameters[i].size();
}
for (const auto& expr : codeExpressions)
{
result += expr->getCPUSize();
}
return result;
}
uint64 Material::getGPUSize() const
{
uint64 result = 0;
for (const auto& expr : codeExpressions) {
result += expr->getGPUSize();
}
return result;
}