Author Topic: [C++] 2D effects (starfield) in Direct3D?  (Read 25263 times)

0 Members and 1 Guest are viewing this topic.

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #20 on: August 05, 2008 »
@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:

Code: [Select]
// 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.
« Last Edit: August 05, 2008 by Naptha »

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #21 on: August 06, 2008 »
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...

Code: [Select]
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

Offline Rbz

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 2757
  • Karma: 493
    • View Profile
    • https://www.rbraz.com/
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #22 on: August 06, 2008 »
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.
Challenge Trophies Won:

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #23 on: August 06, 2008 »
You need to make your texture coordinates in the same sequence of your triangle strip.

In words that a simpleton can understand?  :-[

Offline Rbz

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 2757
  • Karma: 493
    • View Profile
    • https://www.rbraz.com/
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #24 on: August 06, 2008 »
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 :)
Challenge Trophies Won:

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #25 on: August 06, 2008 »
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...
« Last Edit: August 06, 2008 by Naptha »

Offline Rbz

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 2757
  • Karma: 493
    • View Profile
    • https://www.rbraz.com/
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #26 on: August 06, 2008 »
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.

Code: [Select]
// 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},
};

Challenge Trophies Won:

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #27 on: August 06, 2008 »
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.

Code: [Select]
// 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. :)
« Last Edit: August 06, 2008 by Naptha »

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #28 on: August 10, 2008 »
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:
Code: [Select]
// 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:
Code: [Select]
#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.

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #29 on: August 10, 2008 »
I can't see any difference!   ???

Jim
Challenge Trophies Won:

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #30 on: August 10, 2008 »
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.


Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #31 on: August 10, 2008 »
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

Offline Rbz

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 2757
  • Karma: 493
    • View Profile
    • https://www.rbraz.com/
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #32 on: August 10, 2008 »
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
Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #33 on: August 10, 2008 »
Damn!  I saw the filter at LINEAR and instantly thought that meant NEAREST!
Jim
Challenge Trophies Won:

Offline Aeko

  • C= 64
  • **
  • Posts: 27
  • Karma: 1
    • View Profile
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #34 on: August 30, 2008 »
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:

Offline Rbz

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 2757
  • Karma: 493
    • View Profile
    • https://www.rbraz.com/
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #35 on: September 03, 2008 »
@Aeko: take a look here -> http://dbfinteractive.com/forum/index.php?topic=2387.15
You will find an example about it.
Challenge Trophies Won:

Offline Aeko

  • C= 64
  • **
  • Posts: 27
  • Karma: 1
    • View Profile
Re: [C++] 2D effects (starfield) in Direct3D?
« Reply #36 on: September 03, 2008 »
Thanks a lot rbz.

Yes, seems it has all I'm looking for.