[DX9] Postprocessing

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Mr. S
Beiträge: 27
Registriert: 09.06.2011, 09:06

[DX9] Postprocessing

Beitrag von Mr. S »

Hallo zusammen,

ich habe eine Minimalanwendung mit DX9 auf Basis der Tutorials im SDK geschrieben. Das Ziel ist es zu lernen wie Postprocessing funktioniert.
dxtest.png
Aktuell möchte ich mit dem Shader einfach nur das Bild in Graustufen umwandeln. Später soll das Bild über mathematische Funktionen auch noch verzerrt werden.Leider befinde ich mich gerade in einer Sackgasse. Hoffentlich kann mir hier jemand helfen.

Code: Alles auswählen

#include <Windows.h>
#include <tchar.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <d3d9.h>
#include <D3dx9tex.h>

#pragma comment(lib, "D3d9.lib")
#pragma comment(lib, "D3dx9.lib")
#pragma comment(lib, "Winmm.lib")

HINSTANCE               g_hInst = NULL;
HWND                    g_hWnd = NULL;
LPDIRECT3D9				g_pD3D = NULL;
LPDIRECT3DDEVICE9		g_pd3dDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
LPDIRECT3DTEXTURE9      g_pObjectTexture = NULL;
LPDIRECT3DTEXTURE9      g_pRenderTexture = NULL;
LPD3DXEFFECT			g_pEffect = NULL;

typedef struct
{
	D3DXVECTOR3 position;	// The position
	D3DCOLOR color;			// The color
	FLOAT tu, tv;			// The texture coordinates
} CUSTOMVERTEX;

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)

char* g_Shader = "texture g_txSrcColor;\n"
"\n"
"sampler2D g_samSrcColor =\n"
"sampler_state\n"
"{\n"
"    Texture = <g_txSrcColor>;\n"
"    AddressU = Clamp;\n"
"    AddressV = Clamp;\n"
"    MinFilter = Point;\n"
"    MagFilter = Linear;\n"
"    MipFilter = Linear;\n"
"};\n"
"\n"
"float3 LuminanceConv = { 0.2125f, 0.7154f, 0.0721f };\n"
"\n"
"float4 PostProcessPS( float2 Tex : TEXCOORD0 ) : COLOR0\n"
"{\n"
"    return dot( (float3)tex2D( g_samSrcColor, Tex ), LuminanceConv );\n"
"}\n"
"\n"
"technique PostProcess\n"
"{\n"
"    pass p0\n"
"    {\n"
"        VertexShader = null;\n"
"        PixelShader = compile ps_2_0 PostProcessPS();\n"
"        ZEnable = false;\n"
"    }\n"
"}\n";

BOOL CreateScene()
{
	// Use D3DX to create a texture from a file based image
	if(FAILED(D3DXCreateTextureFromFile(g_pd3dDevice, _T("banana.bmp"), &g_pObjectTexture)))
	{
		// If texture is not in current folder, try parent folder
		if(FAILED( D3DXCreateTextureFromFile(g_pd3dDevice, _T("..\\banana.bmp"), &g_pObjectTexture)))
		{
			MessageBox(NULL, _T("Could not find banana.bmp"), _T("Error"), MB_OK);
			return FALSE;
		}
	}

	// Create the vertex buffer.
	if(FAILED(g_pd3dDevice->CreateVertexBuffer(50 * 2 * sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL))) return FALSE;

	// Fill the vertex buffer. We are setting the tu and tv texture
	// coordinates, which range from 0.0 to 1.0
	CUSTOMVERTEX* pVertices;
	if(FAILED( g_pVB->Lock(0, 0, ( void** )&pVertices, 0))) return FALSE;
	for(DWORD i = 0; i < 50; i++)
	{
		FLOAT theta = ( 2 * M_PI * i ) / ( 50 - 1 );

		pVertices[2 * i + 0].position .x = sinf(theta);
		pVertices[2 * i + 0].position .y = -1.0f;
		pVertices[2 * i + 0].position .z = cosf(theta);
		pVertices[2 * i + 0].color = 0xffffffff;
		pVertices[2 * i + 0].tu = ((FLOAT)i) / 49;
		pVertices[2 * i + 0].tv = 1.0f;
		pVertices[2 * i + 1].position.x = sinf(theta);
		pVertices[2 * i + 1].position.y = 1.0f;
		pVertices[2 * i + 1].position.z = cosf(theta);
		pVertices[2 * i + 1].color = 0xff808080;
		pVertices[2 * i + 1].tu = ((FLOAT)i) / 49;
		pVertices[2 * i + 1].tv = 0.0f;
	}
	g_pVB->Unlock();

	// Create the effect
	DWORD dwShaderFlags = 0;
	dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
	dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
	dwShaderFlags |= D3DXSHADER_NO_PRESHADER;
#ifdef _DEBUG
	dwShaderFlags |= D3DXSHADER_DEBUG;
#endif

	ID3DXBuffer* err = NULL;
	if(FAILED(D3DXCreateEffect(g_pd3dDevice, g_Shader, strlen(g_Shader), NULL, NULL, 0, NULL, &g_pEffect, &err))) return FALSE;

	g_pEffect->SetTexture("g_txSrcColor", g_pRenderTexture);

	return TRUE;
}

void Render()
{
	if(NULL == g_pd3dDevice) return;

	// Clear the backbuffer to a blue color
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

	// Begin the scene
	if(SUCCEEDED(g_pd3dDevice->BeginScene()))
	{
		D3DXMATRIXA16 matWorld;
		D3DXMatrixIdentity(&matWorld);
		D3DXMatrixRotationX(&matWorld, timeGetTime() / 1000.0f);
		g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);

		D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );
		D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
		D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
		D3DXMATRIXA16 matView;
		D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec);
		g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);

		D3DXMATRIXA16 matProj;
		D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f);
		g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);

		g_pd3dDevice->SetTexture(0, g_pObjectTexture);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

		g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
		g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);

		//begin the effect 
		UINT uiPasses = 0;
		g_pEffect->Begin(&uiPasses, 0);
		for (UINT uiPass = 0; uiPass < uiPasses; uiPass++)
		{
			//render an effect pass
			g_pEffect->BeginPass(uiPass);
			
			//render the rectangle 
			g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2 * 50 - 2);
			
			g_pEffect->EndPass();
		}
		g_pEffect->End();

		g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2 * 50 - 2);

		g_pd3dDevice->EndScene();
	}

	// Present the backbuffer contents to the display
	g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	PAINTSTRUCT ps;
	HDC hdc;
	
	switch (message) 
	{
		case WM_PAINT:
			hdc = BeginPaint(hWnd, &ps);
			EndPaint(hWnd, &ps);
			break;
	
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
	
		case WM_KEYDOWN:
			if(wParam == VK_ESCAPE) PostQuitMessage(0);
			break;

		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}
	
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	//
	// Register class
	//
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style          = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc    = WndProc;
	wcex.cbClsExtra     = 0;
	wcex.cbWndExtra     = 0;
	wcex.hInstance      = hInstance;
	wcex.hIcon          = LoadIcon(NULL, (LPCTSTR)IDI_APPLICATION);
	wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName   = NULL;
	wcex.lpszClassName  = _T("DXTest");
	wcex.hIconSm        = LoadIcon(NULL, (LPCTSTR)IDI_APPLICATION);
	if(!RegisterClassEx(&wcex)) return FALSE;

	//
	// Create window
	//
	g_hInst = hInstance;
	RECT rc = { 0, 0, 800, 600 };
	AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE);
	g_hWnd = CreateWindow(wcex.lpszClassName, _T("DirectX Test"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL);
	if(!g_hWnd)
		return FALSE;
	else
		ShowWindow(g_hWnd, nShowCmd);

	//
	// Init D3D
	//
	if(NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) return FALSE;

	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

	if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice)))
	{
		return FALSE;
	}

	g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
	g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
	g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);

	//
	// Create content
	//
	if(CreateScene() == FALSE) return FALSE;

	//
	// Main message loop
	//
	MSG msg = {0};
	while(WM_QUIT != msg.message )
	{
		if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
		else
		{
			Render();
		}
	}

	//
	// Cleanup D3D
	//
	if(g_pObjectTexture != NULL) g_pObjectTexture->Release();
	if(g_pEffect != NULL) g_pEffect->Release();
	if(g_pRenderTexture != NULL) g_pRenderTexture->Release();
	if(g_pVB != NULL) g_pVB->Release();
	if(g_pd3dDevice != NULL) g_pd3dDevice->Release();
	if(g_pD3D != NULL) g_pD3D->Release();

	UnregisterClass(wcex.lpszClassName, wcex.hInstance);
	return (int)msg.wParam;
}
Wenn ich es richtig verstanden habe muss die Szene in/auf eine Textur (g_pRenderTexture) gerendert werden, welche als Argument an den Effekt übergeben wird, oder? Wie macht man das?

THX
Mr. S
Specialist
Establishment
Beiträge: 135
Registriert: 29.08.2003, 14:22
Kontaktdaten:

Re: [DX9] Postprocessing

Beitrag von Specialist »

Du erstellst dir eine Texture mit CreateTexture(), holst dir davon die Surface und setzt sie als Rendertarget. Dann renderst du deine Szene quasi autimatisch in diese Textur ohne dass die Szene erstmal auf dem Monitor erscheint.
Anschließend kannst du die Textur mit deiner Szene nehmen und auf ein Fullscreenquad, also ein Rechteck, das so groß ist wie dein Fenster rendern.
In diesem Schritt kannst du die Textur per Shader natürlich beliebig verändert, z.B. deinen gewünschten Schwarz-Weiß-Effekt drauflegen.
Graustufen erhälst du indem du einfach den Durchschnitt der drei Farbwerte eines Pixels ausgiebst.
Mr. S
Beiträge: 27
Registriert: 09.06.2011, 09:06

Re: [DX9] Postprocessing

Beitrag von Mr. S »

Vielen Dank für die Hilfe! Ich habe jetzt ein Surface mit Textur erstellt. Aber es funktioniert nicht. Ich bekomme jetzt einfach ein leeres Fenster. Was habe ich falsch gemacht?

Code: Alles auswählen

#include <Windows.h>
#include <tchar.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <d3d9.h>
#include <D3dx9tex.h>

#pragma comment(lib, "D3d9.lib")
#pragma comment(lib, "D3dx9.lib")
#pragma comment(lib, "Winmm.lib")

HINSTANCE				g_hInst = NULL;
HWND					g_hWnd = NULL;
RECT					g_rcSize = { 0, 0, 800, 600 };
LPDIRECT3D9				g_pD3D = NULL;
LPDIRECT3DDEVICE9		g_pd3dDevice = NULL;
LPDIRECT3DVERTEXBUFFER9	g_pVBGeometry = NULL;
LPDIRECT3DVERTEXBUFFER9	g_pVBPostProcess = NULL;
LPDIRECT3DTEXTURE9		g_pObjectTexture = NULL;
LPDIRECT3DTEXTURE9		g_pRenderTexture = NULL;
LPDIRECT3DSURFACE9		g_pRenderSurface = NULL;
LPDIRECT3DSURFACE9		g_pOrigTargetSurface = NULL;
LPD3DXEFFECT			g_pEffect = NULL;

typedef struct
{
	D3DXVECTOR3 position;	// The position
	D3DCOLOR color;			// The color
	FLOAT tu, tv;			// The texture coordinates
} CUSTOMVERTEX;

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)

typedef struct
{
	float x, y, z, rhw;
	float tu, tv;       // Texcoord for post-process source
} PPVERT;

#define D3DFVF_PPVERT (D3DFVF_XYZRHW | D3DFVF_TEX1)

char* g_Shader = "texture g_txSrcColor;\n"
"\n"
"sampler2D g_samSrcColor =\n"
"sampler_state\n"
"{\n"
"    Texture = <g_txSrcColor>;\n"
"    AddressU = Clamp;\n"
"    AddressV = Clamp;\n"
"    MinFilter = Point;\n"
"    MagFilter = Linear;\n"
"    MipFilter = Linear;\n"
"};\n"
"\n"
"float3 LuminanceConv = { 0.2125f, 0.7154f, 0.0721f };\n"
"\n"
"float4 PostProcessPS( float2 Tex : TEXCOORD0 ) : COLOR0\n"
"{\n"
"    return dot( (float3)tex2D( g_samSrcColor, Tex ), LuminanceConv );\n"
"}\n"
"\n"
"technique PostProcess\n"
"{\n"
"    pass p0\n"
"    {\n"
"        VertexShader = null;\n"
"        PixelShader = compile ps_2_0 PostProcessPS();\n"
"        ZEnable = false;\n"
"    }\n"
"}\n";

BOOL CreateScene()
{
	// Use D3DX to create a texture from a file based image
	if(FAILED(D3DXCreateTextureFromFile(g_pd3dDevice, _T("banana.bmp"), &g_pObjectTexture)))
	{
		// If texture is not in current folder, try parent folder
		if(FAILED( D3DXCreateTextureFromFile(g_pd3dDevice, _T("..\\banana.bmp"), &g_pObjectTexture)))
		{
			MessageBox(NULL, _T("Could not find banana.bmp"), _T("Error"), MB_OK);
			return FALSE;
		}
	}

	// Create RTT
	if(FAILED(D3DXCreateTexture(g_pd3dDevice, g_rcSize.right - g_rcSize.left, g_rcSize.bottom - g_rcSize.top, D3DUSAGE_DYNAMIC, 1, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &g_pRenderTexture))) return FALSE;
	g_pd3dDevice->GetRenderTarget(0, &g_pOrigTargetSurface);
	D3DSURFACE_DESC desc;
	g_pOrigTargetSurface->GetDesc(&desc);
	if(FAILED(g_pd3dDevice->CreateRenderTarget(g_rcSize.right - g_rcSize.left, g_rcSize.bottom - g_rcSize.top, D3DFMT_X8R8G8B8, desc.MultiSampleType, desc.MultiSampleQuality, false, &g_pRenderSurface, NULL))) return FALSE;
	g_pRenderTexture->GetSurfaceLevel(0, &g_pRenderSurface);

	// Create the effect
	DWORD dwShaderFlags = 0;
	dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
	dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
	dwShaderFlags |= D3DXSHADER_NO_PRESHADER;
#ifdef _DEBUG
	dwShaderFlags |= D3DXSHADER_DEBUG;
#endif

	ID3DXBuffer* err = NULL;
	if(FAILED(D3DXCreateEffect(g_pd3dDevice, g_Shader, strlen(g_Shader), NULL, NULL, 0, NULL, &g_pEffect, &err))) return FALSE;

	g_pEffect->SetTexture("g_txSrcColor", g_pRenderTexture);

	// Create the post-process vertex buffer.
	if(FAILED(g_pd3dDevice->CreateVertexBuffer(6 * sizeof(PPVERT), 0, D3DFVF_PPVERT, D3DPOOL_DEFAULT, &g_pVBPostProcess, NULL))) return FALSE;
	PPVERT quad[] =
	{
		{ 0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.0f },
		{ (FLOAT)(g_rcSize.right - g_rcSize.left), 0.0f, 0.5f, 1.0f, 1.0f, 0.0f },
		{ (FLOAT)(g_rcSize.right - g_rcSize.left), (FLOAT)(g_rcSize.bottom - g_rcSize.top), 0.5f, 1.0f, 1.0f, 1.0f },
		{ 0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.0f },
		{ (FLOAT)(g_rcSize.right - g_rcSize.left), (FLOAT)(g_rcSize.bottom - g_rcSize.top), 0.5f, 1.0f, 1.0f, 1.0f },
		{ 0.0f, (FLOAT)(g_rcSize.bottom - g_rcSize.top), 0.5f, 1.0f, 0.0f, 1.0f }
	};
	PPVERT* pOutputVertices;
	if(FAILED(g_pVBPostProcess->Lock(0, 0, (void**)&pOutputVertices, 0))) return FALSE;
	memcpy(pOutputVertices, quad, sizeof(quad));
	g_pVBPostProcess->Unlock();

	// +++ SCENE +++

	// Create the object vertex buffer.
	if(FAILED(g_pd3dDevice->CreateVertexBuffer(50 * 2 * sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVBGeometry, NULL))) return FALSE;

	// Fill the vertex buffer. We are setting the tu and tv texture
	// coordinates, which range from 0.0 to 1.0
	CUSTOMVERTEX* pVertices;
	if(FAILED(g_pVBGeometry->Lock(0, 0, (void**)&pVertices, 0))) return FALSE;
	for(DWORD i = 0; i < 50; i++)
	{
		FLOAT theta = (FLOAT)(2.0 * M_PI * (double)i) / 49.0f;

		pVertices[2 * i + 0].position .x = sinf(theta);
		pVertices[2 * i + 0].position .y = -1.0f;
		pVertices[2 * i + 0].position .z = cosf(theta);
		pVertices[2 * i + 0].color = 0xffffffff;
		pVertices[2 * i + 0].tu = ((FLOAT)i) / 49;
		pVertices[2 * i + 0].tv = 1.0f;
		pVertices[2 * i + 1].position.x = sinf(theta);
		pVertices[2 * i + 1].position.y = 1.0f;
		pVertices[2 * i + 1].position.z = cosf(theta);
		pVertices[2 * i + 1].color = 0xff808080;
		pVertices[2 * i + 1].tu = ((FLOAT)i) / 49;
		pVertices[2 * i + 1].tv = 0.0f;
	}
	g_pVBGeometry->Unlock();

	return TRUE;
}

void Render()
{
	if(NULL == g_pd3dDevice) return;

	// Set render target
	g_pd3dDevice->SetRenderTarget(0, g_pRenderSurface);

	// Clear the backbuffer to a blue color
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

	// Begin the scene
	if(SUCCEEDED(g_pd3dDevice->BeginScene()))
	{
		D3DXMATRIXA16 matWorld;
		D3DXMatrixIdentity(&matWorld);
		D3DXMatrixRotationX(&matWorld, timeGetTime() / 1000.0f);
		g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);

		D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );
		D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
		D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
		D3DXMATRIXA16 matView;
		D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec);
		g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);

		D3DXMATRIXA16 matProj;
		D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f);
		g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);

		g_pd3dDevice->SetTexture(0, g_pObjectTexture);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

		g_pd3dDevice->SetStreamSource(0, g_pVBGeometry, 0, sizeof(CUSTOMVERTEX));
		g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
		g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2 * 50 - 2);

		g_pd3dDevice->EndScene();
	}

	// restore original render target
	g_pd3dDevice->SetRenderTarget(0, g_pOrigTargetSurface);

	// Clear the backbuffer to a blue color
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

	// Begin the scene
	if(SUCCEEDED(g_pd3dDevice->BeginScene()))
	{
		g_pd3dDevice->SetTexture(0, g_pRenderTexture);

		// begin the effect 
		g_pEffect->SetTexture("g_txSrcColor", g_pRenderTexture);
		g_pEffect->SetTechnique(g_pEffect->GetTechniqueByName("PostProcess"));

		UINT uiPasses = 0;
		g_pEffect->Begin(&uiPasses, 0);
		for (UINT uiPass = 0; uiPass < uiPasses; uiPass++)
		{
			// render an effect pass
			g_pEffect->BeginPass(uiPass);
			
			// render the rectangle 
			g_pd3dDevice->SetStreamSource(0, g_pVBGeometry, 0, sizeof(PPVERT));
			g_pd3dDevice->SetFVF(D3DFVF_PPVERT);
			g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
			
			g_pEffect->EndPass();
		}
		g_pEffect->End();
		
		g_pd3dDevice->SetTexture(0, NULL);

		g_pd3dDevice->EndScene();
	}

	// Present the backbuffer contents to the display
	g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	PAINTSTRUCT ps;
	HDC hdc;
	
	switch (message) 
	{
		case WM_PAINT:
			hdc = BeginPaint(hWnd, &ps);
			EndPaint(hWnd, &ps);
			break;
	
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
	
		case WM_KEYDOWN:
			if(wParam == VK_ESCAPE) PostQuitMessage(0);
			break;

		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}
	
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	//
	// Register class
	//
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style          = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc    = WndProc;
	wcex.cbClsExtra     = 0;
	wcex.cbWndExtra     = 0;
	wcex.hInstance      = hInstance;
	wcex.hIcon          = LoadIcon(NULL, (LPCTSTR)IDI_APPLICATION);
	wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName   = NULL;
	wcex.lpszClassName  = _T("DXTest");
	wcex.hIconSm        = LoadIcon(NULL, (LPCTSTR)IDI_APPLICATION);
	if(!RegisterClassEx(&wcex)) return FALSE;

	//
	// Create window
	//
	g_hInst = hInstance;
	AdjustWindowRect(&g_rcSize, WS_OVERLAPPEDWINDOW, FALSE);
	g_hWnd = CreateWindow(wcex.lpszClassName, _T("DirectX Test"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, g_rcSize.right - g_rcSize.left, g_rcSize.bottom - g_rcSize.top, NULL, NULL, hInstance, NULL);
	if(!g_hWnd)
		return FALSE;
	else
		ShowWindow(g_hWnd, nShowCmd);

	//
	// Init D3D
	//
	if(NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) return FALSE;

	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.BackBufferWidth = g_rcSize.right - g_rcSize.left;
	d3dpp.BackBufferHeight = g_rcSize.bottom - g_rcSize.top;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

	if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice)))
	{
		return FALSE;
	}

	g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
	g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
	g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);

	//
	// Create content
	//
	if(CreateScene() == FALSE) return FALSE;

	//
	// Main message loop
	//
	MSG msg = {0};
	while(WM_QUIT != msg.message )
	{
		if( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
		else
		{
			Render();
		}
	}

	//
	// Cleanup D3D
	//
	if(g_pObjectTexture != NULL) g_pObjectTexture->Release();
	if(g_pEffect != NULL) g_pEffect->Release();
	if(g_pRenderTexture != NULL) g_pRenderTexture->Release();
	if(g_pVBGeometry != NULL) g_pVBGeometry->Release();
	if(g_pd3dDevice != NULL) g_pd3dDevice->Release();
	if(g_pD3D != NULL) g_pD3D->Release();

	UnregisterClass(wcex.lpszClassName, wcex.hInstance);
	return (int)msg.wParam;
}
Benutzeravatar
Schrompf
Moderator
Beiträge: 4855
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [DX9] Postprocessing

Beitrag von Schrompf »

Du musst Deine Renderziel-Textur mit D3DUSAGE_RENDERTARGET anstatt D3DUSAGE_DYNAMIC erstellen. Lies hier nochmal nach, was die Flags bedeuten.

Und warum erzeugst Du aus der OrigTargetSurface nochmal ein Rendertarget? Die OrigTargetSurface ist bereits das Rendertarget des Standard-Backbuffers, genau die willst Du haben, wenn Du Dinge ins eigene Fenster rendern willst.

Schalte im DirectX Control Panel (Startmenü) mal die Debug Runtime an, dann sollten bei Visual Studio genaue Fehlermeldungen kommen, was Du falsch machst. Er müsst dort zumindest bei den jeweiligen SetRenderTarget()-Aufrufen meckern.

Für später:
Lass das SetTextureStageState()-Gedöns sein und schreib einen PixelShader. Als ich das das letzte Mal ausprobiert habe (schon viele Jahre her), haben alle Treiber Probleme gehabt, nach einem PixelShader wieder zurück auf die Fixed Pipeline zu schalten. Und da die eh schon seit einem Jahrzehnt ausgestorben ist, kommst Du besser, sowas gleich seinzulassen. Das Gleiche gilt für FVFs - lösche den Mist und erstelle saubere Vertex Input Declarations.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8240
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [DX9] Postprocessing

Beitrag von Krishty »

Volle Zustimmung bei Shadern.

Gegen FVF spricht aber doch nicht viel, oder? Wenn man eine einfache Vertex-Datenstruktur hat, verbraucht das nur einen Bruchteil des Quell- und Maschinentexts einer Vertex Declaration. Bei allem weiterführenden (andere Komponenten als float) müsste man eh erstmal in den Caps prüfen, ob die Plattform das kennt.

Es ist nur wichtig zu verstehen, dass es sich dabei um ein Array von Bits handelt, die man mit Konstanten setzt; und dass man deshalb die Komponenten nicht in beliebiger Reihenfolge liefern darf.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4855
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [DX9] Postprocessing

Beitrag von Schrompf »

Gut, Geschmackssache. Ich mag Vertex-Eingabedeklarationen halt lieber, weil da explizit da steht, welche Daten in welchem Format wo liegen. FVFs funktionieren nur wegen einer Menge impliziter Festlegungen, die ich nicht immer so präsent habe, dass ich fehlerfrei damit arbeiten könnte. Und sobald Normal Mapping oder irgendwas dazu kommt, ist für FVFs eh der Ofen aus.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Mr. S
Beiträge: 27
Registriert: 09.06.2011, 09:06

Re: [DX9] Postprocessing

Beitrag von Mr. S »

Erst einmal vielen Dank für die rasche Hilfe! :!:
Schrompf hat geschrieben:Du musst Deine Renderziel-Textur mit D3DUSAGE_RENDERTARGET anstatt D3DUSAGE_DYNAMIC erstellen. Lies hier nochmal nach, was die Flags bedeuten.
Ups, da habe ich nicht aufgepasst. Copy & Paste halt ohne nachzudenken. :oops:
Schrompf hat geschrieben:Und warum erzeugst Du aus der OrigTargetSurface nochmal ein Rendertarget? Die OrigTargetSurface ist bereits das Rendertarget des Standard-Backbuffers, genau die willst Du haben, wenn Du Dinge ins eigene Fenster rendern willst.
Hm, das verstehe ich nicht. Es werden doch zwei Targets benötigt, oder nicht? Einmal das Target um die Szene zu rendern und einmal das Target um die gerenderte Textur zu rendern. :?:
Schrompf hat geschrieben:Schalte im DirectX Control Panel (Startmenü) mal die Debug Runtime an, dann sollten bei Visual Studio genaue Fehlermeldungen kommen, was Du falsch machst. Er müsst dort zumindest bei den jeweiligen SetRenderTarget()-Aufrufen meckern.
Danke für den Tipp! SetRenderTarget läuft einwandfrei, nur beim zweiten DrawPrimitive meckert er:
Direct3D9: (ERROR) :Current vertex shader declaration doesn't match VB's FVF
Schrompf hat geschrieben:Für später:
Lass das SetTextureStageState()-Gedöns sein und schreib einen PixelShader. Als ich das das letzte Mal ausprobiert habe (schon viele Jahre her), haben alle Treiber Probleme gehabt, nach einem PixelShader wieder zurück auf die Fixed Pipeline zu schalten. Und da die eh schon seit einem Jahrzehnt ausgestorben ist, kommst Du besser, sowas gleich seinzulassen. Das Gleiche gilt für FVFs - lösche den Mist und erstelle saubere Vertex Input Declarations.
Ich habe (noch) nicht so viel Ahnung von Shadern, daher verstehe ich gerade nur Bahnhof. :?
Benutzeravatar
Schrompf
Moderator
Beiträge: 4855
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [DX9] Postprocessing

Beitrag von Schrompf »

Mr. S hat geschrieben:Erst einmal vielen Dank für die rasche Hilfe! :!:
Gerne doch.
Schrompf hat geschrieben:Und warum erzeugst Du aus der OrigTargetSurface nochmal ein Rendertarget? Die OrigTargetSurface ist bereits das Rendertarget des Standard-Backbuffers, genau die willst Du haben, wenn Du Dinge ins eigene Fenster rendern willst.
Hm, das verstehe ich nicht. Es werden doch zwei Targets benötigt, oder nicht? Einmal das Target um die Szene zu rendern und einmal das Target um die gerenderte Textur zu rendern. :?:
Korrekt, es werden zwei Targets gebraucht. Aber Du als Programmierer erzeugst in Deinem Code nur eins davon direkt, nämlich die Rendertarget-Textur. Das andere Rendertarget wird implizit bei CreateDevice() erzeugt. Du holst es Dir direkt in der Erzeugung mittels

Code: Alles auswählen

 g_pd3dDevice->GetRenderTarget(0, &g_pOrigTargetSurface);
Und das reicht. Diese g_pOrigTargetSurface ist das, was Du nachher SetRenderTarget() in die Hand drückst, um das Fenster als Renderziel zu bestimmen. Das GetDesc() und CreateRenderTarget() dahinter in Deinem Code kannst Du knicken.
Schrompf hat geschrieben:Schalte im DirectX Control Panel (Startmenü) mal die Debug Runtime an, dann sollten bei Visual Studio genaue Fehlermeldungen kommen, was Du falsch machst. Er müsst dort zumindest bei den jeweiligen SetRenderTarget()-Aufrufen meckern.
Danke für den Tipp! SetRenderTarget läuft einwandfrei, nur beim zweiten DrawPrimitive meckert er:
Direct3D9: (ERROR) :Current vertex shader declaration doesn't match VB's FVF
Hier bin ich überfragt. Laut Deinem Code benutzt Du D3DFVF_PPVERT sowohl beim Erzeugen des VertexBuffers als auch beim Rendern nachher, es müsste also zusammenpassen. Vielleicht hat das D3DFVF_XYZRHW, was Du da verwendest, irgendne spezielle Bedeutung... ich habe keine Ahnung. Wie gesagt, Du benutzt da Zeug, was seit 10 Jahren ausgestorben ist. Entsprechend dünn sind auch meine Kenntnisse von der Materie.
Schrompf hat geschrieben:Für später:
Lass das SetTextureStageState()-Gedöns sein und schreib einen PixelShader. Als ich das das letzte Mal ausprobiert habe (schon viele Jahre her), haben alle Treiber Probleme gehabt, nach einem PixelShader wieder zurück auf die Fixed Pipeline zu schalten. Und da die eh schon seit einem Jahrzehnt ausgestorben ist, kommst Du besser, sowas gleich seinzulassen. Das Gleiche gilt für FVFs - lösche den Mist und erstelle saubere Vertex Input Declarations.
Ich habe (noch) nicht so viel Ahnung von Shadern, daher verstehe ich gerade nur Bahnhof. :?
Ultrakurz-Abriss einer Grafikkarte auf DX9-Niveau:

Vertex Assembler: lädt pro Vertex aus den angeschlossenen VertexBuffern die Daten in die Eingaberegister des Vertex Shaders. Aus welchen Buffern er die Daten zieht und wie er die konvertiert, damit sie im VertexShader als float ankommen, beschreibt die Vertex Input Declaration.

Du benutzt aktuell FVFs, das sind im Endeffekt nur Bitkonstanten, die der Treiber dann live in eine Vertex Input Declaration umwandelt. Du kannst aber auch direkt eine VID erzeugen und dort detailliert angeben, wie die Daten in Deiner Vertexstruktur aussehen.

Vertex Shader: ist ein kleines Programm, was auf der Grafikkarte pro Vertex ausgeführt wird. Du erstellst die, indem Du etwas Code kompilierst und den entstehenden Code-Blob in einen Shader verpackst.

Stell Dir Shader wie ein Fließband vor - vorne tust Du irgendwas auf das Fließband drauf, dann rollen Deine Daten langsam in eine dunkle Kammer rein, dann hämmert und rappelt es und hinten rollen aus der dunklen Kammer andere Daten wieder raus. Im Falle des VertexShaders stehen am Anfang des Fließbandes ein oder mehrere große Container - das sind Deine VertexBuffer. Der Vertex Assembler ist ein Roboterarm, der aus den Containern jeweils Einzelteile rausnimmt und hübsch angeordnet auf das Band legt. Diese zusammengestellten Datensätze sind jeweils ein Vertex. Jeder Vertex rollt nun nacheinander in die Maschine rein, wird dort nach dem VertexShader-Programm verarbeitet und kommt hinten wieder rausgerollt.

Am Ende dieses Fließbandes hast Du den Rasterizer, der sich pro Dreieck die nächsten drei fertig verarbeiteten Datensätze vom Fließband nimmt und schaut, wo die drei Vertexpositionen auf dem Bildschirm wären. Diese drei Ecken bilden ein Dreieck auf dem Bildschirmu und der Rasterizer bestimmt, welche Pixel von dem Dreieck betroffen sind. Für jeden Pixel, den das Dreieck abdeckt, bestimmt der Rasterizer einen Datensatz, indem er die Datensätze der drei Ecken quasi anteilig zusammenmischt, je nachdem wie nah der Bildschirmpixel der jeweiligen Ecke ist. Das Ergebnis ist dann ein neuer Datensatz pro betroffenem Zielpixel.

Pixel Shader: Diese Datensätze pro Zielpixel werden dann - Du ahnst es sicher schon - wieder auf ein Fließband getan. Nämlich das des PixelShaders. Der PixelShader bekommt die Daten für jeden betroffenen Zielpixel, verarbeitet die Daten nach Deinem PixelShader-Programm, und hinten raus auf dem Fließband kommt die Farbe, die auf diesen Pixel soll.

Dahinter hast Du dann nur noch den Output Merger, der jeweils eine Pixelposition und eine Farbe dazu vom PixelShader bekommt und diese Farbe dann an der vorgegebenen Position einmassiert. Der Output Merger macht Alpha Blending und sowas.

Jede der Fließband-Maschinen, also sowohl Vertex- als auch PixelShader, haben jetzt noch weitere Daten zu Verfügung. Neben den Datenhäufchen, die per Fließband angerollt kommen, haben die Shader noch Konstantenspeicher. Das ist quasi ein Zettel mit maximal ein paar hundert Zeilen, und auf jeder Zeile stehen vier Kommazahlen. Dieser Zettel ist der Konstantenspeicher des Shaders, den Zettel beschreibst Du im Programm vorher und dann bleibt der Zettel gleich, solange das Fließband läuft. Genauso haben alle Shader zusätzlich Texturen. Die kannst Du Dir vorstellen wie die großen Kartenständer aus dem Geographie-Unterricht in der Schule. Jede Textur ist ein Kartenständer mit einer großen Karte dran. Und für jeden DrawCall schiebst Du ein paar dieser Kartenständer an die Fließband-Maschine ran, so dass die Maschine von der Karte was lesen kann, wenn sie das braucht. Und auch die Kartenständer bleiben da unverändert stehen, solange das Fließband läuft.

Wenn Du eine Grafikkarte dazu bringen willst, irgendwas zu rendern, bedeutet das folgendes:

Am Anfang erstellst Du:
Vertex Input Declaration, Vertex Shader, Pixel Shader, Vertex Buffer mit Inhalt, Index Buffer mit Inhalt, Texturen mit Inhalt

Pro DrawCall tust Du:
- Vertex Input Declaration setzen
- VertexShader setzen
- VertexBuffer anklemmen, um den VertexShader zu füttern
- evtl. IndexBuffer anklemmen
- alle Konstanten im VertexShader-Konstantenspeicher mit Werten versorgen
- PixelShader setzen
- Texturen für den PixelShader anklemmen
- alle Konstanten im PixelShader-Konstantenspeicher mit Werten versorgen
- DrawCall abfeuern

Fertig.

[edit] Ich sehe gerade, Du liest das schon. Nur als Warnung: ich habe hier ein Dutzend Mal Details korrigiert.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Mr. S
Beiträge: 27
Registriert: 09.06.2011, 09:06

Re: [DX9] Postprocessing

Beitrag von Mr. S »

Hi Schrompf,

das ist definitive die Beste Beschreibung von Vertex- und Pixelshadern die ich bisher gelesen habe. :P Vielen Dank für deine Mühe!
Schrompf hat geschrieben:Korrekt, es werden zwei Targets gebraucht. Aber Du als Programmierer erzeugst in Deinem Code nur eins davon direkt, nämlich die Rendertarget-Textur. Das andere Rendertarget wird implizit bei CreateDevice() erzeugt. Du holst es Dir direkt in der Erzeugung mittels

Code: Alles auswählen

 g_pd3dDevice->GetRenderTarget(0, &g_pOrigTargetSurface);
Und das reicht. Diese g_pOrigTargetSurface ist das, was Du nachher SetRenderTarget() in die Hand drückst, um das Fenster als Renderziel zu bestimmen. Das GetDesc() und CreateRenderTarget() dahinter in Deinem Code kannst Du knicken.
Brauche ich den kein zweites Surface für RTT? g_pOrigTargetSurface ist das Original-Surface für die Ausgabe (wird ja auch später benutzt um die Textur auf das Fenster zu rendern) während ich g_pRenderSurface erstellt habe um auf die Textur zu rendern. Muss ich nicht zuerst die Textur bzw. das passende Surface als Renderziel setzen?
Schrompf hat geschrieben:Hier bin ich überfragt. Laut Deinem Code benutzt Du D3DFVF_PPVERT sowohl beim Erzeugen des VertexBuffers als auch beim Rendern nachher, es müsste also zusammenpassen. Vielleicht hat das D3DFVF_XYZRHW, was Du da verwendest, irgendne spezielle Bedeutung... ich habe keine Ahnung. Wie gesagt, Du benutzt da Zeug, was seit 10 Jahren ausgestorben ist. Entsprechend dünn sind auch meine Kenntnisse von der Materie.
Ok, ich schaue mir einmal Vertex Declaration an. Ich habe die DX9 Grundlagen aus dem Tutorial http://www.chadvernon.com/blog/resources/directx9/ gelernt und da wird halt FVF verwendet.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4855
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [DX9] Postprocessing

Beitrag von Schrompf »

Mr. S hat geschrieben:Hi Schrompf,

das ist definitive die Beste Beschreibung von Vertex- und Pixelshadern die ich bisher gelesen habe. :P Vielen Dank für deine Mühe!
Freut mich, dass es Dir hilft. War definitiv mehr Tipparbeit, als ich eigentlich gerade investieren sollte :-)
Schrompf hat geschrieben:Korrekt, es werden zwei Targets gebraucht. Aber Du als Programmierer erzeugst in Deinem Code nur eins davon direkt, nämlich die Rendertarget-Textur. Das andere Rendertarget wird implizit bei CreateDevice() erzeugt. Du holst es Dir direkt in der Erzeugung mittels

Code: Alles auswählen

 g_pd3dDevice->GetRenderTarget(0, &g_pOrigTargetSurface);
Und das reicht. Diese g_pOrigTargetSurface ist das, was Du nachher SetRenderTarget() in die Hand drückst, um das Fenster als Renderziel zu bestimmen. Das GetDesc() und CreateRenderTarget() dahinter in Deinem Code kannst Du knicken.
Brauche ich den kein zweites Surface für RTT? g_pOrigTargetSurface ist das Original-Surface für die Ausgabe (wird ja auch später benutzt um die Textur auf das Fenster zu rendern) während ich g_pRenderSurface erstellt habe um auf die Textur zu rendern. Muss ich nicht zuerst die Textur bzw. das passende Surface als Renderziel setzen?
Ich verstehe die Frage nicht. Daher mein Versuch, das nochmal schrittweise zu erklären.

Du hast ab Start ein Rendertarget. Nämlich der BackBuffer. Das ist eine unsichtbare Surface im Hintergrund, die am Ende, wenn Du mit dem Frame fertig bist, bei Present() ins Fenster geblittet wird. Der BackBuffer ist keine Textur, Du kannst den nie als Textur an einen Shader anklemmen. Aber es ist eine Surface, die Du als Rendertarget setzen kannst.

Dann erzeugst Du eine Textur, bei der Du Direct3D mitteilst, dass Du die auch als Rendertarget benutzen willst. Rendertarget-Texturen haben ein zusätzliches Rudel an Anforderungen, die Du erfüllen musst - Du darfst die z.B. nur im D3DPOOL_DEFAULT anlegen und gibst üblicherweise nur 1 MipMap-Level an. Jede Textur besteht aus 1 bis X Surfaces. Du besorgst Dir mit GetSurfaceLevel() die Surface und kannst die dann für SetRenderTarget() benutzen.

Am Anfang machst Du also folgendes:

Code: Alles auswählen

g_pd3dDevice->GetRenderTarget(0, &g_pOrigTargetSurface); // das RenderTarget des BackBuffers 
D3DXCreateTexture(g_pd3dDevice, .... , D3DUSAGE_RENDERTARGET, .... , D3DPOOL_DEFAULT, &g_pRenderTexture);
g_pRenderTexture->GetSurfaceLevel(0, &g_pRenderSurface); // das Rendertarget der Textur
Dir fällt, wenn Du genau hinguckst, evtl. auch auf, dass Du in Deinem Eingangs-Code g_pRenderSurface zweimal beschreibst. Einmal bei CreateRenderTarget() (ehrlich: die Funktion hab ich bei Dir zum ersten Mal gesehen) und dann sofort auf der nächsten Zeile nochmal bei g_pRenderTexture->GetSurfaceLevel(). Du hast dort also eine Memory Leak geschaffen, aber mehr auch nicht. Das CreateRenderTarget() ist definitiv unnütz.

Pro Frame tust Du dann also folgendes:

Code: Alles auswählen

Device->SetRenderTarget( g_pRenderSurface);
... Szene rendern ...
Device->SetRenderTarget( g_pOrigTargetSurface);
... PostProcessing-Rechteck rendern ...
Present();
und Fertig.
Schrompf hat geschrieben:Hier bin ich überfragt. Laut Deinem Code benutzt Du D3DFVF_PPVERT sowohl beim Erzeugen des VertexBuffers als auch beim Rendern nachher, es müsste also zusammenpassen. Vielleicht hat das D3DFVF_XYZRHW, was Du da verwendest, irgendne spezielle Bedeutung... ich habe keine Ahnung. Wie gesagt, Du benutzt da Zeug, was seit 10 Jahren ausgestorben ist. Entsprechend dünn sind auch meine Kenntnisse von der Materie.
Ok, ich schaue mir einmal Vertex Declaration an. Ich habe die DX9 Grundlagen aus dem Tutorial http://www.chadvernon.com/blog/resources/directx9/ gelernt und da wird halt FVF verwendet.
Wow, Chad.... der hat damals den X-Exporter geschrieben, den wir alle benutzt haben. Scheiße, ich bin alt.

Ich finde auf die Schnelle ehrlich gesagt gar kein Tutorial, das tatsächlich mal Vertex Input Declarations benutzt. Nichtmal, wenn ich genau nach diesen Wörtern plus "Tutorial" google. Schau mal, ob Du da was findest. Die Benutzung ist aber eigentlich wirklich schlicht. Notfalls hack ich Dir hier was zusammen, aber ich würde ehrlich gesagt auf die halbe Stunde Arbeit gern verzichten.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4855
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [DX9] Postprocessing

Beitrag von Schrompf »

Nochwas. Wenn Du das Programm dann zum Laufen bekommen hast, wird das Fullscreen-Quad etwas seltsam aussehen. Das liegt daran, dass der Clip Space, in dem Pretransformed Vertices liegen, von -1 bis +1 geht. Deine Vertizes müssten also diese Positionen haben:

Code: Alles auswählen

(-1,  1)        ( 1,  1)
(-1, -1)        ( 1, -1)
Also X von links -1 bis rechts +1 und Y von unten (!!!) -1 bis oben +1.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Mr. S
Beiträge: 27
Registriert: 09.06.2011, 09:06

Re: [DX9] Postprocessing

Beitrag von Mr. S »

Ahh, so langsam verstehe ich das Ganze. Vielen Dank!

Das g_pRenderTexture->GetSurfaceLevel() das Surface anlegt wusste ich nicht. In der Funktionsbeschreibung steht nur Retrieves the specified texture surface level und nicht das das Surface erstellt wird. Daher habe ich es vorher mit CreateRenderTarget angelegt.

Code: Alles auswählen

typedef struct
{
	D3DXVECTOR3 position;	// The position
	D3DCOLOR color;			// The color
	FLOAT tu, tv;			// The texture coordinates
} CUSTOMVERTEX;

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)

const D3DVERTEXELEMENT9 declaration[] =
{
	{ 0, 0 * sizeof(float),D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_POSITION, 0 },
	{ 0, 3 * sizeof(float),D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
	D3DDECL_END()
};

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

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

Vertex g_quadVertices[] =
{
   //  x     y     z       color
   { -1.0f,-1.0f, 0.0f, 0xffffff00, }, // Bottom-Left,  color = yellow
   {  1.0f,-1.0f, 0.0f, 0xff00ff00, }, // Bottom-Right, color = green
   {  1.0f, 1.0f, 0.0f, 0xffff0000, }, // Top-Right,    color = red
   { -1.0f, 1.0f, 0.0f, 0x000000ff, }  // Top-Left,     color = blue
};

char* g_Shader = "texture g_txSrcColor;\n"
"\n"
"sampler2D g_samSrcColor =\n"
"sampler_state\n"
"{\n"
"    Texture = <g_txSrcColor>;\n"
"    AddressU = Clamp;\n"
"    AddressV = Clamp;\n"
"    MinFilter = Point;\n"
"    MagFilter = Linear;\n"
"    MipFilter = Linear;\n"
"};\n"
"\n"
"float3 LuminanceConv = { 0.2125f, 0.7154f, 0.0721f };\n"
"\n"
"float4 PostProcessPS( float2 Tex : TEXCOORD0 ) : COLOR0\n"
"{\n"
"    return dot( (float3)tex2D( g_samSrcColor, Tex ), LuminanceConv );\n"
"}\n"
"\n"
"technique PostProcess\n"
"{\n"
"    pass p0\n"
"    {\n"
"        VertexShader = null;\n"
"        PixelShader = compile ps_2_0 PostProcessPS();\n"
"        ZEnable = false;\n"
"    }\n"
"}\n";

BOOL CreateScene()
{
	// Use D3DX to create a texture from a file based image
	if(FAILED(D3DXCreateTextureFromFile(g_pd3dDevice, _T("banana.bmp"), &g_pObjectTexture)))
	{
		// If texture is not in current folder, try parent folder
		if(FAILED( D3DXCreateTextureFromFile(g_pd3dDevice, _T("..\\banana.bmp"), &g_pObjectTexture)))
		{
			MessageBox(NULL, _T("Could not find banana.bmp"), _T("Error"), MB_OK);
			return FALSE;
		}
	}

	// Create RTT
	g_pd3dDevice->GetRenderTarget(0, &g_pOrigTargetSurface); // das RenderTarget des BackBuffers 
	if(FAILED(D3DXCreateTexture(g_pd3dDevice, g_rcSize.right - g_rcSize.left, g_rcSize.bottom - g_rcSize.top, D3DUSAGE_RENDERTARGET, 1, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &g_pRenderTexture))) return FALSE; // Textur mit Surface erstellen
	g_pRenderTexture->GetSurfaceLevel(0, &g_pRenderSurface); // das Rendertarget der Textur

	// Create the effect
	DWORD dwShaderFlags = 0;
	dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
	dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
	dwShaderFlags |= D3DXSHADER_NO_PRESHADER;
#ifdef _DEBUG
	dwShaderFlags |= D3DXSHADER_DEBUG;
#endif

	ID3DXBuffer* err = NULL;
	if(FAILED(D3DXCreateEffect(g_pd3dDevice, g_Shader, strlen(g_Shader), NULL, NULL, 0, NULL, &g_pEffect, &err))) return FALSE;

	g_pEffect->SetTexture("g_txSrcColor", g_pRenderTexture);

	// Create the post-process vertex buffer.
	if(FAILED(g_pd3dDevice->CreateVertexBuffer(4 * sizeof(Vertex), D3DUSAGE_WRITEONLY, Vertex::FVF_Flags, D3DPOOL_DEFAULT, &g_pVBPostProcess, NULL))) return FALSE;
	void* pVerticesQuad = NULL;
	g_pVBPostProcess->Lock(0, sizeof(g_quadVertices), (void**)&pVerticesQuad, 0);
	memcpy(pVerticesQuad, g_quadVertices, sizeof(g_quadVertices));
	g_pVBPostProcess->Unlock();

	// +++ SCENE +++

	// Create the object vertex buffer.
	if(FAILED(g_pd3dDevice->CreateVertexBuffer(50 * 2 * sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVBGeometry, NULL))) return FALSE;

	// Fill the vertex buffer. We are setting the tu and tv texture
	// coordinates, which range from 0.0 to 1.0
	CUSTOMVERTEX* pVertices;
	if(FAILED(g_pVBGeometry->Lock(0, 0, (void**)&pVertices, 0))) return FALSE;
	for(DWORD i = 0; i < 50; i++)
	{
		FLOAT theta = (FLOAT)(2.0 * M_PI * (double)i) / 49.0f;

		pVertices[2 * i + 0].position .x = sinf(theta);
		pVertices[2 * i + 0].position .y = -1.0f;
		pVertices[2 * i + 0].position .z = cosf(theta);
		pVertices[2 * i + 0].color = 0xffffffff;
		pVertices[2 * i + 0].tu = ((FLOAT)i) / 49;
		pVertices[2 * i + 0].tv = 1.0f;
		pVertices[2 * i + 1].position.x = sinf(theta);
		pVertices[2 * i + 1].position.y = 1.0f;
		pVertices[2 * i + 1].position.z = cosf(theta);
		pVertices[2 * i + 1].color = 0xff808080;
		pVertices[2 * i + 1].tu = ((FLOAT)i) / 49;
		pVertices[2 * i + 1].tv = 0.0f;
	}
	g_pVBGeometry->Unlock();

	return TRUE;
}

void Render()
{
	if(NULL == g_pd3dDevice) return;

	// Set render target
	g_pd3dDevice->SetRenderTarget(0, g_pRenderSurface);

	// Clear the backbuffer to a blue color
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

	// Begin the scene
	if(SUCCEEDED(g_pd3dDevice->BeginScene()))
	{
		D3DXMATRIXA16 matWorld;
		D3DXMatrixIdentity(&matWorld);
		D3DXMatrixRotationX(&matWorld, timeGetTime() / 1000.0f);
		g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);

		D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );
		D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
		D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
		D3DXMATRIXA16 matView;
		D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec);
		g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);

		D3DXMATRIXA16 matProj;
		D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f);
		g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);

		g_pd3dDevice->SetTexture(0, g_pObjectTexture);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

		g_pd3dDevice->SetStreamSource(0, g_pVBGeometry, 0, sizeof(CUSTOMVERTEX));
		g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
		g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2 * 50 - 2);

		g_pd3dDevice->EndScene();
	}

	// restore original render target
	g_pd3dDevice->SetRenderTarget(0, g_pOrigTargetSurface);

	// Clear the backbuffer to a blue color
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

	// Begin the scene
	if(SUCCEEDED(g_pd3dDevice->BeginScene()))
	{
		LPDIRECT3DVERTEXDECLARATION9 pVertexDeclaration = NULL;
		g_pd3dDevice->CreateVertexDeclaration( declaration, &pVertexDeclaration);
		g_pd3dDevice->SetVertexDeclaration(pVertexDeclaration);
		g_pd3dDevice->SetStreamSource(0, g_pVBPostProcess, 0, sizeof(Vertex));

		D3DXMATRIXA16 identity;
		D3DXMatrixIdentity(&identity);
		g_pd3dDevice->SetTransform(D3DTS_WORLD, &identity);
		g_pd3dDevice->SetTransform(D3DTS_VIEW, &identity);
		g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &identity);

		g_pd3dDevice->SetTexture(0, g_pRenderTexture);

		// begin the effect
		g_pEffect->SetTexture("g_txSrcColor", g_pRenderTexture);
		g_pEffect->SetTechnique(g_pEffect->GetTechniqueByName("PostProcess"));

		UINT uiPasses = 0;
		g_pEffect->Begin(&uiPasses, 0);
		for (UINT uiPass = 0; uiPass < uiPasses; uiPass++)
		{
			// render an effect pass
			g_pEffect->BeginPass(uiPass);
			
			// render the rectangle 
			g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
			
			g_pEffect->EndPass();
		}
		g_pEffect->End();
		
		g_pd3dDevice->SetTexture(0, NULL);

		g_pd3dDevice->EndScene();
		pVertexDeclaration->Release();
	}

	// Present the backbuffer contents to the display
	g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}
Das Programm kompiliert und startet ohne Fehler. Allerdings habe ich jetzt nur ein schwarzes Fenster. Achja, in der Debugger-Ausgabe steht auch noch:
Direct3D9: (INFO) :======================= Hal SWVP device selected

Direct3D9: (INFO) :Using FF to PS converter

Direct3D9: (INFO) :Using FF to VS converter in software vertex processing

Direct3D9: (ERROR) :************************************************************
Direct3D9: (ERROR) :ASSERTION FAILED! File s:\gfx_aug09\windows\directx\dxg\inactive\d3d9\d3d\fw\lhbatchfilter.cpp Line 3466: pArgs->Flags.Discard
Direct3D9: (ERROR) :************************************************************
Direct3D9: (ERROR) :************************************************************
Direct3D9: (ERROR) :ASSERTION FAILED! File s:\gfx_aug09\windows\directx\dxg\inactive\d3d9\d3d\fw\lhbatchfilter.cpp Line 3466: pArgs->Flags.Discard
Direct3D9: (ERROR) :************************************************************
Direct3D9: (ERROR) :************************************************************
Direct3D9: (ERROR) :ASSERTION FAILED! File s:\gfx_aug09\windows\directx\dxg\inactive\d3d9\d3d\fw\lhbatchfilter.cpp Line 3466: pArgs->Flags.Discard
Direct3D9: (ERROR) :************************************************************
Muss da noch etwas eingestellt werden?
Schrompf hat geschrieben:Scheiße, ich bin alt.
Ja, das geht mir auch immer wieder durch den Kopf :lol:
Benutzeravatar
Schrompf
Moderator
Beiträge: 4855
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [DX9] Postprocessing

Beitrag von Schrompf »

GetSurfaceLevel() legt ja auch keine Surface an. CreateTexture() tut das, und GetSurfaceLevel() gibt Dir nur die Surface zurück, damit Du reinrendern kannst. Oder sonstwas damit anstellen.

Begriffserklärung: eine Surface ist eine 2D-Grafik. Eine Textur besteht aus 1 bis x solcher Surfaces, wobei Surface Level 0 das Bild enthält, was Du im Malprogramm siehst, und jedes höhere Level ist eine MipMap davon, die halb so groß ist wie die vorherige. Rendertarget-Texturen haben zumeist nur ein MipLevel, nämlich Level 0, also nur die Grafik in voller Auflösung. All diese Surfaces werden bei CreateTexture() angelegt und bilden zusammen die Textur. Und wenn Du im Device eine Textur anklemmst, meint das immer die Grafik und alle MipMaps davon. Nur kann die Grafikkarte halt nicht in alle gleichzeitig reinrendern, sondern rendert immer nur in eine Surface.

Kurz: eine Textur enthält eine oder mehrere Surfaces. Wenn Du in eine Textur rendern willst, renderst Du nur in eine Surface davon. Wenn Du im Shader aus einer Textur lesen willst, stehen Dir aber alle Surfaces der Textur zur Verfügung. Und üblicherweise wählt die Grafikkarte selbst aus, aus welchem der MipMap-Level sie liest.

Zu der Assertion: das Internet weiß da auch keinen Rat. Du kannst ja mal mit dem Debugger Schritt für Schritt über jeden Direct3D-Aufruf drübergehen und gucken, bei welchem D3D-Aufruf die Meldung kommt. Teile des Internets meinen, das trat bei denen nur mit Software Vertex Processing auf. Das ist eh ne dumme Idee, die Du gleich mal korrigieren kannst: nimm immer Hardware Vertex Processing. Die letzte Grafikkarte, die Software Vertex Processing brauchte, kaum 2002 auf den Markt.

Die Meldung hat aber wahrscheinlich nichts mit dem schwarzen Bildschirm zu tun, den Du siehst. Ist der Bildschirm wirklich schwarz? Weil Du nach meinem Wissen mit Blau leerst. Probier das mal aus: leere das Rendertarget mit Rot z.b. den BackBuffer dann mit Grün, und schau, welche Farbe Du siehst. Ändere dann mal Deinen PostProcessing-PixelShader, so dass der eine konstante Farbe zurückgibt, zum Beispiel Gelb. Dann wieder beobachten, welche Farbe Du siehst.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Mr. S
Beiträge: 27
Registriert: 09.06.2011, 09:06

Re: [DX9] Postprocessing

Beitrag von Mr. S »

Die Fehlerausgabe im Debugger erschien beim Aufruf von CreateDevice. Nach dem Austausch von D3DCREATE_SOFTWARE_VERTEXPROCESSING durch D3DCREATE_HARDWARE_VERTEXPROCESSING sind keine Meldungen mehr da.

Ich habe in den Pixelshader einfach einmal

Code: Alles auswählen

return float4(1, 0, 0, 1);
geschrieben und dann ein rotes Fenster bekommen.

Code: Alles auswählen

return tex2D(g_samSrcColor, Tex);
gibt ein blaues Fenster zurück. D. h. es scheint jetzt zu funktionieren, nur fehlt da die Geometrie.

Vielen Dank für deine Hilfe!
Benutzeravatar
Schrompf
Moderator
Beiträge: 4855
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [DX9] Postprocessing

Beitrag von Schrompf »

Fehlen tut da nix mehr - wenn Du die Ausgabe des PixelShaders siehst, bedeutet das ja, dass da mindestens ein Dreieck gemalt wird, was den Bildschirm vollständig überdeckt. Schau nochmal Deine Geometrie durch. So müssen alle Vertizes nach dem VertexShader aussehen:

Position X von links nach rechts von -1 bis +1
Position Y von unten nach oben von -1 bis +1
Position Z von vorn nach hinten von 0 bis 1
Position W für 2D-Grafik immer 1 (entsprecht Orthogonal-Projektion

Textur X und Y von links oben bis rechts unten von 0 bis 1

Schreibe also solche Vertizes in den VertexBuffer und entferne erstmal alle Rechnungen aus dem VertexShader. Dann schau, dass Du es so zum Laufen bekommst. Danach können wir dann grübeln, was da schief geht.

Und bitte bitte: entferne jegliche Fixed Function Pipeline aus Deinem Programm. Das Hin- und Herwechseln zwischen Shadern zu Fixed Function ist voller hässlicher Nebeneffekte und Treiber-Unsicherheiten. Und noch dazu bist Du seit Jahren sicherlich der Erste, der das benutzt, Du bist also völlig allein, wenn Du dadurch Probleme bekommst. Tu das nicht.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Mr. S
Beiträge: 27
Registriert: 09.06.2011, 09:06

Re: [DX9] Postprocessing

Beitrag von Mr. S »

Schrompf hat geschrieben:Und bitte bitte: entferne jegliche Fixed Function Pipeline aus Deinem Programm. Das Hin- und Herwechseln zwischen Shadern zu Fixed Function ist voller hässlicher Nebeneffekte und Treiber-Unsicherheiten. Und noch dazu bist Du seit Jahren sicherlich der Erste, der das benutzt, Du bist also völlig allein, wenn Du dadurch Probleme bekommst. Tu das nicht.
Auf die Gefahr hin für allgemeine Heiterkeit zu sorgen: Was? :?: Ich verstehe mal wieder nur Bahnhof. :oops:
Specialist
Establishment
Beiträge: 135
Registriert: 29.08.2003, 14:22
Kontaktdaten:

Re: [DX9] Postprocessing

Beitrag von Specialist »

Code: Alles auswählen

g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);

g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);

g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
Das hier zum Beispiel ist Teil der Fixed Function Pipeline. Früher, als es noch keine Shader gab, war man auf fest definierte Funktionen der Grafikkarte angewiesen.
Ein paar davon siehst du hier in deinem eigenen Code:
- View-Matrix setzen
- Projection-Matrix setzen
- Funktionen für Texture-Stage 0 setzen

Ein Texel / Pixel durchlief früher keine Shader sondern mehrere Texture-Stages. Innerhalb dieser Stages konnten verschiedene Dinge getan werden, z.B. einfach nur eine Textur samplen oder Texturen vermischen etc.
Da dies alles, wie bereits gesagt, fest definiert war und man es nur an oder abwählen konnte, hieß der Kram Fixed Function Pipeline.

Mittlerweile gibt es keine Fixed Function Pipeline mehr, denn glücklicherweise haben wir die Shader, die wesentlich flexibler sind.
Deine o.g. Aufrufe werden heutzutage auch komplett über Shader emuliert, daher macht es eh keinen Sinn mehr sie zu verwenden.
Und wie Schrompf bereits sagte, kann es zu Problemen kommen, wenn man Shader und die FFP vermischt. Daher, raus damit ;)
Antworten