背景: - 过去 6 周我一直在尝试学习 Directx 11 编程。
我正在尝试在 2D 背景上绘制 2D 精灵,它本身也是 2D 精灵。问题是这两行
d3dDevice_->CreateBlendState( &blendDesc, &alphaBlendState_ );
d3dContext_->OMSetBlendState(alphaBlendState_, blendFactor, 0xFFFFFFFF);
启用 dds 图像中的 alpha 透明度。我喜欢混合精灵的选项,但现在每个精灵都与我的蓝色背景混合,从而产生蓝色徽标、图标等。
如何使 Alpha 混合忽略 directx 11 中的特定图像?
由于背景精灵是第一个被绘制的,我无法在代码中稍后在渲染其他精灵时激活混合,而每个精灵都变成蓝色。
提前致谢 :)
编辑:过去 3 周我一直在研究这个问题,但仍然没有解决方案。每次在 DeviceContext 中启用混合状态似乎都适用于屏幕上绘制的每个纹理,无论渲染顺序如何。
下面是头文件的源代码:
class GameSpriteDemo : public Dx11DemoBase
{
public:
GameSpriteDemo( );
virtual ~GameSpriteDemo( );
bool LoadContent( );
void UnloadContent( );
void Update( float dt );
void Render( );
void DisableBlending();
ID3D11ShaderResourceView* getColorMap(int);
int UniqSpriteAmount();
// text rendering system
private:
bool DrawString( char* message, float startX, float startY );
private:
ID3D11VertexShader* solidColorVS_;
ID3D11VertexShader* solidColorVS_2;
ID3DX11Effect* effect_;
vector<ID3D11VertexShader*> solidColorVShaders;
ID3D11PixelShader* solidColorPS_;
ID3D11PixelShader* solidColorPS_2;
ID3D11InputLayout* inputLayout_;
ID3D11InputLayout* inputLayout2;
ID3D11Buffer* vertexBuffer_;
vector<ID3D11Buffer*> vertexBuffers;
ID3D11ShaderResourceView* colorMap_;
vector<ID3D11ShaderResourceView*> colorMaps;
ID3D11SamplerState* colorMapSampler_;
vector<ID3D11SamplerState*> colorSamplers;
ID3D11BlendState* alphaBlendState_;
ID3D11BlendState* alphaBlendStateOff;
vector<LPCTSTR> elements2D;
vector<GameSprite> sprites_;
ID3D11Buffer* mvpCB_;
XMMATRIX vpMatrix_;
};
#endif
这是cpp文件的源代码:(不需要基类DxD11DemoClass,因为它只设置了SwapChain和D3DContext)
bool GameSpriteDemo::LoadContent( )
{
// add sprite textures to the engine, giving them index 0, 1, 2... etc.
elements2D.push_back("placeholder3.dds");
elements2D.push_back("cav.dds");
elements2D.push_back("Stats.dds");
// create sprites
XMFLOAT2 sprite1Pos( 0.0f, 500.0f);
GameSprite sprite1(getDevice(), "placeholder3.dds", 0, sprite1Pos, 0.0f);
XMFLOAT2 sprite1Scale( 0.5f, 0.5f );
XMFLOAT2 mini(0.8f, 0.6f);
sprite1.SetScale(mini);
sprites_.push_back(sprite1);
XMFLOAT2 sprite2Pos( 200.0f, 100.0f );
GameSprite sprite2(getDevice(), "Stats.dds", 2, sprite2Pos, 2.0f);
// sprites_.push_back(sprite2);
XMFLOAT2 sprite3Pos( 290.0f, 300.0f );
GameSprite sprite3(getDevice(), "cav.dds", 1, sprite3Pos, 2.0f);
sprite3.SetScale(sprite1Scale);
sprites_.push_back(sprite3);
// create vertex buffers, colorMaps and colorSamplers
for (int i = 0; i <= elements2D.size(); i++) {
solidColorVShaders.push_back(solidColorVS_);
colorMaps.push_back(colorMap_);
colorSamplers.push_back(colorMapSampler_);
vertexBuffers.push_back(vertexBuffer_);
}
// continue
ID3DBlob* vsBuffer = 0;
bool compileResult = CompileD3DShader( "TextureMap.fx", "VS_Main", "vs_4_0", &vsBuffer );
if( compileResult == false )
{
DXTRACE_MSG( "Error compiling the vertex shader!" );
return false;
}
HRESULT d3dResult;
d3dResult = d3dDevice_->CreateVertexShader( vsBuffer->GetBufferPointer( ),
vsBuffer->GetBufferSize( ), 0, &solidColorVShaders[0] );
if( FAILED( d3dResult ) )
{
DXTRACE_MSG( "Error creating the vertex shader!" );
if( vsBuffer )
vsBuffer->Release( );
return false;
}
D3D11_INPUT_ELEMENT_DESC solidColorLayout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
unsigned int totalLayoutElements = ARRAYSIZE( solidColorLayout );
d3dResult = d3dDevice_->CreateInputLayout( solidColorLayout, totalLayoutElements,
vsBuffer->GetBufferPointer( ), vsBuffer->GetBufferSize( ), &inputLayout_ );
vsBuffer->Release( );
if( FAILED( d3dResult ) )
{
DXTRACE_MSG( "Error creating the input layout!" );
return false;
}
ID3DBlob* psBuffer = 0;
compileResult = CompileD3DShader( "TextureMap.fx", "PS_Main", "ps_4_0", &psBuffer );
if( compileResult == false )
{
DXTRACE_MSG( "Error compiling pixel shader!" );
return false;
}
d3dResult = d3dDevice_->CreatePixelShader( psBuffer->GetBufferPointer( ),
psBuffer->GetBufferSize( ), 0, &solidColorPS_ );
psBuffer->Release( );
if( FAILED( d3dResult ) )
{
DXTRACE_MSG( "Error creating pixel shader!" );
return false;
}
// create ColorMap, ColorSampler and VertexBuffer for each unique sprite
D3D11_SAMPLER_DESC colorMapDesc;
D3D11_BUFFER_DESC vertexDesc;
D3D11_SUBRESOURCE_DATA resourceData;
for (int j = 0; j < elements2D.size(); j++) {
d3dResult = D3DX11CreateShaderResourceViewFromFile( d3dDevice_,
elements2D[j], 0, 0, &colorMaps[j], 0 );
if( FAILED( d3dResult ) )
{
DXTRACE_MSG( "Failed to load the texture image!" );
return false;
}
ZeroMemory( &colorMapDesc, sizeof( colorMapDesc ) );
colorMapDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
colorMapDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
colorMapDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
colorMapDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
colorMapDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
colorMapDesc.MaxLOD = D3D11_FLOAT32_MAX;
d3dResult = d3dDevice_->CreateSamplerState( &colorMapDesc, &colorSamplers[j] );
if( FAILED( d3dResult ) )
{
DXTRACE_MSG( "Failed to create color map sampler state!" );
return false;
}
float Width = sprites_[j].getWidth();
float Height = sprites_[j].getHeight();
VertexPos vertices[] =
{
{ XMFLOAT3( Width, Height, 1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( Width, -Height, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -Width, -Height, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -Width, -Height, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -Width, Height, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( Width, Height, 1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
};
ZeroMemory( &vertexDesc, sizeof( vertexDesc ) );
vertexDesc.Usage = D3D11_USAGE_DEFAULT;
vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexDesc.ByteWidth = sizeof( VertexPos ) * 6;
ZeroMemory( &resourceData, sizeof( resourceData ) );
resourceData.pSysMem = vertices;
d3dResult = d3dDevice_->CreateBuffer( &vertexDesc, &resourceData, &vertexBuffers[j] );
if( FAILED( d3dResult ) )
{
DXTRACE_MSG( "Failed to create vertex buffer!" );
return false;
}
}
// end of foor loop
// create text fonts
d3dResult = D3DX11CreateShaderResourceViewFromFile( d3dDevice_,
"font.dds", 0, 0, &colorMap_, 0 );
if( FAILED( d3dResult ) )
{
DXTRACE_MSG( "Failed to load the texture image!" );
return false;
}
D3D11_SAMPLER_DESC colorMapDesc2;
ZeroMemory( &colorMapDesc2, sizeof( colorMapDesc2 ) );
colorMapDesc2.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
colorMapDesc2.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
colorMapDesc2.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
colorMapDesc2.ComparisonFunc = D3D11_COMPARISON_NEVER;
colorMapDesc2.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
colorMapDesc2.MaxLOD = D3D11_FLOAT32_MAX;
d3dResult = d3dDevice_->CreateSamplerState( &colorMapDesc2, &colorMapSampler_ );
if( FAILED( d3dResult ) )
{
DXTRACE_MSG( "Failed to create color map sampler state!" );
return false;
}
D3D11_BUFFER_DESC vertexDesc2;
ZeroMemory( &vertexDesc2, sizeof( vertexDesc2 ) );
vertexDesc2.Usage = D3D11_USAGE_DYNAMIC;
vertexDesc2.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vertexDesc2.BindFlags = D3D11_BIND_VERTEX_BUFFER;
const int sizeOfSprite = sizeof( VertexPos ) * 6;
const int maxLetters = 24;
vertexDesc2.ByteWidth = sizeOfSprite * maxLetters;
d3dResult = d3dDevice_->CreateBuffer( &vertexDesc2, 0, &vertexBuffer_ );
if( FAILED( d3dResult ) )
{
DXTRACE_MSG( "Failed to create vertex buffer!" );
return false;
}
// end of font creation
D3D11_BUFFER_DESC constDesc;
ZeroMemory( &constDesc, sizeof( constDesc ) );
constDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constDesc.ByteWidth = sizeof( XMMATRIX );
constDesc.Usage = D3D11_USAGE_DEFAULT;
d3dResult = d3dDevice_->CreateBuffer( &constDesc, 0, &mvpCB_ );
if( FAILED( d3dResult ) )
{
return false;
}
XMMATRIX view = XMMatrixIdentity( );
XMMATRIX projection = XMMatrixOrthographicOffCenterLH( 0.0f, 1366.0f, 0.0f, 768.0f, 0.1f, 100.0f );
vpMatrix_ = XMMatrixMultiply( view, projection );
D3D11_BLEND_DESC blendDesc;
ZeroMemory( &blendDesc, sizeof( blendDesc ) );
blendDesc.RenderTarget[0].BlendEnable = TRUE;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
float blendFactor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
d3dDevice_->CreateBlendState( &blendDesc, &alphaBlendState_ );
// create the disabled blend state
blendDesc.RenderTarget[0].BlendEnable = FALSE;
d3dDevice_->CreateBlendState( &blendDesc, &alphaBlendStateOff );
d3dContext_->OMSetBlendState( alphaBlendState_, blendFactor, 0xFFFFFFFF );
// holy shit here we go again
ID3DBlob* vsBuffer2 = 0;
compileResult = CompileD3DShader( "TextMap.fx", "VS_Main", "vs_4_0", &vsBuffer2 );
if( compileResult == false )
{
DXTRACE_MSG( "Error compiling the vertex shader!" );
return false;
}
d3dResult = d3dDevice_->CreateVertexShader( vsBuffer2->GetBufferPointer( ),
vsBuffer2->GetBufferSize( ), 0, &solidColorVS_2 );
ID3DBlob* psBuffer2 = 0;
compileResult = CompileD3DShader( "TextureMap.fx", "PS_Main", "ps_4_0", &psBuffer2 );
if( compileResult == false )
{
DXTRACE_MSG( "Error compiling pixel shader!" );
return false;
}
d3dResult = d3dDevice_->CreatePixelShader( psBuffer2->GetBufferPointer( ),
psBuffer2->GetBufferSize( ), 0, &solidColorPS_2 );
psBuffer2->Release( );
return true;
}
void GameSpriteDemo::UnloadContent( )
{
if( colorMapSampler_ ) colorMapSampler_->Release( );
if( colorMap_ ) colorMap_->Release( );
if( solidColorVShaders[0] ) solidColorVShaders[0]->Release( );
if( solidColorPS_ ) solidColorPS_->Release( );
if( inputLayout_ ) inputLayout_->Release( );
if( vertexBuffer_ ) vertexBuffer_->Release( );
if( mvpCB_ ) mvpCB_->Release( );
if( alphaBlendState_ ) alphaBlendState_->Release( );
if( alphaBlendStateOff ) alphaBlendStateOff->Release( );
colorMapSampler_ = 0;
colorMap_ = 0;
solidColorVShaders[0] = 0;
solidColorPS_ = 0;
inputLayout_ = 0;
vertexBuffer_ = 0;
mvpCB_ = 0;
alphaBlendState_ = 0;
alphaBlendStateOff = 0;
}
void GameSpriteDemo::Update( float dt )
{
// Nothing to update
}
bool GameSpriteDemo::DrawString( char* message, float startX, float startY )
{
// Size in bytes for a single sprite.
const int sizeOfSprite = sizeof( VertexPos ) * 6;
// Demo's dynamic buffer setup for max of 24 letters.
const int maxLetters = 24;
int length = strlen( message );
// Clamp for strings too long.
if( length > maxLetters )
length = maxLetters;
// Char's width on screen.
float charWidth = 32.0f / (1366.0f*1.0f);
// Char's height on screen.
float charHeight = 32.0f / (768.0f*1.0f);
// Char's texel width.
float texelWidth = 32.0f / 896.0f;
// verts per-triangle (3) * total triangles (2) = 6.
const int verticesPerLetter = 6;
D3D11_MAPPED_SUBRESOURCE mapResource;
HRESULT d3dResult = d3dContext_->Map( vertexBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapResource );
if( FAILED( d3dResult ) )
{
DXTRACE_MSG( "Failed to map resource!" );
return false;
}
// Point to our vertex buffer's internal data.
VertexPos *spritePtr = ( VertexPos* )mapResource.pData;
const int indexA = static_cast<char>( 'A' );
const int indexZ = static_cast<char>( 'Z' );
const int index_a = static_cast<char>( 'a' );
for( int i = 0; i < length; ++i )
{
float thisStartX = startX + ( charWidth * static_cast<float>( i ) );
float thisEndX = thisStartX + charWidth;
float thisEndY = startY + charHeight;
spritePtr[0].pos = XMFLOAT3( thisEndX, thisEndY, 1.0f );
spritePtr[1].pos = XMFLOAT3( thisEndX, startY, 1.0f );
spritePtr[2].pos = XMFLOAT3( thisStartX, startY, 1.0f );
spritePtr[3].pos = XMFLOAT3( thisStartX, startY, 1.0f );
spritePtr[4].pos = XMFLOAT3( thisStartX, thisEndY, 1.0f );
spritePtr[5].pos = XMFLOAT3( thisEndX, thisEndY, 1.0f );
int texLookup = 0;
int letter = static_cast<char>( message[i] );
if (letter == index_a) {
texLookup = (indexZ - indexA) + 2;
}
else if( letter < indexA || letter > indexZ )
{
// Grab one index past Z, which is a blank space in the texture.
texLookup = ( indexZ - indexA ) + 1;
}
else
{
// A = 0, B = 1, Z = 25, etc.
texLookup = ( letter - indexA );
}
float tuStart = 0.0f + ( texelWidth * static_cast<float>( texLookup ) );
float tuEnd = tuStart + texelWidth;
spritePtr[0].tex0 = XMFLOAT2( tuEnd, 0.0f );
spritePtr[1].tex0 = XMFLOAT2( tuEnd, 1.0f );
spritePtr[2].tex0 = XMFLOAT2( tuStart, 1.0f );
spritePtr[3].tex0 = XMFLOAT2( tuStart, 1.0f );
spritePtr[4].tex0 = XMFLOAT2( tuStart, 0.0f );
spritePtr[5].tex0 = XMFLOAT2( tuEnd, 0.0f );
spritePtr += 6;
}
d3dContext_->Unmap( vertexBuffer_, 0 );
d3dContext_->Draw( 6 * length, 0 );
return true;
}
void GameSpriteDemo::Render( )
{
if( d3dContext_ == 0 )
return;
float clearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
d3dContext_->ClearRenderTargetView( backBufferTarget_, clearColor );
unsigned int stride = sizeof( VertexPos );
unsigned int offset = 0;
d3dContext_->IASetInputLayout( inputLayout_ );
d3dContext_->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
d3dContext_->VSSetShader( solidColorVShaders[0], 0, 0 );
d3dContext_->PSSetShader( solidColorPS_, 0, 0 );
XMMATRIX world;
XMMATRIX mvp;
int index;
for (int k = 0; k < sprites_.size(); k++) {
index = sprites_[k].getIndex();
d3dContext_->IASetVertexBuffers( 0, 1, &vertexBuffers[index], &stride, &offset );
d3dContext_->PSSetShaderResources( 0, 1, &colorMaps[index] );
d3dContext_->PSSetSamplers( 0, 1, &colorSamplers[index] );
world = sprites_[k].GetWorldMatrix();
mvp = XMMatrixMultiply( world, vpMatrix_ );
mvp = XMMatrixTranspose( mvp );
d3dContext_->UpdateSubresource( mvpCB_, 0, 0, &mvp, 0, 0 );
d3dContext_->VSSetConstantBuffers( 0, 1, &mvpCB_ );
d3dContext_->Draw( 6, 0 );
}
// render text
DisableBlending();
d3dContext_->IASetVertexBuffers( 0, 1, &vertexBuffer_, &stride, &offset );
d3dContext_->PSSetShaderResources( 0, 1, &colorMap_ );
d3dContext_->PSSetSamplers( 0, 1, &colorMapSampler_ );
d3dContext_->VSSetShader( solidColorVS_2, 0, 0 );
d3dContext_->PSSetShader( solidColorPS_2, 0, 0 );
DrawString( "PROTOTYPE TEXT", -0.2f, 0.0f );
swapChain_->Present( 0, 0 );
}
ID3D11ShaderResourceView* GameSpriteDemo::getColorMap(int index) {
return colorMaps[index];
}
// this functions disables the alpha blending
void GameSpriteDemo::DisableBlending() {
float blendFactor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
d3dContext_->OMSetBlendState( alphaBlendStateOff, blendFactor, 0xFFFFFFFF );
}
启用混合绘图时的结果屏幕 http://i49.tinypic.com/33kao9v.jpg
这是我正在使用的两个 FX 文件的 HLSL 代码(第一个用于精灵,第二个用于文本)
纹理贴图.fx
cbuffer cbChangesPerFrame : register( b0 )
{
matrix mvp_;
};
Texture2D colorMap_ : register( t0 );
SamplerState colorSampler_ : register( s0 );
struct VS_Input
{
float4 pos : POSITION;
float2 tex0 : TEXCOORD0;
};
struct PS_Input
{
float4 pos : SV_POSITION;
float2 tex0 : TEXCOORD0;
};
PS_Input VS_Main( VS_Input vertex )
{
PS_Input vsOut = ( PS_Input )0;
vsOut.pos = mul( vertex.pos, mvp_ );
vsOut.tex0 = vertex.tex0;
return vsOut;
}
float4 PS_Main( PS_Input frag ) : SV_TARGET
{
return colorMap_.Sample( colorSampler_, frag.tex0 );
}
文本映射.fx
Texture2D colorMap_ : register( t0 );
SamplerState colorSampler_ : register( s0 );
struct VS_Input
{
float4 pos : POSITION;
float2 tex0 : TEXCOORD0;
};
struct PS_Input
{
float4 pos : SV_POSITION;
float2 tex0 : TEXCOORD0;
};
PS_Input VS_Main( VS_Input vertex )
{
PS_Input vsOut = ( PS_Input )0;
vsOut.pos = vertex.pos;
vsOut.tex0 = vertex.tex0;
return vsOut;
}
float4 PS_Main( PS_Input frag ) : SV_TARGET
{
return colorMap_.Sample( colorSampler_, frag.tex0 );
}
我想知道也许可以使用像素着色器来为特定的 2D 图像执行 alpha 混合,但我的第一次尝试根本没有奏效。
希望有人能以某种方式找到解决方案:)
并再次感谢您的帮助。