Removal of OpenGL rubber banding artefacts - c++

I'm working with some OpenGL code for scientific visualization and I'm having issues getting its rubber banding working on newer hardware. The code is drawing a "Zoom Window" over an existing scene with one corner of the "Zoom Window" at the stored left-click location, and the other under the mouse as it is moved. On the second left-click the scene zooms into the selected window.
The symptoms I am seeing as the mouse is moved across the scene are:
Rubber banding artefacts appearing which are the lines used to create the "Zoom Window" not being removed from the buffer by the second "RenderLogic" pass (see code below)
I can clearly see the contents of the previous buffer flashing up and disappearing as the buffers are swapped
The above problem doesn't happen on low end hardware such as the integrated graphics on a netbook I have. Also, I can't recall this problem ~5 years ago when this code was written.
Here are the relevant code sections, trimmed down to focus on the relevant OpenGL:
// Called by every mouse move event
// Makes use of current device context (m_hDC) and rendering context (m_hRC)
void MyViewClass::DrawLogic()
{
BOOL bSwapRv = FALSE;
// Make the rendering context current
if (!wglMakeCurrent(m_hDC, m_hRC))
// ... error handling
// Perform the logic rendering
glLogicOp(GL_XOR);
glEnable(GL_COLOR_LOGIC_OP);
// Draws the rectangle on the buffer using XOR op
RenderLogic();
bSwapRv = ::SwapBuffers(m_hDC);
// Removes the rectangle from the buffer via a second pass
RenderLogic();
glDisable(GL_COLOR_LOGIC_OP);
// Release the rendering context
if (!wglMakeCurrent(NULL, NULL))
// ... error handling
}
void MyViewClass::RenderLogic(void)
{
glLineWidth(1.0f);
glColor3f(0.6f,0.6f,0.6f);
glEnable(GL_LINE_STIPPLE);
glLineStipple(1, 0x0F0F);
glBegin(GL_LINE_LOOP);
// Uses custom "Point" class with Coords() method returning double*
// Draw rectangle with corners at clicked location and current location
glVertex2dv(m_pntClickLoc.Coords());
glVertex2d(m_pntCurrLoc.X(), m_pntClickLoc.Y());
glVertex2dv(m_pntCurrLoc.Coords());
glVertex2d(m_pntClickLoc.X(), m_pntCurrLoc.Y());
glEnd();
glDisable(GL_LINE_STIPPLE);
}
// Setup code that might be relevant to the buffer configuration
bool MyViewClass::SetupPixelFormat()
{
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
1, // Version number (?)
PFD_DRAW_TO_WINDOW // Format must support window
| PFD_SUPPORT_OPENGL // Format must support OpenGL
| PFD_DOUBLEBUFFER, // Must support double buffering
PFD_TYPE_RGBA, // Request an RGBA format
32, // Select a 32 bit colour depth
0, 0, 0, 0, 0, 0, // Colour bits ignored (?)
8, // Alpha buffer bits
0, // Shift bit ignored (?)
0, // No accumulation buffer
0, 0, 0, 0, // Accumulation bits ignored
16, // 16 bit Z-buffer
0, // No stencil buffer
0, // No accumulation buffer (?)
PFD_MAIN_PLANE, // Main drawing layer
0, // Number of overlay and underlay planes
0, 0, 0 // Layer masks ignored (?)
};
PIXELFORMATDESCRIPTOR chosen_pfd;
memset(&chosen_pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
chosen_pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
// Find the closest match to the pixel format
m_uPixelFormat = ::ChoosePixelFormat(m_hDC, &pfd);
// Make sure a pixel format could be found
if (!m_uPixelFormat)
return false;
::DescribePixelFormat(m_hDC, m_uPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosen_pfd);
// Set the pixel format for the view
::SetPixelFormat(m_hDC, m_uPixelFormat, &chosen_pfd);
return true;
}
Any pointers on how to remove the artefacts will be much appreciated.
#Krom - image below

With OpenGL it's canonical to redraw the whole viewport if just anything changes. Consider this: Modern system draw animates complex scenes at well over 30 FPS.
But I understand, that you may want to avoid this. So the usual approach is to first copy the frontbuffer in a texture, before drawing the first rubberband. Then for each rubberband redraw "reset" the image by drawing a framebuffer filling quad with the texture.

I know I'm posting to a year and half old question but in case anyone else comes across this.
I've had this happen to me myself is because you are trying to remove the lines off of the wrong buffer. For example you draw your rectangle on buffer A call swapBuffer and then try to remove the rectangle off of buffer B. What you would want to do is keep track of 2 "zoom window" rectangles while your doing the drawing one for buffer A and one for buffer B and then keep track of which one is the most recent.

If you're using Vista/7 and Aero, try switching to the Classic theme.

Related

How to properly fill up SwapChain Struct to use Mulitsampling?

Hi I just start with DirectX under CoreWindow^ + C++/CLI, all things seems to be ok until I want to start using a Mulitsampling.
This example is rendering the simple triangle
Working example without AA
When I fill the SwapChain struct like this:
UINT m4xMsaaQuality;
dev->CheckMultisampleQualityLevels(DXGI_FORMAT_B8G8R8A8_UNORM,4, &m4xMsaaQuality);
// set up the swap chain description
DXGI_SWAP_CHAIN_DESC1 scd = { 0 };
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how the swap chain should be used
scd.BufferCount =2;
scd.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // the most common swap chain format
scd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // the recommended flip mode
scd.SampleDesc.Count = 4; // >1 enable anti-aliasing
scd.SampleDesc.Quality = m4xMsaaQuality-1;
CoreWindow^ Window = CoreWindow::GetForCurrentThread(); // get the window pointer
// create the swap chain
dxgiFactory->CreateSwapChainForCoreWindow(
dev.Get(), // address of the device
reinterpret_cast<IUnknown*>(Window), // address of the window
&scd, // address of the swap chain description
nullptr, // advanced
&swapchain); // address of the new swap chain pointer
// get a pointer directly to the back buffer
ComPtr<ID3D11Texture2D> backbuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (&backbuffer));`
the
dxgiFactory->CreateSwapChainForCoreWindow(
dev.Get(), // address of the device
reinterpret_cast<IUnknown*>(Window), // address of the window
&scd, // address of the swap chain description
nullptr, // advanced
&swapchain);
return "nullptr",
I checked that m4xMsaaQuality is equal "17" so scd.SampleDesc.Quality =16
How I should fill up the SwapChain struct?
Flip swap effects are not compatible with a multisampling surface. You need to create a non-msaa swap chain and explicitly resolve your msaa render to the swapchain buffers.
YES! Finally I menage to use this multisampling, I realize that
ResolveSubresource
Copy a multisampled resource into a non-multisampled resource.
That why I don't have to recreating one more time the RenderViewTarget, just I can use my.
I still have question is there is some way to increase the anti-aliasing? The maximum sample what I can put in offScreenSurfaceDesc.SampleDesc.Count is 8.
Init_DirectX with MSAA enable
Here is working solution.
Thank you for your answer, I read in MSDN about Multisampling in UWP app. But still I can't to render the smooth triangle. I changed the way of swapping - now should be correct for UWP application. I used also the ResolveSubresource
Can you take a look? The Window is complete black without a triangle. So far I finished with this code, Mostly I suspect the render target bacause when I uncomment this:
dev->CreateRenderTargetView(backbuffer.Get(), &renderTargetViewDesc, &rendertarget);
And in Render Method [line:210, 214] use "renderTarget"
[210] devcon->OMSetRenderTargets(1, rendertarget.GetAddressOf(), nullptr);
[214]devcon->ClearRenderTargetView(rendertarget.Get(), color);
Everything back to normal (of course without MSAA)
Init_DirectX - render fail

SDL and c++ -- More efficient way of leaving a trail behind the player?

so i'm fairly new with SDL, and i'm trying to make a little snowboarding game. When the player is moving down the hill, I want to leave a trail of off-coloured snow behind him. Currently, the way i have this working is I have an array (with 1000 elements) that stores the players last position. Then each frame, I have a for loop that loops 1000 times, to draw out the trail texture in all these last 1000 positions of the player...
I feel this is extremely inefficient, and i'm looking for some better alternatives!
The Code:
void Player::draw()
{
if (posIndex >= 1000)
{
posIndex = 0;
}
for (int i = 0; i < 1000; i++) // Loop through all the 1000 past positions of the player
{
// pastPlayerPos is an array of SDL_Rects that stores the players last 1000 positions
// This line calculates teh location to draw the trail texture
SDL_Rect trailRect = {pastPlayerPos[i].x, pastPlayerPos[i].y, 32, 8};
// This draws the trail texture
SDL_RenderCopy(Renderer, Images[IMAGE_TRAIL], NULL, &trailRect);
}
// This draws the player
SDL_Rect drawRect = {(int)x, (int)y, 32, 32};
SDL_RenderCopy(Renderer, Images[0], NULL, &drawRect);
// This is storing the past position
SDL_Rect tempRect = {x, y, 0, 0};
pastPlayerPos[posIndex] = tempRect;
posIndex++; // This is to cycle through the array to store the new position
This is the result, which is exactly what i'm trying to accomplish, but i'm just looking for a more efficient way. If there isn't one, i will stick with this.
There are multiple solutions. I'll give you two.
1.
Create screen-size surface. Fill it with alpha. On each player move, draw it's current position into this surface - so each movement will add you extra data to this would-be mask. Then blit this surface on screen (beware of blit order). In your case it could be improved by disabling alpha and initially filling surface with white, and blitting it first, before anything else. With that approach you can skip screen clearing after flip, by the way.
I recommend starting with this one.
2.
Not easy one, but may be more efficient (it depends). Save array points where player actually changed movement direction. After it, you need to draw chainline between these points. There is however no builtin functions in SDL to draw lines; maybe there are in SDL_gfx, i never tried it. This approach may be better if you'll use OpenGL backend later on; with SDL (or any other ordinary 2D drawing library), it's not too useful.

Driver error when using multiple shaders

I'm using 3 different shaders:
a tessellation shader to use the tessellation feature of DirectX11 :)
a regular shader to show how it would look without tessellation
and a text shader to display debug-info such as FPS, model count etc.
All of these shaders are initialized at the beginning.
Using the keyboard, I can switch between the tessellation shader and regular shader to render the scene. Additionally, I also want to be able toggle the display of debug-info using the text shader.
Since implementing the tessellation shader the text shader doesn't work anymore. When I activate the DebugText (rendered using the text-shader) my screens go black for a while, and Windows displays the following message:
Display Driver stopped responding and has recovered
This happens with either of the two shaders used to render the scene.
Additionally:
I can start the application using the regular shader to render the scene and then switch to the tessellation shader. If I try to switch back to the regular shader I get the same error as with the text shader.
What am I doing wrong when switching between shaders?
What am I doing wrong when displaying text at the same time?
What file can I post to help you help me? :) thx
P.S. I already checked if my keyinputs interrupt at the wrong time (during render or so..), but that seems to be ok
Testing Procedure
Regular Shader without text shader
Add text shader to Regular Shader by keyinput (works now, I built the text shader back to only vertex and pixel shader) (somthing with the z buffer is stil wrong...)
Remove text shader, then change shader to Tessellation Shader by key input
Then if I add the Text Shader or switch back to the Regular Shader
Switching/Render Shader
Here the code snipet from the Renderer.cpp where I choose the Shader according to the boolean "m_useTessellationShader":
if(m_useTessellationShader)
{
// Render the model using the tesselation shader
ecResult = m_ShaderManager->renderTessellationShader(m_D3D->getDeviceContext(), meshes[lod_level]->getIndexCount(),
worldMatrix, viewMatrix, projectionMatrix, textures, texturecount,
m_Light->getDirection(), m_Light->getAmbientColor(), m_Light->getDiffuseColor(),
(D3DXVECTOR3)m_Camera->getPosition(), TESSELLATION_AMOUNT);
} else {
// todo: loaded model depends on distance to camera
// Render the model using the light shader.
ecResult = m_ShaderManager->renderShader(m_D3D->getDeviceContext(),
meshes[lod_level]->getIndexCount(), lod_level, textures, texturecount,
m_Light->getDirection(), m_Light->getAmbientColor(), m_Light->getDiffuseColor(),
worldMatrix, viewMatrix, projectionMatrix);
}
And here the code snipet from the Mesh.cpp where I choose the Typology according to the boolean "useTessellationShader":
// RenderBuffers is called from the Render function. The purpose of this function is to set the vertex buffer and index buffer as active on the input assembler in the GPU. Once the GPU has an active vertex buffer it can then use the shader to render that buffer.
void Mesh::renderBuffers(ID3D11DeviceContext* deviceContext, bool useTessellationShader)
{
unsigned int stride;
unsigned int offset;
// Set vertex buffer stride and offset.
stride = sizeof(VertexType);
offset = 0;
// Set the vertex buffer to active in the input assembler so it can be rendered.
deviceContext->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset);
// Set the index buffer to active in the input assembler so it can be rendered.
deviceContext->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0);
// Check which Shader is used to set the appropriate Topology
// Set the type of primitive that should be rendered from this vertex buffer, in this case triangles.
if(useTessellationShader)
{
deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST);
}else{
deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
return;
}
RenderShader
Could there be a problem using sometimes only vertex and pixel shader and after switching using vertex, hull, domain and pixel shader?
Here a little overview of my architecture:
TextClass: uses font.vs and font.ps
deviceContext->VSSetShader(m_vertexShader, NULL, 0);
deviceContext->PSSetShader(m_pixelShader, NULL, 0);
deviceContext->PSSetSamplers(0, 1, &m_sampleState);
RegularShader: uses vertex.vs and pixel.ps
deviceContext->VSSetShader(m_vertexShader, NULL, 0);
deviceContext->PSSetShader(m_pixelShader, NULL, 0);
deviceContext->PSSetSamplers(0, 1, &m_sampleState);
TessellationShader: uses tessellation.vs, tessellation.hs, tessellation.ds, tessellation.ps
deviceContext->VSSetShader(m_vertexShader, NULL, 0);
deviceContext->HSSetShader(m_hullShader, NULL, 0);
deviceContext->DSSetShader(m_domainShader, NULL, 0);
deviceContext->PSSetShader(m_pixelShader, NULL, 0);
deviceContext->PSSetSamplers(0, 1, &m_sampleState);
ClearState
I'd like to switch between 2 shaders and it seems they have different context parameters, right? In clearstate methode it says it resets following params to NULL:
I found following in my Direct3D Class:
depth-stencil state -> m_deviceContext->OMSetDepthStencilState
rasterizer state -> m_deviceContext->RSSetState(m_rasterState);
blend state -> m_device->CreateBlendState
viewports -> m_deviceContext->RSSetViewports(1, &viewport);
I found following in every Shader Class:
input/output resource slots -> deviceContext->PSSetShaderResources
shaders -> deviceContext->VSSetShader to - deviceContext->PSSetShader
input layouts -> device->CreateInputLayout
sampler state -> device->CreateSamplerState
These two I didn't understand, where can I find them?
predications -> ?
scissor rectangles -> ?
Do I need to store them all localy so I can switch between them, because it doesn't feel right to reinitialize the Direct3d and the Shaders by every switch (key input)?!
Have you checked if the device is being reset by the system. Check the return variable of the Present() Method. When switching shaders abruptly DX tends to reset the device for some odd reason.
If this is the problem, just recreate the device and context and you should be good.
Right now you have
void Direct3D::endScene()
{
// Present the back buffer to the screen since rendering is complete.
if(m_vsync_enabled)
{
// Lock to screen refresh rate.
m_swapChain->Present(1, 0);
}
else
{
// Present as fast as possible.
m_swapChain->Present(0, 0);
}
return;
}
I would suggest doing something like so to catch the return value of Present()
ULONG Direct3D::endScene()
{
int synch = 0;
if(m_vsync_enabled)
synch = 1;
// Present as fast as possible or synch it to 1 vertical blank
return m_swapChain->Present(synch, 0);
}
Of course this is only MY way of doing it, and there are many. Also, I forgot to tell you that the issue I had in the past was also using the Effects library. Have you recompiled it in your system? If not, then do so. Or even better get rid of it, that's what I did when I solved my problem.

Color picking with AntiAliasing in OpenGL?

I'm having a problem with color picking and antialiasing in OpenGL. When AA is activated results from glReadPixels are obviously wrong on object edges and object intersections. For example:
I render a box #28 (RGBA: 28, 0, 0, 0) near a box #32 (RGBA: 32, 0, 0, 0). With AA, I can get a wrong ReadPixel value (e.g. 30) where the cube and triangle overlap, or value of 14 on boxes edge, due to the AA algorithm.
I have ~4000 thousand objects I need to be able to pick (it's a jigsaw puzzle game). It is vital to be able to select objects by shape.
I've tried to disable AA with glDisable(GL_MULTISAMPLE) but it does not works with certain AA modes (I read it depends on AA implementation - SS, MS, CS ..)
So, how do I pick an underlying object?
A way do temporary disable AA?
Using a different buffer or even rendering context?
Any other suggestion?
Why not use an FBO as your pick buffer?
I use this hack: pick not just one pixel, but all the 3x3=9 pixels around the picking point. If they are all same, we are safe. Otherwise, it must be on edge and we can skip that.
int renderer::pick_(int x, int y)
{
static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__,
"only works on little-endian architecture");
static_assert(sizeof(int) == 4,
"only works on architecture that has int size of 4");
// sort of edge detection. selection only happens at non-edge
// since the edge may cause anti-aliasing glitch
int ids[3*3];
glReadPixels(x-1, y-1, 3, 3, GL_RGBA, GL_UNSIGNED_BYTE, ids);
for (auto& id: ids) id &= 0x00FFFFFF; // mask out alpha
if (ids[0] == 0x00FFFFFF) return -1; // pure white for background
// prevent anti-aliasing glitch
bool same = true;
for (auto id: ids) same = (same && id == ids[0]);
if (same) return ids[0];
return -2; // edge
}

Want to place several images with transparent colour on the same background

I am desparately searching for place several graphics having a transparent background on the same background with GDI+. I did not have any programming experience with Windows or graphic programming (like games) before, so it is more difficult to find a solution. GDI+ has a transparent colour. GDI+ only uses the transparency information to bitmap this colour properly on another image. Once bitmaped, however, the first image is no more transparent. If you put the same image several times on the same background, you will see that only the first placement was transparent.
My problem is placing several transparent objects on a background at once. You can see the code below that works for one ship (nNrOfShips = 1;). If you write a larger value for this variable, no ship will be placed.
How should I modify the code? I also tried to use Ship arrays, but no ship appears on the screen. You may create your own example by using a background with (slightly) changing colour and just place an image transparently. I hope that that example would help me.
Here the code example...
HDC hdcScreen = GetLockedScreen();
m_hdcShip = CreateCompatibleDC(hdcScreen);
ReleaseLockedScreen();
// Draw the ship image on restored background
Graphics grBkg(m_hdcNewBackground);
grBkg.SetSmoothingMode(SmoothingModeHighQuality);
// Restore new background
BitBlt(m_hdcNewBackground, 0, 0,
GetWtsMetrics(wtsm_ScreenSizeX), GetWtsMetrics(wtsm_ScreenSizeY),
m_hdcSavedBackground, 0, 0, SRCCOPY); // 20100125 SAE
BYTE nNrOfShips = 1; // DATA->GetNrOfShips();
for (BYTE nShipId = 0; nShipId < nNrOfShips; nShipId++)
{
Ship ship = DATA->GetShipList()[nShipId];
ShipModel shipModel = DATA->FindShipModel(ship.nShipModelId); // 20100202 SAE
WORD nCurResId = DATA->FindCurShipResourceId(ship); // 20100131 SAE
WORD nIndex = nCurResId - shipModel.nFirstResId; // 20100131 SAE
assert(nIndex >= 0);
ShipResource shipRes = (*shipModel.pvectResource)[nIndex]; // 20100202 SAE
// 20100126 SAE
// Always take the first (upper left) coordinates of the ship rectangle:
QuadrantVector &wpQuadrants =
*DATA->GetWallpapers()[DATA->SelectWallpaper()].pvectQuadrant;
do
{ // 20100115 SAE: Determine first the coordinates of the ship
ship.vectRectangle = DATA->RandomRectangleCoordinates(
shipModel.nHeight, shipModel.nWidth);
} while (!DATA->AreCoordinatesValid(ship.vectRectangle, wpQuadrants) &&
!DATA->AreShipsTooClose(ship, DATA->GetShipList(), DATA->GetDistance()));
grBkg.TranslateTransform(ship.vectRectangle[0].fX,
ship.vectRectangle[0].fY);
grBkg.RotateTransform(0); // 20100201 SAE
grBkg.DrawImage(shipRes.pimgPicture,
-shipModel.nWidth/2, -shipModel.nHeight/2);
// Determine bounding rectangle of ship after drawing on transformed page
// 20100125 SAE
Rect rcSrc(-shipModel.nWidth/2, -shipModel.nHeight/2,
shipModel.nWidth, shipModel.nHeight);
TransformRect(&grBkg, &m_rcCurShip, &rcSrc,
CoordinateSpacePage, CoordinateSpaceWorld);
} // for
DeleteDC(m_hdcShip);
m_hdcShip = 0;
Use the Bitmap.MakeTransparent() method on the images when you load them. You'll need to select the color that's the background color for those images. Storing the images in the PNG format with the transparency selected in the graphics editor would be another way.