2D Pixel Shader has no effect? - xna

I set up a basic pixel shader (right now, its configured for testing), and it doesn't seem to do anything. I set it up like so:
uniform extern texture ScreenTexture;
const float bloomThreshhold = 0.4;
const float existingPixelColorMult = 1.1;
sampler ScreenS = sampler_state
{
Texture = <ScreenTexture>;
};
float4 BloomedColor(float2 texCoord: TEXCOORD0) : COLOR
{
// pick a pixel on the screen for this pixel, based on
// the calculated offset and direction
float2 temp = texCoord;
temp.x += 1;
float4 mainPixelColor = 0;
/*
float4 pixelPlus1X = tex2D(ScreenS, temp);
temp.x -= 2;
float4 pixelMinus1X = tex2D(ScreenS, temp);
temp.x += 1;
temp.y += 1;
float4 pixelPlus1Y = tex2D(ScreenS, temp);
temp.y -= 2;
float4 pixelMinus1Y = tex2D(ScreenS, temp);
*/
return mainPixelColor;
}
technique Bloom
{
pass P0
{
PixelShader = compile ps_1_1 BloomedColor();
}
}
with the loading code like:
glowEffect = Content.Load<Effect>("GlowShader");
glowEffect.CurrentTechnique = glowEffect.Techniques[0];
and use code is:
spriteBatch.Begin();
glowEffect.Begin();
glowEffect.CurrentTechnique.Passes[0].Begin();
spriteBatch.Draw(screenImage, Vector2.Zero, Color.White);
spriteBatch.End();
glowEffect.CurrentTechnique.Passes[0].End();
glowEffect.End();
Loading seems to work fine, and there are no errors thrown when I use that method to render the texture, but it acts like the effect code isn't in there. It can't be that I'm using the wrong version of shaders (I tested with 2.0 and 1.1 versions), so why? (Using XNA 3.1)

You're returning 0 for every pixel. You have commented out any code that would return a different value than 0. 0 is black and if you're doing any sort of render you'll either get black (if the blend mode shows this as a color) or no change (if the blend mode multiplies the result). You can of course (if you were just attempting to see if the shader is being loaded and operated) try using an oddball color. Neon green anyone? Then, once you confirm it is being at least processed, start uncommenting that code and assessing the result.
Finally, if Bloom is what you're after, Microsoft has a very useful sample you will probably learn a lot from here:
http://create.msdn.com/en-US/education/catalog/sample/bloom

If you're using XNA 4.0, see what Shawn Hargreaves has to say about this.

Related

2D Water Bump Mapping - Monogame

Thanks for taking the time to check out my issue.
I am working on improving the ocean in my first attempt at a game. I have decided on a using a bump map against my ocean tiles to add a little texture to the water. To do this, I draw my water tiles to a renderTarget and then apply a pixel shader while drawing the render target to the backbuffer.
The problem I am having is that the pixel shader seems to offset or displace the position of render target that is drawn. Observe these two photos:
This image is the game without running the pixel shader. Notice the "shallow water" around the islands which is a solid color here.
With the pixel shader is run, that shallow water is offset to the right consistently.
I am using the bump map provided in riemers novice bump mapping. One possible thought I had was that the dimensions of this bump map do not match the render target I am applying it on. However, I'm not entirely sure how I would create/resize this bump map.
My HLSL pixel shader looks like this:
#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif
matrix WorldViewProjection;
float xWaveLength;
float xWaveHeight;
texture bumpMap;
sampler2D bumpSampler = sampler_state
{
Texture = <bumpMap>;
};
texture water;
sampler2D waterSampler = sampler_state
{
Texture = <water>;
};
// MAG,MIN,MIRRR SETTINGS? SEE RIEMERS
struct VertexShaderInput
{
float4 Position : POSITION0;
float2 TextureCords : TEXCOORD;
float4 Color : COLOR0;
};
struct VertexShaderOutput
{
float4 Pos : SV_POSITION;
float2 BumpMapSamplingPos : TEXCOORD2;
float4 Color : COLOR0;
};
VertexShaderOutput MainVS(in VertexShaderInput input)
{
VertexShaderOutput output = (VertexShaderOutput)0;
output.BumpMapSamplingPos = input.TextureCords/xWaveLength;
output.Pos = mul(input.Position, WorldViewProjection);
output.Color = input.Color;
return output;
}
float4 MainPS(float4 pos : SV_POSITION, float4 color1 : COLOR0, float2 texCoord : TEXCOORD0) : COLOR
{
float4 bumpColor = tex2D(bumpSampler, texCoord.xy);
//get offset
float2 perturbation = xWaveHeight * (bumpColor.rg - 0.5f)*2.0f;
//apply offset to coordinates in original texture
float2 currentCoords = texCoord.xy;
float2 perturbatedTexCoords = currentCoords + perturbation;
//return the perturbed values
float4 color = tex2D(waterSampler, perturbatedTexCoords);
return color;
}
technique oceanRipple
{
pass P0
{
//VertexShader = compile VS_SHADERMODEL MainVS();
PixelShader = compile PS_SHADERMODEL MainPS();
}
};
And my monogame draw call looks like this:
public void DrawMap(SpriteBatch sbWorld, SpriteBatch sbStatic, RenderTarget2D worldScene, GameTime gameTime)
{
// Set Water RenderTarget
_graphics.SetRenderTarget(waterScene);
_graphics.Clear(Color.CornflowerBlue);
sbWorld.Begin(_cam, SpriteSortMode.Texture);
foreach (var t in BoundingBoxLocations.OceanTileLocationList)
{
TilePiece tile = (TilePiece)t;
tile.DrawTile(sbWorld);
}
sbWorld.End();
// set up gamescene draw
_graphics.SetRenderTarget(worldScene);
_graphics.Clear(Color.PeachPuff);
// water
sbWorld.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
oceanRippleEffect.Parameters["bumpMap"].SetValue(waterBumpMap);
oceanRippleEffect.Parameters["water"].SetValue(waterScene);
//oceanRippleEffect.Parameters["xWaveLength"].SetValue(3f);
oceanRippleEffect.Parameters["xWaveHeight"].SetValue(0.3f);
ExecuteTechnique("oceanRipple");
sbWorld.Draw(waterScene, Vector2.Zero, Color.White);
sbWorld.End();
// land
sbWorld.Begin(_cam, SpriteSortMode.Texture);
foreach (var t in BoundingBoxLocations.LandTileLocationList)
{
TilePiece tile = (TilePiece)t;
tile.DrawTile(sbWorld);
}
sbWorld.End();
}
Can anyone see any issues with my code or otherwise that might be causing this offset issue?
Any help is much appreciated. Thanks!
EDIT
If I modify the xWaveHeight shader parameter, it changes where the offset appears. A value of 0 will not offset, but then the bump mapping is not applied. Is there any way around this?
I understand that the offset is being caused by the pixel shader perturbation, but I'm wondering if there is a way to undo this offset while preserving the bump mapping. In the linked riemer's tutorial, a vertex shader is included. I'm not quite sure if I need this, but when I include my vertex shader in the technique, and modify the pixel shader to the following, no water is drawn.
float4 MainPS(in VertexShaderOutput output) : COLOR
{
float4 bumpColor = tex2D(bumpSampler, output.BumpMapSamplingPos.xy);
//get offset
float2 perturbation = xWaveHeight * (bumpColor.rg - 0.5f)*2.0f;
//apply offset to coordinates in original texture
float2 currentCoords = output.BumpMapSamplingPos.xy;
float2 perturbatedTexCoords = currentCoords + perturbation;
//return the perturbed values
float4 color = tex2D(waterSampler, perturbatedTexCoords);
return color;
}
First of all, for what you seem to be wanting to do, bump mapping is actually the wrong approach: bump mapping is about changing the surface normal (basicly "rotating" the pixel in 3D space), so following light calculations (such as reflection) see your surface as more complex then it really is (Notice that the texture of that pixel stays where it is). So, bump mapping would not at all modify the position of the ocean tile texture, but modify what is reflected by the ocean (for example, by changing the sample position of a skybox, so the reflection of the sky in the water is distorted). The way you are implementing it is more like "What if my screen would be an ocean and would reflect an image of tiles with ocean textures".
If you really want to use bump mapping, you would need some kind of big sky texture, and then, while (not after) drawing the ocean tiles, you would calculate a sample position of the reflection of this sky texture (based on the position of the tile on the screen) and then modify that sample position with bump mapping. All while drawing the tiles, not after drawing them to a render target.
It is also possible to do this deffered (more similar to what you are doing now) - actually, there are multiple ways of doing so - but either way you would still need to sample the final color from a sky texture, not from the render target your tiles were drawn on. The render target from your tiles would instead contain "meta" informations (depending on how exactly you want to do this). These informations could be a color that is multiplied with the color from the sky texture (creating "colored" water, eg. for different bioms or to simulate sun sets/sun rises), or a simple 1 or 0 to tell wether or not there is any ocean, or a per-tile bump map (which would you allow to apply a "screen global" and a "per tile" bump mapping in one go. You would still need a way to say "this pixel is not an ocean, don't do anything for that" in the render target), or - if you use multiple render targets - all of these at once. In any way, the sample position to sample from your render target(s) is not modified by bump mapping, only the sample position of the texture that is reflected by the ocean is. That way, there's also no displacement of the ocean, since we aren't touching that sample positions at all.
Now, to create a look that is more similar to what you seem to be wanting (according to your images), you wouldn't use bump mapping, but instead apply a small noise to the sample position in your pixel shader (the rest of the code doesn't need to change). For that, your shader would look more like this:
texture noiseTexture;
sampler2D noiseSampler = sampler_state
{
Texture = <noiseTexture>;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
float2 noiseOffset;
float2 noisePower;
float noiseFrequency;
VertexShaderOutput MainVS(in VertexShaderInput input)
{
VertexShaderOutput output = (VertexShaderOutput)0;
output.Pos = mul(input.Position, WorldViewProjection);
output.Color = input.Color;
return output;
}
float4 MainPS(float4 pos : SV_POSITION, float4 color1 : COLOR0, float2 texCoord : TEXCOORD0) : COLOR
{
float4 noise = tex2D(noiseSampler, (texCoord.xy + noiseOffset.xy) * noiseFrequency);
float2 offset = noisePower * (noise.xy - 0.5f) * 2.0f;
float4 color = tex2D(waterSampler, texCoord.xy + offset.xy);
return color;
}
Where noisePower would be (at most) approx. 1 over the number of horizontal/vertical tiles on the screen, noiseOffset can be used to "move" the noise over time on the screen (should be in range [-1;1]), and noiseFrequency is an artistic parameter (I would start with twice the max noise power, and then modify it from there, with higher values making the ocean more distorted). This way, the border of the tiles is distorted, but never moved more then one tile in any direction (thanks to the noisePower parameter). It is also important to use the correct kind of noise texture here: white noise, blue noise, maybe a "not really noise" texture that's build out of sinus waves, etc. Important is the fact that the "average" value of each pixel is about 0.5, so there's no overall displacement happening, and that the values are well distributed in the texture. Appart from that, see what kind of noise looks best for you.
Side note to the shader code: I haven't tested that code. Just that you know, not that there would be much room for mistakes.
Edit: As a side node: Of course the sky texture doesn't need to actualy look like a sky ;)

what is the 'alpha' value of pixel shader?

hi there day i am in process to make 2d game using directx11 api.
and it come to point that i need to use transparent effect.
so i have a green background and one footprint on middle.
and simply without setting anything but alpha value of returning color in pixel shader, i made a bit of success, but the problem is that it doesn't work for white color.
this is Pixel Shader code
cbuffer CB_TRANSPARENCY : register(b0)
{
float tp;
};
Texture2D footprint : register(t0);
SamplerState samplerState : register(s0);
struct PS_INPUT
{
float4 pos : SV_POSITION;
float2 tex : TEXCOORD;
};
float4 main(PS_INPUT input) : SV_Target
{
float3 texColor = footprint.Sample(samplerState, input.tex).xyz;
return float4(texColor, tp);
}
it there something that i miss?
or should i use some blendingstate thing?
any help would be appreciated
[edit] here's something to edit. actually alpha value doesn't do anything without blending setting. just one variable to be used for any custom calculation.
In my project, i was using spritebathch,spritefont class for rendering font on screen,
So i guess in spritebatch class, there might be blendingState under the hood that blend black color, so that i have got this effect without setting my blendingState.
Yes, you need to create a blend state with appropriate alpha processing mode and then make sure that created blend state is attached to output merging stage of the rendering pipeline prior to drawing:
D3D11_BLEND_DESC blendStateDesc{};
blendStateDesc.AlphaToCoverageEnable = FALSE;
blendStateDesc.IndependentBlendEnable = FALSE;
blendStateDesc.RenderTarget[0].BlendEnable = TRUE;
blendStateDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendStateDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendStateDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendStateDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
blendStateDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
blendStateDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendStateDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
if(not SUCCEEDED(p_device->CreateBlendState(&blendStateDesc, &blendState)))
{
std::abort();
}
p_device_context->OMSetBlendState(blendState, nullptr, 0xFFFFFFFF);
//draw calls...

How to manually render a mesh loaded with the DirectX Toolkit

I have a c++/cx project where I'm rendering procedural meshes using DirectX-11, it all seems to work fine, but now I wanted to also import and render meshes from files (from fbx to be exact).
I was told to use the DirectX Toolkit for this.
I followed the tutorials of the toolkit, and that all worked,
but then I tried doing that in my project but it didn't seem to work. The imported mesh was not visible, and the existing procedural meshes were rendered incorrectly (as if without a depth buffer).
I then tried manually rendering the imported mesh (identical to the procedural meshes, without using the Draw function from DirectXTK)
This works better, the existing meshes are all correct, but the imported mesh color's are wrong; I use a custom made vertex and fragment shader, that uses only vertex position and color data, but for some reason the imported mesh's normals are send to shader instead of the vertex-colors.
(I don't even want the normals to be stored in the mesh, but I don't seem to have the option to export to fbx without normals, and even if I remove them manually from the fbx, at import the DirectXTK seem to recalculate the normals)
Does anyone know what I'm doing wrong?
This is all still relatively new to me, so any help appreciated.
If you need more info, just let me know.
Here is my code for rendering meshes:
First the main render function (which is called once every update):
void Track3D::Render()
{
if (!_loadingComplete)
{
return;
}
static const XMVECTORF32 up = { 0.0f, 1.0f, 0.0f, 0.0f };
// Prepare to pass the view matrix, and updated model matrix, to the shader
XMStoreFloat4x4(&_constantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(_CameraPosition, _CameraLookat, up)));
// Clear the back buffer and depth stencil view.
_d3dContext->ClearRenderTargetView(_renderTargetView.Get(), DirectX::Colors::Transparent);
_d3dContext->ClearDepthStencilView(_depthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
// Set render targets to the screen.
ID3D11RenderTargetView *const targets[1] = { _renderTargetView.Get() };
_d3dContext->OMSetRenderTargets(1, targets, _depthStencilView.Get());
// Here I render everything:
_TrackMesh->Render(_constantBufferData);
RenderExtra();
_ImportedMesh->Render(_constantBufferData);
Present();
}
The Present-function:
void Track3D::Present()
{
DXGI_PRESENT_PARAMETERS parameters = { 0 };
parameters.DirtyRectsCount = 0;
parameters.pDirtyRects = nullptr;
parameters.pScrollRect = nullptr;
parameters.pScrollOffset = nullptr;
HRESULT hr = S_OK;
hr = _swapChain->Present1(1, 0, &parameters);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
OnDeviceLost();
}
else
{
if (FAILED(hr))
{
throw Platform::Exception::CreateException(hr);
}
}
}
Here's the render function which I call on every mesh:
(All of the mesh-specific data is gotten from the imported mesh)
void Mesh::Render(ModelViewProjectionConstantBuffer constantBufferData)
{
if (!_loadingComplete)
{
return;
}
XMStoreFloat4x4(&constantBufferData.model, XMLoadFloat4x4(&_modelMatrix));
// Prepare the constant buffer to send it to the Graphics device.
_d3dContext->UpdateSubresource(
_constantBuffer.Get(),
0,
NULL,
&constantBufferData,
0,
0
);
UINT offset = 0;
_d3dContext->IASetVertexBuffers(
0,
1,
_vertexBuffer.GetAddressOf(),
&_stride,
&_offset
);
_d3dContext->IASetIndexBuffer(
_indexBuffer.Get(),
DXGI_FORMAT_R16_UINT, // Each index is one 16-bit unsigned integer (short).
0
);
_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
_d3dContext->IASetInputLayout(_inputLayout.Get());
// Attach our vertex shader.
_d3dContext->VSSetShader(
_vertexShader.Get(),
nullptr,
0
);
// Send the constant buffer to the Graphics device.
_d3dContext->VSSetConstantBuffers(
0,
1,
_constantBuffer.GetAddressOf()
);
// Attach our pixel shader.
_d3dContext->PSSetShader(
_pixelShader.Get(),
nullptr,
0
);
SetTexture();
// Draw the objects.
_d3dContext->DrawIndexed(
_indexCount,
0,
0
);
}
And this is the vertex shader:
cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
matrix model;
matrix view;
matrix projection;
};
struct VertexShaderInput
{
float3 pos : POSITION;
//float3 normal : NORMAL0; //uncommenting these changes the color data for some reason (but always wrong)
//float2 uv1 : TEXCOORD0;
//float2 uv2 : TEXCOORD1;
float3 color : COLOR0;
};
struct VertexShaderOutput
{
float3 color : COLOR0;
float4 pos : SV_POSITION;
};
VertexShaderOutput main(VertexShaderInput input)
{
VertexShaderOutput output;
float4 pos = float4(input.pos, 1.0f);
// Transform the vertex position into projected space.
pos = mul(pos, model);
pos = mul(pos, view);
pos = mul(pos, projection);
output.pos = pos;
output.color = input.color;
return output;
}
And this is the pixel shader:
struct PixelShaderInput
{
float3 color: COLOR0;
};
float4 main(PixelShaderInput input) : SV_TARGET
{
return float4(input.color.r, input.color.g, input.color.b, 1);
}
The most likely issue is that you are not setting enough state for your drawing, and that the DirectX Tool Kit drawing functions are setting states that don't match what your existing code requires.
For performance reasons, DirectX Tool Kit does not 'save & restore' state. Instead each draw function sets the state it needs fully and then leaves it. I document which state is impacted in the wiki under the State management section for each class.
Your code above sets the vertex buffer, index buffer, input layout, vertex shader, pixel shader, primitive topology, and VS constant buffer in slot 0.
You did not set blend state, depth/stencil state, or the rasterizer state. You didn't provide the pixel shader so I don't know if you need any PS constant buffers, samplers, or shader resources.
Try explicitly setting the blend state, depth/stencil state, and rasterizer state before you draw your procedural meshes. If you just want to go back to the defined defaults instead of whatever DirectX Tool Kit did, call:
_d3dContext->RSSetState(nullptr);
_d3dContext->OMSetBlendState(nullptr, nullptr, 0);
_d3dContext->OMSetDepthStencilState(nullptr, 0xffffffff);
See also the CommonStates class.
It's generally not a good idea to use identifiers that start with _ in C++. Officially all identifiers that start with _X where X is a capital letter or __ are reserved for the compiler and library implementers so it could conflict with some compiler stuff. m_ or something similar is better.

Transparency shader cover model

I am using XNA, implementing the HLSL shader and i have a problem with transparency
in the shader;
When rendering two models and they are facing each other the model behind is seen only
when it is first rendered
Let me explain...
blue cone = vector3(0,0,0) - first target
green cone = vector3(50,0,50) - second target
here rendering blue first and then the green and blue cone is seen
can see
now the other way before the green then blue and you do not see
cannot see
As long as they are two cones I can calculate the distance from the camera and render
before the most distant (the only solution I found by searching on the net), but if I
have several models and sizes, it can happen that a model A is most distant of a model B
but that its size may lead him to hide the model B.
Here put some code i use
.fx file
float4x4 World;
float4x4 View;
float4x4 Projection;
float3 Color;
texture ColorTexture : DIFFUSE ;
sampler2D ColorSampler = sampler_state {
Texture = <ColorTexture>;
FILTER = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
struct VertexShaderInput
{
float4 Position : POSITION0;
float3 UV : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float3 UV : TEXCOORD0;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
float4 projPosition = mul(viewPosition, Projection);
output.Position = projPosition;
output.UV = input.UV;
return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float4 map = tex2D(ColorSampler,input.UV);
return float4(map.rgb * Color, map.a);
}
technique Textured
{
pass Pass1
{
ZEnable = true;
ZWriteEnable = true;
AlphaBlendEnable = true;
DestBlend = DestAlpha;
SrcBlend=BlendFactor;
VertexShader = compile vs_3_0 VertexShaderFunction();
PixelShader = compile ps_3_0 PixelShaderFunction();
}
}
draw code in XNA project
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.DarkGray);
for (int i = 0; i < 2; i++)
{
ModelEffect.Parameters["View"].SetValue(this.View);
ModelEffect.Parameters["Projection"].SetValue(this.Projection);
ModelEffect.Parameters["ColorTexture"].SetValue(this.colorTextured);
ModelEffect.CurrentTechnique = ModelEffect.Techniques["Textured"];
Vector3 Scala = new Vector3(2, 3, 1);
if (i == 0)
{
World = Matrix.CreateScale(Scala) * Matrix.CreateWorld(FirstTarget, Vector3.Forward, Vector3.Up);
ModelEffect.Parameters["Color"].SetValue(new Vector3(0, 0, 255));// blu
}
else
{
World = Matrix.CreateScale(Scala) * Matrix.CreateWorld(SecondTarget, Vector3.Forward, Vector3.Up);
ModelEffect.Parameters["Color"].SetValue(new Vector3(0, 255, 0));// verde
}
ModelEffect.Parameters["World"].SetValue(World);
foreach (ModelMesh mesh in Emitter.Meshes)
{
foreach (ModelMeshPart effect in mesh.MeshParts)
{
effect.Effect = ModelEffect;
}
mesh.Draw();
}
}
base.Draw(gameTime);
}
the for cycle I need for chage sort rendering...
Is there any procedure to be able to work around this problem?
I hope I explained myself, I think we should work on the file .fx ...or not?
I'm on the high seas :)
This is a classic computer graphics problem -- what you'll need to do depends on your specific model and need, but transparency is as you've discovered order dependent -- as Nico mentioned, if you sort entire meshes back-to-front (draw the back ones first) for each frame, you will be okay, but what about curved surfaces that need to draw sometimes in front of themselves (that is, they are self-occluding from the camera's point of view)? Then you have to go much farther and sort the polys within the mesh (adios, high performance!). If you don't sort, chances are, the order will look correct on average 50% or less of the time (unless your model is posed just right).
If you are drawing transparent cones, as they rotate to different views they will look correct sometimes and wrong other times, if two-sided rendering is enabled. Most of the time wrong.
One option is to just turn off depth-write buffering during the pass(es) where you draw the transparent items. Again, YMMV according to the scene's needs, but this can be a useful fix in many cases. Another is to segment the model and sort the meshes.
In games, many strategies have been followed, including re-ordering the models by hand, forcing the artists to limit transparency to certain passes only, drawing two passes per transparent layer (one with transparent color, and another with opaque but no color write to get the Z buffer correct), sending models back for a re-do, or even, if the errors are small or the action is fast, just accepting broken transparency.
There have been various solutions proposed to this general problem -- "OIT" (Order Independent Transparency) is a big enough topic to get its own wikipedia page: http://en.wikipedia.org/wiki/Order-independent_transparency

Efficient way to render a bunch of layered textures?

What's the efficient way to render a bunch of layered textures? I have some semitransparent textured rectangles that I position randomly in 3D space and render them from back to front.
Currently I call d3dContext->PSSetShaderResources() to feed the pixel shader with a new texture before each call to d3dContext->DrawIndexed(). I have a feeling that I am copying the texture to the GPU memory before each draw. I might have 10-30 ARGB textures roughly 1024x1024 pixels each and they are associated across 100-200 rectangles that I render on screen. My FPS is OK at 100, but goes pretty bad around 200. I possibly have some inefficiencies elsewhere since this is my first semi-serious D3D code, but I strongly suspect this has to do with copying the textures back and forth. 30*1024*1024*4 is 120MB, which is a bit high for a Metro Style App that should target any Windows 8 device. So putting them all in there might be a stretch, but maybe I could at least cache a few somehow? Any ideas?
*EDIT - Some code snippets added
Constant Buffer
struct ModelViewProjectionConstantBuffer
{
DirectX::XMMATRIX model;
DirectX::XMMATRIX view;
DirectX::XMMATRIX projection;
float opacity;
float3 highlight;
float3 shadow;
float textureTransitionAmount;
};
The Render Method
void RectangleRenderer::Render()
{
// Clear background and depth stencil
const float backgroundColorRGBA[] = { 0.35f, 0.35f, 0.85f, 1.000f };
m_d3dContext->ClearRenderTargetView(
m_renderTargetView.Get(),
backgroundColorRGBA
);
m_d3dContext->ClearDepthStencilView(
m_depthStencilView.Get(),
D3D11_CLEAR_DEPTH,
1.0f,
0
);
// Don't draw anything else until all textures are loaded
if (!m_loadingComplete)
return;
m_d3dContext->OMSetRenderTargets(
1,
m_renderTargetView.GetAddressOf(),
m_depthStencilView.Get()
);
UINT stride = sizeof(BasicVertex);
UINT offset = 0;
// The vertext buffer only has 4 vertices of a rectangle
m_d3dContext->IASetVertexBuffers(
0,
1,
m_vertexBuffer.GetAddressOf(),
&stride,
&offset
);
// The index buffer only has 4 vertices
m_d3dContext->IASetIndexBuffer(
m_indexBuffer.Get(),
DXGI_FORMAT_R16_UINT,
0
);
m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_d3dContext->IASetInputLayout(m_inputLayout.Get());
FLOAT blendFactors[4] = { 0, };
m_d3dContext->OMSetBlendState(m_blendState.Get(), blendFactors, 0xffffffff);
m_d3dContext->VSSetShader(
m_vertexShader.Get(),
nullptr,
0
);
m_d3dContext->PSSetShader(
m_pixelShader.Get(),
nullptr,
0
);
m_d3dContext->PSSetSamplers(
0, // starting at the first sampler slot
1, // set one sampler binding
m_sampler.GetAddressOf()
);
// number of rectangles is in the 100-200 range
for (int i = 0; i < m_rectangles.size(); i++)
{
// start rendering from the farthest rectangle
int j = (i + m_farthestRectangle) % m_rectangles.size();
m_vsConstantBufferData.model = m_rectangles[j].transform;
m_vsConstantBufferData.opacity = m_rectangles[j].Opacity;
m_vsConstantBufferData.highlight = m_rectangles[j].Highlight;
m_vsConstantBufferData.shadow = m_rectangles[j].Shadow;
m_vsConstantBufferData.textureTransitionAmount = m_rectangles[j].textureTransitionAmount;
m_d3dContext->UpdateSubresource(
m_vsConstantBuffer.Get(),
0,
NULL,
&m_vsConstantBufferData,
0,
0
);
m_d3dContext->VSSetConstantBuffers(
0,
1,
m_vsConstantBuffer.GetAddressOf()
);
m_d3dContext->PSSetConstantBuffers(
0,
1,
m_vsConstantBuffer.GetAddressOf()
);
auto a = m_rectangles[j].textureId;
auto b = m_rectangles[j].targetTextureId;
auto srv1 = m_textures[m_rectangles[j].textureId].textureSRV.GetAddressOf();
auto srv2 = m_textures[m_rectangles[j].targetTextureId].textureSRV.GetAddressOf();
ID3D11ShaderResourceView* srvs[2];
srvs[0] = *srv1;
srvs[1] = *srv2;
m_d3dContext->PSSetShaderResources(
0, // starting at the first shader resource slot
2, // set one shader resource binding
srvs
);
m_d3dContext->DrawIndexed(
m_indexCount,
0,
0
);
}
}
Pixel Shader
cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
matrix model;
matrix view;
matrix projection;
float opacity;
float3 highlight;
float3 shadow;
float textureTransitionAmount;
};
Texture2D baseTexture : register(t0);
Texture2D targetTexture : register(t1);
SamplerState simpleSampler : register(s0);
struct PixelShaderInput
{
float4 pos : SV_POSITION;
float3 norm : NORMAL;
float2 tex : TEXCOORD0;
};
float4 main(PixelShaderInput input) : SV_TARGET
{
float3 lightDirection = normalize(float3(0, 0, -1));
float4 baseTexelColor = baseTexture.Sample(simpleSampler, input.tex);
float4 targetTexelColor = targetTexture.Sample(simpleSampler, input.tex);
float4 texelColor = lerp(baseTexelColor, targetTexelColor, textureTransitionAmount);
float4 shadedColor;
shadedColor.rgb = lerp(shadow.rgb, highlight.rgb, texelColor.r);
shadedColor.a = texelColor.a * opacity;
return shadedColor;
}
As Jeremiah has suggested, you are not probably moving texture from CPU to GPU for each frame as you would have to create new texture for each frame or using "UpdateSubresource" or "Map/UnMap" methods.
I don't think that instancing is going to help for this specific case, as the number of polygons is extremely low (I would start to worry with several millions of polygons). It is more likely that your application is going to be bandwidth/fillrate limited, as your are performing lots of texture sampling/blending (It depends on tecture fillrate, pixel fillrate and the nunber of ROP on your GPU).
In order to achieve better performance, It is highly recommended to:
Make sure that all your textures have all mipmaps generated. If they
don't have any mipmaps, It will hurt a lot the cache of the GPU. (I also assume that you are using texture.Sample method in HLSL, and not texture.SampleLevel or variants)
Use Direct3D11 Block Compressed texture on the GPU, by using a tool
like texconv.exe or preferably the sample from "Windows DirectX 11
Texture Converter".
On a side note, you will probably get more attention for this kind of question on https://gamedev.stackexchange.com/.
I don't think you are doing any copying back and forth from GPU to system memory. You usually have to explicitly do that a call to Map(...), or by blitting to a texture you created in system memory.
One issue, is you are making a DrawIndexed(...) call for each texture. GPUs work most efficiently if you send it a bunch of work to do by batching. One way to accomplish this is to set n-amount of textures to PSSetShaderResources(i, ...), and do a DrawIndexedInstanced(...). Your shader code would then read each of the shader resources and draw them. I do this in my C++ DirectCanvas code here (SpriteInstanced.cpp). This can make for a lot of code, but the result is very efficient (I even do the matrix ops in the shader for more speed).
One other, maybe a lot easier way, is to give the DirectXTK spritebatch a shot.
I used it here in this project...only for a simple blit but it may be a good start to see the minor amount of setup needed to use the spritebatch.
Also, if possible, try to "atlas" your texture. For instance, try to fit as many "images" in a texture as possible and blit from them vs having a single texture for each.

Resources