[SOLVED][2.1] HLMS + Manual Textures

Discussion area about developing with Ogre2 branches (2.1, 2.2 and beyond)
Post Reply
al2950
OGRE Expert User
OGRE Expert User
Posts: 1221
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 154

[SOLVED][2.1] HLMS + Manual Textures

Post by al2950 »

It would appear the hlms texture manager is only able to create HLMS compatible textures by loading from file only?

I am finishing up porting OgreProcedural, but part of its functionality is procedural textures and I can not get them to work. I have not yet looked at generating a Hlms texture directly in OgreProcedural, only converting like the Pbs sample.

I also curious how lets say a dynamic environment map would work, as it would be updated ever x frames?
Last edited by al2950 on Thu Jul 23, 2015 11:34 pm, edited 1 time in total.

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

Re: [2.1] HLMS + Manual Textures

Post by dark_sylinc »

Just create a regular texture (most likely array texture because that's what PBS wants except for cubemaps; even if the texture array has only one slice) and call HlmsPbsDatablock::setTexture.

Unlit can work with regular 2D textures and 2D array textures, but PBS expects strictly array textures.

The HlmsTextureManager just wraps around the real TextureManager so that textures can be batched together in arrays (or UV atlases in mobile) in order to reduce API overhead. That's all.

User avatar
pergy
Gnoblar
Posts: 6
Joined: Tue Mar 31, 2015 2:35 pm

Re: [2.1] HLMS + Manual Textures

Post by pergy »

Hello,
I used this code successfully for the same purpose:

Code: Select all

		Ogre::HlmsManager *hlmsManager = mGraphicsSystem->getRoot()->getHlmsManager();
		Ogre::HlmsTextureManager *hlmsTextureManager = hlmsManager->getTextureManager();
		Ogre::HlmsUnlit *hlmsUnlit = static_cast<Ogre::HlmsUnlit*>( hlmsManager->getHlms(Ogre::HLMS_UNLIT) );

		Ogre::TexturePtr myTexture = Ogre::TextureManager::getSingletonPtr()->createManual(
			"MyTexture", 
			Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, 
			Ogre::TEX_TYPE_2D, 1024, 768, 0, Ogre::PF_A8R8G8B8, Ogre::TU_DYNAMIC_WRITE_ONLY);

		Ogre::HlmsTextureManager::TextureLocation texLocation = 
			hlmsTextureManager->createOrRetrieveTexture("MyTextureLocation", "MyTexture", Ogre::HlmsTextureManager::TEXTURE_TYPE_DIFFUSE);

		texLocation.texture = myTexture;
		
		Ogre::String datablockName = "MyTextureDatablock";
		Ogre::HlmsUnlitDatablock *datablock = static_cast<Ogre::HlmsUnlitDatablock*>(
			hlmsUnlit->createDatablock( datablockName,
			datablockName,
			Ogre::HlmsMacroblock(),
			Ogre::HlmsBlendblock(),
			Ogre::HlmsParamVec() ) );		

		datablock->setTexture( Ogre::PBSM_DIFFUSE, texLocation.xIdx, texLocation.texture );
and could assign it to Item or ManualObject by 'setDatablock'
However, I couldn't assign it to OverlayContainer, even though it has the same Datablock setter from Renderable (it seems, that the fact, its getVaos().empty() make it unable to hold it, when Hlms::calculateHashFor).
Any thought on that?
Cheers

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.1] HLMS + Manual Textures

Post by xrgo »

TEX_TYPE_2D works with unlit datablock, for pbs has to be array

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

Re: [2.1] HLMS + Manual Textures

Post by dark_sylinc »

As I said, using the HlmsTextureManager is unnecessary.

Apparently I'll have to show it with some code:

Code: Select all

Ogre::TexturePtr myTexture = Ogre::TextureManager::getSingletonPtr()->createManual(
			"MyTexture", 
			Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, 
			Ogre::TEX_TYPE_2D_ARRAY, 1024, 768, 1, 0, Ogre::PF_A8R8G8B8, Ogre::TU_DYNAMIC_WRITE_ONLY);
pbsDatablock->setTexture( Ogre::PBSM_DIFFUSE, 0, myTexture );
Done.

pergy wrote:However, I couldn't assign it to OverlayContainer, even though it has the same Datablock setter from Renderable (it seems, that the fact, its getVaos().empty() make it unable to hold it, when Hlms::calculateHashFor).
The "old" v1 Overlays & Billboards (and therefore, particle FXs too) had the horrible behavior of creating the vertex data at the last and worst possible moment. Often this data won't be available when setting the Hlms datablock, which is needed by the Hlms to analyze the geometry structure, and thus causes the error you see.

As a nasty workaround, for these objects you have to set the datablock by name via OverlayElement::setMaterialName and Ogre will look and set the actual datablock when the Overlay's geometry data is initialized.
Perhaps this will eventually be solved in the future, but it seemed to me it required some lengthy refactor to make it happen, so right now this workaround will do.

al2950
OGRE Expert User
OGRE Expert User
Posts: 1221
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 154

Re: [2.1] HLMS + Manual Textures

Post by al2950 »

Thanks for all the replies. :)

It now works, well sort of, I get a black texture for diffuse, but at least the normal map works :D. Most likely a bug in the texture generation

User avatar
pergy
Gnoblar
Posts: 6
Joined: Tue Mar 31, 2015 2:35 pm

Re: [SOLVED][2.1] HLMS + Manual Textures

Post by pergy »

The "old" v1 Overlays & Billboards (and therefore, particle FXs too) had the horrible behavior of creating the vertex data at the last and worst possible moment. Often this data won't be available when setting the Hlms datablock, which is needed by the Hlms to analyze the geometry structure, and thus causes the error you see.
Thanks for clarify it! Also, the workaroud works fine! ;)

al2950
OGRE Expert User
OGRE Expert User
Posts: 1221
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 154

Re: [SOLVED][2.1] HLMS + Manual Textures

Post by al2950 »

I was going to start a new topic but it relates to my original issue.

This issue is that the HLMS PBS texture management loads textures directly from disk making it 'difficult' to deal with dynamic textures. To be clear here I am talking about reflection map, which I generate on the fly. Now I suppose I could try and ensure everytime a graphics object is loaded I ensure the reflection map is set to the dynamic one, but I really dont like that solution!

Anyway I have a couple of solutions but I think following is the best solution and I would appreciate any feedback on implementing it.

I propose that you can set the global reflection map in OgreHlmsPbs, then every time a datablock is loaded and a specific reflection map is NOT set and it can use the global reflection map in OgreHlmsPbs. Now the reason I like this solution is that in the future we are going to want to support reflection probes, and the way I see them working is an extension of the simple idea outlined above.

Any thought!?

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

Re: [SOLVED][2.1] HLMS + Manual Textures

Post by dark_sylinc »

I think the best solution to your particular problem would be to add a function to alias a texture name of the HlmsTextureManager to an existing external texture.

like this:

Code: Select all

TexturePtr externalTexture = ...;
hlmsTextureManager->aliasToTexture( "Name it should be referred as", externalTexture, xIdx, yIdx, /* ... more parameters? ...*/ );
That way materials using a reflection texture with the given name will refer to the texture you want.

Now, you touched a different subject too, which is dynamic probes. That requires a little more thought because normally we want to support more than one probe, and select based on proximity.
This is quite difficult (specially if you want to target DX10 hardware too, because there is no cubemap array).

You'll also probably want to have some sort of bitmask of which reflection textures can affect the material (not sure if this is good).

All of this would mean the cubemap gets selected at runtime per frame based on object's position (or at regular frame intervals) and not once at loading. Also means the position and the material get tied, instead of being material specific and Item independent. This would affect how we sort the RenderQueue.

Another option would be to duplicate the datablock, one for each cubemap combination, and have some helper code check the current positions of each object and change the datablocks on the fly according to proximity to the probes. (this is probably the most straightforward and easiest approach, but assumes you know which objects can move beyond probe boundaries so only those get evaluated, and that the number of dynamic objects isn't too big otherwise overhead could start getting noticed, specially if they change too often as datablocks are not meant to change often).
Another option is to go for DX11 only (makes things easier, we just send an index per object with the probes to select). Or support both options (do we have the man power?)

There are many variants, each with its drawbacks and strengths. Not a carefree thing to do, which is why I've been delaying doing it.

al2950
OGRE Expert User
OGRE Expert User
Posts: 1221
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 154

Re: [SOLVED][2.1] HLMS + Manual Textures

Post by al2950 »

Ah yes, that should solve my current issues thank you.

As for your other information... I am afraid some of it is beyond my knowledge however could you clear a couple of things up?

Currently, eg in the PBS, textures are bound to the shaders during fillBuffersFor everytime an object is rendered. How would this be different from selecting the nearest cubemap. Or am i missing something when it comes to sorting the renderqueue, so when it comes to rebinding the textures it only rebinds them if they change which is not going to be every renderable because the hlms texture manager puts textures into a single texture array? This make this line make sense

Code: Select all

            if( datablock->mTextureHash != mLastTextureHash )
            {
The next question is how expensive is rebinding textures...... never mind a quick google...
most expensive GPU operation is binding a texture to a slot
Thanks for the info, I think I answered all my questions!! And for the record I think we should only support env probes for Dx11 hardware, as although possible supporting it for Dx10 hardware in a perfomant way would require quite a lot of work, and potentially unnecessary pollution of things like render queue :(

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

Re: [SOLVED][2.1] HLMS + Manual Textures

Post by dark_sylinc »

Currently, eg in the PBS, textures are bound to the shaders during fillBuffersFor everytime an object is rendered. How would this be different from selecting the nearest cubemap. Or am i missing something when it comes to sorting the renderqueue, so when it comes to rebinding the textures it only rebinds them if they change which is not going to be every renderable because the hlms texture manager puts textures into a single texture array? This make this line make sense
You've oversimplified your notion about the Hlms handling texture, hence your confusion.
The Hlms does use texture arrays to heavily reduce switching textures, however texture switching still may be required if:
  • The texture is in a different array because the other one was full (the amount of slices is limited and preallocated...).
  • The texture is in a different array because the format is different (e.g. previous material used BC1 compression on diffuse texture, next material uses RGBA8888; or the resolution is different)
  • The material has a different 'signature' (I just made that term); e.g. previous material used a diffuse and normal texture, next material uses only a specular texture.
The mTextureHash is a hash of this 'signature'; so if it doesn't change, it means next material uses exactly the same combination of diffuse/normal/specular/etc arrays as the previous one (it may use different textures, but it uses textures that are in the same array as the previous material). This should be reasonably common.

mTextureHash is also used by the RenderQueue to ensure many objects with this same signature get batched together. Note that changing a single texture means breaking auto-instancing.

DX12 makes things easier by being much more flexible and powerful (on Tier 1 we can bind together up to 256 textures of any resolution and format and select them dynamically via an index, on T2 there is virtually no limit); but sadly we have to support older APIs and HW.

One more thing I forgot about cubemap probes:
There are two solutions:
1. External code (e.g. doesn't have to be embedded into the PBS, but might need an interface to talk to it) iterates through dynamic objects, and changes the datablock based on the object's position and its proximity to the probes.
This is relatively easy to support, and very compatible with all platforms and HW. Problem is that assumes you won't be changing datablocks very often (i.e. not useful for scenes where objects move very fast and keep switching from areas) and there aren't too many dynamic objects. Datablock count may also explode, but I doubt this could be a problem. Biggest problem I see is that you can't just grab the Item's datablock to e.g. change the colour, because the actual datablock may be changing all the time.

2. Internal code where cubemap arrays are used. The PBS just needs to send the slice index to select the proper cubemaps to blend (based on proximity to probes). For the user, this is like a magic solution. "It just works" in all cases in all situations without hassles.
The only problem is that cubemap array support was introduced by DX11 HW. There is a workaround though: DX10 hardware can do the same if we use texture 2D arrays and select the face manually via shader code (e.g. 3 cubemaps is just a texture2d arrays of 18 slices). It would be slow for DX10 hw (and also filtering quality around the edges won't be the same), but at least we can guarantee the feature will work on old hardware too. Or we can just forget about DX10 hw for this method, and let users select method 1 if they want compatibility.

Both 1. & 2. should be able to share the code that selects the probe based on proximity, since essentially it should be the same.
There also needs to be an interface that builds the probes, and where the user tells what cubemaps to use for each probes (and their locations and sizes)

al2950
OGRE Expert User
OGRE Expert User
Posts: 1221
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 154

Re: [SOLVED][2.1] HLMS + Manual Textures

Post by al2950 »

Thanks for info, all much clearer now :D.

I like the idea of having a 'reflection probe' component that a HLMS implementation can use.... of course its going to be while before you, me or anyone else will tackle this, so things may change!

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [SOLVED][2.1] HLMS + Manual Textures

Post by xrgo »

I was investigating this issue, I want multiple cubemaps too!!!! with box projection and all those features
I have the box projected cubemap working but since they are zone based its really necessary to have support for multiple cubemaps.
I like the cube map array approach, but Ogre doesn't have TEX_TYPE_CUBE_MAP_ARRAY implemented, I tried to implemented but I got a little lost so I continued with other things on my ToDo... But I definitely going to tackle this someday, its a must have feature for me.
Hey Matias can you implement TEX_TYPE_CUBE_MAP_ARRAY? I am guessing is something you can do in a few minutes xD, with that I can do all the shader stuffs =)

al2950
OGRE Expert User
OGRE Expert User
Posts: 1221
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 154

Re: [SOLVED][2.1] HLMS + Manual Textures

Post by al2950 »

After having a quick look at this creating a extra function to alias an externally create texture to HlmsTextureManager would be fine, however I believe a better and more useful function would be to an explicit 'create' method in HlmsTextureManager that creates a new texture, or slot in a texture array for the given parameters. This seems cleaner as letting someone adding any externally created texture to something like the HlmsTextureManager seems like asking for trouble!

Anyway I am going to go ahead and add the explicit 'createTexture' method in HlmsTextureManager. If anyone thinks this is a bad idea please let me know!

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

Re: [SOLVED][2.1] HLMS + Manual Textures

Post by dark_sylinc »

Well the HlmsTextureManager doesn't really "create" texture as it is a manager within another manager (it just wraps around the original TextureManager; seen from another perspective it's a fancy texture packer).

In fact I was very careful in that HlmsPbsDatablock::setTexture accepts a regular TexturePtr and an int to the the array index, instead of a structure that belongs to the HlmsTextureManager. You can literally create a TexturePtr of type TEX_TYPE_2D_ARRAY and assign it to the datablock, without ever using the HlmsTextureManager.

The script interface uses the HlmsTextureManager because it can track the array index, treating textures like they were separate, hiding the fact that they are being packed together.

I can see textures as the next big thing needing refactor and cleanup (won't happen soon), which should erase the need to use unnecessary workarounds like these (a manager that manages a manager).
Since non-array cubemap textures are supported (in fact right now it's the only type supported) perhaps it would make more sense that the PBS datablock looks for a regular cubemap texture in the old TextureManager if it failed to find another of the same name in the HlmsTextureManager.

al2950
OGRE Expert User
OGRE Expert User
Posts: 1221
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 154

Re: [SOLVED][2.1] HLMS + Manual Textures

Post by al2950 »

Hmmm, ok! I have written the 'Create' function and re-factored the hlmsTextureManager a bit so there is no duplicate code and all works as expected, although auto mipmaps are causing a few issues, so I am currently having a quick look into that.

I appreciate what you are saying about managers of managers, but now I have got to know the HlmsTextureManager I really like it. I think its good to have that higher level, that can determine how texture data should be used based on usage type and system capabilities, ie texture array/atlas or even something simple like gamma/noGamma. One of the reason I went down the route of a 'Create' function instead of using some form of fall back, that looks for a 'normal' texture if not found, was discussions like env probes. Env probes will all be dynamic, expect for a static falback texture, and I think it would be bad to have a separate 'EnvProbeManager' managing its own CubeMapArray or 2DTexArray, and so it makes much more sense for it to 'Request' a texture slot from a central manager. Anyway as you said the textures need a big re factor, but I think a lot of the functionality of HLMSTextureManager will probably end up there anyway :)

Having said all that I am happy to go with what you see is best at this time, so please instruct and I shall do :D

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

Re: [SOLVED][2.1] HLMS + Manual Textures

Post by dark_sylinc »

I'm interested to see those refactors. After all I'm not the bearer of absolute truths.

Post Reply