Using more fx effect in one quad

Started by
18 comments, last by Adaline 10 years, 2 months ago

First one side note:

You don't have to call CommitChanges, SetTexture and SetStreamSource for each pass. They don't change between passes, so calling the methods with the same arguments is just slowing your program.

Now to the main problem - you are not doing what people were telling you to do ;)

You need to create an empty texture using D3DXCreateTexture with D3DUSAGE_RENDERTARGET and the same width and height as your backbuffer. I'll refer to this texture as to <RTtexture>.

Then, when rendering, you set this <RTtexture> texture as your render target (this step doesn't have to do anything with effect) using device->SetRenderTarget. Now you render the quad with the first effect.

Then you set your backbuffer as the render target again using device->SetRenderTarget. And you also set your <RTtexture> texture as an input (resource) texture for your effect. And you render the quad using the second effect.

What happens is this:

- <RTtexture> texture starts as empty.

- you render the result of the first effect to it

- you use the result of the first effect, which now is in <RTtexture>, as input for the second effect

- you render the result of the second effect to the backbuffer and display it

Because you render the second effect using a texture which already has the first effect in it, you'll get combined effects.

Advertisement

First one side note:

You don't have to call CommitChanges, SetTexture and SetStreamSource for each pass. They don't change between passes, so calling the methods with the same arguments is just slowing your program.

Now to the main problem - you are not doing what people were telling you to do ;)

You need to create an empty texture using D3DXCreateTexture with D3DUSAGE_RENDERTARGET and the same width and height as your backbuffer. I'll refer to this texture as to <RTtexture>.

Then, when rendering, you set this <RTtexture> texture as your render target (this step doesn't have to do anything with effect) using device->SetRenderTarget. Now you render the quad with the first effect.

Then you set your backbuffer as the render target again using device->SetRenderTarget. And you also set your <RTtexture> texture as an input (resource) texture for your effect. And you render the quad using the second effect.

What happens is this:

- <RTtexture> texture starts as empty.

- you render the result of the first effect to it

- you use the result of the first effect, which now is in <RTtexture>, as input for the second effect

- you render the result of the second effect to the backbuffer and display it

Because you render the second effect using a texture which already has the first effect in it, you'll get combined effects.

I can't resolve this problem !

when i create a texture as empty , i set it to effect1 and i input it in effect 2 then i use it randertarget .
the problem here is , the RTtexture after first frame is become a randertarget , in this case i can't see the first effect because it overwrite by the second effect.

Can you give me small exemple plz happy.png ?

anyone ?

You'll have to show us your most recent code.

This is my code :


i create an empty texture : D3DXCreateTextureFromFileInMemoryEx(engine_device,buffer,size,width,height,D3DX_FROM_FILE,D3DUSAGE_RENDERTARGET,D3DFMT_UNKNOWN,D3DPOOL_MANAGED,D3DX_DEFAULT,D3DX_DEFAULT,D3DCOLOR_ARGB(255, 255, 0, 255), 0, 0, &RTtexture);



then in render :

i set RTtexture a render target then i use it in first effect :


pixelShader1->SetTexture("textureMap", RTtexture);
pixelShader1->Begin()
for( UINT uPass = 0; uPass < uPasses; ++uPass )
{
    pixelShader1->BeginPass( uPass );
    pixelShader1->CommitChanges();

    engine_device->SetTexture(0,RTtexture);
    
    engine_device->SetStreamSource(0, QUAD_VB, 0, sizeof(SIZE_VERTEX));
    engine_device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2); ////draw the quad
    pixelShader1->EndPass();

}

then i input the same texture to effect 2
pixelShader2->SetTexture("textureMap", RTtexture);
pixelShader2->Begin()
for( UINT uPass = 0; uPass < uPasses; ++uPass )
{
    pixelShader2->BeginPass( uPass );
    pixelShader2->CommitChanges();

    engine_device->SetTexture(0,RTtexture);
    
    engine_device->SetStreamSource(0, QUAD_VB, 0, sizeof(SIZE_VERTEX));
    engine_device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);  //// draw the quad
    pixelShader2->EndPass();

}

the result is effect 2 !!!

Hello

Where do you change your render target ?

Render the first pass on the texture as render target.

Then render the second pass using this texture as input on your final render target.

before the rendering loop :

Create a texture T with the same size and format as your back-buffer

in the rendering loop :

Set the texture T as render target (output)

Draw the first effect

Set the texture T as shader resource (input)

Set the back-buffer as render target

Draw the second effect

SetRenderTarget() is a member of IDirect3DDevice9

Hope it helps ...

i still not get it working , is there any exemple ?

thank you Tournicoti

Hello, I never used DX9 myself, but it should be something like that :

Before the rendering loop :


D3DXCreateTextureFromFileInMemoryEx(engine_device,buffer,size,width,height,D3DX_FROM_FILE,D3DUSAGE_RENDERTARGET,D3DFMT_UNKNOWN,D3DPOOL_MANAGED,D3DX_DEFAULT,D3DX_DEFAULT,D3DCOLOR_ARGB(255, 255, 0, 255), 0, 0, &RTtexture);

(This is what you already do)

In the rendering loop, assuming there's only one pass for each effect, (which is probably not the case) :


engine_device->SetRenderTarget(0,&RTTexture);
pixelShader1->SetTexture("textureMap",&backBuffer);
pixelShader1->Begin();
for( UINT uPass = 0; uPass < uPasses; ++uPass )
{
    pixelShader1->BeginPass( uPass );
    engine_device->SetStreamSource(0, QUAD_VB, 0, sizeof(SIZE_VERTEX));
    engine_device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2); ////draw the quad
    pixelShader1->EndPass();

}

engine_device->SetRenderTarget(0,&backBuffer);
pixelShader2->SetTexture("textureMap", RTtexture);
pixelShader2->Begin()
for( UINT uPass = 0; uPass < uPasses; ++uPass )
{
    pixelShader2->BeginPass( uPass ); 
    engine_device->SetStreamSource(0, QUAD_VB, 0, sizeof(SIZE_VERTEX));
    engine_device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);  //// draw the quad
    pixelShader2->EndPass();

}

.... where backBuffer is what you got when creating the swap chain during the initialization of your program.

More generally, what's missing in your code is setting the correct render target for each effect : you mustn't set RTtexture as a shader resource (shader->SetTexture()) for the first effect, but as the render target (device->SetRenderTarget). Then in the second effect, set RTtexture as a shader resource (shader->SetTexture()), and the back buffer as render target (device->SetRenderTarget()).

If there are several passes (for each effect), it's a bit more complicated since you will have to change your render target and your input texture between passes, but the idea is the same. This is called "ping pong rendering".http://http://xboxforums.create.msdn.com/forums/t/47136.aspx

(For example, if the blur effect needs two passes

Pass 1 :

shader resource = back buffer

render target= RTTexture

Pass 2 :

shader resource = RTTexture

render target= back buffer

The idea is to switch the back buffer and the shader resource (input texture) between each pass.)

PS : I could give some more specific pseudo-code if you can tell how many passes there are for each effect.

Before the rendering loop :


D3DXCreateTextureFromFileInMemoryEx(engine_device,buffer,size,width,height,D3DX_FROM_FILE,D3DUSAGE_RENDERTARGET,D3DFMT_UNKNOWN,D3DPOOL_MANAGED,D3DX_DEFAULT,D3DX_DEFAULT,D3DCOLOR_ARGB(255, 255, 0, 255), 0, 0, &RTtexture);

(This is what you already do)

Why do you (and game_developer2013) use this function? It's just a slight variation of D3DXCreateTextureFromFile. Both these functions create a texture from an image file (.bmp, .jpg, .tga etc.) and not an empty texture. The only difference between them is that D3DXCreateTextureFromFile reads the data from a file on a disc, while for D3DXCreateTextureFromFileInMemory you have to first read the file yourself to a memory buffer (that's good for example if you use your own file compression or packing systems).

What you really need to create an empty render target texture is D3DXCreateTexture.

Before the rendering loop :


D3DXCreateTextureFromFileInMemoryEx(engine_device,buffer,size,width,height,D3DX_FROM_FILE,D3DUSAGE_RENDERTARGET,D3DFMT_UNKNOWN,D3DPOOL_MANAGED,D3DX_DEFAULT,D3DX_DEFAULT,D3DCOLOR_ARGB(255, 255, 0, 255), 0, 0, &RTtexture);

(This is what you already do)

Why do you (and game_developer2013) use this function? It's just a slight variation of D3DXCreateTextureFromFile. Both these functions create a texture from an image file (.bmp, .jpg, .tga etc.) and not an empty texture. The only difference between them is that D3DXCreateTextureFromFile reads the data from a file on a disc, while for D3DXCreateTextureFromFileInMemory you have to first read the file yourself to a memory buffer (that's good for example if you use your own file compression or packing systems).

What you really need to create an empty render target texture is D3DXCreateTexture.

My mistake you're right rolleyes.gif

I just copy-pasted this line, more focused on the problem of passes.

Thanks.

This topic is closed to new replies.

Advertisement