Direct3D C++ - rendering misses every second line

Started by
7 comments, last by phowwad 9 years, 11 months ago

Hi,

I am writing a school project of mine, drawing different circuits transfer function (voltage transfer and phase). I wrote my code in C++ msvc Win32 native app with D3D9 and it works just fine. Only problem is, somehow rendering misses every second line, actually not missing but barely drawing it, and it's very frustrating. What could be the problem?

[attachment=21163:d3d9.png]


void render(void)
	{
		D3DXMATRIX world, scale, translate, center;
		D3DXMATRIX view;
		D3DXMATRIX final;
		H transfer;
		LPVOID lpVertices;
		DWORD vertexCount;
		VERTEX vertex;
		double xScale, yScale;
		double marginsWidthH, marginsWidthV;

		// ha nem létezik az áramkör
		if (lpcirc == NULL)
			return;

		// elkérjük a transzfer karakterisztikát
		transfer = lpcirc->getH();
		// ha üres
		if (transfer.count == 0)
			return;

		// margó szélessége egységre nézve
		marginsWidthH = BODE_WINDOW_MARGIN / (WindowWidth / 2.0f);
		marginsWidthV = BODE_WINDOW_MARGIN / (WindowHeight / 2.0f);

		// Identitás mátrix mindenre
		D3DXMatrixIdentity(&world);
		D3DXMatrixIdentity(&scale);
		D3DXMatrixIdentity(&center);
		D3DXMatrixIdentity(&translate);
		// Identitás mátrix a nézetre
		D3DXMatrixIdentity(&view);

		/// =========================================
		/// Pár adat, amit el?re ki kell számolni
		/// =========================================
		// min, max frekvenciakitev?
		double pwMin = transfer.fs[0].pw;
		double pwMax = transfer.fs[transfer.count - 1].pw;
		// min, max átvitel
		double fsMin = 10.0 * log(ABS2(transfer.minFs.Zu2_u1));
		double fsMax = 10.0 * log(ABS2(transfer.maxFs.Zu2_u1));
		// min, max fázis
		double phMin = ARG(transfer.minPh.Zu2_u1);
		double phMax = ARG(transfer.maxPh.Zu2_u1);

		/// =========================================
		/// Transzferkarakterisztika
		/// =========================================

		// egységre leskálázva, margó beleszámít
		xScale = (1.0 - marginsWidthH) / (pwMax - pwMin);
		// abszolútérték skálája egységre nézve
		yScale = (1.0 - marginsWidthV) / (fsMax - fsMin);

		// töröljük a képerny?t
		lpd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0xFFDDDDDD, 1.0f, 0);
		// kezd?dhet a rajzolás
		lpd3dDevice->BeginScene();

		// betoljuk a függvényt az origóba
		D3DXMatrixTranslation(&center, (float) -pwMin, (float) -fsMax, 0.0);
		// megskálázzuk, hogy a diagramunk elférjen az ablakban
		D3DXMatrixScaling(&scale, 2.0f * (float) xScale, 2.0f * (float) yScale, 1.0f);
		// eltoljuk a függvényt a -1.0-ba x tengelyen (ablak bal széle) + margó
		// y tengelyen 1.0 (ablak teteje ) - margó
		D3DXMatrixTranslation(&translate, -1.0f + (float) marginsWidthH, 1.0f - (float) marginsWidthV, 0.0f);

		// ered? mátrix
		final = world * center * scale * translate;
		// transzformációk beállítása
		lpd3dDevice->SetTransform(D3DTS_WORLD, &final);
		lpd3dDevice->SetTransform(D3DTS_VIEW, &view);

		/// =========================================
		/// Transzferkarakterisztika rajzolása
		/// =========================================

		// elkérjük a vertex buffert
		lpd3dVertexBuffer->Lock(0, BODE_VERTEXBUFFER_SIZE, (LPVOID*) &lpVertices, 0);
		// egyel?re nincs pont
		vertexCount = 0;

		// végigmegyünk az összes ponton az átviteli függvényben
		for (int i = 0; i < transfer.count; i++)
		{
			vertex.color = 0x66000000;
			vertex.x = (float) transfer.fs[i].pw;
			vertex.y = (float) (10.0 * log(ABS2(transfer.fs[i].Zu2_u1)));
			vertex.z = 1.0f;

			// bemásoljuk a videómemóriába
			memcpy(((VERTEX*) lpVertices + vertexCount), &vertex, sizeof(VERTEX));
			// egyel több pont a halmazban
			vertexCount++;
		}

		// feloldjuk a videómemóriát
		lpd3dVertexBuffer->Unlock();

		lpd3dDevice->SetStreamSource(0, lpd3dVertexBuffer, 0, sizeof(VERTEX));
		lpd3dDevice->SetFVF(BODE_D3DFVF);
		lpd3dDevice->DrawPrimitive(D3DPT_LINESTRIP, 0, vertexCount - 1);

		/// =========================================
		/// Transzferkarakterisztika VÉGE
		/// =========================================

		// Identitás mátrix mindenre
		D3DXMatrixIdentity(&world);
		D3DXMatrixIdentity(&scale);
		D3DXMatrixIdentity(&center);
		D3DXMatrixIdentity(&translate);
		// Identitás mátrix a nézetre
		D3DXMatrixIdentity(&view);

		/// =========================================
		/// Fázismenet
		/// =========================================

		// egységre leskálázva, margó beleszámít
		xScale = (1.0 - marginsWidthH) / (pwMax - pwMin);
		// abszolútérték skálája egységre nézve
		yScale = (1.0 - marginsWidthV) / (phMax - phMin);

		// betoljuk a függvényt az origóba
		D3DXMatrixTranslation(&center, (float) -pwMin, (float) -phMax, 0.0f);
		// megskálázzuk, hogy a diagramunk elférjen az ablakban
		D3DXMatrixScaling(&scale, 2.0f * (float) xScale, 2.0f * (float) yScale, 1.0f);
		// eltoljuk a függvényt a -1.0-ba x tengelyen (ablak bal széle) + margó
		// y tengelyen 1.0 (ablak teteje ) - margó
		D3DXMatrixTranslation(&translate, -1.0f + (float) marginsWidthH, 1.0f - (float) marginsWidthV, 0.0f);

		// ered? mátrix
		final = world * center * scale * translate;
		// transzformációk beállítása
		lpd3dDevice->SetTransform(D3DTS_WORLD, &final);
		lpd3dDevice->SetTransform(D3DTS_VIEW, &view);

		/// =========================================
		/// Fázismenet rajzolása
		/// =========================================

		// elkérjük a vertex buffert
		lpd3dVertexBuffer->Lock(0, BODE_VERTEXBUFFER_SIZE, (LPVOID*) &lpVertices, 0);
		// egyel?re nincs pont
		vertexCount = 0;

		// végigmegyünk az összes ponton az átviteli függvényben
		for (int i = 0; i < transfer.count; i++)
		{
			vertex.color = 0xFFFF0000;
			vertex.x = (float) transfer.fs[i].pw;
			vertex.y = (float) ARG(transfer.fs[i].Zu2_u1);
			vertex.z = 1.0f;

			// bemásoljuk a videómemóriába
			memcpy(((VERTEX*) lpVertices + vertexCount), &vertex, sizeof(VERTEX));
			// egyel több pont a halmazban
			vertexCount++;
		}

		// feloldjuk a videómemóriát
		lpd3dVertexBuffer->Unlock();

		lpd3dDevice->SetStreamSource(0, lpd3dVertexBuffer, 0, sizeof(VERTEX));
		lpd3dDevice->SetFVF(BODE_D3DFVF);
		lpd3dDevice->DrawPrimitive(D3DPT_LINESTRIP, 0, vertexCount - 1);

		/// =========================================
		/// Fázismenet VÉGE
		/// =========================================


		// vége a rajzolásnak
		lpd3dDevice->EndScene();
		// mutassa meg az eredményt
		lpd3dDevice->Present(NULL, NULL, NULL, NULL);
	}
Advertisement

lpd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

Maybe adding this line before DrawPrimite will be helpful.

Please, share the result.

That may be the VERY common mistake that you forget about the window borders and top bar when you specify dimensions. If you make a window 800x600 pixels large, you cannot use this values also as backbuffer dimensions, because the client area will be less than 800x600 (depends on the Windows version and settings). Because then DirectX performs some stretching for you, which will result in errors similar to yours (as it tries to display a 800x600 image on a lets say 784x578 large area).

You must use the AdjustWindowRect function to find the window dimensions required for a particular client area size. (Or the inverse, using for example GetClientRect, but AdjustWindowRect is IMHO better because it allows you to have a specific backbuffer size rather than window size.)


lpd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

Maybe adding this line before DrawPrimite will be helpful.

Please, share the result.

Unfortunately it didn't work, I also tried other Render switches with no solution.


You must use the AdjustWindowRect function to find the window dimensions required for a particular client area size.

So what you say is when DirectX is done converting everything to pixel, in the processing of this little stretch some pixels get faded because their size becomes less than 1?

I don't know what kind of filtering (if any) it's doing during this process. But the result almost never is satisfying ;)

I also don't know whether it really is the source of your problem, that was just a tip. How do you create your window and how do you set the backbuffer dimensions?

Well Tom,

You saved me biggrin.png, setting buffer sizes to Client area solved the problem, Thanks.

Strange is I have another project, and there is no problem with such thing, actually I copied all the initialization from there.

Here is the result of your contribution:

[attachment=21178:Screenshot (3).png]


lpd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

Maybe adding this line before DrawPrimite will be helpful.

Please, share the result.

Unfortunately it didn't work, I also tried other Render switches with no solution.


You must use the AdjustWindowRect function to find the window dimensions required for a particular client area size.

So what you say is when DirectX is done converting everything to pixel, in the processing of this little stretch some pixels get faded because their size becomes less than 1?

When you create a D3D device in a windowed mode, one of two things will happen.

If you don't specify a backbuffer width and height in your present params (i.e leave them at 0) D3D will take the size from the window's current client rect.

If you do specify them it will use that size. However, if that size doesn't match the client rect, D3D will need to either stretch or squeeze the backbuffer during a Present. In 3D that normally can't even be visually noticed, but in 2D it can be very obvious. I say "visually" because another side-effect of this stretching or squeezing is that your program will run slower. This can be quite subtle; in the order or 20% or so, i.e not slow enough for you to realise that something bad is happening (you may err on the side of assuming that your number of draw calls, or your state changes or something else is the cause and decide to just accept it as it's not too bad, you still make 60fps, and you have other priorities), but still not insignificantly slower than it should be.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.


Strange is I have another project, and there is no problem with such thing, actually I copied all the initialization from there.

There most certainly is the very same problem, it just may be less visible (almost invisible).

In more complex graphics, like in a normal game, you probably wouldn't notice at all that few rows and columns of pixels are badly displayed.

And also in a project like this one, where you have 1 pixel thin lines, you may be lucky - for example in the screenshot you showed here, if the errors were not in the horizontal zone, but in the slope, do you think you would notice it?


if the errors were not in the horizontal zone, but in the slope, do you think you would notice it?

makes sense :D

This topic is closed to new replies.

Advertisement