Need help writing pixel shader (*compiled*)

Started by
5 comments, last by shrooms 16 years, 3 months ago
I'm not sure if this is the right place to put this topic, but I'm a definitely a beginner. I've come across this site a few times just by using google to find the answers I need, so I figured you guys have a large knowledge base and this would be a good place to ask this question. If you've used DXTweaker, you'll know that the user can create their own post-processing filters. The filters are .xml files which one can modify easily. Over the past few days, I've been learning how this *compiled* code (correct me if I'm wrong) works. I'm trying to create a post-filter that gives the game a sin-city look, where everything is black and white except for key red objects:

<Effect Display="Test">
  <Pass Destination="Display">
    <Source Sampler="0" Name="Backbuffer"/>
    <FConst Start="0">
      <Vector X="0.5" Y="1.0" Z="1.0" W="1.0"/>
    </FConst>
    <PixelShader>
      <![CDATA[
      ps_2_0
      dcl_2d s0
      dcl t0.xy   
      texld r0, t0, s0
      
mul r3,r0.r,r0.r //multiply the red channel by itself
mul r3,r3,r3 //multiply the result by itself again
sub r3,r3,c0 //make the whites red, on black

dp3 r0,r0,r0 //grayscale the original image
    
    ***not sure what to do here!***
     
      mov oC0,r0
      ]]>
    </PixelShader>
  </Pass>
</Effect>
Basically, I've taken the reds from the original image and put them on a black background (r3). I've also grayscaled the original image (r0). I want to multiply in the reds onto my grayscaled image, but the problem is that it also multiplies in the black background that they're on. The result puts the reds how they should be, but the rest of the image is understandably very dark or black. How do I use only the red from r3 and multiply that red into r0? Thanks for any help that you can give.
Advertisement
Well what I think you probably want to do is instead of multiplying your "red" value with your "gray" value, you should instead subtract it from the gray value's blue and green components and then add it to the red component. This way if the red value is high you end up with just red, and if the red value is low you end up with just gray. I tried this approach, and it seemed to work just fine.

My second suggestion is that if you're writing shaders for D3D, you should try using HLSL. HLSL is much more intuitive and easy to work with than shader assembly, and you can compile it into assembly using the fxc tool that comes with the DirectX SDK. It will also optimize the code for you, which is a plus.

I created some HLSL code that looked like this:

 sampler2D backBuffer : register( s0 );struct PS_INPUT{    float2 texel0 : TEXCOORD0;};struct PS_OUTPUT{    float4 color : COLOR0;};void psSinCity( in PS_INPUT IN, out PS_OUTPUT OUT ){    float4 color = tex2D( backBuffer, IN.texel0 );    float3 gray = dot(color.rgb, color.rgb);    float red = color.r * color.r;    red = red * red;    gray.r += red;    gray.g -= red;    gray.b -= red;	    OUT.color = float4(gray, 1.0f);}


...and fxc compiled it into this assembly:

//// Generated by Microsoft (R) HLSL Shader Compiler 9.19.949.2111////   fxc /T ps_2_0 /E psSinCity /Fc SinCity.txt SinCity.fx////// Parameters:////   sampler2D backBuffer;////// Registers:////   Name         Reg   Size//   ------------ ----- ----//   backBuffer   s0       1//    ps_2_0    def c0, 1, 0, 0, 0    dcl t0.xy    dcl_2d s0    texld r0, t0, s0    mov r1.w, c0.x    dp3 r0.y, r0, r0    mul r0.x, r0.x, r0.x    mad r1.x, r0.x, r0.x, r0.y    mad r1.yz, r0.x, -r0.x, r0.y    mov oC0, r1// approximately 7 instruction slots used (1 texture, 6 arithmetic)
Good thinking, works like a charm :) Thanks
Hi,

i have problems compiling the effect. maybe someone
knows what to do.

this is what i get when i try to compile the effect:

--------------------

..Shaders>fxc /LD shader.fx
Microsoft (R) D3D10 Shader Compiler 9.19.949.2106
Copyright (C) Microsoft Corporation 2002-2007. All rights reserved.

shader.fx(1): error X3000: syntax error: unexpected token 'backBuffer'

compilation failed; no code produced

--------------------

and without the /LD switch:

..Shaders>fxc shader.fx
Microsoft (R) D3D10 Shader Compiler 9.19.949.2106
Copyright (C) Microsoft Corporation 2002-2007. All rights reserved.

error X3501: 'main': entrypoint not found

compilation failed; no code produced

-----------------
If you're going to try to compile the code I posted as an effect, you'll need to include some extra bits of code that specify what the vertex shader and pixel shader functions are. Something like this should work:

technique Render{    pass p0    {        VertexShader = NULL;        PixelShader = compile ps_2_0 psSinCity();    }}


Then you could compile it with something like this:
fxc /T fx_2_0 SinCity.fx


You'll notice I use the /T switch, which specifies the profile I want to use. In this case I'm using fx_2_0, since it's a D3D9 effect.

You can also just compile as a pixel or vertex shader, which is what I originally did. You can see the command in the assembly output file:
fxc /T ps_2_0 /E psSinCity /Fc SinCity.txt SinCity.fx


You'll see here I specify the pixel shader profile, and I also specify what the entry-point is of the shader (the psSinCity function). I also use the /Fc switch to have the compiler output assembly to a text file.
you made my day =)
just discovered that fxc works not with UTF-8 encoded files.
so beware =)

This topic is closed to new replies.

Advertisement