From 7103db47de7dec7a6f40435f37c39294b11ab44e Mon Sep 17 00:00:00 2001 From: ducphamhong Date: Tue, 17 May 2022 15:50:00 +0700 Subject: [PATCH] #80 Add render decal projection (sample collision) --- Assets/BuiltIn/Textures/UVTest.png | Bin 0 -> 4432 bytes .../Source/Collision/COctreeBuilder.cpp | 4 +- .../Collision/Source/Decal/CDecalData.cpp | 14 +- .../Collision/Source/Decal/CDecalData.h | 7 + .../Collision/Source/Decal/CDecals.cpp | 31 +++- .../Skylicht/Collision/Source/Decal/CDecals.h | 12 +- .../Source/Decal/CDecalsRenderer.cpp | 164 +++++++++++++++++- .../Collision/Source/Decal/CDecalsRenderer.h | 2 + Samples/Collision/Source/CViewDemo.cpp | 34 +++- 9 files changed, 232 insertions(+), 36 deletions(-) create mode 100644 Assets/BuiltIn/Textures/UVTest.png diff --git a/Assets/BuiltIn/Textures/UVTest.png b/Assets/BuiltIn/Textures/UVTest.png new file mode 100644 index 0000000000000000000000000000000000000000..3db6e96305fe6dec8e5752da79306a797e253a5f GIT binary patch literal 4432 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 literal 0 HcmV?d00001 diff --git a/Projects/Skylicht/Collision/Source/Collision/COctreeBuilder.cpp b/Projects/Skylicht/Collision/Source/Collision/COctreeBuilder.cpp index ef7718657..3ec7478e1 100644 --- a/Projects/Skylicht/Collision/Source/Collision/COctreeBuilder.cpp +++ b/Projects/Skylicht/Collision/Source/Collision/COctreeBuilder.cpp @@ -373,9 +373,7 @@ namespace Skylicht core::triangle3df& triangle = collision->Triangles[listTriID[i]]; // if triangle collide the bbox - if (box.isPointInside(triangle.pointA) || - box.isPointInside(triangle.pointB) || - box.isPointInside(triangle.pointC)) + if (!triangle.isTotalOutsideBox(box)) { p[n + used] = ▵ c[n + used] = collision; diff --git a/Projects/Skylicht/Collision/Source/Decal/CDecalData.cpp b/Projects/Skylicht/Collision/Source/Decal/CDecalData.cpp index f2f19cea8..526ffa7aa 100644 --- a/Projects/Skylicht/Collision/Source/Decal/CDecalData.cpp +++ b/Projects/Skylicht/Collision/Source/Decal/CDecalData.cpp @@ -32,11 +32,12 @@ namespace Skylicht CDecalRenderData::CDecalRenderData() : Texture(NULL) { + Material = new CMaterial("DecalRenderer", "BuiltIn/Shader/Basic/TextureColorAlpha.xml"); } CDecalRenderData::~CDecalRenderData() { - + delete Material; } IMPLEMENT_DATA_TYPE_INDEX(CDecalData); @@ -45,13 +46,20 @@ namespace Skylicht TextureRotation(0.0f), LifeTime(0.0f), Distance(0.0f), - RenderData(NULL) + RenderData(NULL), + Collision(NULL), + Change(true) { + MeshBuffer = new CMeshBuffer(getVideoDriver()->getVertexDescriptor(EVT_STANDARD)); + MeshBuffer->setHardwareMappingHint(scene::EHM_STREAM); + SMaterial& mat = MeshBuffer->getMaterial(); + mat.TextureLayer[0].TextureWrapU = E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE; + mat.TextureLayer[0].TextureWrapV = E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE; } CDecalData::~CDecalData() { - + MeshBuffer->drop(); } } \ No newline at end of file diff --git a/Projects/Skylicht/Collision/Source/Decal/CDecalData.h b/Projects/Skylicht/Collision/Source/Decal/CDecalData.h index c0df9a732..1c53be47e 100644 --- a/Projects/Skylicht/Collision/Source/Decal/CDecalData.h +++ b/Projects/Skylicht/Collision/Source/Decal/CDecalData.h @@ -25,6 +25,8 @@ This file is part of the "Skylicht Engine". #pragma once #include "Entity/IEntityData.h" +#include "Material/CMaterial.h" +#include "Collision/CCollisionBuilder.h" namespace Skylicht { @@ -32,6 +34,7 @@ namespace Skylicht { public: ITexture* Texture; + CMaterial* Material; DECLARE_DATA_TYPE_INDEX; @@ -50,6 +53,10 @@ namespace Skylicht float LifeTime; float Distance; CDecalRenderData* RenderData; + bool Change; + + IMeshBuffer* MeshBuffer; + CCollisionBuilder* Collision; DECLARE_DATA_TYPE_INDEX; diff --git a/Projects/Skylicht/Collision/Source/Decal/CDecals.cpp b/Projects/Skylicht/Collision/Source/Decal/CDecals.cpp index d6b0acf0b..33474873f 100644 --- a/Projects/Skylicht/Collision/Source/Decal/CDecals.cpp +++ b/Projects/Skylicht/Collision/Source/Decal/CDecals.cpp @@ -66,35 +66,52 @@ namespace Skylicht return CComponentSystem::loadSerializable(object); } + void CDecals::setTexture(ITexture* texture) + { + m_renderData->Texture = texture; + m_renderData->Material->setTexture(0, texture); + + std::vector& entities = getEntities(); + for (CEntity* entity : entities) + { + CDecalData* decal = (CDecalData*)entity->getDataByIndex(CDecalData::DataTypeIndex); + if (decal != NULL) + { + m_renderData->Material->applyMaterial(decal->MeshBuffer->getMaterial()); + } + } + } + CEntity* CDecals::addDecal( const core::vector3df& position, const core::vector3df& dimension, const core::vector3df& normal, float textureRotation, float lifeTime, - float distance) + float distance, + CCollisionBuilder* collision) { // References // https://sourceforge.net/p/irrext/code/HEAD/tree/trunk/extensions/scene/ISceneNode/DecalSystem - CEntity* entity = createEntity(); CDecalData* decalData = entity->addData(); decalData->Dimension = dimension; decalData->Normal = normal; + decalData->Normal.normalize(); decalData->TextureRotation = textureRotation; decalData->LifeTime = lifeTime; decalData->Distance = distance; decalData->RenderData = m_renderData; + decalData->Collision = collision; + // add transform CWorldTransformData* transform = (CWorldTransformData*)entity->getDataByIndex(CWorldTransformData::DataTypeIndex); transform->Relative.setTranslation(position); - return entity; - } - - void CDecals::bake() - { + // apply material + m_renderData->Material->applyMaterial(decalData->MeshBuffer->getMaterial()); + return entity; } } \ No newline at end of file diff --git a/Projects/Skylicht/Collision/Source/Decal/CDecals.h b/Projects/Skylicht/Collision/Source/Decal/CDecals.h index 6a1d2e23d..4f5cf7bb7 100644 --- a/Projects/Skylicht/Collision/Source/Decal/CDecals.h +++ b/Projects/Skylicht/Collision/Source/Decal/CDecals.h @@ -30,6 +30,8 @@ This file is part of the "Skylicht Engine". #include "CDecalsRenderer.h" #include "CDecalData.h" +#include "Collision/CCollisionBuilder.h" + namespace Skylicht { class CDecals : public CEntityHandler @@ -50,10 +52,7 @@ namespace Skylicht virtual void loadSerializable(CObjectSerializable* object); - inline void setTexture(ITexture* texture) - { - m_renderData->Texture = texture; - } + void setTexture(ITexture* texture); CEntity* addDecal( const core::vector3df& position, @@ -61,9 +60,8 @@ namespace Skylicht const core::vector3df& normal, float textureRotation, float lifeTime, - float distance); - - void bake(); + float distance, + CCollisionBuilder* collision); DECLARE_GETTYPENAME(CDecals); }; diff --git a/Projects/Skylicht/Collision/Source/Decal/CDecalsRenderer.cpp b/Projects/Skylicht/Collision/Source/Decal/CDecalsRenderer.cpp index 0d75940d3..166d6cbeb 100644 --- a/Projects/Skylicht/Collision/Source/Decal/CDecalsRenderer.cpp +++ b/Projects/Skylicht/Collision/Source/Decal/CDecalsRenderer.cpp @@ -53,7 +53,6 @@ namespace Skylicht if (renderData != NULL) { CVisibleData* visibleData = (CVisibleData*)entity->getDataByIndex(CVisibleData::DataTypeIndex); - if (visibleData->Visible) { CWorldTransformData* transform = (CWorldTransformData*)entity->getDataByIndex(CWorldTransformData::DataTypeIndex); @@ -64,13 +63,15 @@ namespace Skylicht else { CDecalData* decalData = (CDecalData*)entity->getDataByIndex(CDecalData::DataTypeIndex); - CVisibleData* visibleData = (CVisibleData*)entity->getDataByIndex(CVisibleData::DataTypeIndex); - - if (visibleData->Visible) + if (decalData != NULL) { - CWorldTransformData* transform = (CWorldTransformData*)entity->getDataByIndex(CWorldTransformData::DataTypeIndex); - m_decalTransforms.push_back(transform); - m_decalData.push_back(decalData); + CVisibleData* visibleData = (CVisibleData*)entity->getDataByIndex(CVisibleData::DataTypeIndex); + if (visibleData->Visible) + { + CWorldTransformData* transform = (CWorldTransformData*)entity->getDataByIndex(CWorldTransformData::DataTypeIndex); + m_decalTransforms.push_back(transform); + m_decalData.push_back(decalData); + } } } } @@ -82,11 +83,160 @@ namespace Skylicht void CDecalsRenderer::update(CEntityManager* entityManager) { + u32 numDecal = m_decalData.size(); + + // create decal buffer + CDecalData** decalDatas = m_decalData.pointer(); + CWorldTransformData** decalTransform = m_decalTransforms.pointer(); + for (u32 i = 0; i < numDecal; i++) + { + CDecalData* decalData = decalDatas[i]; + if (decalData->Change == true && decalData->Collision) + { + initDecal(decalData, decalTransform[i]->World.getTranslation()); + decalData->Change = false; + } + } } void CDecalsRenderer::render(CEntityManager* entityManager) { + u32 numDecal = m_decalData.size(); + + // create decal buffer + CDecalData** decalDatas = m_decalData.pointer(); + CWorldTransformData** decalTransform = m_decalTransforms.pointer(); + + IVideoDriver* videoDriver = getVideoDriver(); + + // reset world transform + videoDriver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + + for (u32 i = 0; i < numDecal; i++) + { + CDecalData* decal = decalDatas[i]; + + video::SMaterial& mat = decal->MeshBuffer->getMaterial(); + + videoDriver->setMaterial(mat); + videoDriver->drawMeshBuffer(decal->MeshBuffer); + } + } + + void CDecalsRenderer::initDecal(CDecalData* decal, const core::vector3df& position) + { + // Create boxes + irr::core::aabbox3df box = irr::core::aabbox3df( + position - decal->Dimension * 0.5f, + position + decal->Dimension * 0.5f + ); + + // Calculate uv rotation + core::quaternion quatDirection; + quatDirection.rotationFromTo(irr::core::vector3df(0, 1, 0), decal->Normal); + + core::vector3df rotation; + quatDirection.toEuler(rotation); + rotation.Y += (decal->TextureRotation * core::DEGTORAD); + + // Create uv rotation matrix + core::matrix4 rotationMatrix; + rotationMatrix.setRotationRadians(rotation); + rotationMatrix.setRotationCenter(core::vector3df(0.5f, 0.5f, 0.5f), core::vector3df(0, 0, 0)); + + // Query tris collision + core::array triangles; + core::array nodes; + decal->Collision->getTriangles(box, triangles, nodes); + u32 triangleCount = triangles.size(); + + // Scale to 0.0f - 1.0f (UV space) + core::vector3df scale = core::vector3df(1, 1, 1) / box.getExtent(); + + // Create scale matrix + irr::core::matrix4 scaleMatrix; + scaleMatrix.setScale(scale); + + irr::core::matrix4 m; + m.setTranslation(-(box.MinEdge * scale)); + m *= scaleMatrix; + + // Clip all triangles and fill vertex and indices + u32 vertexIndex = 0; + std::map positions; + + IIndexBuffer* indices = decal->MeshBuffer->getIndexBuffer(); + IVertexBuffer* vertices = decal->MeshBuffer->getVertexBuffer(); + + for (u32 i = 0; i < triangleCount; i++) + { + u32 index = 0; + + core::triangle3df uvTriangle = *triangles[i]; + core::triangle3df& triangle = *triangles[i]; + + core::vector3df triangleNormal = triangle.getNormal(); + triangleNormal.normalize(); + + // Scale & Translate positions + m.transformVect(uvTriangle.pointA); + m.transformVect(uvTriangle.pointB); + m.transformVect(uvTriangle.pointC); + + // Rotate positions + rotationMatrix.transformVect(uvTriangle.pointA); + rotationMatrix.transformVect(uvTriangle.pointB); + rotationMatrix.transformVect(uvTriangle.pointC); + + // Fill vertices and indices + { + for (u32 p = 0; p < 3; p++) + { + core::vector3df uvPos = uvTriangle.pointA; + core::vector3df pos = triangle.pointA; + + if (p == 1) + { + uvPos = uvTriangle.pointB; + pos = triangle.pointB; + } + else if (p == 2) + { + uvPos = uvTriangle.pointC; + pos = triangle.pointC; + } + + // Search if vertex already exists in the vertices list + std::map::iterator iter = positions.find(uvPos); + if (iter != positions.end()) + { + index = iter->second; + } + // Add vertex to list + else + { + index = vertexIndex; + positions.insert(std::pair(uvPos, vertexIndex)); + + pos += triangleNormal * decal->Distance; + + vertices->addVertex( + &video::S3DVertex( + pos, + triangleNormal, + video::SColor(255, 255, 255, 255), + core::vector2df(uvPos.X, 1 - uvPos.Z)) + ); + vertexIndex++; + } + + indices->addIndex(index); + } + } + } + decal->MeshBuffer->recalculateBoundingBox(); + decal->MeshBuffer->setDirty(); } } \ No newline at end of file diff --git a/Projects/Skylicht/Collision/Source/Decal/CDecalsRenderer.h b/Projects/Skylicht/Collision/Source/Decal/CDecalsRenderer.h index 2fd92253c..b822506bf 100644 --- a/Projects/Skylicht/Collision/Source/Decal/CDecalsRenderer.h +++ b/Projects/Skylicht/Collision/Source/Decal/CDecalsRenderer.h @@ -53,5 +53,7 @@ namespace Skylicht virtual void update(CEntityManager* entityManager); virtual void render(CEntityManager* entityManager); + + void initDecal(CDecalData* decal, const core::vector3df& position); }; } \ No newline at end of file diff --git a/Samples/Collision/Source/CViewDemo.cpp b/Samples/Collision/Source/CViewDemo.cpp index f8ae15e3e..4101a63c5 100644 --- a/Samples/Collision/Source/CViewDemo.cpp +++ b/Samples/Collision/Source/CViewDemo.cpp @@ -42,6 +42,9 @@ void CViewDemo::onInit() CZone* zone = context->getActiveZone(); CGameObject* obj = zone->createEmptyObject(); m_decals = obj->addComponent(); + + ITexture* texture = CTextureManager::getInstance()->getTexture("BuiltIn/Textures/UVTest.png"); + m_decals->setTexture(texture); } void CViewDemo::onDestroy() @@ -127,16 +130,30 @@ void CViewDemo::onUpdate() } else if (m_currentTest == 2) { + core::vector3df normal = triangle.getNormal(); + normal.normalize(); + // draw bbox query core::aabbox3df box; core::vector3df halfBox = core::vector3df(m_decalSizeX * 0.5f, m_decalSizeY * 0.5f, m_decalSizeZ * 0.5f); - box.MinEdge = intersection - halfBox; - box.MaxEdge = intersection + halfBox; - sceneDebug->addBoudingBox(box, SColor(255, 0, 255, 0)); + box.MinEdge = -halfBox; + box.MaxEdge = halfBox; - // draw intersection point - core::vector3df normal = triangle.getNormal().normalize(); + core::quaternion r1; + r1.rotationFromTo(core::vector3df(0.0f, 1.0f, 0.0f), normal); + core::quaternion r2; + r2.fromAngleAxis(-m_decalRotation * core::DEGTORAD, core::vector3df(0.0f, 1.0f, 0.0f)); + + core::quaternion q = r2 * r1; + + core::matrix4 bbMatrix = q.getMatrix(); + bbMatrix.setTranslation(intersection); + + sceneDebug->addTransformBBox(box, SColor(255, 0, 255, 0), bbMatrix); + + + // draw center & projection vector core::line3df line; line.start = intersection; line.end = intersection + normal; @@ -147,13 +164,12 @@ void CViewDemo::onUpdate() { m_decals->addDecal( intersection, - core::vector3df(m_bboxSizeX, m_bboxSizeY, m_bboxSizeZ), + core::vector3df(m_decalSizeX, m_decalSizeX, m_decalSizeX), normal, m_decalRotation, m_decalLifeTime, - 0.0f); - - m_decals->bake(); + 0.01f, + collisionMgr); m_addDecal = false; }