Skip to content

Commit

Permalink
Update code for loading normal map from image
Browse files Browse the repository at this point in the history
Signed-off-by: Ian Chen <[email protected]>
  • Loading branch information
iche033 committed Sep 18, 2024
1 parent 21993f0 commit 615dfd5
Showing 1 changed file with 122 additions and 5 deletions.
127 changes: 122 additions & 5 deletions ogre2/src/Ogre2Material.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <OgreMaterialManager.h>
#include <OgrePixelFormatGpuUtils.h>
#include <OgreTechnique.h>
#include <OgreTextureBox.h>
#include <OgreTextureFilters.h>
#include <OgreTextureGpuManager.h>
#include <Vao/OgreVaoManager.h>
#ifdef _MSC_VER
Expand Down Expand Up @@ -130,6 +132,13 @@ class gz::rendering::Ogre2MaterialPrivate
return "invalid";
}
}

/// \brief Helper function to convert normal maps to two-component normalized
/// signed 8-bit format, and generate mip maps
/// \param[in/out] _texture Normal map texture
/// \param[in/out] _image Normal map image data to be uploaded to the texture
public: void PrepareAndUploadNormalMap(Ogre::TextureGpu *_texture,
Ogre::Image2 &_image);
};

using namespace gz;
Expand Down Expand Up @@ -1215,6 +1224,8 @@ void Ogre2Material::SetTextureMapDataImpl(const std::string& _name,
root->getRenderSystem()->getTextureGpuManager();

// create the gpu texture
Ogre::uint32 filters = Ogre::TextureFilter::TypeGenerateDefaultMipmaps;
filters |= this->ogreDatablock->suggestFiltersForType(_type);
Ogre::uint32 textureFlags = 0;
textureFlags |= Ogre::TextureFlags::AutomaticBatching;
Ogre::TextureGpu *texture = textureMgr->createOrRetrieveTexture(
Expand All @@ -1223,7 +1234,7 @@ void Ogre2Material::SetTextureMapDataImpl(const std::string& _name,
textureFlags | Ogre::TextureFlags::ManualTexture,
Ogre::TextureTypes::Type2D,
Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME,
0u);
filters);

// Has to be loaded
if (texture->getWidth() == 0)
Expand All @@ -1236,13 +1247,20 @@ void Ogre2Material::SetTextureMapDataImpl(const std::string& _name,
texture->setTextureType(Ogre::TextureTypes::Type2D);
texture->setNumMipmaps(1u);
texture->setResolution(_img->Width(), _img->Height());
texture->scheduleTransitionTo(Ogre::GpuResidency::Resident);
texture->waitForData();

// upload raw color image data to gpu texture
Ogre::Image2 img;
img.loadDynamicImage(&data[0], false, texture);
img.uploadTo(texture, 0, 0);
if (_type == Ogre::PBSM_NORMAL)
{
this->dataPtr->PrepareAndUploadNormalMap(texture, img);
}
else
{
// upload raw color image data to gpu texture
texture->scheduleTransitionTo(Ogre::GpuResidency::Resident);
texture->waitForData();
img.uploadTo(texture, 0, 0);
}
}

// Now assign it to the material
Expand Down Expand Up @@ -1558,3 +1576,102 @@ ShaderParamsPtr Ogre2Material::FragmentShaderParams()
{
return this->dataPtr->fragmentShaderParams;
}

//////////////////////////////////////////////////
void Ogre2MaterialPrivate::PrepareAndUploadNormalMap(Ogre::TextureGpu *_texture,
Ogre::Image2 &_image)
{
// The code below is adapted from ogre-next v2-3. It replicates the steps that
// ogre does when it loads a normal map from file.
// Here we adapte the code to load a normal map texture from an image in
// memory
// \todo(iche033) See if there is a way to reuse these functions
// from ogre-next without copying the code here.

// Step 1: convert to two component signed 8 bit format:
// Ogre::PFG_RG8_SNORM format
// see PrepareForNormalMapping::_executeStreaming function in
// OgreMain/src/OgreTextureFilters.cpp
const Ogre::uint8 numMipmaps = _image.getNumMipmaps();
const Ogre::PixelFormatGpu dstFormat = Ogre::PFG_RG8_SNORM;
const Ogre::uint32 rowAlignment = 4u;
const size_t dstSizeBytes = Ogre::PixelFormatGpuUtils::calculateSizeBytes(
_image.getWidth(),
_image.getHeight(),
_image.getDepth(),
_image.getNumSlices(),
dstFormat, numMipmaps,
rowAlignment );
void *imgData = OGRE_MALLOC_SIMD( dstSizeBytes, Ogre::MEMCATEGORY_RESOURCE);
for (Ogre::uint8 mip = 0; mip<numMipmaps; ++mip)
{
Ogre::TextureBox srcBox = _image.getData( mip );
const Ogre::uint32 width = srcBox.width;
const Ogre::uint32 height = srcBox.height;

Ogre::TextureBox dstBox = srcBox;
dstBox.bytesPerPixel =
Ogre::PixelFormatGpuUtils::getBytesPerPixel(dstFormat);
dstBox.bytesPerRow =
Ogre::PixelFormatGpuUtils::getSizeBytes(
width, 1u, 1u, 1u, dstFormat, 4u);
dstBox.bytesPerImage =
Ogre::PixelFormatGpuUtils::getSizeBytes(width, height, 1u, 1u,
dstFormat, 4u);
dstBox.data = Ogre::PixelFormatGpuUtils::advancePointerToMip(
imgData, width, height, srcBox.depth, srcBox.numSlices, mip, dstFormat);

Ogre::PixelFormatGpuUtils::convertForNormalMapping(
srcBox, _image.getPixelFormat(),
dstBox, dstFormat);
}
_image.loadDynamicImage(imgData, _image.getWidth(), _image.getHeight(),
_image.getDepthOrSlices(), _image.getTextureType(), dstFormat, false,
numMipmaps);
_texture->setPixelFormat(dstFormat);

// _image.save(_name + ".png", 0, 1);
// std::cerr << "tex format " << texture->getWidth() << " " << texture->getHeight() << ": " << texture->getPixelFormat() << " mip "
// << static_cast<int>(texture->getNumMipmaps()) << std::endl;
//std::cerr << "image format " << _image.getWidth() << " " << _image.getHeight() << ": " << _image.getPixelFormat() << std::endl;
//std::cerr << " Ogre::PFG_RG8_SNORM " << Ogre::PFG_RG8_SNORM << std::endl;

// Step 2: Set mip map count
// see GenerateHwMipmaps::_executeStreaming function in
// OgreMain/src/OgreTextureFilters.cpp
Ogre::uint8 maxMipmaps = Ogre::PixelFormatGpuUtils::getMaxMipmapCount(
_texture->getWidth(),
_texture->getHeight(),
_texture->getDepth() );
_texture->setNumMipmaps(maxMipmaps);

_texture->scheduleTransitionTo(Ogre::GpuResidency::Resident);
_texture->waitForData();
_image.uploadTo(_texture, 0, 0);

// Step 3: Generate and copy mip maps
// see GenerateHwMipmaps::_executeSerial function in
// OgreMain/src/OgreTextureFilters.cpp
Ogre::TextureGpuManager *textureManager = _texture->getTextureManager();
Ogre::TextureGpu *tempTexture = textureManager->createTexture(
"___tempMipmapTexture",
Ogre::GpuPageOutStrategy::Discard,
Ogre::TextureFlags::RenderToTexture |
Ogre::TextureFlags::AllowAutomipmaps |
Ogre::TextureFlags::DiscardableContent,
_texture->getTextureType());
tempTexture->copyParametersFrom(_texture);
tempTexture->unsafeScheduleTransitionTo(Ogre::GpuResidency::Resident);
Ogre::TextureBox box = _texture->getEmptyBox(0);
_texture->copyTo(tempTexture, box, 0, box, 0);
tempTexture->_autogenerateMipmaps();

Ogre::uint8 mipmaps = _texture->getNumMipmaps();
for (size_t i = 1u; i < mipmaps; ++i)
{
box = _texture->getEmptyBox( i );
tempTexture->copyTo(_texture, box, i, box, i);
}
textureManager->destroyTexture(tempTexture);
tempTexture = 0;
}

0 comments on commit 615dfd5

Please sign in to comment.