Color Picking, Constant Buffers, and Shaders

posted in 2d Game Creation
Published October 21, 2014
Advertisement
FINALLY!!! Constant buffer worked without errors. I guess I kept running into bad examples. Many were missing information. I simply wanted to do color picking and set a constant buffer for the color. So both the color picking and the constant buffer (to set the object/shape to a solid color to be referenced) were a pain.
So
R - What kinds of pick (gui, object/shape, control point)
G - index1 (example - object index)
B - index2 (example - shape index)

So I finally wrote directx functions that are similar to my opengl counterparts.


For now this is my constant buffer (the name is from the msdn example). Vector4f is my own (x, y, z, w).
The other is my PixelShader, to which is stored in a vector for multiple shaders.struct VS_CONSTANT_BUFFER{Vector4f modifier;};struct PixelShader{ID3D11PixelShader* shader; ID3D11Buffer* g_pConstantBuffer11;Vector4f modifier;};
This is my AddShader routine. I currently have both my pixel shader and vertex shader in the same file, but left it like this in case I change my mind. I just give the same file name for both pix and vert.Vector2i Shaders::AddShader(ID3D11Device *dev, ID3D11DeviceContext *devcon, char* pix, char* vert){cShade = -1;//The Shaders. cShade holds the index of current shader loaded. -1 means none.pVS.resize(pVS.size() + 1);pPS.resize(pPS.size() + 1);pLayout.resize(pLayout.size() + 1);ID3D10Blob *VS, *PS;HRESULT HRV = D3DX11CompileFromFile(vert, 0, 0, "VShader", "vs_4_0", 0, 0, 0, &VS, 0, 0);HRESULT HRP = D3DX11CompileFromFile(pix, 0, 0, "PShader", "ps_4_0", 0, 0, 0, &PS, 0, 0);//Create the shaders and give the pointers. Vertex currently does not have extra parameters is just a std::vectordev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS[pVS.size() - 1]);dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS[pPS.size() - 1].shader);//Each time the shaders are set, the modifier will be set to this initial valuepPS[pPS.size() - 1].modifier.x = 1.0f;pPS[pPS.size() - 1].modifier.y = 1.0f;pPS[pPS.size() - 1].modifier.z = 1.0f;pPS[pPS.size() - 1].modifier.w = 1.0f;//modify is what will be sent to the constant buffermodify.modifier = pPS[pPS.size() - 1].modifier;//constant buffer setup section STARTD3D11_BUFFER_DESC bd;ZeroMemory(&bd, sizeof(bd));bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;bd.ByteWidth = sizeof(modify);bd.Usage = D3D11_USAGE_DEFAULT;HRESULT hr = dev->CreateBuffer(&bd, 0, &pPS[pPS.size() - 1].g_pConstantBuffer11);if( !FAILED( hr ) )devcon->VSSetConstantBuffers( 0, 1, &pPS[pPS.size() - 1].g_pConstantBuffer11 );//constant buffer setup section ENDD3D11_INPUT_ELEMENT_DESC ied[] ={{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},{"UV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0},}; dev->CreateInputLayout(ied, 3, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout[pLayout.size() - 1]);return Vector2i(pPS.size() -1, pVS.size() - 1);}
This part of the code I saw so many different variations on. This one worked for me (finally).D3D11_BUFFER_DESC bd;ZeroMemory(&bd, sizeof(bd));bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;bd.ByteWidth = sizeof(modify);bd.Usage = D3D11_USAGE_DEFAULT;HRESULT hr = dev->CreateBuffer(&bd, 0, &pPS[pPS.size() - 1].g_pConstantBuffer11);if( !FAILED( hr ) )devcon->VSSetConstantBuffers( 0, 1, &pPS[pPS.size() - 1].g_pConstantBuffer11 );
I selected my shader for drawing here.void Shaders::SetShader(ID3D11DeviceContext *devcon, int index){if (cShade == index) return;cShade = index;devcon->VSSetShader(pVS[index], 0, 0);devcon->PSSetShader(pPS[index].shader, 0, 0);devcon->IASetInputLayout(pLayout[index]);SetConstantBuffer(devcon, pPS[cShade].modifier);}
This code is used after I select the shader for the current draw (or when the shader is first selected). This will update the constant buffer to a new value. I can use it for color picking and other fun stuff.void Shaders::SetConstantBuffer(ID3D11DeviceContext *devcon, Vector4f aMod){modify.modifier = aMod;devcon->UpdateSubresource(pPS[cShade].g_pConstantBuffer11, 0, 0, &modify, 0, 0);devcon->PSSetConstantBuffers(0, 1, &pPS[cShade].g_pConstantBuffer11);}
And this is the shader for my ellipsestruct VOut{ float4 position : SV_POSITION; float4 color : COLOR; float2 uv : UV;};cbuffer VS_CONSTANT_BUFFER : register(b0){ float4 modifier;};VOut VShader(float4 position : POSITION, float4 color : COLOR, float2 uv : UV){ VOut output; output.position = position; output.color = color; output.uv = uv; return output;}float4 PShader(float4 position : SV_POSITION, float4 color : COLOR, float2 uv : UV) : SV_TARGET{ float result = (uv.x * uv.x + uv.y * uv.y); if (color.a < 1.0) color = float4(.50, .50, .50, 1.0) * color; if (result > 1) discard; if (modifier.w == 0.0) { color.r = modifier.x; color.g = modifier.y; color.b = modifier.z; color.a = 1.0; } return color;}

[Edit] Forgot Color Picking.
The Color format of the 1x1 texture must be the same as your backbuffer, or this is SO fail (took a while on that). The mouse must be in bounds or the srcbox will be said to be invalid.Vector4f PickColor(int the2d, int x, int y, ID3D11Device *dev, ID3D11DeviceContext *devcon){ID3D11Texture2D *BackBuffer;HRESULT hr = swapchain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast< void** >( &BackBuffer ));Vector4f a = Vector4f(0, 0, 0 ,0);ID3D11Texture2D *Surface;D3D11_TEXTURE2D_DESC StagedDesc = {1,//Width;1,//Height;1,//MipLevels;1,//ArraySize;DXGI_FORMAT_R8G8B8A8_UNORM,//DXGI_FORMAT Format;1, 0,//DXGI_SAMPLE_DESC SampleDesc;D3D11_USAGE_STAGING,//D3D11_USAGE Usage;0,//UINT BindFlags;D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE,//UINT CPUAccessFlags;0//UINT MiscFlags;};dev->CreateTexture2D( &StagedDesc, NULL, &Surface);D3D11_BOX srcBox;srcBox.left = x;srcBox.right = srcBox.left + 1;srcBox.top = y;srcBox.bottom = srcBox.top + 1;srcBox.front = 0;srcBox.back = 1;devcon->CopySubresourceRegion(Surface, 0, 0, 0, 0, BackBuffer, 0, &srcBox);D3D11_MAPPED_SUBRESOURCE msr;if (devcon->Map(Surface, 0, D3D11_MAP_READ_WRITE, 0, &msr) != S_OK) return Vector4f(-1, -1, -1, -1);void *pixelA = msr.pData;std::vector pixel;pixel.resize(4);memcpy(&pixel[0], pixelA, 4);a.x = (float)pixel[0];a.y = (float)pixel[1];a.z = (float)pixel[2];a.w = (float)pixel[3];pixel.resize(0);devcon->Unmap(Surface, 0);Surface->Release();BackBuffer->Release();return a;}
Previous Entry Bezier, it's french
0 likes 1 comments

Comments

tnovelli

Say, have you noticed that the usual RGB-HSL color pickers are artistically awkward? I went looking for something better and found the CIELUV perceptual colorspace. It's got some oddities as you can see in my JS implementation (http://tnovelli.net/junk/color.html) and the geeky vaccuum-tube-era formulas are overkill for this, but it does seem like an improvement.

Just thought I'd throw that out there. Curious what other devs & artists think of it.

October 23, 2014 11:27 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement