Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update code for loading normal and albedo maps from image data #1068

Merged
merged 7 commits into from
Sep 23, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
iche033 marked this conversation as resolved.
Show resolved Hide resolved
// 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);
iche033 marked this conversation as resolved.
Show resolved Hide resolved
// 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)
iche033 marked this conversation as resolved.
Show resolved Hide resolved
{
box = _texture->getEmptyBox( i );
tempTexture->copyTo(_texture, box, i, box, i);
}
textureManager->destroyTexture(tempTexture);
tempTexture = 0;
}
Loading