[Solved] Create an animated texture from image file(s) without using scripts? Topic is solved

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


knn217
Halfling
Posts: 78
Joined: Wed Jan 25, 2023 9:04 am
x 5

[Solved] Create an animated texture from image file(s) without using scripts?

Post by knn217 »

Hello, I've recently learned how to load a texture from an image file and put it on a 2D plane.
My next goal is to learn how to do the same thing but for animated texture.
I've been looking through HlmsUnlitDatablock and setAnimationMatrix seems to be the answer, but I can't figure out how to use the function.
Is there a code snippet for extracting Matrix4 from an image or from combining multiple images?

I saw texture anim in Ogre_v1's manual but it requires material script, is this the only way or is there a way to do this in C++?

Last edited by knn217 on Sun Jul 16, 2023 2:45 am, edited 3 times in total.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5476
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1358

Re: Create an animated texture from image file(s)?

Post by dark_sylinc »

Hi!

Do you animate this by switching between multiple textures?, or did you create an atlas (e.g. a 1024x1024 containing 256 textures of 16x16 each in a grid)?

knn217
Halfling
Posts: 78
Joined: Wed Jan 25, 2023 9:04 am
x 5

Re: Create an animated texture from image file(s)?

Post by knn217 »

dark_sylinc wrote: Sun Jul 09, 2023 4:08 pm

Hi!

Do you animate this by switching between multiple textures?, or did you create an atlas (e.g. a 1024x1024 containing 256 textures of 16x16 each in a grid)?

Thanks for the reply!
Examples of both methods would be appreciated since I'm just trying to learn Ogre-next's basics, so the more knowledge the better.
I didn't create an atlas, but I found "flame_anim.png" in Ogre-next's texture folder so I planned to use that.

Here are the functions I used to create a plane mesh with texture, not sure I did it the right way tho, though this was sort of a combination of the billboard test + UpdatingDecalsAndAreaLightTex sample:

Code: Select all


Ogre::MeshPtr LowLevelOgreNext::CreatePlaneV2(
    const Ogre::String& name, const Ogre::String& groupName, const Ogre::Plane& plane, Ogre::Real width, Ogre::Real height,
    Ogre::uint32 xsegments, Ogre::uint32 ysegments, bool normals, unsigned short numTexCoordSets, Ogre::Real uTile, Ogre::Real vTile,
    const Ogre::Vector3& upVector, Ogre::v1::HardwareBuffer::Usage vertexBufferUsage, Ogre::v1::HardwareBuffer::Usage indexBufferUsage,
    bool vertexShadowBuffer, bool indexShadowBuffer)
{
    Ogre::v1::MeshPtr planeMeshV1 = mMeshMgrV1->createPlane(
        name + "v1", groupName, plane, width, height, xsegments, ysegments, normals, numTexCoordSets, uTile, vTile,
        upVector, vertexBufferUsage, indexBufferUsage, vertexShadowBuffer, indexShadowBuffer);

Ogre::MeshPtr planeMesh = mMeshMgr->createByImportingV1(
    name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, planeMeshV1.get(), true,
    true, true);

planeMeshV1->unload();

return planeMesh;
}

//-----------------------------------------------------------------------------------
Ogre::SceneNode* LowLevelOgreNext::CreateTexturePlane(
    const Ogre::Plane& plane, Ogre::Real width, Ogre::Real height, const Ogre::Vector3& upVector, 
    const Ogre::String meshName, const Ogre::String materialName, const Ogre::String aliasName, const Ogre::String textureName,
    static const Ogre::uint32 areaLightsPoolId)
{
    // Create the scene node
    Ogre::SceneNode* PlaneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    
// Create the mesh for the plane Ogre::MeshPtr v2LightPlane = CreatePlaneV2( meshName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 1.0f, 1.0f, 1, 1, true, 1, 1.0f, 1.0f, upVector, Ogre::v1::HardwareBuffer::HBU_STATIC, Ogre::v1::HardwareBuffer::HBU_STATIC); Ogre::Hlms* hlmsUnlit = mRoot->getHlmsManager()->getHlms(Ogre::HLMS_UNLIT); Ogre::HlmsMacroblock macroblock; macroblock.mCullMode = Ogre::CULL_NONE; Ogre::HlmsBlendblock blendBlock; blendBlock.setBlendType(Ogre::SBT_TRANSPARENT_ALPHA); // Setup datablock Ogre::HlmsDatablock* datablockBase = hlmsUnlit->getDatablock(materialName); if (!datablockBase) { //datablockBase = hlmsUnlit->createDatablock(materialName, materialName, macroblock, Ogre::HlmsBlendblock(), Ogre::HlmsParamVec()); datablockBase = hlmsUnlit->createDatablock(materialName, materialName, macroblock, blendBlock, Ogre::HlmsParamVec()); } assert(dynamic_cast<Ogre::HlmsUnlitDatablock*>(datablockBase)); Ogre::HlmsUnlitDatablock* datablock = static_cast<Ogre::HlmsUnlitDatablock*>(datablockBase); datablock->setUseColour(true); datablock->setTexture(0u, textureName); // Create the plane Item //Ogre::Item* item = mSceneMgr->createItem(meshName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); Ogre::Item* item = mSceneMgr->createItem(v2LightPlane, Ogre::SCENE_DYNAMIC); item->setCastShadows(false); item->setDatablock(datablock); PlaneNode->attachObject(item); PlaneNode->setScale(width, height, 1.0f); return PlaneNode; }
knn217
Halfling
Posts: 78
Joined: Wed Jan 25, 2023 9:04 am
x 5

Re: Create an animated texture from image file(s)?

Post by knn217 »

dark_sylinc wrote: Sun Jul 09, 2023 4:08 pm

Do you animate this by switching between multiple textures?, or did you create an atlas (e.g. a 1024x1024 containing 256 textures of 16x16 each in a grid)?

I found the solution for the atlas format:

Code: Select all

// ...create the datablock and add a Controller for it 
    
datablock->setTexture(0u, "flames_anim.png"); datablock->setEnableAnimationMatrix(0u, true); mController = OGRE_NEW Ogre::TextureAnimationControllerValue(datablock, 0u); mController->tiledAnimation(4, 4); mController->scrollAnimation(true, true); // update mController->setValue(texture_frame); // -0.25 each update since there are 4 frames each row texture_frame -= 0.25;

I still have some questions though:


  1. When I look at the code for mController->setValue(...), it seems I have to set the frames backward (i.e. 1 -> 0.75 -> 0.5 -> 0.25 -> 0) for the animation to get down the next row (mCurrentVerticalFrame++). Is there a reason for this since it's quite counterintuitive?

  2. How do I do this for multiple texture files instead of 1 atlas?

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5476
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1358

Re: Create an animated texture from image file(s) without using scripts?

Post by dark_sylinc »

Ahh!!!

Thank you! I am not very familiar with TextureAnimationControllerValue but yes, that is the solution.

When I look at the code for mController->setValue(...), it seems I have to set the frames backward (i.e. 1 -> 0.75 -> 0.5 -> 0.25 -> 0) for the animation to get down the next row (mCurrentVerticalFrame++). Is there a reason for this since it's quite counterintuitive?

Assuming it's not a bug (which looks at a simple glance like it's not), that often has to do on whether how the frames are layed out in the texture (i.e. the texture is mirrored) and the plane's UVs (e.g. it's not the same if the plane is upside down, or scaled by y = -1, or the v is flipped).

The problem is likely with how the plane's geometry was generated. Try negating the -upVector in mMeshMgrV1->createPlane().

(note that if the plane disappears, it's because it is now facing the other way, i.e. hardware culling doing its job, just rotate it or move the camera to the other side).

Btw animating using multiple textures is just about manually doing:

Code: Select all

datablock->setTexture( 0u, texture[texIdx] );
timeToNextFrame -= timeSinceLast;
if( timeToNextFrame <= 0.0f )
{
    timeToNextFrame += 1.0f;
    texIdx = (texIdx + 1u) % numTextures;
}
knn217
Halfling
Posts: 78
Joined: Wed Jan 25, 2023 9:04 am
x 5

Re: Create an animated texture from image file(s) without using scripts?

Post by knn217 »

Oh right, the solution was there all along! :oops:
For some reason, I had tunnel vision that the solution was to combine the textures somehow and then also use animation matrix
Forgot that I can just load a new texture in and didn't have to deal with the textures' different dimensions

Thanks for the answer! :D


For people who want to set their texture atlas to a specific row and column:
_The class Ogre::TextureAnimationControllerValue is actually not needed, only for ease of use with the scale and scroll animation functions.
_Instead, you can set it with: datablock->setAnimationMatrix(Ogre::matrix4) - which is what TextureAnimationControllerValue does anyway.

Here's an example using Ogre's texture atlas file: "flames_anim.png" which has 4 rows and 4 columns:

Code: Select all


// Setup datablock 
    datablock->setTexture(0u, "flames_anim.png"); 
    // need this to apply matrix animation   
datablock->setEnableAnimationMatrix(0u, true); // Update // horizontal and vertical scale is 1/4 since there are 4 rows and 4 columns. Ogre::Real scale_h = 1.0/4.0; Ogre::Real scale_v = 1.0/4.0; // The current displayed row and column of the texture atlas. Ogre::Real row = 0; Ogre::Real col = 0; // Create the matrix from the params above. Ogre::Matrix4 mat( scale_h, 0, 0, row, 0, scale_v, 0, col, 0, 0, 1.0, 0, 0, 0, 0, 1.0); datablock->setAnimationMatrix(0u, mat); // scroll the row 1/4 since there are 4 texture columns in 1 row. // You can also scroll a different number like 0.1 and get an interpolated column between column 0 and column 0.25. row += 1.0/4.0;