DrawPrimitiveUP and Clipping

Started by
6 comments, last by fsforall 16 years, 8 months ago
Hello, I have two simple Direct3D questions : 1) How do I set the width of a line or polygon line drawn with DrawPrimitiveUP ? CUSTOMVERTEX v1[2]; v1[0].x = x1; v1[0].y = y1; v1[0].z = 1; v1[0].rhw = 10; v1[0].color = color; v1[1].x = x2; v1[1].y = y2; v1[1].z = 1; v1[1].rhw = 10; v1[1].color = color; g_pd3dDevice->DrawPrimitiveUP(D3DPT_LINESTRIP,1,&v1,sizeof(CUSTOMVERTEX)); This is the code that I have to draw two lines, however, the width of the line is one pixel even though I have it set to 10. This is how I set FVF : g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); and struct CUSTOMVERTEX { FLOAT x, y, z, rhw; DWORD color; }; 2) The second question : How can I set clipping to an area inside a polygon ? I know the SetScissorRect function, but I need more than four edges for the clip. However, I like the method used for this. Thank you very much for your help in advance.
Advertisement
1. You'll need to use ID3DXLine, or write your own code to draw lines using polygons.

2. Clip planes are probably not what you want here. I'd suggest you use the stencil buffer to do it.
Hi,

Thanks for your reply. I used ID3DXLine and its performance is very bad. It took me 1ms to draw just one line. This is my code, maybe something was wrong with it :

D3DXCreateLine(g_pd3dDevice, &lpLine);
D3DLine[0].x = x1;
D3DLine[0].y = y1;
D3DLine[1].x = x2;
D3DLine[1].y = y2;
lpLine->SetWidth(w);
//lpLine->SetAntialias(true);
lpLine->Begin();
lpLine->Draw(D3DLine, 2, color);
lpLine->End();
lpLine->Release();

For the stencil buffer, here is how I want to use it :

I want to draw something, set the clip, draw something inside the clipped region and then reset the clip. This works just like in GDI+ with the SetClip function.

Does the stencil buffer allow me to do that or does it delete everything inside the clipping region ? That is why I said that SetScissorRect sounds good, because I can define when to stop/start clipping. Can I do the same with the stencil buffer ?
Quote:Original post by fsforall
I used ID3DXLine and its performance is very bad. It took me 1ms to draw just one line.
Have you followed profiling advice in "Accurately profiling Direct3D API calls"? If not, your timing values are most likely misleading.

That doesn't mean ID3DXLine isn't slow, just that you might not be assessing it properly [wink]

I doubt your code is efficient - I'm not 100% sure, but ID3DXLine probably creates resources, which is a general bad thing to do in the core render loop. Create one (or more) ID3DXLine instances at load-time and simply modify them only when necessary.

Also, look into batching where possible - typically you want to maximize the work done inside the Begin()/End() block rather than repeatedly calling them for each line segment.

Quote:Original post by fsforall
Can I do the same with the stencil buffer ?
Yes, this is an ideal use of the stencil buffer feature. You'll probably find it is more flexible than GDI+ and a little more involved, but yes it will do what you want. Basically you clear the stencil buffer to some default value (e.g. 0) and you then draw your clip region as simple, solid geometry and set the stencil buffer to increment by 1. After rendering you have a buffer with all 0's except for 1's inside your custom region. The next step is to render your normal geometry but with stencil testing enabled - and set it to pass the test only when stencil=1 (to draw inside) or stencil=0 (to draw outside). Simple [smile]

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

Hi Jack,

Thanks for your very quick and professional answer.

I see how the stencil buffer works, here is how I need to get it working :

Clear window (black).
Draw a grey rectangle.
Set Clip to a small part inside the rectangle.
Draw some lines, they are big, but I want them to show only inside the clipped area.
Reset the clip.
Draw something else over.



This is where I think that the problem lays, I will need to draw something else over after I reset the clipping area. It is some nested Set Clip statements that I might need.

So with the stencil buffer, I would need to create one, render with the stencil and then render again over.

Or something else that I need is to set clip, draw, reset and then set clip in another area.

Please let me know if you understand what I am trying to achieve.
Hi,

I made some progress with the stencil, but I need your help. Here is my code so far :

g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_STENCIL, D3DCOLOR_XRGB(0,0,255), 1.0f, 0x0);
g_pd3dDevice->SetViewport(&vp);
g_pd3dDevice->BeginScene();
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);

SetColor(D3DCOLOR_XRGB(0, 255, 0));
DrawLine(4.5, 0 * dy,0 * dx,292 * dx,273 * dy);

g_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
g_pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);
g_pd3dDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
g_pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);

FillCircle(150,150,50, 10);

g_pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0x0000000F);
g_pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
g_pd3dDevice->SetRenderState( D3DRS_STENCILREF, 0x1 );

FillRectangle(0.0,0.0,100,100);

What I am trying to do is to draw a line, to clip and display only inside the circle and then to reset the clip so I can draw normally anywhere on the screen, as seen by FillRectangle. However, this code does not work. Any help is greatly appreciated.
You can call ::Clear() with only the D3DCLEAR_STENCIL flag at any point in the frame. Excessive usage is bad, but there is no reason why you can't clear it several times - most tutorials/samples do a single ::Clear() at the start and that's it, so it's rarely demonstrated!

In your situation, you should be fine if you just clear the stencil buffer between rendering the two clipping regions. Provided you don't muddle up the flags any visible pixels already written will not be erased.

Roughly, in pseudo code:

Clear( Target | Depth | Stencil )for_each( clipping region ){    Clear( Stencil, 0 )    SetRenderState( Stencil_Enable = true )    SetRenderState( Stencil_Pass = Increment )    SetRenderState( Stencil_Func = Always )    SetRenderState( Color_Write = None )    Render_Clipping_Polygons()    SetRenderState( Stencil_Pass = Keep )    SetRenderState( Stencil_Func = Equals )    SetRenderState( Stencil_Ref = 1 )    SetRenderState( Color_Write = All )    Render_Geometry_That_Can_Be_Clipped()}Present()


Might have mixed some of the states up, but hopefully that should get you rolling [smile]

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

Thanks for your help, Jack. It works great !

This topic is closed to new replies.

Advertisement