Dark Bit Factory & Gravity
PROGRAMMING => C / C++ /C# => Topic started by: Naptha on July 25, 2008
-
Hi all, back with more questions :)
I've been playing around with cubes some more and have written a class that can generate stuff like the attached program. Now I'd like to add a horizontal starfield behind it and was wondering how to go about it.
After looking around a bit I had the idea that I can generate a layered starfield by either creating a texture for each layer and then blending them, or simply drawing all layers to one texture starting with the back layer. I then thought I could render the 3D foreground to a texture with an alpha mask (somehow ???) and blend it with the background... when rendering the cubes to a texture can I change
pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);to have a D3DCOLOR_ARGB in order to make it transparent for blending?
As you can probably tell, I have no idea how to do any of this right now. Am I on the right track? If I did manage to end up with a texture that had the 3D foreground on the starfield background, would I just draw a textured quad to display it? How do you position the quad?
Your views and advice are greatly appreciated as always. :)
-
You can simply blend your layers additively (1*src + 1*dst) and don't have to care about an alpha-channel.
However, you will gain some speed by settings a distinct alpha-value for black pixels and use the alpha-test to skip them (you just need to request your texture in a format that includes an alpha-channel).
Still your solution will require plenty of fill-rate, so it's probably faster & more flexible to draw each "star" using a single (textured) polygon.
Then again the layering gives some interessting options, like eg pre-motion-blurring the textures.
-
@Naptha: I'm more into OpenGL but.... the principles should apply to DX as well. 2D fx with a 3D engine is a question of projection matrix. Do you know how to do that? I hope yes. Otherwise let me know.
Regarding 2D stars, try just to draw points. OpenGL can draw points, I do not know about DX, otherwhise a 1-pixel triangle/quad would be much faster than a big texture, as most of the pixels would be black.
-
@hellfire:
Motion blurring the starfield layers was exactly one of the effects I wanted to try eventually. :)
If I blend the cube foreground additively with the starfield, wouldn't you see the stars over (or blended into) the cubes?
I think I may try getting a starfield example working first before worrying about that though. ;)
@stormbringer:
I found an article which describes setting up the projection matrix for 2D effects, so I do understand it now. :)
Good tip on the points, I haven't come across points in DX yet, I will have a look, but otherwise I'll go with small quads, rather than writing to a screen-sized texture.
-
Right, I forgot about the cubes...
Since the stars are in the background anyways, I would just draw the cubes last.
Otherwise you can handle alpha the way you figured out yourself already.
-
@Naptha: if you want to add motion blur on the 2d stars, I still suggest to us a "trail" for each star. Basically you would have a simple 2d particle system, each particle being a "star" containing the current x,y coordiante plus an array of the previous x,y coordinates.
In C, this would look like this:
#define kTrailLength (5)
typedef struct _Star2D
{
float x[kTrailLength];
float y[kTrailLength];
};
then you can simply shift the values in the array at each drawing pass, or if you use a timer, when the timer has reached a certain threshold (depeding on the frame rate you want). Using a gradient of colors (say black to white) will give you a nice trail. The brightest color for the current star coordinates, the darker colors for the previous states.
Another alternative is to use lines if your stars are not to large (e.g. 1 or 2 pixels in size). This would give pretty much the same effect, although a bit different, visually speaking.
DX just as OpenGL are good at drawing zillions of lines/points... (i.e. fast, with hardware acceleration)
-
Ok, well I decided I wanted to learn how to manipulate textures in memory, so I've gone that route first. So far I've created three "layer" textures, written starfields to each, and multitextured a quad with all three. I doesn't move yet but I thought I'd post what I have so far for feedback.
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <d3d9.h>
#include <d3dx9.h>
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768
#define DENSITY 500
// lib replacement stuff --------------------------------------------------------
// Thanks to Jim for most of this :)
static unsigned int next = 1;
__forceinline void MEMSET( void *_dst, int _val, size_t _sz )
{
while ( _sz ) ((BYTE *)_dst)[--_sz] = _val;
}
int rand(void)
{
next = next * 1103515245 + 12345;
return (int)((next/65536) % 32768);
}
void srand(unsigned int seed)
{
next = seed;
}
extern "C"
{
int _fltused;
void __declspec(naked) _chkstk(void)
{
#define _PAGESIZE_ 1000h
__asm
{
push ecx
; Calculate new TOS.
lea ecx, [esp] + 8 - 4 ; TOS before entering function + size for ret value
sub ecx, eax ; new TOS
; Handle allocation size that results in wraparound.
; Wraparound will result in StackOverflow exception.
sbb eax, eax ; 0 if CF==0, ~0 if CF==1
not eax ; ~0 if TOS did not wrapped around, 0 otherwise
and ecx, eax ; set to 0 if wraparound
mov eax, esp ; current TOS
and eax, not ( _PAGESIZE_ - 1) ; Round down to current page boundary
cs10:
cmp ecx, eax ; Is new TOS
jb short cs20 ; in probed page?
mov eax, ecx ; yes.
pop ecx
xchg esp, eax ; update esp
mov eax, dword ptr [eax] ; get return address
mov dword ptr [esp], eax ; and put it at new TOS
ret
; Find next lower page and probe
cs20:
sub eax, _PAGESIZE_ ; decrease by PAGESIZE
test dword ptr [eax],eax ; probe page.
jmp short cs10
}
}
}
// ------------------------------------------------------------------------------
struct VERTEX
{
FLOAT x, y, z;
DWORD color;
FLOAT u1, v1;
FLOAT u2, v2;
FLOAT u3, v3;
};
#define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX3)
void createStarLayer(int (&starsX)[DENSITY], int (&starsY)[DENSITY])
{
for(int ii=0; ii < DENSITY; ii++)
{
starsX[ii] = rand()%((SCREEN_WIDTH)+1);
starsY[ii] = rand()%((SCREEN_HEIGHT)+1);
}
}
void drawStarLayer(LPDIRECT3DTEXTURE9 tex, DWORD color, int (&starsX)[DENSITY], int (&starsY)[DENSITY])
{
LPDIRECT3DSURFACE9 surface;
tex->GetSurfaceLevel(0, &surface);
D3DLOCKED_RECT rect;
surface->LockRect(&rect, 0, 0);
DWORD* pData=(DWORD*)(rect.pBits);
MEMSET(pData,0,(SCREEN_HEIGHT*SCREEN_WIDTH*4));
for(int ii=0; ii < DENSITY; ii++)
{
pData[starsX[ii]+(SCREEN_WIDTH-1)*starsY[ii]] = color;
}
surface->UnlockRect();
}
void WinMainCRTStartup()
{
HWND hWnd = ( CreateWindowEx(WS_EX_TOPMOST, "edit",0,0,0,0,0,0,0,0,0,0) );
static int d3dpp[] = {
SCREEN_WIDTH,
SCREEN_HEIGHT,
D3DFMT_X8R8G8B8,
1,
D3DMULTISAMPLE_2_SAMPLES,
0,
D3DSWAPEFFECT_DISCARD,
(int)hWnd,
0,
1,
D3DFMT_D16,
0,
0,
0
};
LPDIRECT3D9 pD3D = Direct3DCreate9( D3D_SDK_VERSION );
LPDIRECT3DDEVICE9 pDevice;
pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
(D3DPRESENT_PARAMETERS*)&d3dpp, &pDevice );
ShowCursor(FALSE);
pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
D3DXMATRIX Ortho2D;
D3DXMATRIX Identity;
D3DXMatrixOrthoLH(&Ortho2D, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 1.0f);
D3DXMatrixIdentity(&Identity);
pDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D);
pDevice->SetTransform(D3DTS_WORLD, &Identity);
pDevice->SetTransform(D3DTS_VIEW, &Identity);
// Declare pointers to textures
LPDIRECT3DTEXTURE9 pLayer1;
LPDIRECT3DTEXTURE9 pLayer2;
LPDIRECT3DTEXTURE9 pLayer3;
LPDIRECT3DTEXTURE9 pDest;
// Create empty textures
D3DXCreateTexture(pDevice, SCREEN_WIDTH, SCREEN_HEIGHT, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pLayer1);
D3DXCreateTexture(pDevice, SCREEN_WIDTH, SCREEN_HEIGHT, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pLayer2);
D3DXCreateTexture(pDevice, SCREEN_WIDTH, SCREEN_HEIGHT, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pLayer3);
D3DXCreateTexture(pDevice, SCREEN_WIDTH, SCREEN_HEIGHT, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pDest);
// Specify a color for each layer
DWORD color1 = D3DCOLOR_XRGB(255, 255, 255);
DWORD color2 = D3DCOLOR_XRGB(175, 175, 175);
DWORD color3 = D3DCOLOR_XRGB(100, 100, 100);
// Create arrays to store star coordinates
int stars1X[DENSITY];
int stars1Y[DENSITY];
int stars2X[DENSITY];
int stars2Y[DENSITY];
int stars3X[DENSITY];
int stars3Y[DENSITY];
// Generate starfield layers
srand(0);
createStarLayer(stars1X, stars1Y);
createStarLayer(stars2X, stars2Y);
createStarLayer(stars3X, stars3Y);
// Create quad to paint dest texture onto
VERTEX vert[] =
{
{ -(SCREEN_WIDTH/2), (SCREEN_HEIGHT/2), 0, D3DCOLOR_XRGB(255, 255, 255), 0, 0, 0, 0, 0, 0,},
{ (SCREEN_WIDTH/2), (SCREEN_HEIGHT/2), 0, D3DCOLOR_XRGB(255, 255, 255), 1, 0, 1, 0, 1, 0,},
{ -(SCREEN_WIDTH/2), -(SCREEN_HEIGHT/2), 0, D3DCOLOR_XRGB(255, 255, 255), 0, 1, 0, 1, 0, 1,},
{ (SCREEN_WIDTH/2), -(SCREEN_HEIGHT/2), 0, D3DCOLOR_XRGB(255, 255, 255), 1, 1, 1, 1, 1, 1,},
};
LPDIRECT3DVERTEXBUFFER9 pVertBuffer = NULL;
pDevice->CreateVertexBuffer(4 * sizeof(VERTEX), D3DUSAGE_WRITEONLY,
D3DFVF_VERTEX, D3DPOOL_MANAGED, &pVertBuffer, NULL);
VOID* pVoid;
pVertBuffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vert, sizeof(vert));
pVertBuffer->Unlock();
// Start render loop
while (!GetAsyncKeyState(VK_ESCAPE))
{
pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->BeginScene();
drawStarLayer(pLayer1, color1, stars1X, stars1Y);
drawStarLayer(pLayer2, color2, stars2X, stars2Y);
drawStarLayer(pLayer3, color3, stars3X, stars3Y);
pDevice->SetFVF(D3DFVF_VERTEX);
pDevice->SetStreamSource(0, pVertBuffer, 0, sizeof(VERTEX));
pDevice->SetTexture(0, pLayer1);
pDevice->SetTexture(1, pLayer2);
pDevice->SetTexture(2, pLayer3);
pDevice->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);
pDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);
pDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADD);
pDevice->SetTextureStageState(1, D3DTSS_COLORARG1,D3DTA_TEXTURE);
pDevice->SetTextureStageState(1, D3DTSS_COLORARG2,D3DTA_CURRENT);
pDevice->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_ADD);
pDevice->SetTextureStageState(2, D3DTSS_COLORARG1,D3DTA_TEXTURE);
pDevice->SetTextureStageState(2, D3DTSS_COLORARG2,D3DTA_CURRENT);
pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
pDevice->EndScene();
pDevice->Present( NULL, NULL, NULL, NULL );
}
ExitProcess(0);
}
There's probably loads of things wrong with this, any help or hints welcome. :)
-
Don't expect your compile to optimize division/modulo by 2^n.
-
Don't expect your compile to optimize division/modulo by 2^n.
Sorry, don't understand what you're referring to by this... :-[
-
@Naptha: as stormbringer told you, is better for you to use points, you can draw zillions of points :)
I did some changes on your code, added a basic particle system and voila! you have some moving stars on your screen.
Now it's your job to add better colors/perspective and timer :)
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <d3d9.h>
#include <d3dx9.h>
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768
// lib replacement stuff --------------------------------------------------------
// Thanks to Jim for most of this :)
static unsigned int next = 1;
__forceinline void MEMSET( void *_dst, int _val, size_t _sz )
{
while ( _sz ) ((BYTE *)_dst)[--_sz] = _val;
}
int rand(void)
{
next = next * 1103515245 + 12345;
return (int)((next/65536) % 32768);
}
void srand(unsigned int seed)
{
next = seed;
}
extern "C"
{
int _fltused;
void __declspec(naked) _chkstk(void)
{
#define _PAGESIZE_ 1000h
__asm
{
push ecx
; Calculate new TOS.
lea ecx, [esp] + 8 - 4 ; TOS before entering function + size for ret value
sub ecx, eax ; new TOS
; Handle allocation size that results in wraparound.
; Wraparound will result in StackOverflow exception.
sbb eax, eax ; 0 if CF==0, ~0 if CF==1
not eax ; ~0 if TOS did not wrapped around, 0 otherwise
and ecx, eax ; set to 0 if wraparound
mov eax, esp ; current TOS
and eax, not ( _PAGESIZE_ - 1) ; Round down to current page boundary
cs10:
cmp ecx, eax ; Is new TOS
jb short cs20 ; in probed page?
mov eax, ecx ; yes.
pop ecx
xchg esp, eax ; update esp
mov eax, dword ptr [eax] ; get return address
mov dword ptr [esp], eax ; and put it at new TOS
ret
; Find next lower page and probe
cs20:
sub eax, _PAGESIZE_ ; decrease by PAGESIZE
test dword ptr [eax],eax ; probe page.
jmp short cs10
}
}
}
// ------------------------------------------------------------------------------
struct VERTEX
{
FLOAT x, y, z;
DWORD color;
};
#define D3DFVF_VERTEX (D3DFVF_XYZ)
#define MAX_STARS 1000
struct Stars
{
float x;
float y;
float speed;
};
static Stars stars[MAX_STARS];
void initStars()
{
for(int i=0; i<MAX_STARS; i++)
{
stars[i].x = (float)(rand()%SCREEN_WIDTH);
stars[i].y = (float)(-rand()%SCREEN_HEIGHT);
stars[i].speed = (float)(rand()%5+1);
}
}
void WinMainCRTStartup()
{
HWND hWnd = ( CreateWindowEx(WS_EX_TOPMOST, "edit",0,0,0,0,0,0,0,0,0,0) );
static int d3dpp[] = {
SCREEN_WIDTH,
SCREEN_HEIGHT,
D3DFMT_X8R8G8B8,
1,
D3DMULTISAMPLE_2_SAMPLES,
0,
D3DSWAPEFFECT_DISCARD,
(int)hWnd,
0,
1,
D3DFMT_D16,
0,
0,
0
};
LPDIRECT3D9 pD3D = Direct3DCreate9( D3D_SDK_VERSION );
LPDIRECT3DDEVICE9 pDevice;
pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
(D3DPRESENT_PARAMETERS*)&d3dpp, &pDevice );
ShowCursor(FALSE);
pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
D3DXMATRIX Ortho2D;
D3DXMATRIX Identity;
D3DXMatrixOrthoLH(&Ortho2D, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 1.0f);
D3DXMatrixIdentity(&Identity);
pDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D);
pDevice->SetTransform(D3DTS_WORLD, &Identity);
pDevice->SetTransform(D3DTS_VIEW, &Identity);
srand(0);
// Create point vertex
VERTEX vert[] =
{
{ -(SCREEN_WIDTH/2), (SCREEN_HEIGHT/2), 0, D3DCOLOR_XRGB(255, 255, 255)}
};
LPDIRECT3DVERTEXBUFFER9 pVertBuffer = NULL;
pDevice->CreateVertexBuffer(4 * sizeof(VERTEX), D3DUSAGE_WRITEONLY,
D3DFVF_VERTEX, D3DPOOL_MANAGED, &pVertBuffer, NULL);
VOID* pVoid;
pVertBuffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vert, sizeof(vert));
pVertBuffer->Unlock();
initStars();
// Start render loop
while (!GetAsyncKeyState(VK_ESCAPE))
{
pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->BeginScene();
for(int i=0; i<MAX_STARS; i++)
{
pDevice->SetFVF(D3DFVF_VERTEX);
pDevice->SetStreamSource(0, pVertBuffer, 0, sizeof(VERTEX));
pDevice->SetTransform(D3DTS_WORLD, &Identity);
D3DXMATRIX matTranslate;
D3DXMatrixTranslation(&matTranslate,stars[i].x,stars[i].y,0.0f);
pDevice->SetTransform(D3DTS_WORLD, &matTranslate);
stars[i].x += stars[i].speed;
if(stars[i].x > (float)SCREEN_WIDTH)
{
stars[i].x = -1.0f;
stars[i].y = (float)(-rand()%SCREEN_HEIGHT);
}
pDevice->DrawPrimitive(D3DPT_POINTLIST, 0, 1);
}
pDevice->EndScene();
pDevice->Present( NULL, NULL, NULL, NULL );
}
ExitProcess(0);
}
-
I think Stormbringer is referring to this
int rand(void)
{
next = next * 1103515245 + 12345;
return (int)((next/65536) % 32768);
}
If your compiler optimises well, it will turn the / and % into shifts. If not then you might want to change it to
int rand(void)
{
next = next * 1103515245 + 12345;
return (int)((next>>16) & 32767);
}
Jim
-
@Naptha: as stormbringer told you, is better for you to use points, you can draw zillions of points :)
I did some changes on your code, added a basic particle system and voila! you have some moving stars on your screen.
Now it's your job to add better colors/perspective and timer :)
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <d3d9.h>
#include <d3dx9.h>
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768
// lib replacement stuff --------------------------------------------------------
// Thanks to Jim for most of this :)
static unsigned int next = 1;
__forceinline void MEMSET( void *_dst, int _val, size_t _sz )
{
while ( _sz ) ((BYTE *)_dst)[--_sz] = _val;
}
int rand(void)
{
next = next * 1103515245 + 12345;
return (int)((next/65536) % 32768);
}
void srand(unsigned int seed)
{
next = seed;
}
extern "C"
{
int _fltused;
void __declspec(naked) _chkstk(void)
{
#define _PAGESIZE_ 1000h
__asm
{
push ecx
; Calculate new TOS.
lea ecx, [esp] + 8 - 4 ; TOS before entering function + size for ret value
sub ecx, eax ; new TOS
; Handle allocation size that results in wraparound.
; Wraparound will result in StackOverflow exception.
sbb eax, eax ; 0 if CF==0, ~0 if CF==1
not eax ; ~0 if TOS did not wrapped around, 0 otherwise
and ecx, eax ; set to 0 if wraparound
mov eax, esp ; current TOS
and eax, not ( _PAGESIZE_ - 1) ; Round down to current page boundary
cs10:
cmp ecx, eax ; Is new TOS
jb short cs20 ; in probed page?
mov eax, ecx ; yes.
pop ecx
xchg esp, eax ; update esp
mov eax, dword ptr [eax] ; get return address
mov dword ptr [esp], eax ; and put it at new TOS
ret
; Find next lower page and probe
cs20:
sub eax, _PAGESIZE_ ; decrease by PAGESIZE
test dword ptr [eax],eax ; probe page.
jmp short cs10
}
}
}
// ------------------------------------------------------------------------------
struct VERTEX
{
FLOAT x, y, z;
DWORD color;
};
#define D3DFVF_VERTEX (D3DFVF_XYZ)
#define MAX_STARS 1000
struct Stars
{
float x;
float y;
float speed;
};
static Stars stars[MAX_STARS];
void initStars()
{
for(int i=0; i<MAX_STARS; i++)
{
stars[i].x = (float)(rand()%SCREEN_WIDTH);
stars[i].y = (float)(-rand()%SCREEN_HEIGHT);
stars[i].speed = (float)(rand()%5+1);
}
}
void WinMainCRTStartup()
{
HWND hWnd = ( CreateWindowEx(WS_EX_TOPMOST, "edit",0,0,0,0,0,0,0,0,0,0) );
static int d3dpp[] = {
SCREEN_WIDTH,
SCREEN_HEIGHT,
D3DFMT_X8R8G8B8,
1,
D3DMULTISAMPLE_2_SAMPLES,
0,
D3DSWAPEFFECT_DISCARD,
(int)hWnd,
0,
1,
D3DFMT_D16,
0,
0,
0
};
LPDIRECT3D9 pD3D = Direct3DCreate9( D3D_SDK_VERSION );
LPDIRECT3DDEVICE9 pDevice;
pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
(D3DPRESENT_PARAMETERS*)&d3dpp, &pDevice );
ShowCursor(FALSE);
pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
D3DXMATRIX Ortho2D;
D3DXMATRIX Identity;
D3DXMatrixOrthoLH(&Ortho2D, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 1.0f);
D3DXMatrixIdentity(&Identity);
pDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D);
pDevice->SetTransform(D3DTS_WORLD, &Identity);
pDevice->SetTransform(D3DTS_VIEW, &Identity);
srand(0);
// Create point vertex
VERTEX vert[] =
{
{ -(SCREEN_WIDTH/2), (SCREEN_HEIGHT/2), 0, D3DCOLOR_XRGB(255, 255, 255)}
};
LPDIRECT3DVERTEXBUFFER9 pVertBuffer = NULL;
pDevice->CreateVertexBuffer(4 * sizeof(VERTEX), D3DUSAGE_WRITEONLY,
D3DFVF_VERTEX, D3DPOOL_MANAGED, &pVertBuffer, NULL);
VOID* pVoid;
pVertBuffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vert, sizeof(vert));
pVertBuffer->Unlock();
initStars();
// Start render loop
while (!GetAsyncKeyState(VK_ESCAPE))
{
pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->BeginScene();
for(int i=0; i<MAX_STARS; i++)
{
pDevice->SetFVF(D3DFVF_VERTEX);
pDevice->SetStreamSource(0, pVertBuffer, 0, sizeof(VERTEX));
pDevice->SetTransform(D3DTS_WORLD, &Identity);
D3DXMATRIX matTranslate;
D3DXMatrixTranslation(&matTranslate,stars[i].x,stars[i].y,0.0f);
pDevice->SetTransform(D3DTS_WORLD, &matTranslate);
stars[i].x += stars[i].speed;
if(stars[i].x > (float)SCREEN_WIDTH)
{
stars[i].x = -1.0f;
stars[i].y = (float)(-rand()%SCREEN_HEIGHT);
}
pDevice->DrawPrimitive(D3DPT_POINTLIST, 0, 1);
}
pDevice->EndScene();
pDevice->Present( NULL, NULL, NULL, NULL );
}
ExitProcess(0);
}
Ahhh, so much simpler than my ugly code! :D
I'm trying to think of a way to colour the stars by 'layer' without defining additional point vertices, although that might just be being obtuse for the sake of it. I did come across the motion blur example in the DX SDK which uses a seperate texture to record the velocity of every pixel on screen, then uses that data in a pixel shader to calculate the blur, I guess something similar could just as easily be used to colour pixels. I don't know the first thing about implementing pixel shaders though :-[ (yet ^-^).
What did you mean by more interesting perspective? ??? And what is a timer? :-[
-
What did you mean by more interesting perspective? And what is a timer?
You can shade your stars by giving a illusion of depth, for example slow running stars can have dark colors (50, 50, 50) and stars that are going faster you can set bright colors (255, 255, 255).
Adding a "delta time" function will guarantee that your stars will run at same speed on all PC configurations, search on this forum and you will find some interesting examples that you can apply on your project.
-
Well, I think I have the colors/perspective thing sorted, though I'm not sure how good my solution is. I wanted to be able to change the number of layers so I put that into a #define, all the calculations are based off that, and I think they are right.
But let me know what you think. ;D
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <d3d9.h>
#include <d3dx9.h>
// lib replacement stuff --------------------------------------------------------
// Thanks to Jim for most of this :)
static unsigned int next = 1;
__forceinline void MEMSET( void *_dst, int _val, size_t _sz )
{
while ( _sz ) ((BYTE *)_dst)[--_sz] = _val;
}
int rand(void)
{
next = next * 1103515245 + 12345;
return (int)((next/65536) % 32768);
}
void srand(unsigned int seed)
{
next = seed;
}
extern "C"
{
int _fltused;
void __declspec(naked) _chkstk(void)
{
#define _PAGESIZE_ 1000h
__asm
{
push ecx
; Calculate new TOS.
lea ecx, [esp] + 8 - 4 ; TOS before entering function + size for ret value
sub ecx, eax ; new TOS
; Handle allocation size that results in wraparound.
; Wraparound will result in StackOverflow exception.
sbb eax, eax ; 0 if CF==0, ~0 if CF==1
not eax ; ~0 if TOS did not wrapped around, 0 otherwise
and ecx, eax ; set to 0 if wraparound
mov eax, esp ; current TOS
and eax, not ( _PAGESIZE_ - 1) ; Round down to current page boundary
cs10:
cmp ecx, eax ; Is new TOS
jb short cs20 ; in probed page?
mov eax, ecx ; yes.
pop ecx
xchg esp, eax ; update esp
mov eax, dword ptr [eax] ; get return address
mov dword ptr [esp], eax ; and put it at new TOS
ret
; Find next lower page and probe
cs20:
sub eax, _PAGESIZE_ ; decrease by PAGESIZE
test dword ptr [eax],eax ; probe page.
jmp short cs10
}
}
}
// ------------------------------------------------------------------------------
#define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768
#define MAX_STARS 2000
#define LAYERS 4
struct VERTEX
{
FLOAT x, y, z;
DWORD color;
};
struct Stars
{
float x;
float y;
int speed;
};
static Stars stars[MAX_STARS];
void initStars()
{
for(int i=0; i<MAX_STARS; i++)
{
stars[i].x = (float)((rand()%SCREEN_WIDTH)-SCREEN_WIDTH/2);
stars[i].y = (float)((rand()%SCREEN_HEIGHT)-SCREEN_HEIGHT/2);
stars[i].speed = (rand()%LAYERS)+1;
}
}
void WinMainCRTStartup()
{
HWND hWnd = ( CreateWindowEx(WS_EX_TOPMOST, "edit",0,0,0,0,0,0,0,0,0,0) );
static int d3dpp[] = {
SCREEN_WIDTH,
SCREEN_HEIGHT,
D3DFMT_X8R8G8B8,
1,
D3DMULTISAMPLE_2_SAMPLES,
0,
D3DSWAPEFFECT_DISCARD,
(int)hWnd,
0,
1,
D3DFMT_D16,
0,
0,
0
};
LPDIRECT3D9 pD3D = Direct3DCreate9( D3D_SDK_VERSION );
LPDIRECT3DDEVICE9 pDevice;
pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
(D3DPRESENT_PARAMETERS*)&d3dpp, &pDevice );
ShowCursor(FALSE);
pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
D3DXMATRIX Ortho2D;
D3DXMATRIX Identity;
D3DXMatrixOrthoLH(&Ortho2D, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 1.0f);
D3DXMatrixIdentity(&Identity);
pDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D);
pDevice->SetTransform(D3DTS_WORLD, &Identity);
pDevice->SetTransform(D3DTS_VIEW, &Identity);
srand(0);
// Create point vertex
VERTEX vert[LAYERS];
for(int i=0; i<LAYERS; i++)
{
int shade = (i+1)*(255/LAYERS);
vert[i].x = 0;
vert[i].y = 0;
vert[i].z = 0;
vert[i].color = D3DCOLOR_XRGB(shade, shade, shade);
}
LPDIRECT3DVERTEXBUFFER9 pVertBuffer = NULL;
pDevice->CreateVertexBuffer(LAYERS * sizeof(VERTEX), D3DUSAGE_WRITEONLY,
D3DFVF_VERTEX, D3DPOOL_MANAGED, &pVertBuffer, NULL);
VOID* pVoid;
pVertBuffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vert, sizeof(vert));
pVertBuffer->Unlock();
initStars();
// Start render loop
while (!GetAsyncKeyState(VK_ESCAPE))
{
pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->BeginScene();
pDevice->SetFVF(D3DFVF_VERTEX);
pDevice->SetStreamSource(0, pVertBuffer, 0, sizeof(VERTEX));
pDevice->SetTransform(D3DTS_WORLD, &Identity);
D3DXMATRIX matTranslate;
for(int i=0; i<MAX_STARS; i++)
{
D3DXMatrixTranslation(&matTranslate,stars[i].x,stars[i].y,0.0f);
pDevice->SetTransform(D3DTS_WORLD, &matTranslate);
stars[i].x += stars[i].speed;
if(stars[i].x > (float)SCREEN_WIDTH/2)
{
stars[i].x = (float)(-SCREEN_WIDTH/2);
stars[i].y = (float)((rand()%SCREEN_HEIGHT)-SCREEN_HEIGHT/2);
}
pDevice->DrawPrimitive(D3DPT_POINTLIST, (stars[i].speed)-1, 1);
}
pDevice->EndScene();
pDevice->Present( NULL, NULL, NULL, NULL );
}
ExitProcess(0);
}
I still need to look at timers, I also plan to change the points to point sprites and (hopefully) add a pixel shader for some blurring.
-
Yeah, much better now and it looks right to me, welldone
Looking forward for the blurred version ;D
-
I've been looking into pixel shaders and there seems to be very little info on them that's freely available. :-\
If I understand it right, a pixel shader acts on all pixels contained within the primitive currently being drawn. If that's the case, how do you create a pixel shader that acts on the full screen? Do you need to render to a texture then draw that (using the shader) as a sprite or on a quad?
-
Yes, render the scene to a texture and then render the texture to the screen as a quad with the pixel shader fx.
Jim
-
Having some trouble rendering to a texture and getting it to display correctly. The starfield is displayed so I assume the quad is correctly positioned etc, however it doesn't scroll - the stars simply start disappering and don't reappear.
I'm tired so I have probably done something silly. ???
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <d3d9.h>
#include <d3dx9.h>
// lib replacement stuff --------------------------------------------------------
// Thanks to Jim for most of this :)
static unsigned int next = 1;
__forceinline void MEMSET( void *_dst, int _val, size_t _sz )
{
while ( _sz ) ((BYTE *)_dst)[--_sz] = _val;
}
int rand(void)
{
next = next * 1103515245 + 12345;
return (int)((next/65536) % 32768);
}
void srand(unsigned int seed)
{
next = seed;
}
extern "C"
{
int _fltused;
void __declspec(naked) _chkstk(void)
{
#define _PAGESIZE_ 1000h
__asm
{
push ecx
; Calculate new TOS.
lea ecx, [esp] + 8 - 4 ; TOS before entering function + size for ret value
sub ecx, eax ; new TOS
; Handle allocation size that results in wraparound.
; Wraparound will result in StackOverflow exception.
sbb eax, eax ; 0 if CF==0, ~0 if CF==1
not eax ; ~0 if TOS did not wrapped around, 0 otherwise
and ecx, eax ; set to 0 if wraparound
mov eax, esp ; current TOS
and eax, not ( _PAGESIZE_ - 1) ; Round down to current page boundary
cs10:
cmp ecx, eax ; Is new TOS
jb short cs20 ; in probed page?
mov eax, ecx ; yes.
pop ecx
xchg esp, eax ; update esp
mov eax, dword ptr [eax] ; get return address
mov dword ptr [esp], eax ; and put it at new TOS
ret
; Find next lower page and probe
cs20:
sub eax, _PAGESIZE_ ; decrease by PAGESIZE
test dword ptr [eax],eax ; probe page.
jmp short cs10
}
}
}
// ------------------------------------------------------------------------------
struct VERTEX
{
FLOAT x, y, z;
DWORD color;
};
struct QUADVERT
{
FLOAT x, y, z;
FLOAT u1, v1;
};
#define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)
#define D3DFVF_QUADVERT (D3DFVF_XYZ | D3DFVF_TEX1)
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768
#define MAX_STARS 2000
#define LAYERS 5
struct Stars
{
float x;
float y;
int speed;
};
static Stars stars[MAX_STARS];
void initStars()
{
for(int i=0; i<MAX_STARS; i++)
{
stars[i].x = (float)((rand()%SCREEN_WIDTH)-SCREEN_WIDTH/2);
stars[i].y = (float)((rand()%SCREEN_HEIGHT)-SCREEN_HEIGHT/2);
stars[i].speed = (rand()%LAYERS)+1;
}
}
void WinMainCRTStartup()
{
HWND hWnd = ( CreateWindowEx(WS_EX_TOPMOST, "edit",0,0,0,0,0,0,0,0,0,0) );
static int d3dpp[] = {
SCREEN_WIDTH,
SCREEN_HEIGHT,
D3DFMT_X8R8G8B8,
1,
D3DMULTISAMPLE_2_SAMPLES,
0,
D3DSWAPEFFECT_DISCARD,
(int)hWnd,
0,
1,
D3DFMT_D16,
0,
0,
0
};
LPDIRECT3D9 pD3D = Direct3DCreate9( D3D_SDK_VERSION );
LPDIRECT3DDEVICE9 pDevice;
pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
(D3DPRESENT_PARAMETERS*)&d3dpp, &pDevice );
ShowCursor(FALSE);
pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
D3DXMATRIX Ortho2D;
D3DXMATRIX Identity;
D3DXMatrixOrthoLH(&Ortho2D, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 1.0f);
D3DXMatrixIdentity(&Identity);
pDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D);
pDevice->SetTransform(D3DTS_VIEW, &Identity);
srand(0);
// Create point vertices
VERTEX vert[LAYERS];
for(int i=0; i<LAYERS; i++)
{
int shade = (i+1)*(255/LAYERS);
vert[i].x = 0;
vert[i].y = 0;
vert[i].z = 0;
vert[i].color = D3DCOLOR_XRGB(shade, shade, shade);
}
LPDIRECT3DVERTEXBUFFER9 pVertBuffer = NULL;
pDevice->CreateVertexBuffer(LAYERS * sizeof(VERTEX), D3DUSAGE_WRITEONLY,
D3DFVF_VERTEX, D3DPOOL_MANAGED, &pVertBuffer, NULL);
VOID* pVoid;
pVertBuffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vert, sizeof(vert));
pVertBuffer->Unlock();
// Create quad vertices
QUADVERT quad[4] =
{
{-(SCREEN_WIDTH/2), (SCREEN_HEIGHT/2), 0, 0, 0},
{(SCREEN_WIDTH/2), (SCREEN_HEIGHT/2), 0, 1, 0},
{-(SCREEN_WIDTH/2), -(SCREEN_HEIGHT/2), 0, 0, 1},
{(SCREEN_WIDTH/2), -(SCREEN_HEIGHT/2), 0, 1, 1},
};
LPDIRECT3DVERTEXBUFFER9 pQuadBuffer = NULL;
pDevice->CreateVertexBuffer(4*sizeof(QUADVERT), D3DUSAGE_WRITEONLY,
D3DFVF_QUADVERT, D3DPOOL_MANAGED, &pQuadBuffer, NULL);
pVoid = NULL;
pQuadBuffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, quad, sizeof(quad));
pQuadBuffer->Unlock();
// initialise stars
initStars();
// initialise offscreen render target
LPDIRECT3DTEXTURE9 pTex = NULL;
D3DXCreateTexture(pDevice, SCREEN_WIDTH, SCREEN_HEIGHT, 1, D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pTex);
LPDIRECT3DSURFACE9 pSurf = NULL, pBackBuffer = NULL;
pTex->GetSurfaceLevel(0, &pSurf);
// Start render loop
while (!GetAsyncKeyState(VK_ESCAPE))
{
// Render geometry to offscreen surface
pDevice->GetRenderTarget(0, &pBackBuffer);
pDevice->SetRenderTarget(0, pSurf);
pDevice->BeginScene();
pDevice->SetFVF(D3DFVF_VERTEX);
pDevice->SetStreamSource(0, pVertBuffer, 0, sizeof(VERTEX));
D3DXMATRIX matTranslate;
for(int i=0; i<MAX_STARS; i++)
{
D3DXMatrixTranslation(&matTranslate,stars[i].x,stars[i].y,0.0f);
pDevice->SetTransform(D3DTS_WORLD, &matTranslate);
stars[i].x += stars[i].speed;
if(stars[i].x > (float)SCREEN_WIDTH/2)
{
stars[i].x = (float)(-SCREEN_WIDTH/2);
stars[i].y = (float)((rand()%SCREEN_HEIGHT)-SCREEN_HEIGHT/2);
}
pDevice->DrawPrimitive(D3DPT_POINTLIST, (stars[i].speed)-1, 1);
}
pDevice->EndScene();
// Render fullscreen quad
pDevice->SetRenderTarget(0, pBackBuffer);
pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->SetFVF(D3DFVF_QUADVERT);
pDevice->SetStreamSource(0, pQuadBuffer, 0, sizeof(QUADVERT));
pDevice->SetTransform(D3DTS_WORLD, &Identity);
pDevice->BeginScene();
pDevice->SetTexture(0,pTex);
pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
pDevice->EndScene();
pDevice->Present( NULL, NULL, NULL, NULL );
}
ExitProcess(0);
}
-
I spotted some problems on your code:
1-the big one is that you're trying to use rendering commands outside pDevice->BeginScene(); ...... pDevice->EndScene(); .
So, have everything inside BeginScene/EndScene, and you don't need to have one for draw stars and another for draw texture quad.
2-You just need to "GetRenderTarget" once, just remove it from main loop.
3-Your quad texture coordinates are wrong, you need to texture it in the same order that you make your triangle vertices sequence.
-
Another possible problem is your texture render target is 1024x768. You probably need to make it 1024x1024 for maximum compatibility.
Jim
-
@rbz: Thanks, I fixed 1 & 2. :)
Are you sure the texture coordinates are wrong? It's definitely displaying the texture across the whole quad. I still have the problem that it's not scrolling though, and the stars are disappearing.
Edit: Well, I discovered the problem but no idea what the cause is... the starfield is rendered once correctly as I saw, but after the first frame it does in fact render the stars with their updated positions each frame. The effect I observed where the stars gradually disappeared is apparently because I wasn't clearing the texture each frame, and having drawn the stars correctly on the first frame, it then draws them black! I have no idea why it would do that, I assume something changed after the first pass through the render-to-texture section of the render loop causes it but as far as I can see everything should be reset correctly. ???
Here's the render loop I have now:
// Start render loop
while (!GetAsyncKeyState(VK_ESCAPE))
{
// Render geometry to offscreen surface
pDevice->BeginScene();
pDevice->SetRenderTarget(0, pSurf);
//pDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->SetFVF(D3DFVF_VERTEX);
pDevice->SetStreamSource(0, pVertBuffer, 0, sizeof(VERTEX));
for(int i=0; i<MAX_STARS; i++)
{
D3DXMatrixTranslation(&matTranslate,stars[i].x,stars[i].y,0.0f);
pDevice->SetTransform(D3DTS_WORLD, &matTranslate);
stars[i].x += stars[i].speed;
if(stars[i].x > (float)SCREEN_WIDTH/2)
{
stars[i].x = (float)(-SCREEN_WIDTH/2);
stars[i].y = (float)((rand()%SCREEN_HEIGHT)-SCREEN_HEIGHT/2);
}
pDevice->DrawPrimitive(D3DPT_POINTLIST, (stars[i].speed)-1, 1);
}
// Render fullscreen quad
pDevice->SetRenderTarget(0, pBackBuffer);
pDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->SetFVF(D3DFVF_QUADVERT);
pDevice->SetStreamSource(0, pQuadBuffer, 0, sizeof(QUADVERT));
pDevice->SetTransform(D3DTS_WORLD, &Identity);
pDevice->SetTexture(0,pTex);
pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
pDevice->EndScene();
pDevice->Present( NULL, NULL, NULL, NULL );
}
Uncommenting the first Clear() will result in a black screen, you can alter the colour it clears to in order to see the stars being drawn in black.
-
Fixed! :updance:
My hunch was right - the only thing set when rendering the quad that wasn't reset when rendering the starfield in the next frame was the texture. I didn't think that would matter, but adding...
pDevice->SetTexture(0,0);
.. before drawing the stars fixed it.
Why direct3d wants to draw a texture on a point primitive with no texture coordinates remains unclear... ??? ::)
Now on to my first pixel shader! ;D
-
Nice one!
Are you sure the texture coordinates are wrong? It's definitely displaying the texture across the whole quad. I still have the problem that it's not scrolling though, and the stars are disappearing.
Yes, I'm sure, if you look carefully on your stars, you will spot some changes in dot sizes when they cross to one triangle to another. You need to make your texture coordinates in the same sequence of your triangle strip.
-
You need to make your texture coordinates in the same sequence of your triangle strip.
In words that a simpleton can understand? :-[
-
Look at this image below:
Your first vertice is:
-(SCREEN_WIDTH/2), (SCREEN_HEIGHT/2) (left / top) so your texture coordinate should be "0.0f, 1.0f"
Second vertice:
(SCREEN_WIDTH/2), (SCREEN_HEIGHT/2) (right / top) and your tex coord texture "1.0f, 1.0f"
3rd vertice:
-(SCREEN_WIDTH/2), -(SCREEN_HEIGHT/2) (left / botton) your tex coord "0.0f, 0.0f"
4th vertice:
(SCREEN_WIDTH/2), -(SCREEN_HEIGHT/2) (rigth / botton) your tex coord "1.0f, 0.0f"
That's all :)
-
But I thought.. in D3D texture coordinates 0,0 is the top left..? ???
Edit: just to put my mind at rest, I changed my texture coordinates to yours and altered the code so that it would draw all stars with a y coordinate of 100. Assuming the texture is drawn the right way up, that would draw a line of stars closer to the top of screen, but when I ran it, it was closer to the bottom...
-
Yes, you were right, my bad :P, it was right for OGL though.
I think the problem that I see here was due to quad size, not sure, I changed your quad setting to this code and it looks ok here.
// Create quad vertices
QUADVERT quad[4] =
{
{-((SCREEN_WIDTH-1)/2), ((SCREEN_HEIGHT-1)/2), 0.0f, 0.0f, 0.0f},
{((SCREEN_WIDTH-1)/2), ((SCREEN_HEIGHT-1)/2), 0.0f, 1.0f, 0.0f},
{-((SCREEN_WIDTH-1)/2), -((SCREEN_HEIGHT-1)/2), 0.0f, 0.0f, 1.0f},
{((SCREEN_WIDTH-1)/2), -((SCREEN_HEIGHT-1)/2), 0.0f, 1.0f, 1.0f},
};
-
Yes, you were right, my bad :P, it was right for OGL though.
I think the problem that I see here was due to quad size, not sure, I changed your quad setting to this code and it looks ok here.
// Create quad vertices
QUADVERT quad[4] =
{
{-((SCREEN_WIDTH-1)/2), ((SCREEN_HEIGHT-1)/2), 0.0f, 0.0f, 0.0f},
{((SCREEN_WIDTH-1)/2), ((SCREEN_HEIGHT-1)/2), 0.0f, 1.0f, 0.0f},
{-((SCREEN_WIDTH-1)/2), -((SCREEN_HEIGHT-1)/2), 0.0f, 0.0f, 1.0f},
{((SCREEN_WIDTH-1)/2), -((SCREEN_HEIGHT-1)/2), 0.0f, 1.0f, 1.0f},
};
You're right, I had wondered about the dimensions of the quad so I started clearing the back buffer to gray to show up any gaps.
Now I'm working on a motion blurring shader which I think is almost done (but probably not), will post it when it works. :)
-
Well it took me longer to get around to implementing a shader than I thought. I have a very basic shader which should do nothing except display the quad with the texture I've rendered to. However, it seems to have some kind of lighting effect (although lighting is turned off) whereby the stars get brighter in the centre of the screen. It's not an unpleasant effect but I've been tearing my hair out trying to figure out why it's happening. :whack: Can anyone shed any light on it?
Here's the shader:
// Global Variables --------------------------
float4x4 matWVP : WorldViewProjection;
texture StarTex;
// Vertex shader -----------------------------
struct VS_INPUT
{
float3 Pos : POSITION;
float2 Tex : TEXCOORD0;
};
struct VS_OUTPUT
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD0;
};
VS_OUTPUT vs_main( VS_INPUT In )
{
VS_OUTPUT Out;
Out.Pos = mul(float4(In.Pos, 1.0f), matWVP);
Out.Tex = In.Tex;
return Out;
}
// Pixel shader ------------------------------
sampler StarTexSampler =
sampler_state
{
Texture = (StarTex);
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};
float4 ps_main(float2 texCoord: TEXCOORD0) : COLOR
{
return tex2D(StarTexSampler, texCoord);
}
// Technique --------------------------------
technique Blur
{
pass P0
{
VertexShader = compile vs_2_0 vs_main();
PixelShader = compile ps_2_0 ps_main();
}
}
And here's the code:
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <d3d9.h>
#include <d3dx9.h>
// lib replacement stuff --------------------------------------------------------
// Thanks to Jim for most of this :)
static unsigned int next = 1;
/*__forceinline void MEMSET( void *_dst, int _val, size_t _sz )
{
while ( _sz ) ((BYTE *)_dst)[--_sz] = _val;
}*/
int rand(void)
{
next = next * 1103515245 + 12345;
return (int)((next/65536) % 32768);
}
void srand(unsigned int seed)
{
next = seed;
}
extern "C"
{
int _fltused;
void __declspec(naked) _chkstk(void)
{
#define _PAGESIZE_ 1000h
__asm
{
push ecx
; Calculate new TOS.
lea ecx, [esp] + 8 - 4 ; TOS before entering function + size for ret value
sub ecx, eax ; new TOS
; Handle allocation size that results in wraparound.
; Wraparound will result in StackOverflow exception.
sbb eax, eax ; 0 if CF==0, ~0 if CF==1
not eax ; ~0 if TOS did not wrapped around, 0 otherwise
and ecx, eax ; set to 0 if wraparound
mov eax, esp ; current TOS
and eax, not ( _PAGESIZE_ - 1) ; Round down to current page boundary
cs10:
cmp ecx, eax ; Is new TOS
jb short cs20 ; in probed page?
mov eax, ecx ; yes.
pop ecx
xchg esp, eax ; update esp
mov eax, dword ptr [eax] ; get return address
mov dword ptr [esp], eax ; and put it at new TOS
ret
; Find next lower page and probe
cs20:
sub eax, _PAGESIZE_ ; decrease by PAGESIZE
test dword ptr [eax],eax ; probe page.
jmp short cs10
}
}
}
// ------------------------------------------------------------------------------
struct VERTEX
{
FLOAT x, y, z;
DWORD color;
};
struct QUADVERT
{
FLOAT x, y, z;
FLOAT u1, v1;
};
#define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)
#define D3DFVF_QUADVERT (D3DFVF_XYZ | D3DFVF_TEX1)
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define MAX_STARS 2000
#define LAYERS 4
struct Stars
{
float x;
float y;
int speed;
};
static Stars stars[MAX_STARS];
void initStars()
{
for(int i=0; i<MAX_STARS; i++)
{
stars[i].x = (float)((rand()%SCREEN_WIDTH)-SCREEN_WIDTH/2);
stars[i].y = (float)((rand()%SCREEN_HEIGHT)-SCREEN_HEIGHT/2);
int temp = ((rand()%LAYERS)+1)-(rand()%LAYERS);
stars[i].speed = temp < 1 ? ((rand()%LAYERS)+1)-(rand()%LAYERS) : temp;
}
}
void WinMainCRTStartup()
{
HWND hWnd = ( CreateWindowEx(WS_EX_TOPMOST, "edit",0,0,0,0,0,0,0,0,0,0) );
static int d3dpp[] = {
SCREEN_WIDTH,
SCREEN_HEIGHT,
D3DFMT_X8R8G8B8,
1,
D3DMULTISAMPLE_NONE,
0,
D3DSWAPEFFECT_DISCARD,
(int)hWnd,
0,
1,
D3DFMT_D16,
0,
0,
0
};
LPDIRECT3D9 pD3D = Direct3DCreate9( D3D_SDK_VERSION );
LPDIRECT3DDEVICE9 pDevice;
pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
(D3DPRESENT_PARAMETERS*)&d3dpp, &pDevice );
ShowCursor(FALSE);
pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
D3DXMATRIX Ortho2D;
D3DXMATRIX Identity;
D3DXMatrixOrthoLH(&Ortho2D, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 1.0f);
D3DXMatrixIdentity(&Identity);
pDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D);
pDevice->SetTransform(D3DTS_VIEW, &Identity);
srand(0);
// Create point vertices
VERTEX vert[LAYERS];
for(int i=0; i<LAYERS; i++)
{
int shade = (i+1)*(255/LAYERS);
vert[i].x = 0;
vert[i].y = 0;
vert[i].z = 0;
vert[i].color = D3DCOLOR_XRGB(shade, shade, shade);
}
LPDIRECT3DVERTEXBUFFER9 pVertBuffer = NULL;
pDevice->CreateVertexBuffer(LAYERS * sizeof(VERTEX), D3DUSAGE_WRITEONLY,
D3DFVF_VERTEX, D3DPOOL_MANAGED, &pVertBuffer, NULL);
VOID* pVoid;
pVertBuffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vert, sizeof(vert));
pVertBuffer->Unlock();
// Create quad vertices
QUADVERT quad[] =
{
{-(SCREEN_WIDTH/2)-1, (SCREEN_HEIGHT/2)+1, 0, 0, 0},
{(SCREEN_WIDTH/2), (SCREEN_HEIGHT/2)+1, 0, 1, 0},
{-(SCREEN_WIDTH/2)-1, -(SCREEN_HEIGHT/2), 0, 0, 1},
{(SCREEN_WIDTH/2), -(SCREEN_HEIGHT/2), 0, 1, 1},
};
LPDIRECT3DVERTEXBUFFER9 pQuadBuffer = NULL;
pDevice->CreateVertexBuffer(4*sizeof(QUADVERT), D3DUSAGE_WRITEONLY,
D3DFVF_QUADVERT, D3DPOOL_MANAGED, &pQuadBuffer, NULL);
pVoid = NULL;
pQuadBuffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, quad, sizeof(quad));
pQuadBuffer->Unlock();
// initialise stars
initStars();
// initialise offscreen render target
LPDIRECT3DTEXTURE9 pTex = NULL;
D3DXCreateTexture(pDevice, SCREEN_WIDTH, SCREEN_HEIGHT, 1, D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pTex);
LPDIRECT3DSURFACE9 pSurf = NULL, pBackBuffer = NULL;
pTex->GetSurfaceLevel(0, &pSurf);
pDevice->GetRenderTarget(0, &pBackBuffer);
D3DXMATRIX matTranslate;
// Initialise shader effect
LPD3DXEFFECT pBlurFX = NULL;
LPD3DXBUFFER pErrors = NULL;
D3DXCreateEffectFromFile(pDevice, "shader.fx", 0, 0, 0, 0, &pBlurFX, &pErrors);
pBlurFX->SetTechnique("Blur");
// Start render loop
while (!GetAsyncKeyState(VK_ESCAPE))
{
// Render geometry to offscreen surface
pDevice->BeginScene();
pDevice->SetRenderTarget(0, pSurf);
pDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
pDevice->SetFVF(D3DFVF_VERTEX);
pDevice->SetStreamSource(0, pVertBuffer, 0, sizeof(VERTEX));
for(int i=0; i<MAX_STARS; i++)
{
D3DXMatrixTranslation(&matTranslate,stars[i].x,stars[i].y,0.0f);
pDevice->SetTransform(D3DTS_WORLD, &matTranslate);
stars[i].x -= stars[i].speed;
if(stars[i].x < (float)-SCREEN_WIDTH/2)
{
stars[i].x = (float)(SCREEN_WIDTH/2);
stars[i].y = (float)((rand()%SCREEN_HEIGHT)-SCREEN_HEIGHT/2);
}
pDevice->DrawPrimitive(D3DPT_POINTLIST, (stars[i].speed)-1, 1);
}
// Render fullscreen quad with effect
pDevice->SetRenderTarget(0, pBackBuffer);
pDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(100, 100, 100), 1.0f, 0);
pDevice->SetFVF(D3DFVF_QUADVERT);
pDevice->SetStreamSource(0, pQuadBuffer, 0, sizeof(QUADVERT));
D3DXMATRIX wvp = Identity * Identity * Ortho2D;
pBlurFX->SetMatrix("matWVP", &wvp);
pBlurFX->SetTexture("StarTex", pTex);
UINT numPasses = 0;
pBlurFX->Begin(&numPasses, 0);
for(UINT i=0; i < numPasses; i++)
{
pBlurFX->BeginPass(i);
pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
pBlurFX->EndPass();
}
pBlurFX->End();
pDevice->EndScene();
pDevice->Present( NULL, NULL, NULL, NULL );
}
ExitProcess(0);
}
It's quite subtle to notice so I've attached two versions of the program, one using the shader, one not.
-
I can't see any difference! ???
Jim
-
Here's two screenshots of what I'm seeing.. I'm sure it's not just my eyes.. ???
One without the shader has even brightness, the shader one is darker at the edges.
-
Found the problem! Apparently this is an artifact of the texture filtering, since I actually want the exact pixels I rendered initially I didn't need filtering anyway so just turning it off in the shader worked. :||
Now to make it do something interesting... :P
-
Hard to see any difference between each one, I can see it only when zooming your screenshot :)
Take a look at this tutorial, it might give you some ideas:
http://freespace.virgin.net/hugo.elias/graphics/x_wuline.htm
-
Damn! I saw the filter at LINEAR and instantly thought that meant NEAREST!
Jim
-
Hi folks,
Is there anyway to include de .fx file, or my be the shader, into the same exe ? . That's: to have only one file.
By the way :goodpost:
-
@Aeko: take a look here -> http://dbfinteractive.com/forum/index.php?topic=2387.15
You will find an example about it.
-
Thanks a lot rbz.
Yes, seems it has all I'm looking for.