Skip to content

Commit 3c79a9a

Browse files
committed
Update code for loading normal and albedo maps from image data (#1068)
Signed-off-by: Ian Chen <ichen@openrobotics.org>
1 parent e227df6 commit 3c79a9a

File tree

1 file changed

+131
-4
lines changed

1 file changed

+131
-4
lines changed

ogre2/src/Ogre2Material.cc

Lines changed: 131 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*
1616
*/
1717

18+
#include <cstddef>
19+
1820
// Note this include is placed in the src file because
1921
// otherwise ogre produces compile errors
2022
#ifdef _MSC_VER
@@ -31,6 +33,8 @@
3133
#include <OgreMaterialManager.h>
3234
#include <OgrePixelFormatGpuUtils.h>
3335
#include <OgreTechnique.h>
36+
#include <OgreTextureBox.h>
37+
#include <OgreTextureFilters.h>
3438
#include <OgreTextureGpuManager.h>
3539
#include <Vao/OgreVaoManager.h>
3640
#ifdef _MSC_VER
@@ -130,6 +134,23 @@ class gz::rendering::Ogre2MaterialPrivate
130134
return "invalid";
131135
}
132136
}
137+
138+
/// \brief Prepare for normal mapping by converting to two-component
139+
/// normalized signed 8-bit format
140+
/// \param[in] _texture Normal map texture
141+
/// \param[in/out] _image Normal map image data
142+
public: void PrepareForNormalMapping(Ogre::TextureGpu *_texture,
143+
Ogre::Image2 &_image);
144+
145+
/// \brief Allocate mimaps for the texture. This should be done when the
146+
/// texture's residency status is still OnStorage.
147+
/// \param[in] _texture Input texture to allocate mimaps
148+
public: void AllocateMipmaps(Ogre::TextureGpu *_texture);
149+
150+
/// \brief Generate mimaps for the texture. This should be done when the
151+
/// texture's residency status is Resident.
152+
/// \param[in] _texture Input texture to generate mimpas
153+
public: void GenerateMipmaps(Ogre::TextureGpu *_texture);
133154
};
134155

135156
using namespace gz;
@@ -1220,6 +1241,8 @@ void Ogre2Material::SetTextureMapDataImpl(const std::string& _name,
12201241
root->getRenderSystem()->getTextureGpuManager();
12211242

12221243
// create the gpu texture
1244+
Ogre::uint32 filters = Ogre::TextureFilter::TypeGenerateDefaultMipmaps;
1245+
filters |= this->ogreDatablock->suggestFiltersForType(_type);
12231246
Ogre::uint32 textureFlags = 0;
12241247
textureFlags |= Ogre::TextureFlags::AutomaticBatching;
12251248
Ogre::TextureGpu *texture = textureMgr->createOrRetrieveTexture(
@@ -1228,7 +1251,7 @@ void Ogre2Material::SetTextureMapDataImpl(const std::string& _name,
12281251
textureFlags | Ogre::TextureFlags::ManualTexture,
12291252
Ogre::TextureTypes::Type2D,
12301253
Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME,
1231-
0u);
1254+
filters);
12321255

12331256
// Has to be loaded
12341257
if (texture->getWidth() == 0)
@@ -1241,13 +1264,31 @@ void Ogre2Material::SetTextureMapDataImpl(const std::string& _name,
12411264
texture->setTextureType(Ogre::TextureTypes::Type2D);
12421265
texture->setNumMipmaps(1u);
12431266
texture->setResolution(_img->Width(), _img->Height());
1244-
texture->scheduleTransitionTo(Ogre::GpuResidency::Resident);
1245-
texture->waitForData();
12461267

1247-
// upload raw color image data to gpu texture
12481268
Ogre::Image2 img;
12491269
img.loadDynamicImage(&data[0], false, texture);
1270+
1271+
// Replicates the steps that ogre does when it loads a texture map from
1272+
// file. For normal maps, it is first converted to a two component signed
1273+
// 8 bit format. Albedo and normal maps will have mipmaps generated.
1274+
// \todo(iche033) See if there is a way to reuse these functions
1275+
// from ogre-next without copying the code here.
1276+
1277+
// Normal maps - convert to two component signed 8 bit format:
1278+
// Ogre::PFG_RG8_SNORM format
1279+
if (_type == Ogre::PBSM_NORMAL)
1280+
this->dataPtr->PrepareForNormalMapping(texture, img);
1281+
1282+
if (_type == Ogre::PBSM_DIFFUSE || _type == Ogre::PBSM_NORMAL)
1283+
this->dataPtr->AllocateMipmaps(texture);
1284+
1285+
// Upload raw color image data to gpu texture
1286+
texture->scheduleTransitionTo(Ogre::GpuResidency::Resident);
1287+
texture->waitForData();
12501288
img.uploadTo(texture, 0, 0);
1289+
1290+
if (_type == Ogre::PBSM_DIFFUSE || _type == Ogre::PBSM_NORMAL)
1291+
this->dataPtr->GenerateMipmaps(texture);
12511292
}
12521293

12531294
// Now assign it to the material
@@ -1563,3 +1604,89 @@ ShaderParamsPtr Ogre2Material::FragmentShaderParams()
15631604
{
15641605
return this->dataPtr->fragmentShaderParams;
15651606
}
1607+
1608+
//////////////////////////////////////////////////
1609+
void Ogre2MaterialPrivate::PrepareForNormalMapping(Ogre::TextureGpu *_texture,
1610+
Ogre::Image2 &_image)
1611+
{
1612+
// code adpated from PrepareForNormalMapping::_executeStreaming function in
1613+
// OgreMain/src/OgreTextureFilters.cpp (v2-3)
1614+
const Ogre::uint8 numMipmaps = _image.getNumMipmaps();
1615+
const Ogre::PixelFormatGpu dstFormat = Ogre::PFG_RG8_SNORM;
1616+
const Ogre::uint32 rowAlignment = 4u;
1617+
const size_t dstSizeBytes = Ogre::PixelFormatGpuUtils::calculateSizeBytes(
1618+
_image.getWidth(),
1619+
_image.getHeight(),
1620+
_image.getDepth(),
1621+
_image.getNumSlices(),
1622+
dstFormat, numMipmaps,
1623+
rowAlignment );
1624+
void *imgData = OGRE_MALLOC_SIMD( dstSizeBytes, Ogre::MEMCATEGORY_RESOURCE);
1625+
for (Ogre::uint8 mip = 0; mip < numMipmaps; ++mip)
1626+
{
1627+
Ogre::TextureBox srcBox = _image.getData( mip );
1628+
const Ogre::uint32 width = srcBox.width;
1629+
const Ogre::uint32 height = srcBox.height;
1630+
1631+
Ogre::TextureBox dstBox = srcBox;
1632+
dstBox.bytesPerPixel =
1633+
Ogre::PixelFormatGpuUtils::getBytesPerPixel(dstFormat);
1634+
dstBox.bytesPerRow =
1635+
Ogre::PixelFormatGpuUtils::getSizeBytes(
1636+
width, 1u, 1u, 1u, dstFormat, 4u);
1637+
dstBox.bytesPerImage =
1638+
Ogre::PixelFormatGpuUtils::getSizeBytes(width, height, 1u, 1u,
1639+
dstFormat, 4u);
1640+
dstBox.data = Ogre::PixelFormatGpuUtils::advancePointerToMip(
1641+
imgData, width, height, srcBox.depth, srcBox.numSlices, mip, dstFormat);
1642+
1643+
Ogre::PixelFormatGpuUtils::convertForNormalMapping(
1644+
srcBox, _image.getPixelFormat(),
1645+
dstBox, dstFormat);
1646+
}
1647+
_image.loadDynamicImage(imgData, _image.getWidth(), _image.getHeight(),
1648+
_image.getDepthOrSlices(), _image.getTextureType(), dstFormat, false,
1649+
numMipmaps);
1650+
_texture->setPixelFormat(dstFormat);
1651+
}
1652+
1653+
//////////////////////////////////////////////////
1654+
void Ogre2MaterialPrivate::AllocateMipmaps(Ogre::TextureGpu *_texture)
1655+
{
1656+
// code adpated from GenerateHwMipmaps::_executeStreaming function in
1657+
// OgreMain/src/OgreTextureFilters.cpp (v2-3)
1658+
Ogre::uint8 maxMipmaps = Ogre::PixelFormatGpuUtils::getMaxMipmapCount(
1659+
_texture->getWidth(),
1660+
_texture->getHeight(),
1661+
_texture->getDepth() );
1662+
_texture->setNumMipmaps(maxMipmaps);
1663+
}
1664+
1665+
//////////////////////////////////////////////////
1666+
void Ogre2MaterialPrivate::GenerateMipmaps(Ogre::TextureGpu *_texture)
1667+
{
1668+
// code adpated from GenerateHwMipmaps::_executeSerial function in
1669+
// OgreMain/src/OgreTextureFilters.cpp (v2-3)
1670+
Ogre::TextureGpuManager *textureManager = _texture->getTextureManager();
1671+
Ogre::TextureGpu *tempTexture = textureManager->createTexture(
1672+
"___tempMipmapTexture",
1673+
Ogre::GpuPageOutStrategy::Discard,
1674+
Ogre::TextureFlags::RenderToTexture |
1675+
Ogre::TextureFlags::AllowAutomipmaps |
1676+
Ogre::TextureFlags::DiscardableContent,
1677+
_texture->getTextureType());
1678+
tempTexture->copyParametersFrom(_texture);
1679+
tempTexture->unsafeScheduleTransitionTo(Ogre::GpuResidency::Resident);
1680+
Ogre::TextureBox box = _texture->getEmptyBox(0);
1681+
_texture->copyTo(tempTexture, box, 0, box, 0);
1682+
tempTexture->_autogenerateMipmaps();
1683+
1684+
Ogre::uint8 mipmaps = _texture->getNumMipmaps();
1685+
for (size_t i = 1u; i < mipmaps; ++i)
1686+
{
1687+
box = _texture->getEmptyBox( i );
1688+
tempTexture->copyTo(_texture, box, i, box, i);
1689+
}
1690+
textureManager->destroyTexture(tempTexture);
1691+
tempTexture = 0;
1692+
}

0 commit comments

Comments
 (0)