For the final project for my graphics class, I wanted to finish something that I wanted to do for the final project in the previous semester. That is to have split screen gaming. I could not finish it during the previous semester, but with better knowledge now, I set out to finish this. My goal for the final project is to create the viewport selector screen in Maya, where you can select which view you want, to view the object. It looks like the image below
The four different parts are different viewports and you can select which viewport you want from this screen.
To create the above view, first, I needed to create five different viewports. One for each square and one for the final selected camera view. We could also have resized the viewport, but this was much easier to implement. Since our window is 512 * 512, Each of the viewports is 256*256.
viewPort[0].TopLeftX = 0.0f; viewPort[0].TopLeftY = 0.0f; viewPort[0].Width = static_cast<float>(i_resolutionWidth); viewPort[0].Height = static_cast<float>(i_resolutionHeight); viewPort[0].MinDepth = 0.0f; viewPort[0].MaxDepth = 1.0f; viewPort[1].TopLeftX = 0.0f; viewPort[1].TopLeftY = 0.0f; viewPort[1].Width = static_cast<float>(i_resolutionWidth/2.0f); viewPort[1].Height = static_cast<float>(i_resolutionWidth/2.0f); viewPort[1].MinDepth = 0.0f; viewPort[1].MaxDepth = 1.0f; viewPort[2].TopLeftX = 256.0f; viewPort[2].TopLeftY = 0.0f; viewPort[2].Width = static_cast<float>(i_resolutionWidth / 2.0f); viewPort[2].Height = static_cast<float>(i_resolutionWidth / 2.0f); viewPort[2].MinDepth = 0.0f; viewPort[2].MaxDepth = 1.0f;
Above is the sample of all the viewports that I created. Viewport 0 is the default viewport. After creating the viewports, we need to create transforms for each of the mesh in the projected space for each of the cameras. So, I calculate and save the per draw call data which contains the transforms and the positions of the cameras for each camera and also calculate the local to projected space for each one of them. Since we will not be rendering all the four camera views at every frame, I only calculate these matrices when I am showing these camera views which reduces the amount of computation required.
After we create these transforms, now it is the time to draw. When drawing to multiple viewports, you need to draw all the meshes multiple times, since the matrix transformations for each camera view is different. Below is the sample code for the switching and drawing of meshes.
I have created a small function in my graphics helper class which we set up in the first semester to change viewports based on a value I send.
constexpr unsigned int viewPortCount = 1; direct3dImmediateContext->RSSetViewports(viewPortCount, &viewPort[i_ViewPortNumber]);
if (showMultipleCameras) { for (auto k = 1; k < 5; k++) { s_constantBuffer_perDrawCall.Update(&s_renderSecondCam[k-1].constantData_perDrawCallNewCam[index]); s_helper->SetViewPort(k); if ((currentMeshIndex ^ meshIndex)) { tempMesh->Draw(true); currentMeshIndex = meshIndex; } else { tempMesh->Draw(false); } } }
You can see the multiple viewports in action below
The first viewport is the perspective mode where the player can move the camera freely, the second is top-down where the camera moves only in Y-axis, third is front, where the camera moves only in Z-axis and the fourth, is side, where the camera moves in X-axis. The controls are given below.
Working with lighting.
Since specular light with PBR is calculated using the angle between the camera and the fragment, I had an issue where when showing all the four viewports, I was calculating the specular and environmental reflections based on only the perspective camera which resulted in wrong lighting values and reflections. To rectify that, I am currently passing the per-frame data per draw call which is really inefficient but was the fastest way I could fix this issue without changing all my render commands. I am working on making this more efficient by updating both my render commands and shaders.
What I learned from this class:
I have learned the meanings of various terms in graphics programming and won’t look like a noob when other people mention texels or PBR. I also better understand the graphics pipeline itself and optimizing the various stages of the pipeline to get most of it. I have also created some cool shaders and showed how to create various illusions utilizing textures. I also learned about the various transformations we need to perform to draw a 3D object onto a 2D surface that is the screen which was helpful when doing this project.
Download: Link
Controls:
Space: To view all viewports and when pressed again switches to the previous active view. The following keys work only in view selector.
1 – Switches to perspective mode.
2 – Switches to Top-down mode.
3 – Switches to Front mode.
4 – Switches to side mode.
Once switched to the given mode:
In perspective mode:
W, S – Move the camera in Z.
A, D – Move Camera in X.
Q, E – Move Camera in Y.
Z, X – Rotate camera around Y.
I, K – Move the first gecko in Z.
J, L – Move gecko in X.
U, O – Move gecko in Y.
In Top-down mode:
W, S – Move the camera in Y.
I, K – Move the first gecko in Z.
J, L – Move gecko in X.
In Front mode:
W, S – Move the camera in Z.
J, L – Move gecko in X.
U, O – Move gecko in Y.
In Side mode:
W, S – Move the camera in X.
I, K – Move the first gecko in Z.
U, O – Move gecko in Y.