feat: add simple transparency
This commit is contained in:
@@ -29,6 +29,11 @@ enum class TextureFilteringMode : std::uint32_t {
|
|||||||
Anisotropic,
|
Anisotropic,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class BlendMode : std::uint32_t {
|
||||||
|
Opaque,
|
||||||
|
Transparent,
|
||||||
|
};
|
||||||
|
|
||||||
// Metallic / roughness workflow, matching glTF:
|
// Metallic / roughness workflow, matching glTF:
|
||||||
// metallic is read from the blue channel, roughness from green and occlusion from red,
|
// metallic is read from the blue channel, roughness from green and occlusion from red,
|
||||||
// so a packed (occlusion)metallicRoughness texture can be used for all three slots.
|
// so a packed (occlusion)metallicRoughness texture can be used for all three slots.
|
||||||
@@ -59,6 +64,9 @@ struct Material {
|
|||||||
float normalScale{1.f};
|
float normalScale{1.f};
|
||||||
float occlusionStrength{1.f};
|
float occlusionStrength{1.f};
|
||||||
|
|
||||||
|
BlendMode blendMode{BlendMode::Opaque};
|
||||||
|
float opacity{1.f};
|
||||||
|
|
||||||
TextureFilteringMode textureFilteringMode{TextureFilteringMode::Linear};
|
TextureFilteringMode textureFilteringMode{TextureFilteringMode::Linear};
|
||||||
|
|
||||||
ImageID diffuseTexture{NULL_IMAGE_ID};
|
ImageID diffuseTexture{NULL_IMAGE_ID};
|
||||||
|
|||||||
@@ -44,6 +44,14 @@ public:
|
|||||||
const IndirectDrawList& drawList,
|
const IndirectDrawList& drawList,
|
||||||
const IndirectDrawList::View& view);
|
const IndirectDrawList::View& view);
|
||||||
|
|
||||||
|
void drawTransparent(
|
||||||
|
VkCommandBuffer cmd,
|
||||||
|
VkExtent2D renderExtent,
|
||||||
|
const RenderResources& resources,
|
||||||
|
const GPUBuffer& sceneDataBuffer,
|
||||||
|
const IndirectDrawList& drawList,
|
||||||
|
const IndirectDrawList::View& view);
|
||||||
|
|
||||||
void cleanup(VkDevice device);
|
void cleanup(VkDevice device);
|
||||||
|
|
||||||
void setRenderWireframe(bool wireframe) {
|
void setRenderWireframe(bool wireframe) {
|
||||||
@@ -72,6 +80,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE};
|
VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE};
|
||||||
std::unique_ptr<Pipeline> m_pipeline;
|
std::unique_ptr<Pipeline> m_pipeline;
|
||||||
|
std::unique_ptr<Pipeline> m_transparentPipeline;
|
||||||
std::unique_ptr<Pipeline> m_depthPrepassPipeline;
|
std::unique_ptr<Pipeline> m_depthPrepassPipeline;
|
||||||
std::unique_ptr<Pipeline> m_selectionPrepassPipeline;
|
std::unique_ptr<Pipeline> m_selectionPrepassPipeline;
|
||||||
|
|
||||||
|
|||||||
@@ -183,6 +183,7 @@ private:
|
|||||||
|
|
||||||
std::vector<MeshDrawCommand> meshDrawCommands;
|
std::vector<MeshDrawCommand> meshDrawCommands;
|
||||||
std::vector<std::size_t> sortedMeshDrawCommands;
|
std::vector<std::size_t> sortedMeshDrawCommands;
|
||||||
|
std::vector<std::size_t> transparentMeshDrawCommands;
|
||||||
IndirectDrawList drawList;
|
IndirectDrawList drawList;
|
||||||
DrawStats lastDrawStats;
|
DrawStats lastDrawStats;
|
||||||
|
|
||||||
|
|||||||
@@ -414,6 +414,16 @@ void MeshRendererComponent::DrawMaterialEditor(RenderResources& resources, GameR
|
|||||||
changed = finished = true;
|
changed = finished = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr std::array<const char*, 2> blendModeNames{"Opaque", "Transparent"};
|
||||||
|
int blendMode = static_cast<int>(material.blendMode);
|
||||||
|
if (ImGui::Combo("Blend", &blendMode, blendModeNames.data(), static_cast<int>(blendModeNames.size()))) {
|
||||||
|
material.blendMode = static_cast<BlendMode>(blendMode);
|
||||||
|
changed = finished = true;
|
||||||
|
}
|
||||||
|
if (material.blendMode == BlendMode::Transparent) {
|
||||||
|
track(ImGui::SliderFloat("Opacity", &material.opacity, 0.0f, 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::SeparatorText("Textures");
|
ImGui::SeparatorText("Textures");
|
||||||
for (const TextureSlot& slot : TextureSlots) {
|
for (const TextureSlot& slot : TextureSlots) {
|
||||||
ImGui::PushID(slot.label);
|
ImGui::PushID(slot.label);
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ MaterialData MaterialCache::toMaterialData(const Material& material) const
|
|||||||
};
|
};
|
||||||
|
|
||||||
return MaterialData{
|
return MaterialData{
|
||||||
.baseColor = glm::vec4(material.baseColor, 1.0f),
|
.baseColor = glm::vec4(material.baseColor, material.blendMode == BlendMode::Transparent ? material.opacity : 1.0f),
|
||||||
.emissiveColor = glm::vec4(material.emissiveColor, 0.0f),
|
.emissiveColor = glm::vec4(material.emissiveColor, 0.0f),
|
||||||
|
|
||||||
.metallicRoughnessNormalOcclusion = glm::vec4{
|
.metallicRoughnessNormalOcclusion = glm::vec4{
|
||||||
|
|||||||
@@ -97,15 +97,9 @@ IndirectDrawList::View IndirectDrawList::addView(
|
|||||||
++view.instanceCount;
|
++view.instanceCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!sortedDrawCommands.empty()) {
|
for (std::size_t drawIndex : sortedDrawCommands) {
|
||||||
for (std::size_t drawIndex : sortedDrawCommands) {
|
assert(drawIndex < drawCommands.size());
|
||||||
assert(drawIndex < drawCommands.size());
|
addDraw(drawCommands[drawIndex]);
|
||||||
addDraw(drawCommands[drawIndex]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const MeshDrawCommand& dc : drawCommands) {
|
|
||||||
addDraw(dc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
|
|||||||
@@ -131,6 +131,36 @@ void MeshPipeline::init(
|
|||||||
pipelineConfig
|
pipelineConfig
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
PipelineConfigInfo pipelineConfig{};
|
||||||
|
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
|
||||||
|
|
||||||
|
pipelineConfig.name = "Mesh Transparent Pipeline";
|
||||||
|
pipelineConfig.pipelineLayout = m_pipelineLayout;
|
||||||
|
|
||||||
|
pipelineConfig.vertexAttributeDescriptions = {};
|
||||||
|
pipelineConfig.vertexBindingDescriptions = {};
|
||||||
|
|
||||||
|
pipelineConfig.colorAttachments = {drawImageFormat};
|
||||||
|
pipelineConfig.depthAttachment = depthImageFormat;
|
||||||
|
|
||||||
|
pipelineConfig.depthStencilInfo.depthWriteEnable = VK_FALSE;
|
||||||
|
pipelineConfig.depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
|
||||||
|
|
||||||
|
pipelineConfig.colorBlendAttachment.blendEnable = VK_TRUE;
|
||||||
|
pipelineConfig.colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||||
|
pipelineConfig.colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
pipelineConfig.colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||||
|
pipelineConfig.colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
|
||||||
|
m_transparentPipeline = std::make_unique<Pipeline>(
|
||||||
|
gfxDevice,
|
||||||
|
vertexShader.string(),
|
||||||
|
fragShader.string(),
|
||||||
|
pipelineConfig
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@@ -187,6 +217,29 @@ void MeshPipeline::draw(
|
|||||||
view);
|
view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MeshPipeline::drawTransparent(
|
||||||
|
VkCommandBuffer cmd,
|
||||||
|
VkExtent2D renderExtent,
|
||||||
|
const RenderResources& resources,
|
||||||
|
const GPUBuffer& sceneDataBuffer,
|
||||||
|
const IndirectDrawList& drawList,
|
||||||
|
const IndirectDrawList::View& view)
|
||||||
|
{
|
||||||
|
if (!m_transparentPipeline || view.commandCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawMeshes(
|
||||||
|
cmd,
|
||||||
|
*m_transparentPipeline,
|
||||||
|
renderExtent,
|
||||||
|
resources,
|
||||||
|
sceneDataBuffer,
|
||||||
|
drawList,
|
||||||
|
view);
|
||||||
|
}
|
||||||
|
|
||||||
void MeshPipeline::drawMeshes(
|
void MeshPipeline::drawMeshes(
|
||||||
VkCommandBuffer cmd,
|
VkCommandBuffer cmd,
|
||||||
const Pipeline& pipeline,
|
const Pipeline& pipeline,
|
||||||
@@ -254,6 +307,7 @@ void MeshPipeline::drawMeshes(
|
|||||||
void MeshPipeline::cleanup(VkDevice device)
|
void MeshPipeline::cleanup(VkDevice device)
|
||||||
{
|
{
|
||||||
m_pipeline.reset();
|
m_pipeline.reset();
|
||||||
|
m_transparentPipeline.reset();
|
||||||
m_depthPrepassPipeline.reset();
|
m_depthPrepassPipeline.reset();
|
||||||
m_selectionPrepassPipeline.reset();
|
m_selectionPrepassPipeline.reset();
|
||||||
|
|
||||||
|
|||||||
@@ -101,13 +101,24 @@ void GameRenderer::endDrawing()
|
|||||||
|
|
||||||
// Grouping by mesh lets IndirectDrawList merge each run into one instanced draw.
|
// Grouping by mesh lets IndirectDrawList merge each run into one instanced draw.
|
||||||
// Material and vertex buffer are per instance, so they don't break a batch.
|
// Material and vertex buffer are per instance, so they don't break a batch.
|
||||||
std::stable_sort(
|
std::ranges::stable_sort(sortedMeshDrawCommands
|
||||||
sortedMeshDrawCommands.begin(),
|
,
|
||||||
sortedMeshDrawCommands.end(),
|
[this](std::size_t left, std::size_t right)
|
||||||
[this](std::size_t left, std::size_t right)
|
{
|
||||||
|
return meshDrawCommands[left].meshId < meshDrawCommands[right].meshId;
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto& materials = resources->materials();
|
||||||
|
transparentMeshDrawCommands.clear();
|
||||||
|
std::erase_if(sortedMeshDrawCommands, [&](std::size_t index)
|
||||||
|
{
|
||||||
|
if (materials.getMaterial(meshDrawCommands[index].materialId).blendMode != BlendMode::Transparent)
|
||||||
{
|
{
|
||||||
return meshDrawCommands[left].meshId < meshDrawCommands[right].meshId;
|
return false;
|
||||||
});
|
}
|
||||||
|
transparentMeshDrawCommands.push_back(index);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera, const SceneData& sceneData)
|
void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera, const SceneData& sceneData)
|
||||||
@@ -161,7 +172,23 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
|
|
||||||
// Culling stays on the CPU: every view (camera, directional light, each spot light)
|
// Culling stays on the CPU: every view (camera, directional light, each spot light)
|
||||||
// gets its own range of indirect commands in this frame's draw list.
|
// gets its own range of indirect commands in this frame's draw list.
|
||||||
|
{
|
||||||
|
ZoneScopedN("Sort Transparent Draws");
|
||||||
|
|
||||||
|
const glm::vec3 cameraPos = camera.GetPosition();
|
||||||
|
const auto distanceSq = [&](std::size_t index)
|
||||||
|
{
|
||||||
|
const glm::vec3 offset = meshDrawCommands[index].worldBoundingSphere.center - cameraPos;
|
||||||
|
return glm::dot(offset, offset);
|
||||||
|
};
|
||||||
|
std::ranges::sort(transparentMeshDrawCommands, [&](std::size_t left, std::size_t right)
|
||||||
|
{
|
||||||
|
return distanceSq(left) > distanceSq(right);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
IndirectDrawList::View mainView;
|
IndirectDrawList::View mainView;
|
||||||
|
IndirectDrawList::View transparentView;
|
||||||
IndirectDrawList::View directionalShadowView;
|
IndirectDrawList::View directionalShadowView;
|
||||||
std::vector<IndirectDrawList::View> spotShadowViews;
|
std::vector<IndirectDrawList::View> spotShadowViews;
|
||||||
{
|
{
|
||||||
@@ -177,6 +204,13 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
edge::createFrustumFromCamera(camera),
|
edge::createFrustumFromCamera(camera),
|
||||||
IndirectDrawList::Filter::All);
|
IndirectDrawList::Filter::All);
|
||||||
|
|
||||||
|
transparentView = drawList.addView(
|
||||||
|
meshes,
|
||||||
|
meshDrawCommands,
|
||||||
|
transparentMeshDrawCommands,
|
||||||
|
edge::createFrustumFromCamera(camera),
|
||||||
|
IndirectDrawList::Filter::All);
|
||||||
|
|
||||||
if (shadowLightDirection)
|
if (shadowLightDirection)
|
||||||
{
|
{
|
||||||
directionalShadowView = drawList.addView(
|
directionalShadowView = drawList.addView(
|
||||||
@@ -416,6 +450,19 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
skyboxPipeline->draw(cmd, *resources, camera, sceneData.skyboxRotation);
|
skyboxPipeline->draw(cmd, *resources, camera, sceneData.skyboxRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "MeshPipeline::drawTransparent");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "MeshPipeline::drawTransparent", vkutil::labelColors::opaque);
|
||||||
|
|
||||||
|
meshPipeline->drawTransparent(
|
||||||
|
cmd,
|
||||||
|
drawImage.getExtent2D(),
|
||||||
|
*resources,
|
||||||
|
sceneDataBuffer.getBuffer(),
|
||||||
|
drawList,
|
||||||
|
transparentView);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "vkCmdEndRendering");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "vkCmdEndRendering");
|
||||||
|
|
||||||
@@ -600,6 +647,7 @@ void GameRenderer::cleanup(GfxDevice& gfxDevice)
|
|||||||
pendingMaterialUploads.clear();
|
pendingMaterialUploads.clear();
|
||||||
meshDrawCommands.clear();
|
meshDrawCommands.clear();
|
||||||
sortedMeshDrawCommands.clear();
|
sortedMeshDrawCommands.clear();
|
||||||
|
transparentMeshDrawCommands.clear();
|
||||||
initialized = false;
|
initialized = false;
|
||||||
GameState::GetInstance().SetRenderer(nullptr);
|
GameState::GetInstance().SetRenderer(nullptr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,18 @@ namespace {
|
|||||||
return TextureFilteringMode::Linear;
|
return TextureFilteringMode::Linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr std::array<std::string_view, 2> BlendModeNames{"opaque", "transparent"};
|
||||||
|
|
||||||
|
[[nodiscard]] BlendMode ParseBlendMode(std::string_view name)
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < BlendModeNames.size(); ++i) {
|
||||||
|
if (BlendModeNames[i] == name) {
|
||||||
|
return static_cast<BlendMode>(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BlendMode::Opaque;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] RenderResources* GetResources()
|
[[nodiscard]] RenderResources* GetResources()
|
||||||
{
|
{
|
||||||
auto& state = GameState::GetInstance();
|
auto& state = GameState::GetInstance();
|
||||||
@@ -110,6 +122,8 @@ namespace MaterialSerialization {
|
|||||||
{"normalScale", material.normalScale},
|
{"normalScale", material.normalScale},
|
||||||
{"occlusionStrength", material.occlusionStrength},
|
{"occlusionStrength", material.occlusionStrength},
|
||||||
{"filtering", FilteringNames.at(static_cast<std::size_t>(material.textureFilteringMode))},
|
{"filtering", FilteringNames.at(static_cast<std::size_t>(material.textureFilteringMode))},
|
||||||
|
{"blend", BlendModeNames.at(static_cast<std::size_t>(material.blendMode))},
|
||||||
|
{"opacity", material.opacity},
|
||||||
};
|
};
|
||||||
|
|
||||||
json textures = json::object();
|
json textures = json::object();
|
||||||
@@ -138,6 +152,8 @@ namespace MaterialSerialization {
|
|||||||
material.normalScale = data.value("normalScale", material.normalScale);
|
material.normalScale = data.value("normalScale", material.normalScale);
|
||||||
material.occlusionStrength = data.value("occlusionStrength", material.occlusionStrength);
|
material.occlusionStrength = data.value("occlusionStrength", material.occlusionStrength);
|
||||||
material.textureFilteringMode = ParseFiltering(data.value("filtering", std::string{"linear"}));
|
material.textureFilteringMode = ParseFiltering(data.value("filtering", std::string{"linear"}));
|
||||||
|
material.blendMode = ParseBlendMode(data.value("blend", std::string{"opaque"}));
|
||||||
|
material.opacity = data.value("opacity", material.opacity);
|
||||||
|
|
||||||
if (data.contains("textures")) {
|
if (data.contains("textures")) {
|
||||||
const json& textures = data.at("textures");
|
const json& textures = data.at("textures");
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 217 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"guid": "a6c64648ac15e99110de13faea6b80e1"
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
1.0,
|
1.0,
|
||||||
1.0
|
1.0
|
||||||
],
|
],
|
||||||
|
"blend": "opaque",
|
||||||
"emissiveColor": [
|
"emissiveColor": [
|
||||||
0.0,
|
0.0,
|
||||||
0.0,
|
0.0,
|
||||||
@@ -34,6 +35,7 @@
|
|||||||
"name": "material_0",
|
"name": "material_0",
|
||||||
"normalScale": 1.0,
|
"normalScale": 1.0,
|
||||||
"occlusionStrength": 1.0,
|
"occlusionStrength": 1.0,
|
||||||
|
"opacity": 1.0,
|
||||||
"roughness": 0.699999988079071,
|
"roughness": 0.699999988079071,
|
||||||
"textures": {
|
"textures": {
|
||||||
"diffuse": {
|
"diffuse": {
|
||||||
@@ -43,12 +45,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"10": {
|
||||||
|
"baseColor": [
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"blend": "transparent",
|
||||||
|
"emissiveColor": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"filtering": "linear",
|
||||||
|
"metallic": 0.0,
|
||||||
|
"name": "Material",
|
||||||
|
"normalScale": 1.0,
|
||||||
|
"occlusionStrength": 1.0,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"roughness": 1.0,
|
||||||
|
"textures": {
|
||||||
|
"diffuse": {
|
||||||
|
"guid": "a6c64648ac15e99110de13faea6b80e1",
|
||||||
|
"path": "game://kobe.png",
|
||||||
|
"srgb": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"2": {
|
"2": {
|
||||||
"baseColor": [
|
"baseColor": [
|
||||||
0.8999999761581421,
|
0.8999999761581421,
|
||||||
0.10000000149011612,
|
0.10000000149011612,
|
||||||
0.10000000149011612
|
0.10000000149011612
|
||||||
],
|
],
|
||||||
|
"blend": "opaque",
|
||||||
"emissiveColor": [
|
"emissiveColor": [
|
||||||
0.35999998450279236,
|
0.35999998450279236,
|
||||||
0.04000000283122063,
|
0.04000000283122063,
|
||||||
@@ -59,6 +89,7 @@
|
|||||||
"name": "ButtonMaterial",
|
"name": "ButtonMaterial",
|
||||||
"normalScale": 1.0,
|
"normalScale": 1.0,
|
||||||
"occlusionStrength": 1.0,
|
"occlusionStrength": 1.0,
|
||||||
|
"opacity": 1.0,
|
||||||
"roughness": 0.4000000059604645
|
"roughness": 0.4000000059604645
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
@@ -67,6 +98,7 @@
|
|||||||
0.949999988079071,
|
0.949999988079071,
|
||||||
0.8500000238418579
|
0.8500000238418579
|
||||||
],
|
],
|
||||||
|
"blend": "opaque",
|
||||||
"emissiveColor": [
|
"emissiveColor": [
|
||||||
1.0,
|
1.0,
|
||||||
0.8199999928474426,
|
0.8199999928474426,
|
||||||
@@ -77,6 +109,7 @@
|
|||||||
"name": "BulbMaterial",
|
"name": "BulbMaterial",
|
||||||
"normalScale": 1.0,
|
"normalScale": 1.0,
|
||||||
"occlusionStrength": 1.0,
|
"occlusionStrength": 1.0,
|
||||||
|
"opacity": 1.0,
|
||||||
"roughness": 1.0
|
"roughness": 1.0
|
||||||
},
|
},
|
||||||
"4": {
|
"4": {
|
||||||
@@ -85,6 +118,7 @@
|
|||||||
0.8999999761581421,
|
0.8999999761581421,
|
||||||
0.8999999761581421
|
0.8999999761581421
|
||||||
],
|
],
|
||||||
|
"blend": "opaque",
|
||||||
"emissiveColor": [
|
"emissiveColor": [
|
||||||
0.0,
|
0.0,
|
||||||
0.0,
|
0.0,
|
||||||
@@ -95,6 +129,7 @@
|
|||||||
"name": "LightSwitchMaterial",
|
"name": "LightSwitchMaterial",
|
||||||
"normalScale": 1.0,
|
"normalScale": 1.0,
|
||||||
"occlusionStrength": 1.0,
|
"occlusionStrength": 1.0,
|
||||||
|
"opacity": 1.0,
|
||||||
"roughness": 0.5
|
"roughness": 0.5
|
||||||
},
|
},
|
||||||
"5": {
|
"5": {
|
||||||
@@ -103,6 +138,7 @@
|
|||||||
0.10000000149011612,
|
0.10000000149011612,
|
||||||
0.10000000149011612
|
0.10000000149011612
|
||||||
],
|
],
|
||||||
|
"blend": "opaque",
|
||||||
"emissiveColor": [
|
"emissiveColor": [
|
||||||
0.35999998450279236,
|
0.35999998450279236,
|
||||||
0.04000000283122063,
|
0.04000000283122063,
|
||||||
@@ -113,7 +149,116 @@
|
|||||||
"name": "WinButtonMaterial",
|
"name": "WinButtonMaterial",
|
||||||
"normalScale": 1.0,
|
"normalScale": 1.0,
|
||||||
"occlusionStrength": 1.0,
|
"occlusionStrength": 1.0,
|
||||||
|
"opacity": 1.0,
|
||||||
"roughness": 0.4000000059604645
|
"roughness": 0.4000000059604645
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"baseColor": [
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"blend": "transparent",
|
||||||
|
"emissiveColor": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"filtering": "linear",
|
||||||
|
"metallic": 0.0,
|
||||||
|
"name": "Material",
|
||||||
|
"normalScale": 1.0,
|
||||||
|
"occlusionStrength": 1.0,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"roughness": 1.0,
|
||||||
|
"textures": {
|
||||||
|
"diffuse": {
|
||||||
|
"guid": "a6c64648ac15e99110de13faea6b80e1",
|
||||||
|
"path": "game://kobe.png",
|
||||||
|
"srgb": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"baseColor": [
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"blend": "transparent",
|
||||||
|
"emissiveColor": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"filtering": "linear",
|
||||||
|
"metallic": 0.0,
|
||||||
|
"name": "Material",
|
||||||
|
"normalScale": 1.0,
|
||||||
|
"occlusionStrength": 1.0,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"roughness": 1.0,
|
||||||
|
"textures": {
|
||||||
|
"diffuse": {
|
||||||
|
"guid": "a6c64648ac15e99110de13faea6b80e1",
|
||||||
|
"path": "game://kobe.png",
|
||||||
|
"srgb": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"baseColor": [
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"blend": "transparent",
|
||||||
|
"emissiveColor": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"filtering": "linear",
|
||||||
|
"metallic": 0.0,
|
||||||
|
"name": "Material",
|
||||||
|
"normalScale": 1.0,
|
||||||
|
"occlusionStrength": 1.0,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"roughness": 1.0,
|
||||||
|
"textures": {
|
||||||
|
"diffuse": {
|
||||||
|
"guid": "a6c64648ac15e99110de13faea6b80e1",
|
||||||
|
"path": "game://kobe.png",
|
||||||
|
"srgb": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"baseColor": [
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"blend": "transparent",
|
||||||
|
"emissiveColor": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"filtering": "linear",
|
||||||
|
"metallic": 0.0,
|
||||||
|
"name": "Material",
|
||||||
|
"normalScale": 1.0,
|
||||||
|
"occlusionStrength": 1.0,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"roughness": 1.0,
|
||||||
|
"textures": {
|
||||||
|
"diffuse": {
|
||||||
|
"guid": "a6c64648ac15e99110de13faea6b80e1",
|
||||||
|
"path": "game://kobe.png",
|
||||||
|
"srgb": true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "Main",
|
"name": "Main",
|
||||||
@@ -7571,7 +7716,6 @@
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"clip": {
|
"clip": {
|
||||||
"guid": "b21bcb92ef324239e14c407ad8b9ff39",
|
|
||||||
"path": "game://MontyOnTheRun.wav"
|
"path": "game://MontyOnTheRun.wav"
|
||||||
},
|
},
|
||||||
"loop": false,
|
"loop": false,
|
||||||
@@ -7607,6 +7751,186 @@
|
|||||||
1.0
|
1.0
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"material": {
|
||||||
|
"localMaterial": "6"
|
||||||
|
},
|
||||||
|
"mesh": "prim://plane?size=1,1"
|
||||||
|
},
|
||||||
|
"enabled": true,
|
||||||
|
"type": "MeshRendererComponent"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": 121,
|
||||||
|
"name": "Decal",
|
||||||
|
"parent": 0,
|
||||||
|
"transform": {
|
||||||
|
"position": [
|
||||||
|
-4.743542194366455,
|
||||||
|
0.3649294674396515,
|
||||||
|
0.07782143354415894
|
||||||
|
],
|
||||||
|
"rotation": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
-0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
1.0,
|
||||||
|
0.9999995231628418,
|
||||||
|
0.9999995827674866
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"material": {
|
||||||
|
"localMaterial": "7"
|
||||||
|
},
|
||||||
|
"mesh": "prim://plane?size=1,1"
|
||||||
|
},
|
||||||
|
"enabled": true,
|
||||||
|
"type": "MeshRendererComponent"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": 122,
|
||||||
|
"name": "Decal",
|
||||||
|
"parent": 0,
|
||||||
|
"transform": {
|
||||||
|
"position": [
|
||||||
|
-4.743542194366455,
|
||||||
|
1.1351869106292725,
|
||||||
|
2.188525676727295
|
||||||
|
],
|
||||||
|
"rotation": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
-0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
1.0,
|
||||||
|
0.9999995231628418,
|
||||||
|
0.9999995827674866
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"material": {
|
||||||
|
"localMaterial": "8"
|
||||||
|
},
|
||||||
|
"mesh": "prim://plane?size=1,1"
|
||||||
|
},
|
||||||
|
"enabled": true,
|
||||||
|
"type": "MeshRendererComponent"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": 123,
|
||||||
|
"name": "Decal",
|
||||||
|
"parent": 0,
|
||||||
|
"transform": {
|
||||||
|
"position": [
|
||||||
|
-4.743542194366455,
|
||||||
|
1.5165855884552002,
|
||||||
|
0.601291835308075
|
||||||
|
],
|
||||||
|
"rotation": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
-0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
1.0,
|
||||||
|
0.9999995231628418,
|
||||||
|
0.9999995827674866
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"material": {
|
||||||
|
"localMaterial": "9"
|
||||||
|
},
|
||||||
|
"mesh": "prim://plane?size=1,1"
|
||||||
|
},
|
||||||
|
"enabled": true,
|
||||||
|
"type": "MeshRendererComponent"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": 124,
|
||||||
|
"name": "Decal",
|
||||||
|
"parent": 0,
|
||||||
|
"transform": {
|
||||||
|
"position": [
|
||||||
|
-4.743542194366455,
|
||||||
|
0.5876348614692688,
|
||||||
|
-1.545495867729187
|
||||||
|
],
|
||||||
|
"rotation": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
-0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
1.0,
|
||||||
|
0.9999995231628418,
|
||||||
|
0.9999995827674866
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"material": {
|
||||||
|
"localMaterial": "10"
|
||||||
|
},
|
||||||
|
"mesh": "prim://plane?size=1,1"
|
||||||
|
},
|
||||||
|
"enabled": true,
|
||||||
|
"type": "MeshRendererComponent"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": 125,
|
||||||
|
"name": "Decal",
|
||||||
|
"parent": 0,
|
||||||
|
"transform": {
|
||||||
|
"position": [
|
||||||
|
-4.743542194366455,
|
||||||
|
1.3765578269958496,
|
||||||
|
-2.816664457321167
|
||||||
|
],
|
||||||
|
"rotation": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
-0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
1.0,
|
||||||
|
0.9999995231628418,
|
||||||
|
0.9999995827674866
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"version": 3
|
"version": 3
|
||||||
|
|||||||
@@ -293,6 +293,8 @@ namespace {
|
|||||||
material.roughnessFactor = 0.55f;
|
material.roughnessFactor = 0.55f;
|
||||||
material.emissiveColor = {1.0f, 0.5f, 0.0f};
|
material.emissiveColor = {1.0f, 0.5f, 0.0f};
|
||||||
material.textureFilteringMode = TextureFilteringMode::Anisotropic;
|
material.textureFilteringMode = TextureFilteringMode::Anisotropic;
|
||||||
|
material.blendMode = BlendMode::Transparent;
|
||||||
|
material.opacity = 0.25f;
|
||||||
material.diffuseTexture = 3;
|
material.diffuseTexture = 3;
|
||||||
material.emissiveTexture = 7;
|
material.emissiveTexture = 7;
|
||||||
material.normalTexture = 9;
|
material.normalTexture = 9;
|
||||||
@@ -315,7 +317,8 @@ namespace {
|
|||||||
check(loaded.name == "Crate" && loaded.baseColor == material.baseColor &&
|
check(loaded.name == "Crate" && loaded.baseColor == material.baseColor &&
|
||||||
close(loaded.metallicFactor, 0.3f) && close(loaded.roughnessFactor, 0.55f) &&
|
close(loaded.metallicFactor, 0.3f) && close(loaded.roughnessFactor, 0.55f) &&
|
||||||
loaded.emissiveColor == material.emissiveColor &&
|
loaded.emissiveColor == material.emissiveColor &&
|
||||||
loaded.textureFilteringMode == TextureFilteringMode::Anisotropic,
|
loaded.textureFilteringMode == TextureFilteringMode::Anisotropic &&
|
||||||
|
loaded.blendMode == BlendMode::Transparent && close(loaded.opacity, 0.25f),
|
||||||
"material factors must round-trip through json");
|
"material factors must round-trip through json");
|
||||||
check(loaded.diffuseTexture == 30 && loaded.emissiveTexture == 70 &&
|
check(loaded.diffuseTexture == 30 && loaded.emissiveTexture == 70 &&
|
||||||
loaded.normalTexture == NULL_IMAGE_ID && loaded.metallicTexture == NULL_IMAGE_ID,
|
loaded.normalTexture == NULL_IMAGE_ID && loaded.metallicTexture == NULL_IMAGE_ID,
|
||||||
|
|||||||
Reference in New Issue
Block a user