1569 lines
70 KiB
C++
1569 lines
70 KiB
C++
#include "stdafx.h"
|
|
#include "MaterialWindow.h"
|
|
|
|
using namespace wi::graphics;
|
|
using namespace wi::ecs;
|
|
using namespace wi::scene;
|
|
|
|
void AddTexturePropertiesString(const wi::graphics::TextureDesc& desc, std::string& str)
|
|
{
|
|
str += "\nResolution: " + std::to_string(desc.width) + " * " + std::to_string(desc.height);
|
|
if (desc.array_size > 1)
|
|
{
|
|
str += " * " + std::to_string(desc.array_size);
|
|
}
|
|
if (desc.depth > 1)
|
|
{
|
|
str += " * " + std::to_string(desc.depth);
|
|
}
|
|
if (has_flag(desc.misc_flags, ResourceMiscFlag::TEXTURECUBE))
|
|
{
|
|
str += " (cubemap)";
|
|
}
|
|
str += "\nMip levels: " + std::to_string(desc.mip_levels);
|
|
str += "\nFormat: ";
|
|
str += GetFormatString(desc.format);
|
|
str += "\nSwizzle: ";
|
|
str += GetSwizzleString(desc.swizzle);
|
|
str += "\nMemory: " + wi::helper::GetMemorySizeText(ComputeTextureMemorySizeInBytes(desc));
|
|
}
|
|
|
|
MaterialComponent* get_material(Scene& scene, PickResult x)
|
|
{
|
|
MaterialComponent* material = scene.materials.GetComponent(x.entity);
|
|
if (material == nullptr)
|
|
{
|
|
// Material could be selected indirectly as part of selected subset:
|
|
ObjectComponent* object = scene.objects.GetComponent(x.entity);
|
|
if (object != nullptr && object->meshID != INVALID_ENTITY)
|
|
{
|
|
MeshComponent* mesh = scene.meshes.GetComponent(object->meshID);
|
|
if (mesh != nullptr)
|
|
{
|
|
Entity materialID = mesh->subsets[x.subsetIndex].materialID;
|
|
material = scene.materials.GetComponent(materialID);
|
|
}
|
|
}
|
|
}
|
|
return material;
|
|
};
|
|
|
|
void ResetTexAnim(MaterialComponent* material)
|
|
{
|
|
if (material->texAnimFrameRate == 0 && material->texAnimDirection.x == 0 && material->texAnimDirection.y == 0)
|
|
{
|
|
material->texAnimElapsedTime = 0;
|
|
material->texMulAdd.z = 0;
|
|
material->texMulAdd.w = 0;
|
|
material->SetDirty();
|
|
}
|
|
}
|
|
|
|
void MaterialWindow::Create(EditorComponent* _editor)
|
|
{
|
|
editor = _editor;
|
|
wi::gui::Window::Create(ICON_MATERIAL " Material", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE | wi::gui::Window::WindowControls::FIT_ALL_WIDGETS_VERTICAL);
|
|
SetSize(XMFLOAT2(300, 1580));
|
|
|
|
closeButton.SetTooltip("Delete MaterialComponent");
|
|
OnClose([this](wi::gui::EventArgs args) {
|
|
|
|
wi::Archive& archive = editor->AdvanceHistory();
|
|
archive << EditorComponent::HISTORYOP_COMPONENT_DATA;
|
|
editor->RecordEntity(archive, entity);
|
|
|
|
editor->GetCurrentScene().materials.Remove(entity);
|
|
|
|
editor->RecordEntity(archive, entity);
|
|
|
|
editor->componentsWnd.RefreshEntityTree();
|
|
});
|
|
|
|
float hei = 18;
|
|
float step = hei + 2;
|
|
float x = 150, y = 0;
|
|
float wid = 130;
|
|
|
|
auto forEachSelected = [this] (auto func) {
|
|
return [=] (auto args) {
|
|
wi::scene::Scene& scene = editor->GetCurrentScene();
|
|
for (auto& x : editor->translator.selected)
|
|
{
|
|
MaterialComponent* material = get_material(scene, x);
|
|
if (material != nullptr)
|
|
func(material, args);
|
|
}
|
|
};
|
|
};
|
|
|
|
presetLoadButton.Create("Load preset");
|
|
presetLoadButton.SetTooltip("Load material preset from file");
|
|
presetLoadButton.SetSize(XMFLOAT2(wid, hei));
|
|
presetLoadButton.OnClick([this](wi::gui::EventArgs args) {
|
|
wi::helper::FileDialogParams params;
|
|
params.type = wi::helper::FileDialogParams::OPEN;
|
|
params.description = "Material Preset (.ini)";
|
|
params.extensions = { "ini" };
|
|
wi::helper::FileDialog(params, [this](std::string fileName) {
|
|
wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [this, fileName](uint64_t userdata) {
|
|
wi::config::File config;
|
|
if (!config.Open(fileName.c_str()))
|
|
{
|
|
wi::backlog::post("Failed to load material preset: " + fileName, wi::backlog::LogLevel::Warning);
|
|
return;
|
|
}
|
|
|
|
if (!config.HasSection("material"))
|
|
{
|
|
wi::backlog::post("Invalid material preset: " + fileName, wi::backlog::LogLevel::Warning);
|
|
return;
|
|
}
|
|
|
|
const wi::config::Section& materialSection = config.GetSection("material");
|
|
|
|
// Apply preset to all selected materials
|
|
wi::scene::Scene& scene = editor->GetCurrentScene();
|
|
for (const auto& selected : editor->translator.selected)
|
|
{
|
|
MaterialComponent* material = get_material(scene, selected);
|
|
if (material == nullptr)
|
|
continue;
|
|
|
|
// Load combobox values
|
|
if (materialSection.Has("ShaderType")) material->shaderType = (MaterialComponent::SHADERTYPE)materialSection.GetInt("ShaderType");
|
|
if (materialSection.Has("BlendMode")) material->userBlendMode = (wi::enums::BLENDMODE)materialSection.GetInt("BlendMode");
|
|
if (materialSection.Has("ShadingRate")) material->shadingRate = (wi::graphics::ShadingRate)materialSection.GetInt("ShadingRate");
|
|
|
|
// Load checkbox values
|
|
if (materialSection.Has("ReceiveShadow")) material->SetReceiveShadow(materialSection.GetBool("ReceiveShadow"));
|
|
if (materialSection.Has("CastShadow")) material->SetCastShadow(materialSection.GetBool("CastShadow"));
|
|
if (materialSection.Has("UseVertexColors")) material->SetUseVertexColors(materialSection.GetBool("UseVertexColors"));
|
|
if (materialSection.Has("SpecularGlossiness")) material->SetUseSpecularGlossinessWorkflow(materialSection.GetBool("SpecularGlossiness"));
|
|
if (materialSection.Has("OcclusionPrimary")) material->SetOcclusionEnabled_Primary(materialSection.GetBool("OcclusionPrimary"));
|
|
if (materialSection.Has("OcclusionSecondary")) material->SetOcclusionEnabled_Secondary(materialSection.GetBool("OcclusionSecondary"));
|
|
if (materialSection.Has("VertexAO")) material->SetVertexAODisabled(!materialSection.GetBool("VertexAO"));
|
|
if (materialSection.Has("Wind")) material->SetUseWind(materialSection.GetBool("Wind"));
|
|
if (materialSection.Has("DoubleSided")) material->SetDoubleSided(materialSection.GetBool("DoubleSided"));
|
|
if (materialSection.Has("Outline")) material->SetOutlineEnabled(materialSection.GetBool("Outline"));
|
|
if (materialSection.Has("PreferUncompressed")) material->SetPreferUncompressedTexturesEnabled(materialSection.GetBool("PreferUncompressed"));
|
|
if (materialSection.Has("DisableStreaming")) material->SetTextureStreamingDisabled(materialSection.GetBool("DisableStreaming"));
|
|
if (materialSection.Has("CoplanarBlending")) material->SetCoplanarBlending(materialSection.GetBool("CoplanarBlending"));
|
|
if (materialSection.Has("CapsuleShadowDisabled")) material->SetCapsuleShadowDisabled(materialSection.GetBool("CapsuleShadowDisabled"));
|
|
|
|
// Load slider values
|
|
if (materialSection.Has("NormalMapStrength")) material->normalMapStrength = materialSection.GetFloat("NormalMapStrength");
|
|
if (materialSection.Has("Roughness")) material->roughness = materialSection.GetFloat("Roughness");
|
|
if (materialSection.Has("Reflectance")) material->reflectance = materialSection.GetFloat("Reflectance");
|
|
if (materialSection.Has("Metalness")) material->metalness = materialSection.GetFloat("Metalness");
|
|
if (materialSection.Has("AlphaRef")) material->alphaRef = materialSection.GetFloat("AlphaRef");
|
|
if (materialSection.Has("EmissiveStrength")) material->emissiveColor.w = materialSection.GetFloat("EmissiveStrength");
|
|
if (materialSection.Has("Saturation")) material->saturation = materialSection.GetFloat("Saturation");
|
|
if (materialSection.Has("Cloak")) material->cloak = materialSection.GetFloat("Cloak");
|
|
if (materialSection.Has("ChromaticAberration")) material->chromatic_aberration = materialSection.GetFloat("ChromaticAberration");
|
|
if (materialSection.Has("Transmission")) material->transmission = materialSection.GetFloat("Transmission");
|
|
if (materialSection.Has("Refraction")) material->refraction = materialSection.GetFloat("Refraction");
|
|
if (materialSection.Has("ParallaxOcclusionMapping")) material->parallaxOcclusionMapping = materialSection.GetFloat("ParallaxOcclusionMapping");
|
|
if (materialSection.Has("AnisotropyStrength")) material->anisotropy_strength = materialSection.GetFloat("AnisotropyStrength");
|
|
if (materialSection.Has("AnisotropyRotation")) material->anisotropy_rotation = materialSection.GetFloat("AnisotropyRotation");
|
|
if (materialSection.Has("DisplacementMapping")) material->displacementMapping = materialSection.GetFloat("DisplacementMapping");
|
|
if (materialSection.Has("SubsurfaceScatteringStrength")) material->subsurfaceScattering.w = materialSection.GetFloat("SubsurfaceScatteringStrength");
|
|
if (materialSection.Has("TexAnimFrameRate")) material->texAnimFrameRate = materialSection.GetFloat("TexAnimFrameRate");
|
|
if (materialSection.Has("TexAnimDirectionU")) material->texAnimDirection.x = materialSection.GetFloat("TexAnimDirectionU");
|
|
if (materialSection.Has("TexAnimDirectionV")) material->texAnimDirection.y = materialSection.GetFloat("TexAnimDirectionV");
|
|
if (materialSection.Has("TexMulX")) material->texMulAdd.x = materialSection.GetFloat("TexMulX");
|
|
if (materialSection.Has("TexMulY")) material->texMulAdd.y = materialSection.GetFloat("TexMulY");
|
|
if (materialSection.Has("SheenRoughness")) material->sheenRoughness = materialSection.GetFloat("SheenRoughness");
|
|
if (materialSection.Has("Clearcoat")) material->clearcoat = materialSection.GetFloat("Clearcoat");
|
|
if (materialSection.Has("ClearcoatRoughness")) material->clearcoatRoughness = materialSection.GetFloat("ClearcoatRoughness");
|
|
if (materialSection.Has("BlendTerrain")) material->blend_with_terrain_height = materialSection.GetFloat("BlendTerrain");
|
|
if (materialSection.Has("Meshblend")) material->mesh_blend = materialSection.GetFloat("Meshblend");
|
|
if (materialSection.Has("InteriorScaleX")) material->interiorMappingScale.x = materialSection.GetFloat("InteriorScaleX");
|
|
if (materialSection.Has("InteriorScaleY")) material->interiorMappingScale.y = materialSection.GetFloat("InteriorScaleY");
|
|
if (materialSection.Has("InteriorScaleZ")) material->interiorMappingScale.z = materialSection.GetFloat("InteriorScaleZ");
|
|
if (materialSection.Has("InteriorOffsetX")) material->interiorMappingOffset.x = materialSection.GetFloat("InteriorOffsetX");
|
|
if (materialSection.Has("InteriorOffsetY")) material->interiorMappingOffset.y = materialSection.GetFloat("InteriorOffsetY");
|
|
if (materialSection.Has("InteriorOffsetZ")) material->interiorMappingOffset.z = materialSection.GetFloat("InteriorOffsetZ");
|
|
if (materialSection.Has("InteriorRotation")) material->interiorMappingRotation = materialSection.GetFloat("InteriorRotation");
|
|
|
|
// Load color values
|
|
if (materialSection.Has("BaseColorR") && materialSection.Has("BaseColorG") && materialSection.Has("BaseColorB") && materialSection.Has("BaseColorA"))
|
|
{
|
|
material->baseColor = XMFLOAT4(materialSection.GetFloat("BaseColorR"), materialSection.GetFloat("BaseColorG"), materialSection.GetFloat("BaseColorB"), materialSection.GetFloat("BaseColorA"));
|
|
}
|
|
if (materialSection.Has("SpecularColorR") && materialSection.Has("SpecularColorG") && materialSection.Has("SpecularColorB") && materialSection.Has("SpecularColorA"))
|
|
{
|
|
material->specularColor = XMFLOAT4(materialSection.GetFloat("SpecularColorR"), materialSection.GetFloat("SpecularColorG"), materialSection.GetFloat("SpecularColorB"), materialSection.GetFloat("SpecularColorA"));
|
|
}
|
|
if (materialSection.Has("EmissiveColorR") && materialSection.Has("EmissiveColorG") && materialSection.Has("EmissiveColorB") && materialSection.Has("EmissiveColorA"))
|
|
{
|
|
material->emissiveColor = XMFLOAT4(materialSection.GetFloat("EmissiveColorR"), materialSection.GetFloat("EmissiveColorG"), materialSection.GetFloat("EmissiveColorB"), materialSection.GetFloat("EmissiveColorA"));
|
|
}
|
|
if (materialSection.Has("SubsurfaceColorR") && materialSection.Has("SubsurfaceColorG") && materialSection.Has("SubsurfaceColorB") && materialSection.Has("SubsurfaceColorA"))
|
|
{
|
|
material->subsurfaceScattering = XMFLOAT4(materialSection.GetFloat("SubsurfaceColorR"), materialSection.GetFloat("SubsurfaceColorG"), materialSection.GetFloat("SubsurfaceColorB"), materialSection.GetFloat("SubsurfaceColorA"));
|
|
}
|
|
if (materialSection.Has("SheenColorR") && materialSection.Has("SheenColorG") && materialSection.Has("SheenColorB") && materialSection.Has("SheenColorA"))
|
|
{
|
|
material->sheenColor = XMFLOAT4(materialSection.GetFloat("SheenColorR"), materialSection.GetFloat("SheenColorG"), materialSection.GetFloat("SheenColorB"), materialSection.GetFloat("SheenColorA"));
|
|
}
|
|
if (materialSection.Has("ExtinctionColorR") && materialSection.Has("ExtinctionColorG") && materialSection.Has("ExtinctionColorB") && materialSection.Has("ExtinctionColorA"))
|
|
{
|
|
material->extinctionColor = XMFLOAT4(materialSection.GetFloat("ExtinctionColorR"), materialSection.GetFloat("ExtinctionColorG"), materialSection.GetFloat("ExtinctionColorB"), materialSection.GetFloat("ExtinctionColorA"));
|
|
}
|
|
|
|
material->SetDirty();
|
|
}
|
|
|
|
SetEntity(entity);
|
|
});
|
|
});
|
|
});
|
|
AddWidget(&presetLoadButton);
|
|
|
|
presetSaveButton.Create("Save preset");
|
|
presetSaveButton.SetTooltip("Save material preset to file");
|
|
presetSaveButton.SetSize(XMFLOAT2(wid, hei));
|
|
presetSaveButton.OnClick([this](wi::gui::EventArgs args) {
|
|
MaterialComponent* material = editor->GetCurrentScene().materials.GetComponent(entity);
|
|
if (material == nullptr)
|
|
return;
|
|
|
|
wi::helper::FileDialogParams params;
|
|
params.type = wi::helper::FileDialogParams::SAVE;
|
|
params.description = "Material Preset (.ini)";
|
|
params.extensions = { "ini" };
|
|
wi::helper::FileDialog(params, [material](std::string fileName) {
|
|
wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [material, fileName](uint64_t userdata) {
|
|
const std::string filePath = wi::helper::ForceExtension(fileName, "ini");
|
|
wi::config::File config;
|
|
config.Open(filePath.c_str());
|
|
|
|
wi::config::Section& materialSection = config.GetSection("material");
|
|
|
|
// Save combobox values
|
|
materialSection.Set("ShaderType", (int)material->shaderType);
|
|
materialSection.Set("BlendMode", (int)material->userBlendMode);
|
|
materialSection.Set("ShadingRate", (int)material->shadingRate);
|
|
|
|
// Save checkbox values
|
|
materialSection.Set("ReceiveShadow", material->IsReceiveShadow());
|
|
materialSection.Set("CastShadow", material->IsCastingShadow());
|
|
materialSection.Set("UseVertexColors", material->IsUsingVertexColors());
|
|
materialSection.Set("SpecularGlossiness", material->IsUsingSpecularGlossinessWorkflow());
|
|
materialSection.Set("OcclusionPrimary", material->IsOcclusionEnabled_Primary());
|
|
materialSection.Set("OcclusionSecondary", material->IsOcclusionEnabled_Secondary());
|
|
materialSection.Set("VertexAO", !material->IsVertexAODisabled());
|
|
materialSection.Set("Wind", material->IsUsingWind());
|
|
materialSection.Set("DoubleSided", material->IsDoubleSided());
|
|
materialSection.Set("Outline", material->IsOutlineEnabled());
|
|
materialSection.Set("PreferUncompressed", material->IsPreferUncompressedTexturesEnabled());
|
|
materialSection.Set("DisableStreaming", material->IsTextureStreamingDisabled());
|
|
materialSection.Set("CoplanarBlending", material->IsCoplanarBlending());
|
|
materialSection.Set("CapsuleShadowDisabled", material->IsCapsuleShadowDisabled());
|
|
|
|
// Save slider values
|
|
materialSection.Set("NormalMapStrength", material->normalMapStrength);
|
|
materialSection.Set("Roughness", material->roughness);
|
|
materialSection.Set("Reflectance", material->reflectance);
|
|
materialSection.Set("Metalness", material->metalness);
|
|
materialSection.Set("AlphaRef", material->alphaRef);
|
|
materialSection.Set("EmissiveStrength", material->emissiveColor.w);
|
|
materialSection.Set("Saturation", material->saturation);
|
|
materialSection.Set("Cloak", material->cloak);
|
|
materialSection.Set("ChromaticAberration", material->chromatic_aberration);
|
|
materialSection.Set("Transmission", material->transmission);
|
|
materialSection.Set("Refraction", material->refraction);
|
|
materialSection.Set("ParallaxOcclusionMapping", material->parallaxOcclusionMapping);
|
|
materialSection.Set("AnisotropyStrength", material->anisotropy_strength);
|
|
materialSection.Set("AnisotropyRotation", material->anisotropy_rotation);
|
|
materialSection.Set("DisplacementMapping", material->displacementMapping);
|
|
materialSection.Set("SubsurfaceScatteringStrength", material->subsurfaceScattering.w);
|
|
materialSection.Set("TexAnimFrameRate", material->texAnimFrameRate);
|
|
materialSection.Set("TexAnimDirectionU", material->texAnimDirection.x);
|
|
materialSection.Set("TexAnimDirectionV", material->texAnimDirection.y);
|
|
materialSection.Set("TexMulX", material->texMulAdd.x);
|
|
materialSection.Set("TexMulY", material->texMulAdd.y);
|
|
materialSection.Set("SheenRoughness", material->sheenRoughness);
|
|
materialSection.Set("Clearcoat", material->clearcoat);
|
|
materialSection.Set("ClearcoatRoughness", material->clearcoatRoughness);
|
|
materialSection.Set("BlendTerrain", material->blend_with_terrain_height);
|
|
materialSection.Set("Meshblend", material->mesh_blend);
|
|
materialSection.Set("InteriorScaleX", material->interiorMappingScale.x);
|
|
materialSection.Set("InteriorScaleY", material->interiorMappingScale.y);
|
|
materialSection.Set("InteriorScaleZ", material->interiorMappingScale.z);
|
|
materialSection.Set("InteriorOffsetX", material->interiorMappingOffset.x);
|
|
materialSection.Set("InteriorOffsetY", material->interiorMappingOffset.y);
|
|
materialSection.Set("InteriorOffsetZ", material->interiorMappingOffset.z);
|
|
materialSection.Set("InteriorRotation", material->interiorMappingRotation);
|
|
|
|
// Save color values
|
|
materialSection.Set("BaseColorR", material->baseColor.x);
|
|
materialSection.Set("BaseColorG", material->baseColor.y);
|
|
materialSection.Set("BaseColorB", material->baseColor.z);
|
|
materialSection.Set("BaseColorA", material->baseColor.w);
|
|
materialSection.Set("SpecularColorR", material->specularColor.x);
|
|
materialSection.Set("SpecularColorG", material->specularColor.y);
|
|
materialSection.Set("SpecularColorB", material->specularColor.z);
|
|
materialSection.Set("SpecularColorA", material->specularColor.w);
|
|
materialSection.Set("EmissiveColorR", material->emissiveColor.x);
|
|
materialSection.Set("EmissiveColorG", material->emissiveColor.y);
|
|
materialSection.Set("EmissiveColorB", material->emissiveColor.z);
|
|
materialSection.Set("EmissiveColorA", material->emissiveColor.w);
|
|
materialSection.Set("SubsurfaceColorR", material->subsurfaceScattering.x);
|
|
materialSection.Set("SubsurfaceColorG", material->subsurfaceScattering.y);
|
|
materialSection.Set("SubsurfaceColorB", material->subsurfaceScattering.z);
|
|
materialSection.Set("SubsurfaceColorA", material->subsurfaceScattering.w);
|
|
materialSection.Set("SheenColorR", material->sheenColor.x);
|
|
materialSection.Set("SheenColorG", material->sheenColor.y);
|
|
materialSection.Set("SheenColorB", material->sheenColor.z);
|
|
materialSection.Set("SheenColorA", material->sheenColor.w);
|
|
materialSection.Set("ExtinctionColorR", material->extinctionColor.x);
|
|
materialSection.Set("ExtinctionColorG", material->extinctionColor.y);
|
|
materialSection.Set("ExtinctionColorB", material->extinctionColor.z);
|
|
materialSection.Set("ExtinctionColorA", material->extinctionColor.w);
|
|
|
|
config.Commit();
|
|
wi::backlog::post("Material preset saved: " + filePath);
|
|
});
|
|
});
|
|
});
|
|
AddWidget(&presetSaveButton);
|
|
|
|
shadowReceiveCheckBox.Create("Receive Shadow: ");
|
|
shadowReceiveCheckBox.SetTooltip("Receives shadow or not?");
|
|
shadowReceiveCheckBox.SetPos(XMFLOAT2(x, y));
|
|
shadowReceiveCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
shadowReceiveCheckBox.OnClick(forEachSelected([] (auto material, auto args) {
|
|
material->SetReceiveShadow(args.bValue);
|
|
}));
|
|
AddWidget(&shadowReceiveCheckBox);
|
|
|
|
shadowCasterCheckBox.Create("Cast Shadow: ");
|
|
shadowCasterCheckBox.SetTooltip("The subset will contribute to the scene shadows if enabled.");
|
|
shadowCasterCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
shadowCasterCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
shadowCasterCheckBox.OnClick(forEachSelected([] (auto material, auto args) {
|
|
material->SetCastShadow(args.bValue);
|
|
}));
|
|
AddWidget(&shadowCasterCheckBox);
|
|
|
|
useVertexColorsCheckBox.Create("Use vertex colors: ");
|
|
useVertexColorsCheckBox.SetTooltip("Enable if you want to render the mesh with vertex colors (must have appropriate vertex buffer)");
|
|
useVertexColorsCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
useVertexColorsCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
useVertexColorsCheckBox.OnClick(forEachSelected([] (auto material, auto args) {
|
|
material->SetUseVertexColors(args.bValue);
|
|
}));
|
|
AddWidget(&useVertexColorsCheckBox);
|
|
|
|
specularGlossinessCheckBox.Create("Spec-gloss workflow: ");
|
|
specularGlossinessCheckBox.SetTooltip("If enabled, surface map will be viewed like it contains specular color (RGB) and smoothness (A)");
|
|
specularGlossinessCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
specularGlossinessCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
specularGlossinessCheckBox.OnClick(forEachSelected([] (auto material, auto args) {
|
|
material->SetUseSpecularGlossinessWorkflow(args.bValue);
|
|
}));
|
|
AddWidget(&specularGlossinessCheckBox);
|
|
|
|
occlusionPrimaryCheckBox.Create("Occlusion 1: ");
|
|
occlusionPrimaryCheckBox.SetTooltip("If enabled, surface map's RED channel will be used as occlusion map");
|
|
occlusionPrimaryCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
occlusionPrimaryCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
occlusionPrimaryCheckBox.OnClick(forEachSelected([] (auto material, auto args) {
|
|
material->SetOcclusionEnabled_Primary(args.bValue);
|
|
}));
|
|
AddWidget(&occlusionPrimaryCheckBox);
|
|
|
|
occlusionSecondaryCheckBox.Create("Occlusion 2: ");
|
|
occlusionSecondaryCheckBox.SetTooltip("If enabled, occlusion map's RED channel will be used as occlusion map");
|
|
occlusionSecondaryCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
occlusionSecondaryCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
occlusionSecondaryCheckBox.OnClick(forEachSelected([] (auto material, auto args) {
|
|
material->SetOcclusionEnabled_Secondary(args.bValue);
|
|
}));
|
|
AddWidget(&occlusionSecondaryCheckBox);
|
|
|
|
vertexAOCheckBox.Create("Vertex AO: ");
|
|
vertexAOCheckBox.SetTooltip("If enabled, vertex ambient occlusion will be enabled (if it exists)");
|
|
vertexAOCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
vertexAOCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
vertexAOCheckBox.OnClick(forEachSelected([] (auto material, auto args) {
|
|
material->SetVertexAODisabled(!args.bValue);
|
|
}));
|
|
AddWidget(&vertexAOCheckBox);
|
|
|
|
windCheckBox.Create("Wind: ");
|
|
windCheckBox.SetTooltip("If enabled, vertex wind weights will affect how much wind offset affects the subset.");
|
|
windCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
windCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
windCheckBox.OnClick(forEachSelected([] (auto material, auto args) {
|
|
material->SetUseWind(args.bValue);
|
|
}));
|
|
AddWidget(&windCheckBox);
|
|
|
|
doubleSidedCheckBox.Create("Double sided: ");
|
|
doubleSidedCheckBox.SetTooltip("Decide whether to render both sides of the material (It's also possible to set this behaviour per mesh).");
|
|
doubleSidedCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
doubleSidedCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
doubleSidedCheckBox.OnClick(forEachSelected([] (auto material, auto args) {
|
|
material->SetDoubleSided(args.bValue);
|
|
}));
|
|
AddWidget(&doubleSidedCheckBox);
|
|
|
|
outlineCheckBox.Create("Cartoon Outline: ");
|
|
outlineCheckBox.SetTooltip("Enable cartoon outline. The Cartoon Outline graphics setting also needs to be enabled for it to show up.");
|
|
outlineCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
outlineCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
outlineCheckBox.OnClick(forEachSelected([] (auto material, auto args) {
|
|
material->SetOutlineEnabled(args.bValue);
|
|
}));
|
|
AddWidget(&outlineCheckBox);
|
|
|
|
preferUncompressedCheckBox.Create("Prefer Uncompressed Textures: ");
|
|
preferUncompressedCheckBox.SetTooltip("For uncompressed textures (jpg, png, etc.) here it is possible to enable/disable auto block compression on importing. \nBlock compression can reduce GPU memory usage and improve performance, but it can result in degraded quality.");
|
|
preferUncompressedCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
preferUncompressedCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
preferUncompressedCheckBox.OnClick(forEachSelected([this] (auto material, auto args) {
|
|
material->SetPreferUncompressedTexturesEnabled(args.bValue);
|
|
textureSlotComboBox.SetSelected(textureSlotComboBox.GetSelected()); // update
|
|
}));
|
|
AddWidget(&preferUncompressedCheckBox);
|
|
|
|
disableStreamingCheckBox.Create("Disable Texture Streaming: ");
|
|
disableStreamingCheckBox.SetTooltip("Disable texture streaming for this material only.");
|
|
disableStreamingCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
disableStreamingCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
disableStreamingCheckBox.OnClick(forEachSelected([this] (auto material, auto args) {
|
|
material->SetTextureStreamingDisabled(args.bValue);
|
|
material->CreateRenderData(true);
|
|
textureSlotComboBox.SetSelected(textureSlotComboBox.GetSelected()); // update
|
|
}));
|
|
AddWidget(&disableStreamingCheckBox);
|
|
|
|
coplanarCheckBox.Create("Coplanar blending: ");
|
|
coplanarCheckBox.SetTooltip("If polygons are coplanar to an opaque surface, then the blending can be done in the opaque pass.\nThis can enable some benefits of opaque render pass to a specific transparent surface.");
|
|
coplanarCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
coplanarCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
coplanarCheckBox.OnClick(forEachSelected([] (auto material, auto args) {
|
|
material->SetCoplanarBlending(args.bValue);
|
|
}));
|
|
AddWidget(&coplanarCheckBox);
|
|
|
|
capsuleShadowCheckBox.Create("Capsule Shadow Disabled: ");
|
|
capsuleShadowCheckBox.SetTooltip("Disable receiving capsule shadows for this material.");
|
|
capsuleShadowCheckBox.SetPos(XMFLOAT2(x, y += step));
|
|
capsuleShadowCheckBox.SetSize(XMFLOAT2(hei, hei));
|
|
capsuleShadowCheckBox.OnClick(forEachSelected([] (auto material, auto args) {
|
|
material->SetCapsuleShadowDisabled(args.bValue);
|
|
}));
|
|
AddWidget(&capsuleShadowCheckBox);
|
|
|
|
|
|
shaderTypeComboBox.Create("Shader: ");
|
|
shaderTypeComboBox.SetTooltip("Select a shader for this material. \nCustom shaders (*) will also show up here (see wi::renderer:RegisterCustomShader() for more info.)\nNote that custom shaders (*) can't select between blend modes, as they are created with an explicit blend mode.");
|
|
shaderTypeComboBox.SetPos(XMFLOAT2(x, y += step));
|
|
shaderTypeComboBox.SetSize(XMFLOAT2(wid, hei));
|
|
shaderTypeComboBox.OnSelect(forEachSelected([this] (auto material, auto args) {
|
|
if (args.iValue >= MaterialComponent::SHADERTYPE_COUNT)
|
|
{
|
|
material->SetCustomShaderID(args.iValue - MaterialComponent::SHADERTYPE_COUNT);
|
|
blendModeComboBox.SetEnabled(false);
|
|
}
|
|
else
|
|
{
|
|
material->shaderType = (MaterialComponent::SHADERTYPE)args.userdata;
|
|
material->SetCustomShaderID(-1);
|
|
blendModeComboBox.SetEnabled(true);
|
|
}
|
|
}));
|
|
shaderTypeComboBox.SetEnabled(false);
|
|
shaderTypeComboBox.SetMaxVisibleItemCount(5);
|
|
AddWidget(&shaderTypeComboBox);
|
|
|
|
blendModeComboBox.Create("Blend mode: ");
|
|
blendModeComboBox.SetPos(XMFLOAT2(x, y += step));
|
|
blendModeComboBox.SetSize(XMFLOAT2(wid, hei));
|
|
blendModeComboBox.OnSelect(forEachSelected([] (auto material, auto args) {
|
|
material->userBlendMode = (wi::enums::BLENDMODE)args.userdata;
|
|
}));
|
|
blendModeComboBox.AddItem("Opaque", wi::enums::BLENDMODE_OPAQUE);
|
|
blendModeComboBox.AddItem("Alpha", wi::enums::BLENDMODE_ALPHA);
|
|
blendModeComboBox.AddItem("Premultiplied", wi::enums::BLENDMODE_PREMULTIPLIED);
|
|
blendModeComboBox.AddItem("Additive", wi::enums::BLENDMODE_ADDITIVE);
|
|
blendModeComboBox.AddItem("Multiply", wi::enums::BLENDMODE_MULTIPLY);
|
|
blendModeComboBox.AddItem("Inverse", wi::enums::BLENDMODE_INVERSE);
|
|
blendModeComboBox.SetEnabled(false);
|
|
blendModeComboBox.SetTooltip("Set the blend mode of the material.");
|
|
AddWidget(&blendModeComboBox);
|
|
|
|
shadingRateComboBox.Create("Shading Rate: ");
|
|
shadingRateComboBox.SetTooltip("Select shading rate for this material. \nSelecting larger shading rate will decrease rendering quality of this material, \nbut increases performance.\nRequires hardware support for variable shading rate");
|
|
shadingRateComboBox.SetPos(XMFLOAT2(x, y += step));
|
|
shadingRateComboBox.SetSize(XMFLOAT2(wid, hei));
|
|
shadingRateComboBox.OnSelect(forEachSelected([] (auto material, auto args) {
|
|
material->shadingRate = (ShadingRate)args.iValue;
|
|
}));
|
|
shadingRateComboBox.AddItem("1X1");
|
|
shadingRateComboBox.AddItem("1X2");
|
|
shadingRateComboBox.AddItem("2X1");
|
|
shadingRateComboBox.AddItem("2X2");
|
|
shadingRateComboBox.AddItem("2X4");
|
|
shadingRateComboBox.AddItem("4X2");
|
|
shadingRateComboBox.AddItem("4X4");
|
|
shadingRateComboBox.SetEnabled(false);
|
|
shadingRateComboBox.SetMaxVisibleItemCount(4);
|
|
AddWidget(&shadingRateComboBox);
|
|
|
|
|
|
cameraComboBox.Create("Camera source: ");
|
|
cameraComboBox.SetTooltip("Select a camera to use as texture");
|
|
cameraComboBox.OnSelect(forEachSelected([this] (auto material, auto args) {
|
|
material->cameraSource = (Entity)args.userdata;
|
|
|
|
auto& scene = editor->GetCurrentScene();
|
|
CameraComponent* camera = scene.cameras.GetComponent((Entity)args.userdata);
|
|
if (camera != nullptr)
|
|
{
|
|
camera->render_to_texture.resolution = XMUINT2(256, 256);
|
|
}
|
|
}));
|
|
AddWidget(&cameraComboBox);
|
|
|
|
|
|
|
|
|
|
// Sliders:
|
|
|
|
normalMapSlider.Create(0, 4, 1, 4000, "Normalmap: ");
|
|
normalMapSlider.SetTooltip("How much the normal map should distort the face normals (bumpiness).");
|
|
normalMapSlider.SetSize(XMFLOAT2(wid, hei));
|
|
normalMapSlider.SetPos(XMFLOAT2(x, y += step));
|
|
normalMapSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetNormalMapStrength(args.fValue);
|
|
}));
|
|
AddWidget(&normalMapSlider);
|
|
|
|
roughnessSlider.Create(0, 1, 0.5f, 1000, "Roughness: ");
|
|
roughnessSlider.SetTooltip("Adjust the surface roughness. Rough surfaces are less shiny, more matte.");
|
|
roughnessSlider.SetSize(XMFLOAT2(wid, hei));
|
|
roughnessSlider.SetPos(XMFLOAT2(x, y += step));
|
|
roughnessSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetRoughness(args.fValue);
|
|
}));
|
|
AddWidget(&roughnessSlider);
|
|
|
|
reflectanceSlider.Create(0, 1, 0.5f, 1000, "Reflectance: ");
|
|
reflectanceSlider.SetTooltip("Adjust the surface [non-metal] reflectivity (also called specularFactor).\nNote: this is not available in specular-glossiness workflow");
|
|
reflectanceSlider.SetSize(XMFLOAT2(wid, hei));
|
|
reflectanceSlider.SetPos(XMFLOAT2(x, y += step));
|
|
reflectanceSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetReflectance(args.fValue);
|
|
}));
|
|
AddWidget(&reflectanceSlider);
|
|
|
|
metalnessSlider.Create(0, 1, 0.0f, 1000, "Metalness: ");
|
|
metalnessSlider.SetTooltip("The more metal-like the surface is, the more the its color will contribute to the reflection color.\nNote: this is not available in specular-glossiness workflow");
|
|
metalnessSlider.SetSize(XMFLOAT2(wid, hei));
|
|
metalnessSlider.SetPos(XMFLOAT2(x, y += step));
|
|
metalnessSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetMetalness(args.fValue);
|
|
}));
|
|
AddWidget(&metalnessSlider);
|
|
|
|
alphaRefSlider.Create(0, 1, 1.0f, 1000, "AlphaRef: ");
|
|
alphaRefSlider.SetTooltip("Adjust the alpha cutoff threshold. Alpha cutout can affect performance");
|
|
alphaRefSlider.SetSize(XMFLOAT2(wid, hei));
|
|
alphaRefSlider.SetPos(XMFLOAT2(x, y += step));
|
|
alphaRefSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetAlphaRef(args.fValue);
|
|
}));
|
|
AddWidget(&alphaRefSlider);
|
|
|
|
emissiveSlider.Create(0, 10, 0.0f, 1000, "Emissive: ");
|
|
emissiveSlider.SetTooltip("Adjust the light emission of the surface. The color of the light emitted is that of the color of the material.");
|
|
emissiveSlider.SetSize(XMFLOAT2(wid, hei));
|
|
emissiveSlider.SetPos(XMFLOAT2(x, y += step));
|
|
emissiveSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetEmissiveStrength(args.fValue);
|
|
}));
|
|
AddWidget(&emissiveSlider);
|
|
|
|
saturationSlider.Create(0, 2, 1, 1000, "Saturation: ");
|
|
saturationSlider.SetTooltip("Adjust the saturation of the material.");
|
|
saturationSlider.SetSize(XMFLOAT2(wid, hei));
|
|
saturationSlider.SetPos(XMFLOAT2(x, y += step));
|
|
saturationSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetSaturation(args.fValue);
|
|
}));
|
|
AddWidget(&saturationSlider);
|
|
|
|
cloakSlider.Create(0, 1.0f, 0.02f, 1000, "Cloak: ");
|
|
cloakSlider.SetTooltip("The cloak effect is a combination of transmission, refraction and roughness, without color tinging.");
|
|
cloakSlider.SetSize(XMFLOAT2(wid, hei));
|
|
cloakSlider.SetPos(XMFLOAT2(x, y += step));
|
|
cloakSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetCloakAmount(args.fValue);
|
|
}));
|
|
AddWidget(&cloakSlider);
|
|
|
|
chromaticAberrationSlider.Create(0, 10.0f, 0, 1000, "Chromatic aberration: ");
|
|
chromaticAberrationSlider.SetTooltip("Separation of RGB colors inside transmissive material.");
|
|
chromaticAberrationSlider.SetSize(XMFLOAT2(wid, hei));
|
|
chromaticAberrationSlider.SetPos(XMFLOAT2(x, y += step));
|
|
chromaticAberrationSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetChromaticAberrationAmount(args.fValue);
|
|
}));
|
|
AddWidget(&chromaticAberrationSlider);
|
|
|
|
transmissionSlider.Create(0, 1.0f, 0.02f, 1000, "Transmission: ");
|
|
transmissionSlider.SetTooltip("Adjust the transmissiveness. More transmissiveness means more diffuse light is transmitted instead of absorbed.");
|
|
transmissionSlider.SetSize(XMFLOAT2(wid, hei));
|
|
transmissionSlider.SetPos(XMFLOAT2(x, y += step));
|
|
transmissionSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetTransmissionAmount(args.fValue);
|
|
}));
|
|
AddWidget(&transmissionSlider);
|
|
|
|
refractionSlider.Create(0, 1, 0, 1000, "Refraction: ");
|
|
refractionSlider.SetTooltip("Adjust the refraction amount for transmissive materials.");
|
|
refractionSlider.SetSize(XMFLOAT2(wid, hei));
|
|
refractionSlider.SetPos(XMFLOAT2(x, y += step));
|
|
refractionSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetRefractionAmount(args.fValue);
|
|
}));
|
|
AddWidget(&refractionSlider);
|
|
|
|
pomSlider.Create(0, 1.0f, 0.0f, 1000, "Par Occl Mapping: ");
|
|
pomSlider.SetTooltip("[Parallax Occlusion Mapping] Adjust how much the bump map should modulate the surface parallax effect. \nOnly works with PBR + Parallax shader.");
|
|
pomSlider.SetSize(XMFLOAT2(wid, hei));
|
|
pomSlider.SetPos(XMFLOAT2(x, y += step));
|
|
pomSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetParallaxOcclusionMapping(args.fValue);
|
|
}));
|
|
AddWidget(&pomSlider);
|
|
|
|
anisotropyStrengthSlider.Create(0, 1.0f, 0.0f, 1000, "Anisotropy Strength: ");
|
|
anisotropyStrengthSlider.SetTooltip("Adjust anisotropy specular effect's strength. \nOnly works with PBR + Anisotropic shader.");
|
|
anisotropyStrengthSlider.SetSize(XMFLOAT2(wid, hei));
|
|
anisotropyStrengthSlider.SetPos(XMFLOAT2(x, y += step));
|
|
anisotropyStrengthSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->anisotropy_strength = args.fValue;
|
|
}));
|
|
AddWidget(&anisotropyStrengthSlider);
|
|
|
|
anisotropyRotationSlider.Create(0, 360, 0.0f, 360, "Anisotropy Rot: ");
|
|
anisotropyRotationSlider.SetTooltip("Adjust anisotropy specular effect's rotation. \nOnly works with PBR + Anisotropic shader.");
|
|
anisotropyRotationSlider.SetSize(XMFLOAT2(wid, hei));
|
|
anisotropyRotationSlider.SetPos(XMFLOAT2(x, y += step));
|
|
anisotropyRotationSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->anisotropy_rotation = wi::math::DegreesToRadians(args.fValue);
|
|
}));
|
|
AddWidget(&anisotropyRotationSlider);
|
|
|
|
|
|
displacementMappingSlider.Create(0, 10.0f, 0.0f, 1000, "Displacement: ");
|
|
displacementMappingSlider.SetTooltip("Adjust how much the bump map should modulate the geometry when using tessellation.");
|
|
displacementMappingSlider.SetSize(XMFLOAT2(wid, hei));
|
|
displacementMappingSlider.SetPos(XMFLOAT2(x, y += step));
|
|
displacementMappingSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetDisplacementMapping(args.fValue);
|
|
}));
|
|
AddWidget(&displacementMappingSlider);
|
|
|
|
subsurfaceScatteringSlider.Create(0, 2, 0.0f, 1000, "Subsurface Scattering: ");
|
|
subsurfaceScatteringSlider.SetTooltip("Subsurface scattering amount. \nYou can also adjust the subsurface color by selecting it in the color picker");
|
|
subsurfaceScatteringSlider.SetSize(XMFLOAT2(wid, hei));
|
|
subsurfaceScatteringSlider.SetPos(XMFLOAT2(x, y += step));
|
|
subsurfaceScatteringSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetSubsurfaceScatteringAmount(args.fValue);
|
|
}));
|
|
AddWidget(&subsurfaceScatteringSlider);
|
|
|
|
texAnimFrameRateSlider.Create(0, 60, 0, 60, "Texcoord anim FPS: ");
|
|
texAnimFrameRateSlider.SetTooltip("Adjust the texture animation frame rate (frames per second). Any value above 0 will make the material dynamic.");
|
|
texAnimFrameRateSlider.SetSize(XMFLOAT2(wid, hei));
|
|
texAnimFrameRateSlider.SetPos(XMFLOAT2(x, y += step));
|
|
texAnimFrameRateSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->texAnimFrameRate = args.fValue;
|
|
ResetTexAnim(material);
|
|
}));
|
|
AddWidget(&texAnimFrameRateSlider);
|
|
|
|
texAnimDirectionSliderU.Create(-0.05f, 0.05f, 0, 1000, "Texcoord anim U: ");
|
|
texAnimDirectionSliderU.SetTooltip("Adjust the texture animation speed along the U direction in texture space.");
|
|
texAnimDirectionSliderU.SetSize(XMFLOAT2(wid, hei));
|
|
texAnimDirectionSliderU.SetPos(XMFLOAT2(x, y += step));
|
|
texAnimDirectionSliderU.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->texAnimDirection.x = args.fValue;
|
|
ResetTexAnim(material);
|
|
}));
|
|
AddWidget(&texAnimDirectionSliderU);
|
|
|
|
texAnimDirectionSliderV.Create(-0.05f, 0.05f, 0, 1000, "Texcoord anim V: ");
|
|
texAnimDirectionSliderV.SetTooltip("Adjust the texture animation speed along the V direction in texture space.");
|
|
texAnimDirectionSliderV.SetSize(XMFLOAT2(wid, hei));
|
|
texAnimDirectionSliderV.SetPos(XMFLOAT2(x, y += step));
|
|
texAnimDirectionSliderV.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->texAnimDirection.y = args.fValue;
|
|
ResetTexAnim(material);
|
|
}));
|
|
AddWidget(&texAnimDirectionSliderV);
|
|
|
|
texMulSliderX.Create(0.01f, 10.0f, 0, 1000, "Texture TileSize X: ");
|
|
texMulSliderX.SetTooltip("Adjust the texture mapping size.");
|
|
texMulSliderX.SetSize(XMFLOAT2(wid, hei));
|
|
texMulSliderX.SetPos(XMFLOAT2(x, y += step));
|
|
texMulSliderX.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetDirty();
|
|
material->texMulAdd.x = args.fValue;
|
|
}));
|
|
AddWidget(&texMulSliderX);
|
|
|
|
texMulSliderY.Create(0.01f, 10.0f, 0, 1000, "Texture TileSize Y: ");
|
|
texMulSliderY.SetTooltip("Adjust the texture mapping size.");
|
|
texMulSliderY.SetSize(XMFLOAT2(wid, hei));
|
|
texMulSliderY.SetPos(XMFLOAT2(x, y += step));
|
|
texMulSliderY.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetDirty();
|
|
material->texMulAdd.y = args.fValue;
|
|
}));
|
|
AddWidget(&texMulSliderY);
|
|
|
|
|
|
sheenRoughnessSlider.Create(0, 1, 0, 1000, "Sheen Roughness: ");
|
|
sheenRoughnessSlider.SetTooltip("This affects roughness of sheen layer for cloth shading.");
|
|
sheenRoughnessSlider.SetSize(XMFLOAT2(wid, hei));
|
|
sheenRoughnessSlider.SetPos(XMFLOAT2(x, y += step));
|
|
sheenRoughnessSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetSheenRoughness(args.fValue);
|
|
}));
|
|
AddWidget(&sheenRoughnessSlider);
|
|
|
|
clearcoatSlider.Create(0, 1, 0, 1000, "Clearcoat: ");
|
|
clearcoatSlider.SetTooltip("This affects clearcoat layer blending.");
|
|
clearcoatSlider.SetSize(XMFLOAT2(wid, hei));
|
|
clearcoatSlider.SetPos(XMFLOAT2(x, y += step));
|
|
clearcoatSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetClearcoatFactor(args.fValue);
|
|
}));
|
|
AddWidget(&clearcoatSlider);
|
|
|
|
clearcoatRoughnessSlider.Create(0, 1, 0, 1000, "Clearcoat Roughness: ");
|
|
clearcoatRoughnessSlider.SetTooltip("This affects roughness of clear coat layer.");
|
|
clearcoatRoughnessSlider.SetSize(XMFLOAT2(wid, hei));
|
|
clearcoatRoughnessSlider.SetPos(XMFLOAT2(x, y += step));
|
|
clearcoatRoughnessSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetClearcoatRoughness(args.fValue);
|
|
}));
|
|
AddWidget(&clearcoatRoughnessSlider);
|
|
|
|
blendTerrainSlider.Create(0, 2, 0, 1000, "Blend with terrain: ");
|
|
blendTerrainSlider.SetTooltip("Blend with terrain height.");
|
|
blendTerrainSlider.SetSize(XMFLOAT2(wid, hei));
|
|
blendTerrainSlider.SetPos(XMFLOAT2(x, y += step));
|
|
blendTerrainSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetBlendWithTerrainHeight(args.fValue);
|
|
}));
|
|
AddWidget(&blendTerrainSlider);
|
|
|
|
meshblendSlider.Create(0, 2, 0, 1000, "Mesh Blend: ");
|
|
meshblendSlider.SetTooltip("Screen space Mesh Blend post process distance falloff.");
|
|
meshblendSlider.SetSize(XMFLOAT2(wid, hei));
|
|
meshblendSlider.SetPos(XMFLOAT2(x, y += step));
|
|
meshblendSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetMeshBlend(args.fValue);
|
|
}));
|
|
AddWidget(&meshblendSlider);
|
|
|
|
interiorScaleXSlider.Create(1, 10, 1, 1000, "Interior Scale X: ");
|
|
interiorScaleXSlider.SetTooltip("Set the cubemap scale for the interior mapping (if material uses interior mapping shader)");
|
|
interiorScaleXSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetInteriorMappingScale(XMFLOAT3(args.fValue, material->interiorMappingScale.y, material->interiorMappingScale.z));
|
|
}));
|
|
AddWidget(&interiorScaleXSlider);
|
|
|
|
interiorScaleYSlider.Create(1, 10, 1, 1000, "Interior Scale Y: ");
|
|
interiorScaleYSlider.SetTooltip("Set the cubemap scale for the interior mapping (if material uses interior mapping shader)");
|
|
interiorScaleYSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetInteriorMappingScale(XMFLOAT3(material->interiorMappingScale.x, args.fValue, material->interiorMappingScale.z));
|
|
}));
|
|
AddWidget(&interiorScaleYSlider);
|
|
|
|
interiorScaleZSlider.Create(1, 10, 1, 1000, "Interior Scale Z: ");
|
|
interiorScaleZSlider.SetTooltip("Set the cubemap scale for the interior mapping (if material uses interior mapping shader)");
|
|
interiorScaleZSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetInteriorMappingScale(XMFLOAT3(material->interiorMappingScale.x, material->interiorMappingScale.y, args.fValue));
|
|
}));
|
|
AddWidget(&interiorScaleZSlider);
|
|
|
|
interiorOffsetXSlider.Create(-10, 10, 0, 2000, "Interior Offset X: ");
|
|
interiorOffsetXSlider.SetTooltip("Set the cubemap offset for the interior mapping (if material uses interior mapping shader)");
|
|
interiorOffsetXSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetInteriorMappingOffset(XMFLOAT3(args.fValue, material->interiorMappingOffset.y, material->interiorMappingOffset.z));
|
|
}));
|
|
AddWidget(&interiorOffsetXSlider);
|
|
|
|
interiorOffsetYSlider.Create(-10, 10, 0, 2000, "Interior Offset Y: ");
|
|
interiorOffsetYSlider.SetTooltip("Set the cubemap offset for the interior mapping (if material uses interior mapping shader)");
|
|
interiorOffsetYSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetInteriorMappingOffset(XMFLOAT3(material->interiorMappingOffset.x, args.fValue, material->interiorMappingOffset.z));
|
|
}));
|
|
AddWidget(&interiorOffsetYSlider);
|
|
|
|
interiorOffsetZSlider.Create(-10, 10, 0, 2000, "Interior Offset Z: ");
|
|
interiorOffsetZSlider.SetTooltip("Set the cubemap offset for the interior mapping (if material uses interior mapping shader)");
|
|
interiorOffsetZSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
material->SetInteriorMappingOffset(XMFLOAT3(material->interiorMappingOffset.x, material->interiorMappingOffset.y, args.fValue));
|
|
}));
|
|
AddWidget(&interiorOffsetZSlider);
|
|
|
|
interiorRotationSlider.Create(0, 360, 0, 360, "Interior Rotation: ");
|
|
interiorRotationSlider.SetTooltip("Set the cubemap horizontal rotation for the interior mapping (if material uses interior mapping shader)");
|
|
interiorRotationSlider.OnSlide(forEachSelected([] (auto material, auto args) {
|
|
float radians = wi::math::DegreesToRadians(args.fValue);
|
|
material->SetInteriorMappingRotation(radians);
|
|
}));
|
|
AddWidget(&interiorRotationSlider);
|
|
|
|
|
|
hei = 20;
|
|
step = hei + 2;
|
|
x = 10;
|
|
|
|
materialNameField.Create("MaterialName");
|
|
materialNameField.SetTooltip("Set a name for the material...");
|
|
materialNameField.SetPos(XMFLOAT2(10, y += step));
|
|
materialNameField.SetSize(XMFLOAT2(300, hei));
|
|
materialNameField.OnInputAccepted([=](wi::gui::EventArgs args) {
|
|
wi::scene::Scene& scene = editor->GetCurrentScene();
|
|
for (auto& x : editor->translator.selected)
|
|
{
|
|
NameComponent* name = scene.names.GetComponent(x.entity);
|
|
if (name == nullptr)
|
|
continue;
|
|
*name = args.sValue;
|
|
|
|
editor->componentsWnd.RefreshEntityTree();
|
|
}
|
|
});
|
|
AddWidget(&materialNameField);
|
|
|
|
colorComboBox.Create("Color picker mode: ");
|
|
colorComboBox.SetSize(XMFLOAT2(120, hei));
|
|
colorComboBox.SetPos(XMFLOAT2(x + 150, y += step));
|
|
colorComboBox.AddItem("Base color");
|
|
colorComboBox.AddItem("Specular color");
|
|
colorComboBox.AddItem("Emissive color");
|
|
colorComboBox.AddItem("Subsurface color");
|
|
colorComboBox.AddItem("Sheen color");
|
|
colorComboBox.AddItem("Extinction color");
|
|
colorComboBox.SetTooltip("Choose the destination data of the color picker.");
|
|
AddWidget(&colorComboBox);
|
|
|
|
colorPicker.Create("Color", wi::gui::Window::WindowControls::NONE);
|
|
colorPicker.SetPos(XMFLOAT2(10, y += step));
|
|
colorPicker.SetVisible(true);
|
|
colorPicker.SetEnabled(true);
|
|
colorPicker.OnColorChanged(forEachSelected([this] (auto material, auto args) {
|
|
switch (colorComboBox.GetSelected())
|
|
{
|
|
default:
|
|
case 0:
|
|
material->SetBaseColor(args.color.toFloat4());
|
|
break;
|
|
case 1:
|
|
material->SetSpecularColor(args.color.toFloat4());
|
|
break;
|
|
case 2:
|
|
{
|
|
XMFLOAT3 col = args.color.toFloat3();
|
|
material->SetEmissiveColor(XMFLOAT4(col.x, col.y, col.z, material->GetEmissiveStrength()));
|
|
}
|
|
break;
|
|
case 3:
|
|
material->SetSubsurfaceScatteringColor(args.color.toFloat3());
|
|
break;
|
|
case 4:
|
|
material->SetSheenColor(args.color.toFloat3());
|
|
break;
|
|
case 5:
|
|
material->SetExtinctionColor(args.color.toFloat4());
|
|
break;
|
|
}
|
|
}));
|
|
AddWidget(&colorPicker);
|
|
|
|
|
|
// Textures:
|
|
|
|
y += colorPicker.GetScale().y;
|
|
|
|
textureSlotComboBox.Create("Texture Slot: ");
|
|
textureSlotComboBox.SetSize(XMFLOAT2(170, hei));
|
|
textureSlotComboBox.SetPos(XMFLOAT2(x + 100, y += step));
|
|
for (int i = 0; i < MaterialComponent::TEXTURESLOT_COUNT; ++i)
|
|
{
|
|
switch (i)
|
|
{
|
|
case MaterialComponent::BASECOLORMAP:
|
|
textureSlotComboBox.AddItem("BaseColor map");
|
|
break;
|
|
case MaterialComponent::NORMALMAP:
|
|
textureSlotComboBox.AddItem("Normal map");
|
|
break;
|
|
case MaterialComponent::SURFACEMAP:
|
|
textureSlotComboBox.AddItem("Surface map");
|
|
break;
|
|
case MaterialComponent::EMISSIVEMAP:
|
|
textureSlotComboBox.AddItem("Emissive map");
|
|
break;
|
|
case MaterialComponent::OCCLUSIONMAP:
|
|
textureSlotComboBox.AddItem("Occlusion map");
|
|
break;
|
|
case MaterialComponent::DISPLACEMENTMAP:
|
|
textureSlotComboBox.AddItem("Displacement map");
|
|
break;
|
|
case MaterialComponent::TRANSMISSIONMAP:
|
|
textureSlotComboBox.AddItem("Transmission map");
|
|
break;
|
|
case MaterialComponent::SHEENCOLORMAP:
|
|
textureSlotComboBox.AddItem("SheenColor map");
|
|
break;
|
|
case MaterialComponent::SHEENROUGHNESSMAP:
|
|
textureSlotComboBox.AddItem("SheenRoughness map");
|
|
break;
|
|
case MaterialComponent::CLEARCOATMAP:
|
|
textureSlotComboBox.AddItem("Clearcoat map");
|
|
break;
|
|
case MaterialComponent::CLEARCOATROUGHNESSMAP:
|
|
textureSlotComboBox.AddItem("ClearcoatRoughness map");
|
|
break;
|
|
case MaterialComponent::CLEARCOATNORMALMAP:
|
|
textureSlotComboBox.AddItem("ClearcoatNormal map");
|
|
break;
|
|
case MaterialComponent::SPECULARMAP:
|
|
textureSlotComboBox.AddItem("Specular map");
|
|
break;
|
|
case MaterialComponent::ANISOTROPYMAP:
|
|
textureSlotComboBox.AddItem("Anisotropy map");
|
|
break;
|
|
case MaterialComponent::TRANSPARENCYMAP:
|
|
textureSlotComboBox.AddItem("Transparency map");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
textureSlotComboBox.OnSelect([this](wi::gui::EventArgs args) {
|
|
|
|
std::string tooltiptext;
|
|
|
|
switch (args.iValue)
|
|
{
|
|
case MaterialComponent::BASECOLORMAP:
|
|
tooltiptext = "RGBA: Basecolor";
|
|
break;
|
|
case MaterialComponent::NORMALMAP:
|
|
tooltiptext = "RG: Normal";
|
|
break;
|
|
case MaterialComponent::SURFACEMAP:
|
|
tooltiptext = "Default workflow: R: Occlusion, G: Roughness, B: Metalness, A: Reflectance\nSpecular-glossiness workflow: RGB: Specular color (f0), A: smoothness";
|
|
break;
|
|
case MaterialComponent::EMISSIVEMAP:
|
|
tooltiptext = "RGBA: Emissive";
|
|
break;
|
|
case MaterialComponent::OCCLUSIONMAP:
|
|
tooltiptext = "R: Occlusion";
|
|
break;
|
|
case MaterialComponent::DISPLACEMENTMAP:
|
|
tooltiptext = "R: Displacement heightmap";
|
|
break;
|
|
case MaterialComponent::TRANSMISSIONMAP:
|
|
tooltiptext = "R: Transmission factor";
|
|
break;
|
|
case MaterialComponent::SHEENCOLORMAP:
|
|
tooltiptext = "RGB: Sheen color";
|
|
break;
|
|
case MaterialComponent::SHEENROUGHNESSMAP:
|
|
tooltiptext = "A: Roughness";
|
|
break;
|
|
case MaterialComponent::CLEARCOATMAP:
|
|
tooltiptext = "R: Clearcoat factor";
|
|
break;
|
|
case MaterialComponent::CLEARCOATROUGHNESSMAP:
|
|
tooltiptext = "G: Roughness";
|
|
break;
|
|
case MaterialComponent::CLEARCOATNORMALMAP:
|
|
tooltiptext = "RG: Normal";
|
|
break;
|
|
case MaterialComponent::SPECULARMAP:
|
|
tooltiptext = "RGB: Specular color, A: Specular intensity [non-metal]";
|
|
break;
|
|
case MaterialComponent::ANISOTROPYMAP:
|
|
tooltiptext = "RG: The anisotropy texture. Red and green channels represent the anisotropy direction in [-1, 1] tangent, bitangent space.\nThe vector is rotated by anisotropyRotation, and multiplied by anisotropyStrength, to obtain the final anisotropy direction and strength.";
|
|
break;
|
|
case MaterialComponent::TRANSPARENCYMAP:
|
|
tooltiptext = "R: transparency.";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
MaterialComponent* material = editor->GetCurrentScene().materials.GetComponent(entity);
|
|
if (material != nullptr)
|
|
{
|
|
textureSlotImage.SetImage(material->textures[args.iValue].resource);
|
|
if (material->textures[args.iValue].resource.IsValid())
|
|
{
|
|
const Texture& texture = material->textures[args.iValue].resource.GetTexture();
|
|
AddTexturePropertiesString(texture.GetDesc(), tooltiptext);
|
|
}
|
|
}
|
|
|
|
textureSlotImage.SetTooltip(tooltiptext);
|
|
|
|
});
|
|
textureSlotComboBox.SetSelected(0);
|
|
textureSlotComboBox.SetTooltip("Choose the texture slot to modify.");
|
|
AddWidget(&textureSlotComboBox);
|
|
|
|
textureSlotLoadButton.Create("Load from file");
|
|
textureSlotLoadButton.SetSize(XMFLOAT2(wid, hei));
|
|
textureSlotLoadButton.SetPos(XMFLOAT2(x, y += step));
|
|
textureSlotLoadButton.SetTooltip("Load texture from file on disk");
|
|
textureSlotLoadButton.OnClick([this](wi::gui::EventArgs args) {
|
|
int slot = textureSlotComboBox.GetSelected();
|
|
wi::helper::FileDialogParams params;
|
|
params.type = wi::helper::FileDialogParams::OPEN;
|
|
params.description = "Texture";
|
|
params.extensions = wi::resourcemanager::GetSupportedImageExtensions();
|
|
wi::helper::FileDialog(params, [this, slot](std::string fileName) {
|
|
wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) {
|
|
MaterialComponent* material = editor->GetCurrentScene().materials.GetComponent(entity);
|
|
const wi::resourcemanager::Flags flags = material->GetTextureSlotResourceFlags(MaterialComponent::TEXTURESLOT(slot));
|
|
|
|
wi::Archive& archive = editor->AdvanceHistory();
|
|
archive << EditorComponent::HISTORYOP_COMPONENT_DATA;
|
|
editor->RecordEntity(archive, entity);
|
|
|
|
material->textures[slot].resource = wi::resourcemanager::Load(fileName, flags);
|
|
material->textures[slot].name = fileName;
|
|
material->SetDirty();
|
|
textureSlotLabel.SetText(wi::helper::GetFileNameFromPath(fileName));
|
|
textureSlotComboBox.SetSelected(slot);
|
|
textureSlotImage.SetImage(material->textures[slot].resource);
|
|
|
|
editor->RecordEntity(archive, entity);
|
|
});
|
|
});
|
|
});
|
|
AddWidget(&textureSlotLoadButton);
|
|
|
|
textureSlotSelectButton.Create("Select texture");
|
|
textureSlotSelectButton.SetSize(XMFLOAT2(wid, hei));
|
|
textureSlotSelectButton.SetPos(XMFLOAT2(x + wid / 3 + 1, y));
|
|
textureSlotSelectButton.SetTooltip("Select texture from current scene");
|
|
textureSlotSelectButton.OnClick([this](wi::gui::EventArgs args) {
|
|
RecreateTexturePickerButtons();
|
|
texturePickerWindow.SetVisible(true);
|
|
});
|
|
AddWidget(&textureSlotSelectButton);
|
|
|
|
textureSlotClearButton.Create("Clear texture");
|
|
textureSlotClearButton.SetSize(XMFLOAT2(wid, hei));
|
|
textureSlotClearButton.SetPos(XMFLOAT2(x + 2 * wid / 3 + 2, y));
|
|
textureSlotClearButton.SetTooltip("Clear texture from slot");
|
|
textureSlotClearButton.OnClick([this](wi::gui::EventArgs args) {
|
|
MaterialComponent* material = editor->GetCurrentScene().materials.GetComponent(entity);
|
|
if (material == nullptr)
|
|
return;
|
|
|
|
const int slot = textureSlotComboBox.GetSelected();
|
|
|
|
if (material->textures[slot].resource.IsValid())
|
|
{
|
|
wi::Archive& archive = editor->AdvanceHistory();
|
|
archive << EditorComponent::HISTORYOP_COMPONENT_DATA;
|
|
editor->RecordEntity(archive, entity);
|
|
|
|
material->textures[slot].resource = {};
|
|
material->textures[slot].name = "";
|
|
material->SetDirty();
|
|
textureSlotLabel.SetText("");
|
|
textureSlotImage.SetImage(wi::Resource());
|
|
|
|
editor->RecordEntity(archive, entity);
|
|
}
|
|
});
|
|
AddWidget(&textureSlotClearButton);
|
|
|
|
textureSlotImage.Create("");
|
|
textureSlotImage.SetSize(XMFLOAT2(180, 180));
|
|
textureSlotImage.SetPos(XMFLOAT2(textureSlotComboBox.GetPosition().x + textureSlotComboBox.GetScale().x - textureSlotImage.GetScale().x, y += step));
|
|
AddWidget(&textureSlotImage);
|
|
|
|
y += textureSlotImage.GetScale().y - step + 2;
|
|
|
|
textureSlotLabel.Create("");
|
|
textureSlotLabel.SetPos(XMFLOAT2(x, y += step));
|
|
textureSlotLabel.SetSize(XMFLOAT2(colorPicker.GetScale().x - hei - 2, hei));
|
|
AddWidget(&textureSlotLabel);
|
|
|
|
textureSlotUvsetField.Create("uvset");
|
|
textureSlotUvsetField.SetText("");
|
|
textureSlotUvsetField.SetTooltip("uv set number");
|
|
textureSlotUvsetField.SetPos(XMFLOAT2(x + textureSlotLabel.GetScale().x + 2, y));
|
|
textureSlotUvsetField.SetSize(XMFLOAT2(hei, hei));
|
|
textureSlotUvsetField.OnInputAccepted(forEachSelected([this] (auto material, auto args) {
|
|
int slot = textureSlotComboBox.GetSelected();
|
|
material->textures[slot].uvset = (uint32_t)args.iValue;
|
|
}));
|
|
AddWidget(&textureSlotUvsetField);
|
|
|
|
// Create texture picker
|
|
const float screenW = editor->GetLogicalWidth();
|
|
const float screenH = editor->GetLogicalHeight();
|
|
|
|
auto wctrl = wi::gui::Window::WindowControls::ALL;
|
|
wctrl &= ~wi::gui::Window::WindowControls::RESIZE_BOTTOMLEFT;
|
|
texturePickerWindow.Create("", wctrl);
|
|
texturePickerWindow.SetVisible(false);
|
|
const float texturePickerWindowW = screenW / 3.20f;
|
|
const float texturePickerWindowH = screenH / 2.0f;
|
|
texturePickerWindow.SetSize(XMFLOAT2(texturePickerWindowW, texturePickerWindowH));
|
|
texturePickerWindow.SetPos(XMFLOAT2(screenW / 2.0f - texturePickerWindowW / 2.0f, screenH / 2.0f - texturePickerWindowH / 2.0f));
|
|
|
|
texturePickerWindow.OnClose([this](wi::gui::EventArgs args) {
|
|
texturePickerWindow.SetVisible(false);
|
|
});
|
|
editor->GetGUI().AddWidget(&texturePickerWindow);
|
|
|
|
|
|
SetMinimized(true);
|
|
SetVisible(false);
|
|
|
|
SetEntity(INVALID_ENTITY);
|
|
}
|
|
|
|
void MaterialWindow::SetEntity(Entity entity)
|
|
{
|
|
const bool changed = this->entity != entity;
|
|
this->entity = entity;
|
|
|
|
const Scene& scene = editor->GetCurrentScene();
|
|
MaterialComponent* material = scene.materials.GetComponent(entity);
|
|
|
|
if (material != nullptr)
|
|
{
|
|
SetEnabled(true);
|
|
|
|
const NameComponent* name = scene.names.GetComponent(entity);
|
|
if (name == nullptr)
|
|
{
|
|
materialNameField.SetValue("[no_name] " + std::to_string(entity));
|
|
}
|
|
else if (name->name.empty())
|
|
{
|
|
materialNameField.SetValue("[name_empty] " + std::to_string(entity));
|
|
}
|
|
else
|
|
{
|
|
materialNameField.SetValue(name->name);
|
|
}
|
|
shadowReceiveCheckBox.SetCheck(material->IsReceiveShadow());
|
|
shadowCasterCheckBox.SetCheck(material->IsCastingShadow());
|
|
useVertexColorsCheckBox.SetCheck(material->IsUsingVertexColors());
|
|
specularGlossinessCheckBox.SetCheck(material->IsUsingSpecularGlossinessWorkflow());
|
|
occlusionPrimaryCheckBox.SetCheck(material->IsOcclusionEnabled_Primary());
|
|
occlusionSecondaryCheckBox.SetCheck(material->IsOcclusionEnabled_Secondary());
|
|
vertexAOCheckBox.SetCheck(!material->IsVertexAODisabled());
|
|
windCheckBox.SetCheck(material->IsUsingWind());
|
|
doubleSidedCheckBox.SetCheck(material->IsDoubleSided());
|
|
outlineCheckBox.SetCheck(material->IsOutlineEnabled());
|
|
preferUncompressedCheckBox.SetCheck(material->IsPreferUncompressedTexturesEnabled());
|
|
disableStreamingCheckBox.SetCheck(material->IsTextureStreamingDisabled());
|
|
coplanarCheckBox.SetCheck(material->IsCoplanarBlending());
|
|
capsuleShadowCheckBox.SetCheck(material->IsCapsuleShadowDisabled());
|
|
normalMapSlider.SetValue(material->normalMapStrength);
|
|
roughnessSlider.SetValue(material->roughness);
|
|
reflectanceSlider.SetValue(material->reflectance);
|
|
metalnessSlider.SetValue(material->metalness);
|
|
cloakSlider.SetValue(material->cloak);
|
|
chromaticAberrationSlider.SetValue(material->chromatic_aberration);
|
|
transmissionSlider.SetValue(material->transmission);
|
|
refractionSlider.SetValue(material->refraction);
|
|
emissiveSlider.SetValue(material->emissiveColor.w);
|
|
saturationSlider.SetValue(material->saturation);
|
|
pomSlider.SetValue(material->parallaxOcclusionMapping);
|
|
anisotropyStrengthSlider.SetValue(material->anisotropy_strength);
|
|
anisotropyRotationSlider.SetValue(wi::math::RadiansToDegrees(material->anisotropy_rotation));
|
|
displacementMappingSlider.SetValue(material->displacementMapping);
|
|
subsurfaceScatteringSlider.SetValue(material->subsurfaceScattering.w);
|
|
texAnimFrameRateSlider.SetValue(material->texAnimFrameRate);
|
|
texAnimDirectionSliderU.SetValue(material->texAnimDirection.x);
|
|
texAnimDirectionSliderV.SetValue(material->texAnimDirection.y);
|
|
texMulSliderX.SetValue(material->texMulAdd.x);
|
|
texMulSliderY.SetValue(material->texMulAdd.y);
|
|
alphaRefSlider.SetValue(material->alphaRef);
|
|
blendModeComboBox.SetSelectedWithoutCallback((int)material->userBlendMode);
|
|
|
|
shaderTypeComboBox.ClearItems();
|
|
shaderTypeComboBox.AddItem("PBR", MaterialComponent::SHADERTYPE_PBR);
|
|
shaderTypeComboBox.AddItem("Planar reflections", MaterialComponent::SHADERTYPE_PBR_PLANARREFLECTION);
|
|
shaderTypeComboBox.AddItem("Par. occl. mapping", MaterialComponent::SHADERTYPE_PBR_PARALLAXOCCLUSIONMAPPING);
|
|
shaderTypeComboBox.AddItem("Anisotropic", MaterialComponent::SHADERTYPE_PBR_ANISOTROPIC);
|
|
shaderTypeComboBox.AddItem("Cloth", MaterialComponent::SHADERTYPE_PBR_CLOTH);
|
|
shaderTypeComboBox.AddItem("Clear coat", MaterialComponent::SHADERTYPE_PBR_CLEARCOAT);
|
|
shaderTypeComboBox.AddItem("Cloth + Clear coat", MaterialComponent::SHADERTYPE_PBR_CLOTH_CLEARCOAT);
|
|
shaderTypeComboBox.AddItem("Terrain blended", MaterialComponent::SHADERTYPE_PBR_TERRAINBLENDED);
|
|
shaderTypeComboBox.AddItem("Water", MaterialComponent::SHADERTYPE_WATER);
|
|
shaderTypeComboBox.AddItem("Cartoon", MaterialComponent::SHADERTYPE_CARTOON);
|
|
shaderTypeComboBox.AddItem("Unlit", MaterialComponent::SHADERTYPE_UNLIT);
|
|
shaderTypeComboBox.AddItem("Interior", MaterialComponent::SHADERTYPE_INTERIORMAPPING);
|
|
for (auto& x : wi::renderer::GetCustomShaders())
|
|
{
|
|
shaderTypeComboBox.AddItem("*" + x.name);
|
|
}
|
|
if (material->GetCustomShaderID() >= 0)
|
|
{
|
|
shaderTypeComboBox.SetSelectedWithoutCallback(MaterialComponent::SHADERTYPE_COUNT + material->GetCustomShaderID());
|
|
}
|
|
else
|
|
{
|
|
shaderTypeComboBox.SetSelectedByUserdataWithoutCallback(material->shaderType);
|
|
}
|
|
shadingRateComboBox.SetSelectedWithoutCallback((int)material->shadingRate);
|
|
|
|
cameraComboBox.ClearItems();
|
|
cameraComboBox.AddItem("INVALID_ENTITY", (uint64_t)INVALID_ENTITY);
|
|
for (size_t i = 0; i < scene.cameras.GetCount(); ++i)
|
|
{
|
|
const Entity cameraEntity = scene.cameras.GetEntity(i);
|
|
const NameComponent* name_component = scene.names.GetComponent(cameraEntity);
|
|
if (name_component != nullptr)
|
|
{
|
|
cameraComboBox.AddItem(name_component->name, (uint64_t)cameraEntity);
|
|
}
|
|
}
|
|
cameraComboBox.SetSelectedByUserdataWithoutCallback((uint64_t)material->cameraSource);
|
|
|
|
colorComboBox.SetEnabled(true);
|
|
colorPicker.SetEnabled(true);
|
|
|
|
switch (colorComboBox.GetSelected())
|
|
{
|
|
default:
|
|
case 0:
|
|
colorPicker.SetPickColor(wi::Color::fromFloat4(material->baseColor));
|
|
break;
|
|
case 1:
|
|
colorPicker.SetPickColor(wi::Color::fromFloat4(material->specularColor));
|
|
break;
|
|
case 2:
|
|
colorPicker.SetPickColor(wi::Color::fromFloat3(XMFLOAT3(material->emissiveColor.x, material->emissiveColor.y, material->emissiveColor.z)));
|
|
break;
|
|
case 3:
|
|
colorPicker.SetPickColor(wi::Color::fromFloat3(XMFLOAT3(material->subsurfaceScattering.x, material->subsurfaceScattering.y, material->subsurfaceScattering.z)));
|
|
break;
|
|
case 4:
|
|
colorPicker.SetPickColor(wi::Color::fromFloat3(XMFLOAT3(material->sheenColor.x, material->sheenColor.y, material->sheenColor.z)));
|
|
break;
|
|
case 5:
|
|
colorPicker.SetPickColor(wi::Color::fromFloat4(material->extinctionColor));
|
|
break;
|
|
}
|
|
|
|
sheenRoughnessSlider.SetEnabled(false);
|
|
clearcoatSlider.SetEnabled(false);
|
|
clearcoatRoughnessSlider.SetEnabled(false);
|
|
switch (material->shaderType)
|
|
{
|
|
case MaterialComponent::SHADERTYPE_PBR_CLOTH:
|
|
sheenRoughnessSlider.SetEnabled(true);
|
|
break;
|
|
case MaterialComponent::SHADERTYPE_PBR_CLEARCOAT:
|
|
clearcoatSlider.SetEnabled(true);
|
|
clearcoatRoughnessSlider.SetEnabled(true);
|
|
break;
|
|
case MaterialComponent::SHADERTYPE_PBR_CLOTH_CLEARCOAT:
|
|
sheenRoughnessSlider.SetEnabled(true);
|
|
clearcoatSlider.SetEnabled(true);
|
|
clearcoatRoughnessSlider.SetEnabled(true);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
sheenRoughnessSlider.SetValue(material->sheenRoughness);
|
|
clearcoatSlider.SetValue(material->clearcoat);
|
|
clearcoatRoughnessSlider.SetValue(material->clearcoatRoughness);
|
|
blendTerrainSlider.SetValue(material->blend_with_terrain_height);
|
|
meshblendSlider.SetValue(material->mesh_blend);
|
|
interiorScaleXSlider.SetValue(material->interiorMappingScale.x);
|
|
interiorScaleYSlider.SetValue(material->interiorMappingScale.y);
|
|
interiorScaleZSlider.SetValue(material->interiorMappingScale.z);
|
|
interiorOffsetXSlider.SetValue(material->interiorMappingOffset.x);
|
|
interiorOffsetYSlider.SetValue(material->interiorMappingOffset.y);
|
|
interiorOffsetZSlider.SetValue(material->interiorMappingOffset.z);
|
|
interiorRotationSlider.SetValue(wi::math::RadiansToDegrees(material->interiorMappingRotation));
|
|
|
|
shadingRateComboBox.SetEnabled(wi::graphics::GetDevice()->CheckCapability(GraphicsDeviceCapability::VARIABLE_RATE_SHADING));
|
|
|
|
if (material->IsUsingSpecularGlossinessWorkflow())
|
|
{
|
|
reflectanceSlider.SetEnabled(false);
|
|
metalnessSlider.SetEnabled(false);
|
|
}
|
|
|
|
const int slot = textureSlotComboBox.GetSelected();
|
|
textureSlotImage.SetImage(material->textures[slot].resource);
|
|
textureSlotLabel.SetText(wi::helper::GetFileNameFromPath(material->textures[slot].name));
|
|
textureSlotUvsetField.SetText(std::to_string(material->textures[slot].uvset));
|
|
if (changed)
|
|
{
|
|
textureSlotComboBox.SetSelected(slot);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
materialNameField.SetValue("No material selected");
|
|
SetEnabled(false);
|
|
colorComboBox.SetEnabled(false);
|
|
colorPicker.SetEnabled(false);
|
|
|
|
textureSlotImage.SetImage(wi::Resource());
|
|
textureSlotLabel.SetText("");
|
|
textureSlotUvsetField.SetText("");
|
|
}
|
|
}
|
|
|
|
void MaterialWindow::RecreateTexturePickerButtons()
|
|
{
|
|
if (editor == nullptr)
|
|
return;
|
|
|
|
// Remove old buttons
|
|
for (auto& button : texturePickerButtons)
|
|
{
|
|
texturePickerWindow.RemoveWidget(&button);
|
|
}
|
|
texturePickerButtons.clear();
|
|
|
|
// Create buttons for each unique texture
|
|
uniqueTextures.clear();
|
|
wi::resourcemanager::CollectResources(uniqueTextures, wi::resourcemanager::ResourceType::TEXTURE);
|
|
for (auto& [textureName, textureResource] : uniqueTextures)
|
|
{
|
|
texturePickerButtons.emplace_back();
|
|
wi::gui::Button& button = texturePickerButtons.back();
|
|
|
|
button.Create("");
|
|
button.SetImage(textureResource);
|
|
std::string tooltipText = wi::helper::GetFileNameFromPath(textureName) + "\nFull path: " + textureName;
|
|
AddTexturePropertiesString(textureResource.GetTexture().GetDesc(), tooltipText);
|
|
button.SetTooltip(tooltipText);
|
|
texturePickerWindow.AddWidget(&button);
|
|
button.SetVisible(false);
|
|
|
|
std::string capturedName = textureName;
|
|
wi::Resource capturedResource = textureResource;
|
|
|
|
button.OnClick([this, capturedName, capturedResource](wi::gui::EventArgs args) {
|
|
MaterialComponent* material = editor->GetCurrentScene().materials.GetComponent(entity);
|
|
if (material == nullptr)
|
|
return;
|
|
|
|
const int slot = textureSlotComboBox.GetSelected();
|
|
|
|
wi::Archive& archive = editor->AdvanceHistory();
|
|
archive << EditorComponent::HISTORYOP_COMPONENT_DATA;
|
|
editor->RecordEntity(archive, entity);
|
|
|
|
material->textures[slot].resource = capturedResource;
|
|
material->textures[slot].name = capturedName;
|
|
material->SetDirty();
|
|
textureSlotLabel.SetText(wi::helper::GetFileNameFromPath(capturedName));
|
|
textureSlotImage.SetImage(capturedResource);
|
|
|
|
editor->RecordEntity(archive, entity);
|
|
});
|
|
}
|
|
uniqueTextures.clear(); // don't hold onto resources that were queried
|
|
|
|
ResizeLayout();
|
|
}
|
|
|
|
void MaterialWindow::ResizeLayout()
|
|
{
|
|
wi::gui::Window::ResizeLayout();
|
|
layout.margin_left = 150;
|
|
|
|
Scene& scene = editor->GetCurrentScene();
|
|
MaterialComponent* material = scene.materials.GetComponent(entity);
|
|
|
|
if (texturePickerWindow.IsVisible())
|
|
{
|
|
uniqueTextures.clear();
|
|
wi::resourcemanager::CollectResources(uniqueTextures, wi::resourcemanager::ResourceType::TEXTURE);
|
|
if (texturePickerButtons.size() != uniqueTextures.size())
|
|
{
|
|
RecreateTexturePickerButtons();
|
|
return;
|
|
}
|
|
uniqueTextures.clear(); // don't hold onto resources that were queried
|
|
}
|
|
|
|
layout.add_fullwidth(materialNameField);
|
|
|
|
const float preset_button_width = layout.width / 2.0f - layout.padding * 1.5f;
|
|
presetLoadButton.SetSize(XMFLOAT2(preset_button_width, presetLoadButton.GetSize().y));
|
|
presetLoadButton.SetPos(XMFLOAT2(layout.padding, layout.y));
|
|
presetSaveButton.SetSize(XMFLOAT2(preset_button_width, presetSaveButton.GetSize().y));
|
|
presetSaveButton.SetPos(XMFLOAT2(presetLoadButton.GetPos().x + presetLoadButton.GetSize().x + layout.padding, layout.y));
|
|
layout.y += presetLoadButton.GetSize().y + layout.padding;
|
|
|
|
layout.add_right(shadowReceiveCheckBox);
|
|
layout.add_right(shadowCasterCheckBox);
|
|
layout.add_right(useVertexColorsCheckBox);
|
|
layout.add_right(specularGlossinessCheckBox);
|
|
layout.add_right(occlusionPrimaryCheckBox);
|
|
layout.add_right(occlusionSecondaryCheckBox);
|
|
layout.add_right(vertexAOCheckBox);
|
|
layout.add_right(windCheckBox);
|
|
layout.add_right(doubleSidedCheckBox);
|
|
layout.add_right(outlineCheckBox);
|
|
layout.add_right(preferUncompressedCheckBox);
|
|
layout.add_right(disableStreamingCheckBox);
|
|
layout.add_right(coplanarCheckBox);
|
|
layout.add_right(capsuleShadowCheckBox);
|
|
layout.add(shaderTypeComboBox);
|
|
layout.add(blendModeComboBox);
|
|
layout.add(shadingRateComboBox);
|
|
layout.add(cameraComboBox);
|
|
layout.add(alphaRefSlider);
|
|
layout.add(normalMapSlider);
|
|
layout.add(roughnessSlider);
|
|
layout.add(reflectanceSlider);
|
|
layout.add(metalnessSlider);
|
|
layout.add(emissiveSlider);
|
|
layout.add(saturationSlider);
|
|
layout.add(cloakSlider);
|
|
layout.add(chromaticAberrationSlider);
|
|
layout.add(transmissionSlider);
|
|
layout.add(refractionSlider);
|
|
layout.add(pomSlider);
|
|
layout.add(anisotropyStrengthSlider);
|
|
layout.add(anisotropyRotationSlider);
|
|
layout.add(displacementMappingSlider);
|
|
layout.add(subsurfaceScatteringSlider);
|
|
layout.add(texAnimFrameRateSlider);
|
|
layout.add(texAnimDirectionSliderU);
|
|
layout.add(texAnimDirectionSliderV);
|
|
layout.add(texMulSliderX);
|
|
layout.add(texMulSliderY);
|
|
layout.add(sheenRoughnessSlider);
|
|
layout.add(clearcoatSlider);
|
|
layout.add(clearcoatRoughnessSlider);
|
|
layout.add(blendTerrainSlider);
|
|
layout.add(meshblendSlider);
|
|
if (material != nullptr && material->shaderType == MaterialComponent::SHADERTYPE_INTERIORMAPPING)
|
|
{
|
|
interiorScaleXSlider.SetVisible(true);
|
|
interiorScaleYSlider.SetVisible(true);
|
|
interiorScaleZSlider.SetVisible(true);
|
|
interiorOffsetXSlider.SetVisible(true);
|
|
interiorOffsetYSlider.SetVisible(true);
|
|
interiorOffsetZSlider.SetVisible(true);
|
|
interiorRotationSlider.SetVisible(true);
|
|
layout.add(interiorScaleXSlider);
|
|
layout.add(interiorScaleYSlider);
|
|
layout.add(interiorScaleZSlider);
|
|
layout.add(interiorOffsetXSlider);
|
|
layout.add(interiorOffsetYSlider);
|
|
layout.add(interiorOffsetZSlider);
|
|
layout.add(interiorRotationSlider);
|
|
}
|
|
else
|
|
{
|
|
interiorScaleXSlider.SetVisible(false);
|
|
interiorScaleYSlider.SetVisible(false);
|
|
interiorScaleZSlider.SetVisible(false);
|
|
interiorOffsetXSlider.SetVisible(false);
|
|
interiorOffsetYSlider.SetVisible(false);
|
|
interiorOffsetZSlider.SetVisible(false);
|
|
interiorRotationSlider.SetVisible(false);
|
|
}
|
|
layout.add(colorComboBox);
|
|
layout.add_fullwidth(colorPicker);
|
|
layout.add(textureSlotComboBox);
|
|
|
|
const float button_width = layout.width / 3.0f - layout.padding * 2.0f / 3.0f;
|
|
|
|
textureSlotClearButton.SetSize(XMFLOAT2(button_width, textureSlotClearButton.GetSize().y));
|
|
textureSlotClearButton.SetPos(XMFLOAT2(layout.width - layout.padding - textureSlotClearButton.GetSize().x, layout.y));
|
|
|
|
textureSlotSelectButton.SetSize(XMFLOAT2(button_width, textureSlotSelectButton.GetSize().y));
|
|
textureSlotSelectButton.SetPos(XMFLOAT2(textureSlotClearButton.GetPos().x - layout.padding - textureSlotSelectButton.GetSize().x, layout.y));
|
|
|
|
textureSlotLoadButton.SetSize(XMFLOAT2(button_width, textureSlotLoadButton.GetSize().y));
|
|
textureSlotLoadButton.SetPos(XMFLOAT2(textureSlotSelectButton.GetPos().x - layout.padding - textureSlotLoadButton.GetSize().x, layout.y));
|
|
|
|
layout.y += textureSlotLoadButton.GetSize().y + layout.padding;
|
|
|
|
layout.add_fullwidth(textureSlotImage);
|
|
layout.add_fullwidth(textureSlotLabel);
|
|
textureSlotLabel.SetSize(XMFLOAT2(textureSlotLabel.GetSize().x - textureSlotLabel.GetSize().y - 2, textureSlotLabel.GetSize().y));
|
|
textureSlotUvsetField.SetPos(XMFLOAT2(textureSlotLabel.GetPos().x + textureSlotLabel.GetSize().x + 2, textureSlotLabel.GetPos().y));
|
|
|
|
// Update texture picker
|
|
if (texturePickerWindow.IsVisible())
|
|
{
|
|
const NameComponent* name = scene.names.GetComponent(entity);
|
|
std::string windowTitle = "Texture Picker";
|
|
if (material && name != nullptr && !name->name.empty())
|
|
{
|
|
windowTitle += " (Entity: " + name->name + ")";
|
|
}
|
|
windowTitle += " [Texture slot: " + textureSlotComboBox.GetItemText(textureSlotComboBox.GetSelected()) + "]";
|
|
texturePickerWindow.moveDragger.SetText(windowTitle);
|
|
|
|
if (!texturePickerButtons.empty())
|
|
{
|
|
wi::gui::Theme theme;
|
|
theme.image.CopyFrom(texturePickerWindow.sprites[wi::gui::IDLE].params);
|
|
theme.image.background = false;
|
|
theme.image.blendFlag = wi::enums::BLENDMODE_ALPHA;
|
|
theme.image.color = wi::Color::White();
|
|
theme.font.CopyFrom(font.params);
|
|
theme.shadow_color = wi::Color::lerp(theme.font.color, wi::Color::Transparent(), 0.25f);
|
|
theme.tooltipFont.CopyFrom(tooltipFont.params);
|
|
theme.tooltipImage.CopyFrom(tooltipSprite.params);
|
|
|
|
constexpr float preview_size = 100;
|
|
constexpr float border = 10;
|
|
const float window_width = texturePickerWindow.GetWidgetAreaSize().x;
|
|
const int cells = std::max(1, int(window_width / (preview_size + border)));
|
|
float offset_y = border;
|
|
|
|
for (size_t i = 0; i < texturePickerButtons.size(); ++i)
|
|
{
|
|
wi::gui::Button& button = texturePickerButtons[i];
|
|
|
|
button.SetTheme(theme);
|
|
button.SetColor(wi::Color::White(), wi::gui::IDLE);
|
|
button.SetColor(wi::Color(255, 255, 255, 150), wi::gui::FOCUS);
|
|
button.SetShadowRadius(0);
|
|
|
|
button.SetSize(XMFLOAT2(preview_size, preview_size));
|
|
button.SetPos(XMFLOAT2((i % cells) * (preview_size + border) + border, offset_y));
|
|
button.SetVisible(IsVisible() && !IsCollapsed());
|
|
button.SetEnabled(true);
|
|
|
|
if ((i % cells) == (cells - 1))
|
|
{
|
|
offset_y += preview_size + border;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|