Page 1 of 1

In the DEKO3D TextureCube example, what's the proper way to render 2 cubes?

Posted: Sat May 06, 2023 7:08 pm
by MJHomebrewer
In the default program under the render function (Example04_TextureCube.cpp) you can see that it does the following under bool onFrame:

Code: Select all

       
        transformState.mdlvMtx = glm::mat4{1.0f};
        transformState.mdlvMtx = glm::translate(transformState.mdlvMtx, glm::vec3{0.0f, 0.0f, -3.0f});
        transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, sinf(period2 * tau) * tau / 8.0f, glm::vec3{1.0f, 0.0f, 0.0f});
        transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, -period1 * tau, glm::vec3{0.0f, 1.0f, 0.0f});
        transformState.mdlvMtx = glm::scale(transformState.mdlvMtx, glm::vec3{0.5f});

        render();
I've been able to get 2 cubes to draw with the below code, but to be honest I'm not sure what I'm doing is right. For starters, it has an annoying flicker. I come from an OpenGL background, which has so far helped me quite a bit in integrating libnx into my pc game engine. But, this still looks very different from your typical swap buffers / clear screen / render methodology. As you can see, I just copied the transformState, changed the transform/scale and called render again.

Code: Select all

        transformState.mdlvMtx = glm::mat4{1.0f};
        transformState.mdlvMtx = glm::translate(transformState.mdlvMtx, glm::vec3{0.0f, 0.0f, -3.0f});
        transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, sinf(period2 * tau) * tau / 8.0f, glm::vec3{1.0f, 0.0f, 0.0f});
        transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, -period1 * tau, glm::vec3{0.0f, 1.0f, 0.0f});
        transformState.mdlvMtx = glm::scale(transformState.mdlvMtx, glm::vec3{0.5f});

        render();
		
        transformState.mdlvMtx = glm::mat4{1.0f};
        transformState.mdlvMtx = glm::translate(transformState.mdlvMtx, glm::vec3{1.5f, 0.0f, -3.0f});
        transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, sinf(period2 * tau) * tau / 8.0f, glm::vec3{1.0f, 0.0f, 0.0f});
        transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, -period1 * tau, glm::vec3{0.0f, 1.0f, 0.0f});
        transformState.mdlvMtx = glm::scale(transformState.mdlvMtx, glm::vec3{0.65f});

        render();	
I see that render does the below. So calling something here twice is causing that flicker evidently. I'd just like to know what I can do to draw 2 cubes devoid of any kind of flickering. Sadly I couldn't find an example in the switch folder that does anything remotely similar to that. It's always just 1 vertex array.

Code: Select all

        dynmem.begin(dyncmd);
        dyncmd.pushConstants(transformUniformBuffer.getGpuAddr(), transformUniformBuffer.getSize(),0, sizeof(transformState), &transformState);
        queue.submitCommands(dynmem.end(dyncmd));
        int slot = queue.acquireImage(swapchain);
        queue.submitCommands(framebuffer_cmdlists[slot]);
        queue.submitCommands(render_cmdlist);
        queue.presentImage(swapchain, slot);

Re: In the DEKO3D TextureCube example, what's the proper way to render 2 cubes?

Posted: Sun May 07, 2023 11:49 am
by fincs
Hi there,

The render function starts and ends a frame, as you can tell by the "acquireImage/presentImage" commands, so you are in effect rendering alternate frames with each cube. You need to change your program so that you upload uniforms, execute the render cmdlist, then reupload uniforms and reexecute the render cmdlist, all within the same frame.

Re: In the DEKO3D TextureCube example, what's the proper way to render 2 cubes?

Posted: Mon May 08, 2023 2:08 am
by MJHomebrewer
fincs wrote: Sun May 07, 2023 11:49 am Hi there,

The render function starts and ends a frame, as you can tell by the "acquireImage/presentImage" commands, so you are in effect rendering alternate frames with each cube. You need to change your program so that you upload uniforms, execute the render cmdlist, then reupload uniforms and reexecute the render cmdlist, all within the same frame.
Hi, thanks for your reply. From your first message I figured that was what the context was.
To break down what you were saying when changing the program, do you mean to do something like this?

Change Render function (remove acquireImage and presentImage):

Code: Select all

void render()
{
        dynmem.begin(dyncmd);
        dyncmd.pushConstants(transformUniformBuffer.getGpuAddr(), transformUniformBuffer.getSize(),0, sizeof(transformState), &transformState);
        queue.submitCommands(dynmem.end(dyncmd));

        queue.submitCommands(framebuffer_cmdlists[slot]);
        queue.submitCommands(render_cmdlist);
}
Then the main loop would look something like this:

Code: Select all


	 int slot = queue.acquireImage(swapchain);


        transformState.mdlvMtx = glm::mat4{1.0f};
        transformState.mdlvMtx = glm::translate(transformState.mdlvMtx, glm::vec3{0.0f, 0.0f, -3.0f});
        transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, sinf(period2 * tau) * tau / 8.0f, glm::vec3{1.0f, 0.0f, 0.0f});
        transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, -period1 * tau, glm::vec3{0.0f, 1.0f, 0.0f});
        transformState.mdlvMtx = glm::scale(transformState.mdlvMtx, glm::vec3{0.5f});

        render();
		
        transformState.mdlvMtx = glm::mat4{1.0f};
        transformState.mdlvMtx = glm::translate(transformState.mdlvMtx, glm::vec3{1.5f, 0.0f, -3.0f});
        transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, sinf(period2 * tau) * tau / 8.0f, glm::vec3{1.0f, 0.0f, 0.0f});
        transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, -period1 * tau, glm::vec3{0.0f, 1.0f, 0.0f});
        transformState.mdlvMtx = glm::scale(transformState.mdlvMtx, glm::vec3{0.65f});

        render();	

        queue.presentImage(swapchain, slot);



Re: In the DEKO3D TextureCube example, what's the proper way to render 2 cubes?

Posted: Thu May 11, 2023 4:30 am
by MJHomebrewer
MJHomebrewer wrote: Mon May 08, 2023 2:08 am
fincs wrote: Sun May 07, 2023 11:49 am Hi there,

The render function starts and ends a frame, as you can tell by the "acquireImage/presentImage" commands, so you are in effect rendering alternate frames with each cube. You need to change your program so that you upload uniforms, execute the render cmdlist, then reupload uniforms and reexecute the render cmdlist, all within the same frame.
Hi, thanks for your reply. From your first message I figured that was what the context was.
To break down what you were saying when changing the program, do you mean to do something like this?

Change Render function (remove acquireImage and presentImage):

Code: Select all

void render()
{
 dynmem.begin(dyncmd);
 dyncmd.pushConstants(transformUniformBuffer.getGpuAddr(), transformUniformBuffer.getSize(),0, sizeof(transformState), &transformState);
 queue.submitCommands(dynmem.end(dyncmd));

 queue.submitCommands(framebuffer_cmdlists[slot]);
 queue.submitCommands(render_cmdlist);
}
Then the main loop would look something like this:

Code: Select all


 int slot = queue.acquireImage(swapchain);


 transformState.mdlvMtx = glm::mat4{1.0f};
 transformState.mdlvMtx = glm::translate(transformState.mdlvMtx, glm::vec3{0.0f, 0.0f, -3.0f});
 transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, sinf(period2 * tau) * tau / 8.0f, glm::vec3{1.0f, 0.0f, 0.0f});
 transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, -period1 * tau, glm::vec3{0.0f, 1.0f, 0.0f});
 transformState.mdlvMtx = glm::scale(transformState.mdlvMtx, glm::vec3{0.5f});

 render();
 
 transformState.mdlvMtx = glm::mat4{1.0f};
 transformState.mdlvMtx = glm::translate(transformState.mdlvMtx, glm::vec3{1.5f, 0.0f, -3.0f});
 transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, sinf(period2 * tau) * tau / 8.0f, glm::vec3{1.0f, 0.0f, 0.0f});
 transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, -period1 * tau, glm::vec3{0.0f, 1.0f, 0.0f});
 transformState.mdlvMtx = glm::scale(transformState.mdlvMtx, glm::vec3{0.65f});

 render(); 

 queue.presentImage(swapchain, slot);


lol I was being dumb and not using my brain. Figured it out. Here's my modified code below:

Image

Code: Select all

    	static const int N = 20;
    static constexpr unsigned NumFramebuffers = N;
    
    Transformation transformState;
    //change this to an array
    CMemPool::Handle transformUniformBuffer[N];

Code: Select all

        // Create the transformation uniform buffer
	for (int i = 0; i < N; i++)
		transformUniformBuffer[i] = pool_data->allocate(sizeof(transformState), DK_UNIFORM_BUF_ALIGNMENT);

in recordStaticCommands() (after clearDepthStencil). Using the same shaders for each cube:

Code: Select all

		for (int i = 0; i < N; i++)
		{
			// Bind state required for drawing the cube
			cmdbuf.bindShaders(DkStageFlag_GraphicsMask, { vertexShader, fragmentShader });
			cmdbuf.bindUniformBuffer(DkStage_Vertex, 0, transformUniformBuffer[i].getGpuAddr(), transformUniformBuffer[i].getSize());
			cmdbuf.bindTextures(DkStage_Fragment, 0, dkMakeTextureHandle(0, 0));
			cmdbuf.bindRasterizerState(rasterizerState);
			cmdbuf.bindColorState(colorState);
			cmdbuf.bindColorWriteState(colorWriteState);
			cmdbuf.bindDepthStencilState(depthStencilState);
			cmdbuf.bindVtxBuffer(0, vertexBuffer.getGpuAddr(), vertexBuffer.getSize());
			cmdbuf.bindVtxAttribState(VertexAttribState);
			cmdbuf.bindVtxBufferState(VertexBufferState);

			// Draw the cube
			cmdbuf.draw(DkPrimitive_Quads, CubeVertexData.size(), 1, 0, 0);
		}
change render:

Code: Select all

        int slot = queue.acquireImage(swapchain);
        queue.submitCommands(framebuffer_cmdlists[slot]);
        queue.submitCommands(render_cmdlist);
        queue.presentImage(swapchain, slot);
and in the gameloop:

Code: Select all

		for (int i = 0; i < N; i++)
		{
			transformState.mdlvMtx = glm::mat4{1.0f};
			transformState.mdlvMtx = glm::translate(transformState.mdlvMtx, glm::vec3{-8.0f + i, 0.0f, -14.0f - (i * -1)});
			transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, sinf(period2 * tau) * tau / 8.0f, glm::vec3{1.0f, 0.0f, 0.0f});
			transformState.mdlvMtx = glm::rotate(transformState.mdlvMtx, -period1 * tau, glm::vec3{0.0f, 1.0f, 0.0f});
			transformState.mdlvMtx = glm::scale(transformState.mdlvMtx, glm::vec3{0.3f + (i *0.1)});
			
			// Begin generating the dynamic command list, for commands that need to be sent only this frame specifically
			dynmem.begin(dyncmd);

			// Update the uniform buffer with the new transformation state (this data gets inlined in the command list)
			dyncmd.pushConstants(transformUniformBuffer[i].getGpuAddr(), transformUniformBuffer[i].getSize(), 0, sizeof(transformState), &transformState);

			// Finish off the dynamic command list (which also submits it to the queue)
			queue.submitCommands(dynmem.end(dyncmd));		
		}

I wouldn't 100% know yet if this is severely unoptimized or not but, it is running at 60fps on ryu.
it makes sense to me that id need a transform buffer for each vertex array. but apparently a frame buffer is needed for each as well which I wouldn't know the reason why. in any case, going through a vulkan tut helped me figure it out the issue. im still a scrub so im gonna go back to learning some more about it