// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #include #include #include #include namespace anki { ANKI_SCENE_COMPONENT_STATICS(DecalComponent) DecalComponent::DecalComponent(SceneNode* node) : SceneComponent(node, getStaticClassId()) , m_node(node) { ANKI_ASSERT(node); if(node->getSceneGraph().getResourceManager().loadResource("EngineAssets/GreenDecal.ankitex", m_debugImage)) { ANKI_SCENE_LOGF("Failed to load resources"); } } DecalComponent::~DecalComponent() { } Error DecalComponent::setLayer(CString texAtlasFname, CString texAtlasSubtexName, F32 blendFactor, LayerType type) { Layer& l = m_layers[type]; ANKI_CHECK(m_node->getSceneGraph().getResourceManager().loadResource(texAtlasFname, l.m_atlas)); ANKI_CHECK(l.m_atlas->getSubImageInfo(texAtlasSubtexName, &l.m_uv[0])); // Add a border to the UVs to avoid complex shader logic if(l.m_atlas->getSubImageMargin() < ATLAS_SUB_IMAGE_MARGIN) { ANKI_SCENE_LOGE("Need image atlas with margin at least %u", ATLAS_SUB_IMAGE_MARGIN); return Error::USER_DATA; } const Vec2 marginf = F32(ATLAS_SUB_IMAGE_MARGIN / 2) / Vec2(F32(l.m_atlas->getWidth()), F32(l.m_atlas->getHeight())); const Vec2 minUv = l.m_uv.xy() - marginf; const Vec2 sizeUv = (l.m_uv.zw() - l.m_uv.xy()) + 2.0f * marginf; l.m_uv = Vec4(minUv.x(), minUv.y(), minUv.x() + sizeUv.x(), minUv.y() + sizeUv.y()); l.m_blendFactor = blendFactor; return Error::NONE; } void DecalComponent::updateInternal() { const Vec3 halfBoxSize = m_boxSize / 2.0f; // Calculate the texture matrix const Mat4 worldTransform(m_trf); const Mat4 viewMat = worldTransform.getInverse(); const Mat4 projMat = Mat4::calculateOrthographicProjectionMatrix(halfBoxSize.x(), -halfBoxSize.x(), halfBoxSize.y(), -halfBoxSize.y(), CLUSTER_OBJECT_FRUSTUM_NEAR_PLANE, m_boxSize.z()); static const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); m_biasProjViewMat = biasMat4 * projMat * viewMat; // Calculate the OBB const Vec4 center(0.0f, 0.0f, -halfBoxSize.z(), 0.0f); const Vec4 extend(halfBoxSize.x(), halfBoxSize.y(), halfBoxSize.z(), 0.0f); const Obb obbL(center, Mat3x4::getIdentity(), extend); m_obb = obbL.getTransformed(m_trf); } void DecalComponent::draw(RenderQueueDrawContext& ctx) const { const Mat3 rot = m_obb.getRotation().getRotationPart(); const Vec4 tsl = m_obb.getCenter().xyz1(); const Vec3 scale = m_obb.getExtend().xyz(); Mat3 nonUniScale = Mat3::getZero(); nonUniScale(0, 0) = scale.x(); nonUniScale(1, 1) = scale.y(); nonUniScale(2, 2) = scale.z(); const Mat4 mvp = ctx.m_viewProjectionMatrix * Mat4(tsl, rot * nonUniScale, 1.0f); const Bool enableDepthTest = ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DEPTH_TEST_ON); if(enableDepthTest) { ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::LESS); } else { ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::ALWAYS); } m_node->getSceneGraph().getDebugDrawer().drawCubes( ConstWeakArray(&mvp, 1), Vec4(0.0f, 1.0f, 0.0f, 1.0f), 1.0f, ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DITHERED_DEPTH_TEST_ON), 2.0f, *ctx.m_stagingGpuAllocator, ctx.m_commandBuffer); const Vec3 pos = m_obb.getCenter().xyz(); m_node->getSceneGraph().getDebugDrawer().drawBillboardTextures( ctx.m_projectionMatrix, ctx.m_viewMatrix, ConstWeakArray(&pos, 1), Vec4(1.0f), ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DITHERED_DEPTH_TEST_ON), m_debugImage->getTextureView(), ctx.m_sampler, Vec2(0.75f), *ctx.m_stagingGpuAllocator, ctx.m_commandBuffer); // Restore state if(!enableDepthTest) { ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::LESS); } } } // end namespace anki