Page 1 of 1

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

Posted: Sat Jul 08, 2023 4:00 pm
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++?


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

Posted: Sun Jul 09, 2023 4:08 pm
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)?


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

Posted: Sun Jul 09, 2023 5:05 pm
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; }

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

Posted: Sat Jul 15, 2023 3:03 pm
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?


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

Posted: Sun Jul 16, 2023 2:20 am
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;
}

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

Posted: Sun Jul 16, 2023 2:38 am
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;