Skip to content

Commit

Permalink
#80 Add render decal projection (sample collision)
Browse files Browse the repository at this point in the history
  • Loading branch information
ducphamhong committed May 17, 2022
1 parent 27aa88f commit 7103db4
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 36 deletions.
Binary file added Assets/BuiltIn/Textures/UVTest.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
14 changes: 11 additions & 3 deletions Projects/Skylicht/Collision/Source/Decal/CDecalData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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<video::S3DVertex>(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();
}
}
7 changes: 7 additions & 0 deletions Projects/Skylicht/Collision/Source/Decal/CDecalData.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@ This file is part of the "Skylicht Engine".
#pragma once

#include "Entity/IEntityData.h"
#include "Material/CMaterial.h"
#include "Collision/CCollisionBuilder.h"

namespace Skylicht
{
class CDecalRenderData : public IEntityData
{
public:
ITexture* Texture;
CMaterial* Material;

DECLARE_DATA_TYPE_INDEX;

Expand All @@ -50,6 +53,10 @@ namespace Skylicht
float LifeTime;
float Distance;
CDecalRenderData* RenderData;
bool Change;

IMeshBuffer* MeshBuffer;
CCollisionBuilder* Collision;

DECLARE_DATA_TYPE_INDEX;

Expand Down
31 changes: 24 additions & 7 deletions Projects/Skylicht/Collision/Source/Decal/CDecals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CEntity*>& 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<CDecalData>();
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;
}
}
12 changes: 5 additions & 7 deletions Projects/Skylicht/Collision/Source/Decal/CDecals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -50,20 +52,16 @@ 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,
const core::vector3df& dimension,
const core::vector3df& normal,
float textureRotation,
float lifeTime,
float distance);

void bake();
float distance,
CCollisionBuilder* collision);

DECLARE_GETTYPENAME(CDecals);
};
Expand Down
164 changes: 157 additions & 7 deletions Projects/Skylicht/Collision/Source/Decal/CDecalsRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}
}
}
}
Expand All @@ -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<core::triangle3df*> triangles;
core::array<CCollisionNode*> 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<core::vector3df, u32> 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<core::vector3df, u32>::iterator iter = positions.find(uvPos);
if (iter != positions.end())
{
index = iter->second;
}
// Add vertex to list
else
{
index = vertexIndex;
positions.insert(std::pair<core::vector3df, u32>(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();
}
}
2 changes: 2 additions & 0 deletions Projects/Skylicht/Collision/Source/Decal/CDecalsRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,7 @@ namespace Skylicht
virtual void update(CEntityManager* entityManager);

virtual void render(CEntityManager* entityManager);

void initDecal(CDecalData* decal, const core::vector3df& position);
};
}
Loading

0 comments on commit 7103db4

Please sign in to comment.