Jump to content
  • Advertisement
Sign in to follow this  
C0D1F1ED

SetRenderState(D3DRS_CLIPPING, FALSE) does not disable clipping

This topic is 4383 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, I have an application where the viewport is smaller than the entire render target, but I don't want the geometry to be clipped to the viewport. I assumed SetRenderState(D3DRS_CLIPPING, FALSE) would do the trick but it still clips to the viewport. So how do I really disable clipping, and what is D3DRS_CLIPPING actually used for? Thanks, c0d1f1ed

Share this post


Link to post
Share on other sites
Advertisement
The viewport, by definition, is the active partition of your render target. Vertices are translated and scaled from the projection(screen) space coordinates ([-1,1] in x/y) to screen(device/display) space coordinates, which is a rectangular area of the total render target. So if you set the viewport to,say, the upper right half of the screen, the rendered image will be scaled to fit the rectangle. This translation and scaling occurs independent whether you use fixed or programmable pipeline.

Edit:
D3DRS_CLIPPING on the other hand, is used to enable/disable geometry clipping planes defined in world space. Primitives behind the plane(s) will not be rendered. I mixed this with D3DRS_CLIPPLANEENABLE, which is the world-space clipping stuff. However, neither have anything to do with viewports.

It seems you want to move the center of the view while still rendering to the whole render target area. This can be done either by altering the view or projection matrices with custom translation. This sounds like a good time to brush up your projection matrix math algebra.

Share this post


Link to post
Share on other sites
Read up on Guard-band clipping. It might also be an issue with a scissor rect.

Does this happen when you run with the Reference Rasterizer?

Share this post


Link to post
Share on other sites
Quote:
Original post by clb
The viewport, by definition, is the active partition of your render target. Vertices are translated and scaled from the projection(screen) space coordinates ([-1,1] in x/y) to screen(device/display) space coordinates, which is a rectangular area of the total render target. So if you set the viewport to,say, the upper right half of the screen, the rendered image will be scaled to fit the rectangle. This translation and scaling occurs independent whether you use fixed or programmable pipeline.

I know. But it's just a scaling of (x, y) from [-1, 1][-1, 1] to the viewport dimensions in screen space, so when clipping is disabled (which prevents coordinates to go outside [-1, 1][-1, 1] before the viewport transform) it should be possible to render outside the viewport.
Quote:
Edit:
D3DRS_CLIPPING on the other hand, is used to enable/disable geometry clipping planes defined in world space. Primitives behind the plane(s) will not be rendered. I mixed this with D3DRS_CLIPPLANEENABLE, which is the world-space clipping stuff. However, neither have anything to do with viewports.

So what does D3DRS_CLIPPING really do then? Whether I enable or disable it, my geometry still gets clipped to the viewport.
Quote:
It seems you want to...

I'm just exploring the API...

Thanks!

Share this post


Link to post
Share on other sites
Quote:
Original post by don
Read up on Guard-band clipping. It might also be an issue with a scissor rect.

Guard band clipping is an implementation optimization, it doesn't have anything to do with the actual clipping behaviour of the API. I'm not using any scissor rectangles.
Quote:
Does this happen when you run with the Reference Rasterizer?

Yes.

Share this post


Link to post
Share on other sites
Here's a small test application illustrating the behaviour:

#include <d3d9.h>
#include <d3dx9.h>

HWND hwnd = 0;
LPDIRECT3D9 d3d = 0;
LPDIRECT3DDEVICE9 device = 0;
LPDIRECT3DVERTEXBUFFER9 vertexBuffer = 0;
LPDIRECT3DINDEXBUFFER9 indexBuffer = 0;

float spinX = 0.0f;
float spinY = 0.0f;

struct Vertex
{
float x;
float y;
float z;
DWORD color;

enum FVF
{
FVF_Flags = D3DFVF_XYZ | D3DFVF_DIFFUSE
};
};

Vertex cubeVertices[] =
{
{-1.0f, 1.0f,-1.0f, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0) }, // 0
{ 1.0f, 1.0f,-1.0f, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0) }, // 1
{-1.0f,-1.0f,-1.0f, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0) }, // 2
{ 1.0f,-1.0f,-1.0f, D3DCOLOR_COLORVALUE(1.0, 1.0, 0.0, 1.0) }, // 3
{-1.0f, 1.0f, 1.0f, D3DCOLOR_COLORVALUE(1.0, 0.0, 1.0, 1.0) }, // 4
{-1.0f,-1.0f, 1.0f, D3DCOLOR_COLORVALUE(0.0, 1.0, 1.0, 1.0) }, // 5
{ 1.0f, 1.0f, 1.0f, D3DCOLOR_COLORVALUE(1.0, 1.0, 1.0, 1.0) }, // 6
{ 1.0f,-1.0f, 1.0f, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0) } // 7
};

WORD cubeIndices[] =
{
0, 1, 2, 3, // Quad 0
4, 5, 6, 7, // Quad 1
4, 6, 0, 1, // Quad 2
5, 2, 7, 3, // Quad 3
1, 6, 3, 7, // Quad 4
0, 2, 4, 5 // Quad 5
};

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void init(void);
void shutDown(void);
void render(void);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX windowClass;
MSG message;

memset(&message, 0, sizeof(message));

windowClass.lpszClassName = "MY_WINDOWS_CLASS";
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WindowProc;
windowClass.hInstance = hInstance;
windowClass.hIcon = 0;
windowClass.hIconSm = 0;
windowClass.hCursor = LoadCursor(0, IDC_ARROW);
windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
windowClass.lpszMenuName = 0;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;

if(!RegisterClassEx(&windowClass)) return E_FAIL;

hwnd = CreateWindowEx(0, "MY_WINDOWS_CLASS", "Viewport test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, hInstance, 0);

if(hwnd == 0) return E_FAIL;

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

init();

while(message.message != WM_QUIT)
{
if(PeekMessage(&message, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
else
{
render();
}
}

shutDown();

UnregisterClass("MY_WINDOWS_CLASS", windowClass.hInstance);

return message.wParam;
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static POINT previousMousePosition;
static POINT currentMousePosition;
static bool mousing;

switch(msg)
{
case WM_KEYDOWN:
if(wParam == VK_ESCAPE)
{
PostQuitMessage(0);
}
break;
case WM_LBUTTONDOWN:
previousMousePosition.x = currentMousePosition.x = LOWORD(lParam);
previousMousePosition.y = currentMousePosition.y = HIWORD(lParam);
mousing = true;
break;
case WM_LBUTTONUP:
mousing = false;
break;
case WM_MOUSEMOVE:
currentMousePosition.x = LOWORD(lParam);
currentMousePosition.y = HIWORD(lParam);

if(mousing)
{
spinX -= (currentMousePosition.x - previousMousePosition.x);
spinY -= (currentMousePosition.y - previousMousePosition.y);
}

previousMousePosition.x = currentMousePosition.x;
previousMousePosition.y = currentMousePosition.y;
break;
case WM_CLOSE:
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}

return 0;
}

void init(void)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);

D3DDISPLAYMODE d3ddm;

d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));

d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);

device->SetRenderState(D3DRS_LIGHTING, FALSE);
device->SetRenderState(D3DRS_ZENABLE, TRUE);
device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);

device->CreateVertexBuffer(8*sizeof(Vertex), D3DUSAGE_WRITEONLY | D3DUSAGE_DONOTCLIP, Vertex::FVF_Flags, D3DPOOL_DEFAULT, &vertexBuffer, 0);

void *vertices = 0;

vertexBuffer->Lock(0, sizeof(cubeVertices), &vertices, 0);
memcpy(vertices, cubeVertices, sizeof(cubeVertices));
vertexBuffer->Unlock();

device->CreateIndexBuffer(24 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &indexBuffer, 0);

void *indices = 0;
indexBuffer->Lock(0, sizeof(cubeIndices), &indices, 0);
memcpy(indices, cubeIndices, sizeof(cubeIndices));
indexBuffer->Unlock();
}

void shutDown(void)
{
if(vertexBuffer != 0) vertexBuffer->Release();
if(indexBuffer != 0) indexBuffer->Release();
if(device != 0) device->Release();
if(d3d != 0) d3d->Release();
}

void render(void)
{
D3DVIEWPORT9 viewport;

viewport.X = 0;
viewport.Y = 0;
viewport.Width = 320;
viewport.Height = 480;
viewport.MinZ = 0;
viewport.MaxZ = 1;

device->SetViewport(&viewport);
device->SetRenderState(D3DRS_CLIPPING, FALSE);

D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH(&matProj, 45.0f, 640.0f / 480.0f, 0.1f, 100.0f);
// Scale and translate back to the center of the window
matProj._11 *= 2;
matProj._31 = 1;
device->SetTransform(D3DTS_PROJECTION, &matProj);

device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE(0.0f,0.0f,0.0f,1.0f), 1.0f, 0);

D3DXMATRIX matTrans;
D3DXMATRIX matRot;
D3DXMATRIX matWorld;

D3DXMatrixTranslation(&matTrans, 0.0f, 0.0f, 4.0f);

D3DXMatrixRotationYawPitchRoll(&matRot, D3DXToRadian(spinX), D3DXToRadian(spinY), 0.0f);
matWorld = matRot * matTrans;
device->SetTransform(D3DTS_WORLD, &matWorld);

device->BeginScene();

device->SetStreamSource(0, vertexBuffer, 0, sizeof(Vertex));
device->SetIndices(indexBuffer);
device->SetFVF(Vertex::FVF_Flags);

device->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, 8, 0, 2);
device->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, 8, 4, 2);
device->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, 8, 8, 2);
device->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, 8, 12, 2);
device->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, 8, 16, 2);
device->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, 8, 20, 2);

device->EndScene();
device->Present(0, 0, 0, 0);
}


You can spin the cube with the mouse. In render(), the viewport is set to the left half of the window, and clipping is disabled. The perspective transform positions the cube back to the center of the window, but because clipping is somehow still active you can only see the left half of it.

Share this post


Link to post
Share on other sites
I dont have an installed SDK to hand, so I might be wrong... but I think you'll need to check out the other D3DXMatrixPerspective**() functions.

I've done this before to implement different (but similar in implementation) effects to the one you describe. Post projection transform your geometry will be in -1...+1 coordinates, the viewport matrix will then remap these to your 0..w and 0..h rasterization coordinates.

Off the top of my head, the D3DXMatrixPerspectiveOffCenterLH() (or similar) allows you to specify a top-left and bottom-right rather than just a height/width.

The SDK documentation should have details on the viewport matrix so you can see the mathemagical details if needs be.

hth
Jack

Share this post


Link to post
Share on other sites
The guard band was a feature that showed up on pre-TNL hardware that allowed apps to disable software clipping and throw the polys that crossed a viewport edge down to the hardware for rasterization and not have to worry about them being clipped.

As you're probably aware, what you want to do is resize your viewport to the render target rect and then draw your polygons. That will give you the result you seem to want.

Share this post


Link to post
Share on other sites
Quote:
Original post by donAs you're probably aware, what you want to do is resize your viewport to the render target rect and then draw your polygons. That will give you the result you seem to want.

I'm sorry but I don't want a result other than understanding the interaction between viewports and clipping for the Direct3D API. More specifically, I want to know what D3DRS_CLIPPING does or doesn't do. So far it doesn't seem to do anything, while the theory and the API documentation tell me it should allow the geometry to be rendered outside the viewport.

Share this post


Link to post
Share on other sites
I think I figured it out... D3DRS_CLIPPING is a legacy render state from the times when clipping was still mostly done in software. On modern hardware it's simply ignored and clipping is always enabled. I think this is what you were trying to tell me with the guard-band clipping, but I didn't know that it was always implicitely enabled.

I think it's very odd that they've kept this in Direct3D 9. I don't think there's any hardware with a DX9 driver that can't do hardware clipping. Even if it does exist, I doubt there's any application still doing its own clipping...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!