Page 1 of 1

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

Posted: Mon Jan 13, 2020 10:31 pm
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

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

Posted: Mon Jan 13, 2020 10:47 pm
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

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

Posted: Mon Jan 13, 2020 10:51 pm
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.

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

Posted: Mon Jan 13, 2020 10:55 pm
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();

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

Posted: Mon Jan 13, 2020 11:25 pm
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).

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

Posted: Tue Jan 14, 2020 5:23 pm
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!

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

Posted: Tue Jan 14, 2020 8:23 pm
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).

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

Posted: Wed Jan 15, 2020 6:59 pm
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?

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

Posted: Wed Jan 15, 2020 8:23 pm
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

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

Posted: Fri Jan 17, 2020 1:50 pm
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!

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

Posted: Fri Jan 17, 2020 4:10 pm
by Nickak2003
I figured it out, I had to use HlmsUnlit instead of Pbs! thanks for the help!