[2.1] Renderable with clipping

Problems building or running the engine, queries about how to use features etc.
Post Reply
ExtraSauce
Gnoblar
Posts: 4
Joined: Sun May 05, 2019 10:20 pm

[2.1] Renderable with clipping

Post by ExtraSauce »

Ogre Version: :?: 2.1
Operating System: :?: Linux
Render System: :?: OpenGL3+

I have spent more time than I should trying to bind Ogre with nuklear, and I have it basically working using MovableObject and Renderable, but I seem to have hit a wall with scissoring.

My goal is to create this using only v2.1 function, with no calls to the v1 namespace. I have used some older examples with dead api calls (https://github.com/OGRECave/ogre-imgui) and Ogre's CustomRenderable/DynamicGeometry examples to get it working, but nuklear relies on glScissor before every glDrawElements call to work properly. Without it I get artifacts like the one below.
2019-05-05-231014_229x255_scrot.png
2019-05-05-231014_229x255_scrot.png (5.44 KiB) Viewed 485 times
I am currently looking into doing something through the command buffer - I am still learning, but if I understand it correctly I would want to create a command that calls the rendersystem->_setViewport(), then on every draw command from nuklear I would want to add that viewport command to the command buffer, followed by a draw command translated from nuklear, and finally finish it with a _setViewport command to reset everything.

Getting into it though, this seemed needlesly complicated and riddled with pitfalls just to apply glScissor to a few elements. Before I get too much deeper into it, are there any alternatives or concepts that I'm missing that would make this simpler?
ExtraSauce
Gnoblar
Posts: 4
Joined: Sun May 05, 2019 10:20 pm

Re: [2.1] Renderable with clipping

Post by ExtraSauce »

One last post before I give up. I basically tried to redo the RenderQueue's renderGL3() function. Code below.
I checked it out on renderdoc and there are calls to glMultiDrawElementsIndirect(0) as expected - though I'm concerned about that 0 - and the vertex/fragment shader is bound properly, but nothing appears on screen and there is no input to the vertex shader. Could that mean the VAO is not created/set correctly?

Code: Select all

	void NkManager::update()
	{
		Ogre::Viewport *vp = mManager->getCurrentViewport();
		if ( !vp ) return;

		// ...
		// nk_convert() to get draw list from nuklear
		// ...
		
		Ogre::Matrix4 ortho {
			2.0f,  0.0f,  0.0f, -1.0f,
			0.0f, -2.0f,  0.0f,  1.0f,
			0.0f,  0.0f, -1.0f,  0.0f,
		   0.0f,  0.0f,  0.0f,  1.0f,
		};
		ortho[0][0] /= (float)vp->getActualWidth();
		ortho[1][1] /= (float)vp->getActualHeight();
		mPass->getVertexProgramParameters()->setNamedConstant( "ProjectionMatrix", ortho );
		Ogre::RenderSystem *mRenderSystem = mManager->getDestinationRenderSystem();

		// PSO state
		Ogre::PsoCacheHelper *psoCache = new Ogre::PsoCacheHelper( mRenderSystem );
		psoCache->clearState();
		psoCache->setBlendblock( mPass->getBlendblock() );
		psoCache->setMacroblock( mPass->getMacroblock() );
		psoCache->setVertexShader( mPass->getVertexProgram() );
		psoCache->setPixelShader( mPass->getFragmentProgram() );

		const struct nk_draw_command *cmd;
		int32_t ri = 0;
		Ogre::uint16 offset = 0;
		nk_draw_foreach( cmd, nkCtx, &cmds ) {
			if ( !cmd->elem_count ) continue;
			mRenderables.push_back( new NkRenderable( mManager ) );
			// createVao() is basically a carbon copy of the customrenderable sample for creating a vao
			mRenderables[ri]->createVao( tempVertices, tempElements, offset,
					cmd->elem_count, mVertexElements );
			// I went through and confirmed to the best of my knowledge that tempVertices/tempElements have
			// the correct vertex coordinates and element list.
			// createVao also seems to create a correct variable mVao in the NkRenderable to the best of my knowledge
			psoCache->setVertexFormat( mRenderables[ri]->mVao->getVertexDeclaration(),
					Ogre::OT_TRIANGLE_LIST, false );
			mRenderables[ri]->mRenderableHash = psoCache->getRenderableHash();
			offset += cmd->elem_count;
			ri += 1;
		}

		// Setup indirect buffer
		Ogre::VaoManager *vaoManager = mManager->getDestinationRenderSystem()->getVaoManager();
		Ogre::IndirectBufferPacked *indirectBuffer = 0;
		unsigned char *indirectDraw = 0;
		unsigned char *startIndirectDraw = 0;
        	int baseInstanceAndIndirectBuffers = 0;
		if( vaoManager->supportsIndirectBuffers() ) {
            		baseInstanceAndIndirectBuffers = 2;
			int numDraws = mRenderables.size();
			size_t requiredBytes = numDraws * sizeof( Ogre::CbDrawCallIndexed );
			indirectBuffer = vaoManager->createIndirectBuffer( requiredBytes,
					Ogre::BT_DYNAMIC_PERSISTENT, 0, false );
			indirectDraw = static_cast<unsigned char*>(
					indirectBuffer->map( 0, indirectBuffer->getNumElements() ) );
		}
		else if( vaoManager->supportsBaseInstance() ) {
            		baseInstanceAndIndirectBuffers = 1;
			indirectDraw = indirectBuffer->getSwBufferPtr();
		}
		startIndirectDraw = indirectDraw;

		std::vector<NkRenderable*>::const_iterator itor = mRenderables.begin();
		std::vector<NkRenderable*>::const_iterator end = mRenderables.end();
		psoCache->clearState();
		psoCache->setRenderTarget( vp->getTarget() );
		while( itor != end ) {
			Ogre::HlmsPso *pso = psoCache->getPso( (*itor)->mRenderableHash );
			mRenderSystem->_setPipelineStateObject( pso );
			
            		mRenderSystem->bindGpuProgramParameters( Ogre::GPT_VERTEX_PROGRAM,
                                                     						mPass->getVertexProgramParameters(),
                                                      						Ogre::GPV_ALL );
            		mRenderSystem->bindGpuProgramParameters( Ogre::GPT_FRAGMENT_PROGRAM,
                                                     						mPass->getFragmentProgramParameters(),
												Ogre::GPV_ALL );

			mRenderSystem->_setVertexArrayObject( (*itor)->mVao );
			
			mRenderSystem->_setIndirectBuffer( indirectBuffer );
			void *indBufOffset = reinterpret_cast<void*>( indirectBuffer->_getFinalBufferStart() +
					( indirectDraw - startIndirectDraw ));

			Ogre::CbDrawCallIndexed *drawCmd = new Ogre::CbDrawCallIndexed(
					baseInstanceAndIndirectBuffers, (*itor)->mVao, indBufOffset );
			mRenderSystem->_render( drawCmd );

			indirectDraw += sizeof( Ogre::CbDrawCallIndexed );
			itor++;
			delete drawCmd;
		}

		if( baseInstanceAndIndirectBuffers == 2 && indirectBuffer )
		{
			indirectBuffer->unmap( Ogre::UO_UNMAP_ALL );
		}

		while( mRenderables.size() > 0 )
		{
			delete mRenderables.back();
			mRenderables.pop_back();
		}
	}
ExtraSauce
Gnoblar
Posts: 4
Joined: Sun May 05, 2019 10:20 pm

Re: [2.1] Renderable with clipping

Post by ExtraSauce »

I'm probably just sending electrons into the aether, but I got it working after going through the renderGL3 code and reading into the indirect buffer a bit more. I'm still concerned about not being able to see the vertex data in RenderDoc, but I can hold off on figuring that out for some other time. I also got it by doing RenderSystem->_setViewport() before every draw call, which feels kind of dirty. I noticed that the master branch has RenderSystem->setScissorTest(), but not v2-1. Why is that removed in 2.1?

One other thing, to use the example in PsoCacheHelper.h I had to change the prototype of setVertex/FragmentShader to accept a const GpuProgramPtr&. I don't know if this is just my lack of experience with C++, but I couldn't get it to work with the result of mPass->getVertexProgram() otherwise.

And lastly, I couldn't get the RenderQueueListener events to fire and had to hook into the RenderTargetListener events. I tried to grep the source to find where that's called and didn't seem to find it. I think only renderQueueStarted fires. Is this correct?
Post Reply