Ogre-Next; Manual Texture: Set specific Pixels - How To?

Problems building or running the engine, queries about how to use features etc.
Post Reply
Nickak2003
Goblin
Posts: 272
Joined: Thu Jun 10, 2004 4:19 am
x 26

Ogre-Next; Manual Texture: Set specific Pixels - How To?

Post by Nickak2003 »

I am trying to render to a texture, and I had it working in ogre1.x. I'm now using ogre-next.

I have been through the demos and searched online but I cant find how to do it. The interfaces and code I can find online are all out-of-date.
This following code is where I'm stuck:

Code: Select all

    Ogre::HlmsPbsDatablock* datablock = static_cast<Ogre::HlmsPbsDatablock*>(
        hlmsPbs->createDatablock(dataBlockName,
            dataBlockName,
            Ogre::HlmsMacroblock(),
            Ogre::HlmsBlendblock(),
            Ogre::HlmsParamVec()
        ) );

    Ogre::String name = "customTexture";
    Ogre::TextureGpu* texture = textureManager->createTexture( name, 
        Ogre::GpuPageOutStrategy::Discard, Ogre::TextureFlags::ManualTexture, Ogre::TextureTypes::Type2D,
        Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

    texture->setResolution(512u, 512u,1u);
    texture->setPixelFormat(Ogre::PFG_RGBA8_UNORM_SRGB);
    texture->setNumMipmaps(1u);

	//code to set individual pixels - please help!

    datablock->setTexture(Ogre::PBSM_DIFFUSE, texture);
    datablock->setDiffuse(Ogre::Vector3(0.0f, 0.0f, 0.0f));

   item->setDatablockOrMaterialName( dataBlockName);


Ogre Version: ogre-next
Operating System: windows 10
Render System: direct x 11
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Ogre-Next; Manual Texture: Set specific Pixels - How To?

Post by dark_sylinc »

Hi!

I'm a bit confused.

Part of your post says you want to create a texture in C++ and set a few textures from CPU
However another part of your post suggests you want to render to this texture from GPU

These two are vastly different operations.
Could you clarify what are you trying to do? Can you point out what you were doing in 1.x?

Thanks
Nickak2003
Goblin
Posts: 272
Joined: Thu Jun 10, 2004 4:19 am
x 26

Re: Ogre-Next; Manual Texture: Set specific Pixels - How To?

Post by Nickak2003 »

I have a pixel buffer that is rendered to, uint8[], and i need to move this into a texture, potentially often, and update an items with that texture.

specifically, my buffer is filled with html/gui info from chrome/cef3 and i need to get this into a texture so i can render a gui on a quad.
Nickak2003
Goblin
Posts: 272
Joined: Thu Jun 10, 2004 4:19 am
x 26

Re: Ogre-Next; Manual Texture: Set specific Pixels - How To?

Post by Nickak2003 »

in 1.x I did the following:
create a quad with a material:

Code: Select all


	renderTexture = Ogre::TextureManager::getSingleton().createManual(
		textureName,
		Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
		Ogre::TEX_TYPE_2D, width, height, 0, Ogre::PF_A8R8G8B8, Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE);

	int sw =	renderTexture->getSrcWidth();
	int sh = renderTexture->getSrcHeight();
	int w = renderTexture->getWidth();
	int h = renderTexture->getHeight();


	Ogre::MaterialPtr material = Ogre::MaterialManager::getSingletonPtr()->create(materialName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	//material->getTechnique(0)->getPass(0)->setCullingMode(Ogre::CULL_NONE); // print both sides of the polygones
	material->getTechnique(0)->getPass(0)->createTextureUnitState(textureName);
	material->getTechnique(0)->getPass(0)->setLightingEnabled(false);
	
	material->setDepthWriteEnabled( false );
	Ogre::PixelFormat pf = renderTexture->getFormat();
	material->getTechnique(0)->getPass(0)->setSceneBlending(Ogre::SceneBlendType::SBT_TRANSPARENT_ALPHA);
	

	Ogre::ManualObject* geo = pSceneMgr->createManualObject(geoName);
	geo->setUseIdentityProjection(true);
	geo->setUseIdentityView(true);
	geo->setDynamic(true);

	// Render just before overlays
	geo->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY);
	
	geo->begin(materialName);

	Ogre::Real x = 0, y = 0;
	int offset = 1;
	/*
	(1) 0, 1			(3) 1, 1
	(0) 0, 0			(2) 1, 0

	0, 2, 1
	2, 3, 1
	*/

	geo->position(Ogre::Vector3(x - offset, y - offset, 0));  geo->textureCoord(0, 1);  
	geo->position(Ogre::Vector3(x - offset, y + offset, 0));  geo->textureCoord(0, 0);
	geo->position(Ogre::Vector3(x + offset, y - offset, 0));  geo->textureCoord(1, 1);
	geo->position(Ogre::Vector3(x + offset, y + offset, 0));  geo->textureCoord(1, 0);

	geo->triangle(0, 2, 1);
	geo->triangle(2, 3, 1);

	geo->end();

	Ogre::AxisAlignedBox aabInf;
	aabInf.setInfinite();
	geo->setBoundingBox(aabInf);


	renderNode = pSceneMgr->getRootSceneNode()->createChildSceneNode(sceneNodeName, Ogre::Vector3(0., 0, 0));

	renderNode->attachObject(geo);

periodically update the material with new data

Code: Select all


	Ogre::HardwarePixelBufferSharedPtr texBuf = renderTexture->getBuffer();
	texBuf->lock(Ogre::HardwareBuffer::HBL_DISCARD);

	memcpy(texBuf->getCurrentLock().data, buffer, size * sizeOfWord);

	texBuf->unlock();
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Ogre-Next; Manual Texture: Set specific Pixels - How To?

Post by dark_sylinc »

I see. You want to upload data to a texture from CPU then.

You'll find what you want in Samples/2.0/ApiUsage/UpdatingDecalsAndAreaLightTex/UpdatingDecalsAndAreaLightTexGameState.cpp

Specifically you want to look at:
  1. UpdatingDecalsAndAreaLightTexGameState::setupLightTexture - Ogre-related code setup
  2. UpdatingDecalsAndAreaLightTexGameState::createAreaMask - Just fills the data pointers
The sample showcases two ways of uploading data from CPU to GPU: Synchronous (main thread) and Asynchronous (background thread).
Which path is taken is controlled by mUseSynchronousMethod bool.

If you want to update the texture every frame, use the synchronous method.

Note: The c_areaLightsPoolId thing is specific to decals and area lights, normally you won't need that (i.e. leave at 0).
Nickak2003
Goblin
Posts: 272
Joined: Thu Jun 10, 2004 4:19 am
x 26

Re: Ogre-Next; Manual Texture: Set specific Pixels - How To?

Post by Nickak2003 »

OK the following is what I've come up with, and it seems to be working. Please review provide any additional help or optimizations.
first, to setup the texture and image I the following, once, beforehand.

Code: Select all


Ogre::Image2 createImageData() {

    const Ogre::uint32 texWidth = 512;
    const Ogre::uint32 texHeight = 512;
    const Ogre::PixelFormatGpu texFormat = Ogre::PixelFormatGpu::PFG_RGBA8_UNORM_SRGB;

    //Fill the texture with a hollow rectangle, 10-pixel thick.
    size_t sizeBytes = Ogre::PixelFormatGpuUtils::calculateSizeBytes(
        texWidth, texHeight, 1u, 1u, texFormat, 1u, 4u);

    Ogre::uint8* data = reinterpret_cast<Ogre::uint8*>(
        OGRE_MALLOC_SIMD(sizeBytes, Ogre::MEMCATEGORY_GENERAL));

    Ogre::Image2 image;
    image.loadDynamicImage(data, texWidth, texHeight, 1u,
        Ogre::TextureTypes::Type2D, texFormat,
        true, 1u);

    return image;
}


Ogre::Image2 createManualTexture(Graphics& graphics, GraphicalObject::Ptr obj) {
    
    Ogre::Root* root = graphics.getRoot();
    Ogre::TextureGpuManager* textureMgr = root->getRenderSystem()->getTextureGpuManager();


    Ogre::TextureGpu* manualTex =
        textureMgr->createOrRetrieveTexture(
            "manualTexture",
            Ogre::GpuPageOutStrategy::AlwaysKeepSystemRamCopy,
            Ogre::TextureFlags::AutomaticBatching,
            Ogre::TextureTypes::Type2D, Ogre::BLANKSTRING);

    manualTex->setNumMipmaps(1);
    manualTex->setResolution(512, 512);
    manualTex->setPixelFormat(Ogre::PixelFormatGpu::PFG_RGBA8_UNORM_SRGB);

    Ogre::Image2 image = createImageData();

    bool canUseSynchronousUpload = manualTex->getNextResidencyStatus() == Ogre::GpuResidency::Resident && manualTex->isDataReady();

    if (!canUseSynchronousUpload) {
        manualTex->waitForData();
    }

    manualTex->scheduleTransitionTo(Ogre::GpuResidency::Resident, &image, false);

    Ogre::HlmsManager* hlmsManager = graphics.getRoot()->getHlmsManager();

    Ogre::HlmsPbs* hlmsPbs = static_cast<Ogre::HlmsPbs*>(hlmsManager->getHlms(Ogre::HLMS_PBS));

    Ogre::String dataBlockName = "customDataBlock";
    Ogre::HlmsPbsDatablock* datablock = static_cast<Ogre::HlmsPbsDatablock*>(
        hlmsPbs->createDatablock(dataBlockName,
            dataBlockName,
            Ogre::HlmsMacroblock(),
            Ogre::HlmsBlendblock(),
            Ogre::HlmsParamVec()
        ));

    datablock->setTexture(Ogre::PbsTextureTypes::PBSM_DIFFUSE, manualTex);

    obj->getItem()->setDatablock(datablock);

    return image;
}
now each frame, I do the following to change the color/data:

Code: Select all

void setRandomColor(Graphics& graphics, Ogre::Image2& image) {

    Ogre::uint8* data = reinterpret_cast<Ogre::uint8*>(image.getData(0).data);

    int r = rand() % 2 * 255;
    int g = rand() % 2 * 255;
    int b = rand() % 2 * 255;

    for (size_t y = 0; y < image.getHeight(); ++y) {
        for (size_t x = 0; x < image.getWidth(); ++x) {
            *data++ = r;
            *data++ = g;
            *data++ = b;
            *data++ = 255;
        }
    }

    Ogre::TextureGpuManager* textureMgr = graphics.getRoot()->getRenderSystem()->getTextureGpuManager();

    Ogre::TextureGpu* manualTexture = textureMgr->findTextureNoThrow("manualTexture");

    bool canUseSynchronousUpload = manualTexture->getNextResidencyStatus() == Ogre::GpuResidency::Resident && manualTexture->isDataReady();

    if (!canUseSynchronousUpload) {
        manualTexture->waitForData();
    }

    image.uploadTo(manualTexture, 0, 0);
}
finally, to clean up:

Code: Select all

void cleanUp(Graphics& graphics, Ogre::Image2& image) {

    Ogre::TextureGpuManager* textureMgr = graphics.getRoot()->getRenderSystem()->getTextureGpuManager();

    Ogre::TextureGpu* manualTexture = textureMgr->findTextureNoThrow("manualTexture");
    textureMgr->destroyTexture(manualTexture);

    image.freeMemory();

}
Thanks for the help!
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Ogre-Next; Manual Texture: Set specific Pixels - How To?

Post by dark_sylinc »

Yep, it looks about correct.

Your setRandomColor doesn't account for bytesPerRow potentially being different than getWidth() * bytesPerPixel; however this is not a problem as long as you keep using PFG_RGBA8_UNORM_SRGB (because bytesPerPixel is multiple of 4u, hence all rows will always be aligned).
Nickak2003
Goblin
Posts: 272
Joined: Thu Jun 10, 2004 4:19 am
x 26

Re: Ogre-Next; Manual Texture: Set specific Pixels - How To?

Post by Nickak2003 »

I need to get the following 1.x pixel format: PF_A8R8G8B8, what is this in, Ogre::PixelFormatGpu, I cant seem to figure it out?
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Ogre-Next; Manual Texture: Set specific Pixels - How To?

Post by dark_sylinc »

It is either PFG_RGBA8_UNORM or PFG_RGBA8_UNORM_SRGB (depending on whether you use hardware gamma correction).
It could also be PFG_BGRA8_UNORM (or PFG_BGRA8_UNORM_SRGB), but this format should only be used as an exception rather than the norm
Nickak2003
Goblin
Posts: 272
Joined: Thu Jun 10, 2004 4:19 am
x 26

Re: Ogre-Next; Manual Texture: Set specific Pixels - How To?

Post by Nickak2003 »

it turns out that it's, Ogre::PFG_BGRA8_UNORM_SRGB, thanks.

One last related question:
Image
My colors are too dark. I understand this has to do with gamma correction which I have enabled on the render system:

Code: Select all

        mRoot->getRenderSystem()->setConfigOption("sRGB Gamma Conversion", "Yes");
        mRoot->initialise(false);

        Ogre::ConfigOptionMap ropts = mRoot->getRenderSystem()->getConfigOptions();

        Ogre::NameValuePairList miscParams;
        miscParams["FSAA"] = ropts["FSAA"].currentValue;
        miscParams["vsync"] = ropts["VSync"].currentValue;
        miscParams["Full Screen"] = ropts["Full Screen"].currentValue;
        miscParams["gamma"] = ropts["sRGB Gamma Conversion"].currentValue;
        
        mWindow = mRoot->createRenderWindow(windowTitle, w, h, fullScreen, &miscParams);
I think maybe it has to do with the manual data block, I am unsure. Right now this is what it looks like:

Code: Select all

		Ogre::HlmsManager* hlmsManager = graphics.getRoot()->getHlmsManager();

		Ogre::HlmsPbs* hlmsPbs = static_cast<Ogre::HlmsPbs*>(hlmsManager->getHlms(Ogre::HLMS_PBS));

		mDataBlock = static_cast<Ogre::HlmsPbsDatablock*>(
			hlmsPbs->createDatablock(mName,
				mName,
				Ogre::HlmsMacroblock(),
				Ogre::HlmsBlendblock(),
				Ogre::HlmsParamVec()
			));

		mDataBlock->setTexture(Ogre::PbsTextureTypes::PBSM_DIFFUSE, mTexture);
I was reading that maybe I need to manually gamma correct each pixel, I hope this isn't the case!

Thanks for the help!
Nickak2003
Goblin
Posts: 272
Joined: Thu Jun 10, 2004 4:19 am
x 26

Re: Ogre-Next; Manual Texture: Set specific Pixels - How To?

Post by Nickak2003 »

I figured it out, I had to use HlmsUnlit instead of Pbs! thanks for the help!
Post Reply