HLSL 3 Can a Pixel Shader be declared alone? - xna

I've been asked to split the question below into multiple questions:
HLSL and Pix number of questions
This is asking the first question, can I in HLSL 3 run a pixel shader without a vertex shader. In HLSL 2 I notice you can but I can't seem to find a way in 3?
The shader will compile fine, I will then however get this error from Visual Studio when calling SpriteBatch Draw().
"Cannot mix shader model 3.0 with earlier shader models. If either the vertex shader or pixel shader is compiled as 3.0, they must both be."
I don't believe I've defined anything in the shader to use anything earlier then 3. So I'm left a bit confused. Any help would be appreciated.

The problem is that the built-in SpriteBatch shader is 2.0. If you specify a pixel shader only, SpriteBatch still uses its built-in vertex shader. Hence the version mismatch.
The solution, then, is to also specify a vertex shader yourself. Fortunately Microsoft provides the source to XNA's built-in shaders. All it involves is a matrix transformation. Here's the code, modified so you can use it directly:
float4x4 MatrixTransform;
void SpriteVertexShader(inout float4 color : COLOR0,
inout float2 texCoord : TEXCOORD0,
inout float4 position : SV_Position)
{
position = mul(position, MatrixTransform);
}
And then - because SpriteBatch won't set it for you - setting your effect's MatrixTransform correctly. It's a simple projection of "client" space (source from this blog post). Here's the code:
Matrix projection = Matrix.CreateOrthographicOffCenter(0,
GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1);
Matrix halfPixelOffset = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
effect.Parameters["MatrixTransform"].SetValue(halfPixelOffset * projection);

You can try the simple examples here. The greyscale shader is a very good example to understand how a minimal pixel shader works.
Basically, you create a Effect under your content project like this one:
sampler s0;
float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
// B/N
//float4 color = tex2D(s0, coords);
//color.gb = color.r;
// Transparent
float4 color = tex2D(s0, coords);
return color;
}
technique Technique1
{
pass Pass1
{
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
You also need to:
Create an Effect object and load its content.
ambienceEffect = Content.Load("Effects/Ambient");
Call your SpriteBatch.Begin() method passing the Effect object you want to use
spriteBatch.Begin( SpriteSortMode.FrontToBack,
BlendState.AlphaBlend,
null,
null,
null,
ambienceEffect,
camera2d.GetTransformation());
Inside the SpriteBatch.Begin() - SpriteBatch.End() block, you must call the Technique inside the Effect
ambienceEffect.CurrentTechnique.Passes[0].Apply();

Related

Draw RGB pixel array to DirectX-11 render view

Given an array of RBG pixels that updates every frame (e.g. 1024x1024), a ID3D11RenderTargetView, ID3D11Device and ID3D11DeviceContext, what's the easiest way to draw these pixels to the render view?
I've been working the angle of creating a vertex buffer for a square (two triangles), trying to make pixels be a proper texture, and figuring out how to make a shader reference the texture sampler. I've been following this tutorial https://learn.microsoft.com/en-us/windows/uwp/gaming/applying-textures-to-primitives .... But to be honest, I don't see how this tutorial has shaders that even reference the texture data (shaders defined on the proceeding tutorial, here).
I am a total DirectX novice, but I am writing a plugin for an application where I am given a directx11 device/view/context, and need to fill it with my pixel data. Many thanks!
IF you can make sure your staging resource matches the exact resolution and format of the render target you are given:
Create a staging resource
Map the staging resource, and copy your data into it.
Unmap the staging resource
UseGetResource on the RTV to get the resource
CopyResource from your staging to that resource.
Otherwise, IF you can count on Direct3D Hardware Feature level 10.0 or better, the easiest way would be:
Create a texture with USAGE_DYNAMIC.
Map it and copy your data into the texture.
Unmap the resource
Render the dynamic texture as a 'full-screen' quad using the 'big-triangle' self-generation trick in the vertex shader:
SamplerState PointSampler : register(s0);
Texture2D<float4> Texture : register(t0);
struct Interpolators
{
float4 Position : SV_Position;
float2 TexCoord : TEXCOORD0;
};
Interpolators main(uint vI : SV_VertexId)
{
Interpolators output;
// We use the 'big triangle' optimization so you only Draw 3 verticies instead of 4.
float2 texcoord = float2((vI << 1) & 2, vI & 2);
output.TexCoord = texcoord;
output.Position = float4(texcoord.x * 2 - 1, -texcoord.y * 2 + 1, 0, 1);
return output;
}
and a pixel shader of:
float4 main(Interpolators In) : SV_Target0
{
return Texture.Sample(PointSampler, In.TexCoord);
}
Then draw with:
ID3D11ShaderResourceView* textures[1] = { texture };
context->PSSetShaderResources(0, 1, textures);
// You need a sampler object.
context->PSSetSamplers(0, 1, &sampler);
// Depending on your desired result, you may need state objects here
context->OMSetBlendState(nullptr, nullptr, 0xffffffff);
context->OMSetDepthStencilState(nullptr, 0);
context->RSSetState(nullptr);
context->IASetInputLayout(nullptr);
contet->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
Draw(3, 0);
For full source for the "Full Screen Quad" drawing, see GitHub.

BasicEffect fog, code used

I want to copy BasicEffect's fog method to use in my own shader so I don't have to declare a basiceffect shader and my own. The HLSL code of the basic effect was released with one of the downloadable samples on XNA Creators Club a while ago and I thought the method needed would be found within that HLSL file. However, all I can see is a function being called but no actual definition for that function. The function called is:
ApplyFog(color, pin.PositionWS.w);
Does anybody know where the definition is and if it's freely acceptable. Otherwise any help on how to replicate it's effect would be great.
I downloaded the sample from here.
Thanks.
Edit: Stil having problems. Think it's to do with getting depth:
VertexToPixel InstancedCelShadeVSNmVc(VSInputNmVc VSInput, in VSInstanceVc VSInstance)
{
VertexToPixel Output = (VertexToPixel)0;
Output.Position = mul(mul(mul(mul(VSInput.Position, transpose(VSInstance.World)), xWorld), xView), xProjection);
Output.ViewSpaceZ = -VSInput.Position.z / xCameraClipFar;
Is that right? Camera clip far is passed in as a constant.
Heres an example of how to achieve a similar effect
In your Vertex Shader Function, you pass the viewspace Z position, divided by the distance of your farplane, that gives you a nice 0..1 mapping for your depthvalues.
Than, in your pixelshader, you use the lerp function to blend between your original color value, and the fogcolor, heres some (pseudo)code:
cbuffer Input //Im used to DX10+ remove the cbuffer for DX9
{
float FarPlane;
float4 FogColor;
}
struct VS_Output
{
//...Whatever else you need
float ViewSpaceZ : TEXCOORD0; //or whatever semantic you'd like to use
}
VS_Output VertexShader(/*Your Input Here */)
{
VS_Output output;
//...Transform to viewspace
VS_Output.ViewSpaceZ = -vsPosition.Z / FarPlane;
return output;
}
float4 PixelShader(VS_Output input) : SV_Target0 // or COLOR0 depending on DX version
{
const float FOG_MIN = 0.9;
const float FOG_MAX = 0.99;
//...Calculate Color
return lerp(yourCalculatedColor, FogColor, lerp(FOG_MIN, FOG_MAX, input.ViewSpaceZ));
}
I've written this from the top of my head, hope it helps.
The constants i've chose will give you a pretty "steep" fog, choose a smaller value for FOG_MIN to get a smoother fog.

Shader execution stops in vertex shader before pixel shader

I’m trying to store the depth information of model in XNA from the lights point of view. The model renders fine using a normal shader.
This is the shader code
float4x4 xShadowMapLight;
///DEPTH MAP
float4 RenderShadowMapPS( VS_SHADOW_OUTPUT In ) : COLOR
{
return float4(1,0,0,0); //In.Depth.x,In.Depth.x,In.Depth.x,0);
}
VS_SHADOW_OUTPUT RenderShadowMapVS(float4 vPos: POSITION)
{
VS_SHADOW_OUTPUT Out;
Out.Position = mul(vPos, xShadowMapLight);
Out.Depth.x = 1-(Out.Position.z/Out.Position.w);
return Out;
}
technique ToonShaderDepthMap
{
pass P0
{
VertexShader = compile vs_2_0 RenderShadowMapVS();
PixelShader = compile ps_2_0 RenderShadowMapPS();
}
}
And this is the way I generate the light matrix that is passed to the shader.
Matrix view = Matrix.CreateLookAt(modelTransform.Translation, new Vector3(0, 500, 75), Vector3.Up);
Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 1.0f, (float)globals.NEAR_PLANE, (float)globals.FAR_PLANE);
Matrix ShadowMapLight = modelTransform * view * projection;
But apparently I’m not always getting to the pixel shader and it stops in the vertex for some reason.
(I have modified the pixel shader to output always a red pixel, so I know when it goes through).
xShadowMapLight is the Matrix containing all the transformations from the lights point of view.
Apparently the problem is in mul(vPos, xShadowMapLight); cause if I change the matrix for an Identity one the shader gets to the pixel one.
Any idea why this might happen?
Thanks in advance,
Walfrido.

General confusion about .fx files and shaders use in DirectX9 in C++ - how exactly do you make the connection with the app?

Well basically,I'm not quite sure how to properly use the Set and Get Parameter methods in DX to use the .fx files.I mean I can't find a good tutorial anywhere.I even had a book about D3D9 and while I got most of it,I'm still unable to use effect files.What's worse is the DirectX Samples provided by microsoft are packed with some DX Utility classes by microsoft and all sorts of other needless complications and I can't quite get it trough the 2k lines of code.I mean I get the basic idea(load,begin,loop with passes,end),but can anyone please point me out to a good tutorial on some simple example.The main thing I don't understand is how to work with the effect parameters :(
Here is a reference sheet I wrote back when I was first learning how to use HLSL shaders in DirectX9. Perhaps it will be of assistance.
IN THE APPLICATION:
Declare needed variables:
ID3DXEffect* shader;
Load the .fx file:
D3DXCreateEffectFromFile( d3dDevice,
_T("filepath.fx"),
0,
0,
0,
0,
&shader,
0
);
Clean up the effect object (some people use a SAFE_RELEASE macro):
if(shader)
shader->Release();
shader = nullptr;
Use the shader to render something:
void Application::Render()
{
unsigned passes = 0;
shader->Begin(&passes,0);
for(unsigned i=0;i<passes;++i)
{
shader->BeginPass(i);
// Set uniforms
shader->SetMatrix("gWorld",&theMatrix);
shader->CommitChanges(); // Not necessary if SetWhatevers are done OUTSIDE of a BeginPass/EndPass pair.
/* Insert rendering instructions here */
// BEGIN EXAMPLE:
d3dDevice->SetVertexDeclaration(vertexDecl);
d3dDevice->SetStreamSource(0,vertexBuffer,0,sizeof(VERT));
d3dDevice->SetIndices(indexBuffer);
d3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,numVerts,0,8);
// END EXAMPLE
shader->EndPass();
}
shader->End();
}
IN THE .FX FILE:
Declare the uniforms (variables you want to set from within the application):
float4x4 gWorld : WORLD;
float4x4 gViewProj : VIEWPROJECTION;
float gTime : TIME;
Texture2D gDiffuseTexture; // requires a matching sampler
sampler gDiffuseSampler = sampler_state // here's the matching sampler
{
Texture = <gDiffuseTexture>;
FILTER = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
Define the vertex shader input structure:
struct VS_INPUT // make this match the vertex structure in Application
{
float3 untransformed_pos : POSITION0;
float3 untransformed_nrm : NORMAL0;
float4 color : COLOR0;
float2 uv_coords : TEXCOORD0;
};
Define the pixel shader input structure (vertex shader output):
struct PS_INPUT
{
float4 transformed_pos : POSITION0;
float4 transformed_nrm : NORMAL0;
float4 color : COLOR0;
float2 uv_coords : TEXCOORD0;
};
Define a vertex shader:
PS_INPUT mainVS (VS_INPUT input)
{
PS_INPUT output;
/* Insert shader instructions here */
return output;
}
Define a pixel shader:
float4 mainPS (PS_INPUT input) : COLOR
{
/* Insert shader instructions here */
return float4(resultColor,1.0f);
}
Define a technique:
technique myTechnique
{
// Here is a quick sample
pass FirstPass
{
vertexShader = compile vs_3_0 mainVS();
pixelShader = compile ps_3_0 mainPS();
// Setting a few of the many D3D renderstates via the effect framework
ShadeMode = FLAT; // flat color interpolation across triangles
FillMode = SOLID; // no wireframes, no point drawing.
CullMode = CCW; // cull any counter-clockwise polygons.
}
}
Can you be a bit more specific about where you're having problems?
The basic idea with the API for Effect parameters is to load your .fx file and then use ID3DXEffect::GetParameterByName() or GetParameterBySemantic() to retrieve a D3DXHANDLE to the parameters you want to modify at runtime. Then in your render loop you can set the values for those parameters using the ID3DXEffect::SetXXX() family of functions (which one you use depends on the type of the parameter you are setting, e.g. Float, Vector, Matrix), passing the D3DXHANDLE you retrieved when you loaded the effect.
The reason you work with D3DXHANDLEs and not directly with parameter name strings is performance - it saves doing lots of string compares in your render loop to look up parameters.
A simple example of how you might use this is defining a texture2D parameter called diffuseTex in your .fx file. When you load the .fx file, use
D3DXHANDLE diffuseTexHandle = effect->GetParameterByName(NULL, "diffuseTex");
and then in your render loop set the appropriate diffuse texture for each model you draw using
LPDIRECT3DTEXTURE9 diffuseTexturePtr = GetMeTheRightTexturePlease();
ID3DXEffect::SetTexture(diffuseTexHandle, diffuseTexturePtr);

XNA pixel shader clamping error

I want to apply a pixel shader onto my background sprite, to create some sort of lighting.
So i draw a Render Target with the light on it and want to merge it onto the background via the Pixel shader.
This is the essential code:
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
lighting.Parameters["lightMask"].SetValue(lightingMask);
lighting.CurrentTechnique.Passes[0].Apply();
spriteBatch.Draw(hexBack, new Vector2(0, 0), Color.White);
spriteBatch.End();
In this case, hexBack is the Rendertarget with a simple sprite drawn in it and lightingMask is the rendertarget with the light texture in it.
Both are Backbuffer width and height.
So when i try to run the program, it crashes with:
XNA Framework Reach profile requires TextureAddressMode to be Clamp when using texture sizes that are not powers of two.
So i tried to set up clamping, but i cant find a way to get it working.
The shader code:
texture lightMask;
sampler mainSampler : register(s0);
sampler lightSampler = sampler_state{Texture = lightMask;};
struct PixelShaderInput
{
float4 TextureCoords: TEXCOORD0;
};
float4 PixelShaderFunction(PixelShaderInput input) : COLOR0
{
float2 texCoord = input.TextureCoords;
float4 mainColor = tex2D(mainSampler, texCoord);
float4 lightColor = tex2D(lightSampler, texCoord);
return mainColor * lightColor;
}
technique Technique1
{
pass Pass1
{
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
Thanks for your help!
pcnx
If you are unable to use power of two textures, you have to change your Spritebath.begin call and specify a SamplerState. The minimum to specify should be
public void Begin (
SpriteSortMode sortMode,
BlendState blendState,
SamplerState samplerState,
DepthStencilState depthStencilState,
RasterizerState rasterizerState
)
The error refers to your texture addressing mode (ie: does the texture wrap around at the edges, or is it clamped at the edges). Nothing to do with a shader.
Use one of the overloads for SpriteBatch.Begin (MSDN) that takes a SamplerState, and pass in SamplerState.LinearClamp (MSDN).
The default for SpriteBatch.Begin is SamplerState.LinearClamp, so you must be setting a different state (eg: LinearWrap) onto the graphics device somewhere else in your code? Don't do that.
(Alternately: change from the Reach profile to the HiDef profile in your project settings.)

Resources