Skip to content

Commit

Permalink
feat: #82 Add bake reflection function
Browse files Browse the repository at this point in the history
  • Loading branch information
ducph committed Jun 3, 2020
1 parent ef101f6 commit 4548637
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 10 deletions.
100 changes: 92 additions & 8 deletions Projects/Skylicht/Engine/Source/ReflectionProbe/CReflectionProbe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ This file is part of the "Skylicht Engine".
#include "Entity/CEntityManager.h"

#include "RenderPipeline/IRenderPipeline.h"
#include "RenderPipeline/CBaseRP.h"

#include "CReflectionProbe.h"

#include "TextureManager/CTextureManager.h"
Expand All @@ -37,14 +39,38 @@ namespace Skylicht
{
CReflectionProbe::CReflectionProbe() :
m_staticTexture(NULL),
m_bakeTexture(NULL)
m_dynamicTexture(NULL),
m_bakeSize(512, 512)
{

for (int i = 0; i < 6; i++)
m_bakeTexture[i] = NULL;
}

CReflectionProbe::~CReflectionProbe()
{
removeBakeTexture();
removeDynamicTexture();
}

void CReflectionProbe::removeBakeTexture()
{
for (int i = 0; i < 6; i++)
{
if (m_bakeTexture[i] != NULL)
{
getVideoDriver()->removeTexture(m_bakeTexture[i]);
m_bakeTexture[i] = NULL;
}
}
}

void CReflectionProbe::removeDynamicTexture()
{
if (m_dynamicTexture == NULL)
{
getVideoDriver()->removeTexture(m_dynamicTexture);
m_dynamicTexture = NULL;
}
}

void CReflectionProbe::initComponent()
Expand All @@ -59,25 +85,83 @@ namespace Skylicht

void CReflectionProbe::bakeProbe(CCamera *camera, IRenderPipeline *rp, CEntityManager *entityMgr)
{
if (m_dynamicTexture == NULL)
m_dynamicTexture = getVideoDriver()->addRenderTargetCubeTexture(m_bakeSize, "bake_cube_reflection", video::ECF_A8R8G8B8);

core::vector3df position = m_gameObject->getPosition();
CBaseRP *baseRP = dynamic_cast<CBaseRP*>(rp);
if (baseRP != NULL)
{
baseRP->renderCubeEnvironment(camera, entityMgr, position, m_dynamicTexture, NULL, 0);

m_dynamicTexture->regenerateMipMapLevels();
}
}

void CReflectionProbe::bakeProbeToFile(CCamera *camera, IRenderPipeline *rp, CEntityManager *entityMgr, const char *outfolder, const char *outname)
{
for (int i = 0; i < 6; i++)
{
if (m_bakeTexture[i] != NULL)
m_bakeTexture[i] = getVideoDriver()->addRenderTargetTexture(m_bakeSize, "bake_reflection", video::ECF_A8R8G8B8);
}

core::vector3df position = m_gameObject->getPosition();
CBaseRP *baseRP = dynamic_cast<CBaseRP*>(rp);
if (baseRP != NULL)
{
baseRP->renderEnvironment(camera, entityMgr, position, m_bakeTexture, NULL, 0);

const char *cubeText[] =
{
"X1",
"X2",
"Y1",
"Y2",
"Z1",
"Z2"
};

char name[512];
for (int i = 0; i < 6; i++)
{
sprintf(name, "%s/%s_%s.png", outfolder, outname, cubeText[i]);
void *imageData = m_bakeTexture[i]->lock(video::ETLM_READ_ONLY);

IImage* im = getVideoDriver()->createImageFromData(
m_bakeTexture[i]->getColorFormat(),
m_bakeTexture[i]->getSize(),
imageData);

if (getVideoDriver()->getDriverType() == video::EDT_DIRECT3D11)
im->swapBG();

getVideoDriver()->writeImageToFile(im, name);
im->drop();

m_bakeTexture[i]->unlock();
}
}
}

bool CReflectionProbe::loadStaticTexture(const char *path)
{
std::string x1 = std::string(path) + "_X1.tga";
std::string x2 = std::string(path) + "_X2.tga";
std::string y1 = std::string(path) + "_Y1.tga";
std::string y2 = std::string(path) + "_Y2.tga";
std::string z1 = std::string(path) + "_Z1.tga";
std::string z2 = std::string(path) + "_Z2.tga";
std::string x1 = std::string(path) + "_X1.png";
std::string x2 = std::string(path) + "_X2.png";
std::string y1 = std::string(path) + "_Y1.png";
std::string y2 = std::string(path) + "_Y2.png";
std::string z1 = std::string(path) + "_Z1.png";
std::string z2 = std::string(path) + "_Z2.png";

m_staticTexture = CTextureManager::getInstance()->getCubeTexture(
x1.c_str(), x2.c_str(),
y1.c_str(), y2.c_str(),
z1.c_str(), z2.c_str()
);

if (m_staticTexture != NULL)
m_staticTexture->regenerateMipMapLevels();

return (m_staticTexture != NULL);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,17 @@ namespace Skylicht
{
protected:
video::ITexture *m_staticTexture;
video::ITexture *m_bakeTexture;

video::ITexture *m_dynamicTexture;

core::dimension2du m_bakeSize;
video::ITexture *m_bakeTexture[6];

protected:

void removeBakeTexture();

void removeDynamicTexture();

public:
CReflectionProbe();
Expand All @@ -47,5 +57,7 @@ namespace Skylicht
bool loadStaticTexture(const char *path);

void bakeProbe(CCamera *camera, IRenderPipeline *rp, CEntityManager *entityMgr);

void bakeProbeToFile(CCamera *camera, IRenderPipeline *rp, CEntityManager *entityMgr, const char *outfolder, const char *outname);
};
}
136 changes: 136 additions & 0 deletions Projects/Skylicht/Engine/Source/RenderPipeline/CBaseRP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,142 @@ namespace Skylicht
driver->drawMeshBuffer(m_drawBuffer);
}

void CBaseRP::renderEnvironment(CCamera *camera, CEntityManager *entityMgr, const core::vector3df& position, ITexture *texture[], int* face, int numFace)
{
if (texture == NULL)
return;

IVideoDriver *driver = getVideoDriver();

core::matrix4 projection;
projection.buildProjectionMatrixPerspectiveFovLH(90.0f * core::DEGTORAD, 1.0f, camera->getNearValue(), camera->getFarValue());

core::vector3df targetDirectX[] = {
core::vector3df(1.0f, 0.0f, 0.0f), // right
core::vector3df(-1.0f, 0.0f, 0.0f), // left

core::vector3df(0.0f, 1.0f, 0.0f), // up
core::vector3df(0.0f,-1.0f, 0.0f), // down

core::vector3df(0.0f, 0.0f, 1.0f), // front
core::vector3df(0.0f, 0.0f,-1.0f), // back
};

// todo: FBO OpenGL is invertY
core::vector3df targetOpenGL[] = {
core::vector3df(1.0f, 0.0f, 0.0f), // right
core::vector3df(-1.0f, 0.0f, 0.0f), // left

core::vector3df(0.0f, 1.0f, 0.0f), // up
core::vector3df(0.0f,-1.0f, 0.0f), // down

core::vector3df(0.0f, 0.0f,-1.0f), // front
core::vector3df(0.0f, 0.0f, 1.0f), // back
};

core::vector3df up[] = {
core::vector3df(0.0f, 1.0f, 0.0f),
core::vector3df(0.0f, 1.0f, 0.0f),

core::vector3df(0.0f, 0.0f,-1.0f),
core::vector3df(0.0f, 0.0f, 1.0f),

core::vector3df(0.0f, 1.0f, 0.0f),
core::vector3df(0.0f, 1.0f, 0.0f),
};

core::vector3df *target = targetDirectX;

if (driver->getDriverType() != video::EDT_DIRECT3D11)
target = targetOpenGL;

core::matrix4 view;

// OpenGL have flipY buffer
// So we fix inverse Y by render to a buffer
ITexture *tempFBO = NULL;
E_DRIVER_TYPE driverType = driver->getDriverType();

SMaterial material;

if (driverType == EDT_OPENGL || driverType == EDT_OPENGLES)
{
video::ECOLOR_FORMAT colorFormat = texture[0]->getColorFormat();
tempFBO = driver->addRenderTargetTexture(texture[0]->getSize(), "tempFBO", colorFormat);

material.setTexture(0, tempFBO);
material.MaterialType = m_textureColorShaderID;
}

if (face != NULL)
{
for (int i = 0; i < numFace; i++)
{
core::dimension2du size = texture[i]->getSize();
float sizeW = (float)size.Width;
float sizeH = (float)size.Height;

int faceID = face[i];
video::E_CUBEMAP_FACE cubemapFace = (video::E_CUBEMAP_FACE)faceID;

view.makeIdentity();
view.buildCameraLookAtMatrixLH(position, position + target[faceID] * 100.0f, up[faceID]);
driver->setTransform(video::ETS_PROJECTION, projection);
driver->setTransform(video::ETS_VIEW, view);

if (tempFBO)
{
// todo: Dont flip TOP & BOTTOM
drawSceneToTexture(tempFBO, entityMgr);

driver->setRenderTargetCube(texture[i], cubemapFace, true, true);
beginRender2D(sizeW, sizeH);
renderBufferToTarget(0, 0, sizeW, sizeH, material, false);
}
else
{
drawSceneToCubeTexture(texture[i], cubemapFace, entityMgr);
}
}
}
else
{
for (int i = 0; i < 6; i++)
{
core::dimension2du size = texture[i]->getSize();
float sizeW = (float)size.Width;
float sizeH = (float)size.Height;

video::E_CUBEMAP_FACE cubemapFace = (video::E_CUBEMAP_FACE)i;

view.makeIdentity();
view.buildCameraLookAtMatrixLH(position, position + target[i] * 100.0f, up[i]);
driver->setTransform(video::ETS_PROJECTION, projection);
driver->setTransform(video::ETS_VIEW, view);

if (tempFBO)
{
// todo: Dont flip TOP & BOTTOM
drawSceneToTexture(tempFBO, entityMgr);

driver->setRenderTarget(texture[i], cubemapFace, true, true);
beginRender2D(sizeW, sizeH);
renderBufferToTarget(0, 0, sizeW, sizeH, material, false);
}
else
{
drawSceneToCubeTexture(texture[i], cubemapFace, entityMgr);
}
}
}

driver->setRenderTarget(NULL);
if (tempFBO != NULL)
{
driver->removeTexture(tempFBO);
}
}

void CBaseRP::renderCubeEnvironment(CCamera *camera, CEntityManager *entityMgr, const core::vector3df& position, ITexture *texture, int* face, int numFace)
{
if (texture == NULL)
Expand Down
2 changes: 2 additions & 0 deletions Projects/Skylicht/Engine/Source/RenderPipeline/CBaseRP.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ namespace Skylicht

void renderBufferToTarget(float dx, float dy, float dw, float dh, float sx, float sy, float sw, float sh, SMaterial& material, bool flipY = true, bool flipX = false);

void renderEnvironment(CCamera *camera, CEntityManager *entityMgr, const core::vector3df& position, ITexture *texture[], int* face, int numFace);

void renderCubeEnvironment(CCamera *camera, CEntityManager *entityMgr, const core::vector3df& position, ITexture *texture, int* face, int numFace);

static void saveFBOToFile(ITexture *texture, const char *output);
Expand Down
3 changes: 2 additions & 1 deletion Samples/SkinnedMesh/Source/SampleSkinnedMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ void SampleSkinnedMesh::onInitApp()

// reflection probe
CGameObject *reflectionProbeObj = zone->createEmptyObject();
reflectionProbeObj->addComponent<CReflectionProbe>();
CReflectionProbe *reflection = reflectionProbeObj->addComponent<CReflectionProbe>();
reflection->loadStaticTexture("Common/Textures/Sky/PaperMill");

// 3D grid
CGameObject *grid = zone->createEmptyObject();
Expand Down

0 comments on commit 4548637

Please sign in to comment.