I recently heard about shader linking in DirectX, and decided to give it a go, following this MSDN tutorial, and seem to have it mostly working. However, it fails in the link stage, giving the error:
error X9214: ID3D11Linker::Link: failed to generate byte code
I get the same error for both the vertex shader and the pixel shader. Compiling the shader library, creating the graph, connecting the nodes and everything seems to work, but the linking still fails. I've been unable to find any details regarding the error code, and the error message isn't particularly helpful. The full relevant code is attached, I hope that someone can see what I'm doing wrong!
Linking.hlsl:
Texture2DArray inTexture : register(t0);
SamplerState samplerState : register(s0);
cbuffer CameraData : register(b0)
{
float4x4 Model;
float4x4 View;
float4x4 Projection;
};
export void VertexFunction(inout float4 position, inout float2 uv)
{
position = mul(position, Model);
position = mul(position, View);
position = mul(position, Projection);
}
export float4 SampleTexture(float2 uv)
{
return inTexture.Sample(samplerState, float3(uv,0));
}
Shader compilation:
//Compile shader to bytecode (exported functions)
ID3DBlob* shaderBlob = nullptr;
ID3DBlob* errorBlob = nullptr;
HRESULT hr = D3DCompileFromFile(aPath.c_str(), NULL, NULL, NULL,
(std::string("lib") + Graphics::Shader::Linking::CShaderLibrary::ShaderModelSuffix).c_str(), D3DCOMPILE_OPTIMIZATION_LEVEL3, 0, &shaderBlob, &errorBlob);
ErrorCheck(hr, errorBlob);
//Create shader library
ID3D11Module* shaderLibrary = nullptr;
hr = D3DLoadModule(shaderBlob->GetBufferPointer(), shaderBlob->GetBufferSize(), &shaderLibrary);
shaderBlob->Release();
ErrorCheck(hr);
//Create shader library instance
ID3D11ModuleInstance *shaderLibraryInstance = nullptr;
hr = shaderLibrary->CreateInstance("", &shaderLibraryInstance);
ErrorCheck(hr);
//Bind the resources, samplers and constant buffers
hr = shaderLibraryInstance->BindResource(0, 0, 1);
ErrorCheck(hr);
hr = shaderLibraryInstance->BindSampler(0, 0, 1);
ErrorCheck(hr);
hr = shaderLibraryInstance->BindConstantBuffer(0, 0, 0);
ErrorCheck(hr);
return new Graphics::Shader::Linking::CShaderLibrary(*shaderLibrary,*shaderLibraryInstance);
Create the vertex shader from graph (its own function):
//Create the vertex shader graph;
ID3D11FunctionLinkingGraph* vertexShaderGraph = nullptr;
HRESULT result = D3DCreateFunctionLinkingGraph(0, &vertexShaderGraph);
EffectHelper::ErrorCheck(result);
//Define the vertex shader input layout
static const D3D11_PARAMETER_DESC vertexInputParameters[] =
{
{ "inputPos", "POSITION0", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1,4,D3D_INTERPOLATION_LINEAR, D3D_PF_IN,0,0,0,0 },
{ "inputUV", "TEXCOORD0", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1,2,D3D_INTERPOLATION_LINEAR,D3D_PF_IN,0,0,0,0}
};
//Create the vertex input node. This will be used by the input assembler
ID3D11LinkingNode* vertexInputNode = nullptr;
result = vertexShaderGraph->SetInputSignature(vertexInputParameters, ARRAYSIZE(vertexInputParameters), &vertexInputNode);
EffectHelper::ErrorCheck(result, vertexShaderGraph);
//Create the vertex function node. This will be sent the data from the input node.
ID3D11LinkingNode* vertexFunctionNode = nullptr;
result = vertexShaderGraph->CallFunction("", &myLibrary, "VertexFunction", &vertexFunctionNode);
EffectHelper::ErrorCheck(result, vertexShaderGraph);
//Pass the value from the input node to the vertex function node (for future info, remember that all function arguments have to be assigned).
result = vertexShaderGraph->PassValue(vertexInputNode, 0, vertexFunctionNode, 0);
EffectHelper::ErrorCheck(result, vertexShaderGraph);
result = vertexShaderGraph->PassValue(vertexInputNode, 1, vertexFunctionNode, 1);
EffectHelper::ErrorCheck(result, vertexShaderGraph);
//Define the output layout for the vertex function
static const D3D11_PARAMETER_DESC vertexShaderOutputParameters[] =
{
{ "outputUV","TEXCOORD0",D3D_SVT_FLOAT, D3D_SVC_VECTOR,1,2,D3D_INTERPOLATION_UNDEFINED,D3D_PF_OUT,0,0,0,0 },
{ "outputPosition", "SV_POSITION", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1,4,D3D_INTERPOLATION_UNDEFINED, D3D_PF_OUT, 0,0,0,0}
};
//Create the vertex output node
ID3D11LinkingNode* vertexShaderOutputNode = nullptr;
result = vertexShaderGraph->SetOutputSignature(vertexShaderOutputParameters, ARRAYSIZE(vertexShaderOutputParameters), &vertexShaderOutputNode);
EffectHelper::ErrorCheck(result, vertexShaderGraph);
//Pass the value from the function node to the output node
result = vertexShaderGraph->PassValue(vertexFunctionNode, 0, vertexShaderOutputNode, 1);
EffectHelper::ErrorCheck(result, vertexShaderGraph);
result = vertexShaderGraph->PassValue(vertexFunctionNode, 1, vertexShaderOutputNode, 0);
EffectHelper::ErrorCheck(result, vertexShaderGraph);
//Finalize the the vertex shader graph
ID3D11ModuleInstance* vertexShaderGraphInstance = nullptr;
result = vertexShaderGraph->CreateModuleInstance(&vertexShaderGraphInstance, nullptr);
EffectHelper::ErrorCheck(result, vertexShaderGraph);
//Create a linker
ID3D11Linker* linker = nullptr;
result = D3DCreateLinker(&linker);
EffectHelper::ErrorCheck(result);
//Hook up the shader library instance
result = linker->UseLibrary(&myLibraryInstance);
EffectHelper::ErrorCheck(result);
//Link the vertex shader. This looks mostly normal, frankly. Interesting. TODO: Something goes wrong here. What? #HelpfulError
ID3DBlob* vertexShaderBlob = nullptr;
ID3DBlob* errorBlob = nullptr;
//Error occurs here
result = linker->Link(vertexShaderGraphInstance, "main", (std::string("vs") + ShaderModelSuffix).c_str(), 0, &vertexShaderBlob, &errorBlob);
EffectHelper::ErrorCheck(result, errorBlob);
//Create the vertex shader. Business as usual?
ID3D11VertexShader* vertexShader = nullptr;
result = MasterSingleton::GetInstance().Get3DEngine().GetFramework().GetDevice().CreateVertexShader(
vertexShaderBlob->GetBufferPointer(),vertexShaderBlob->GetBufferSize(),nullptr,&vertexShader);
EffectHelper::ErrorCheck(result);
Create the pixel shader from graph (also its own function):
//Create pixel shader graph
ID3D11FunctionLinkingGraph* pixelShaderGraph = nullptr;
HRESULT result = D3DCreateFunctionLinkingGraph(0, &pixelShaderGraph);
EffectHelper::ErrorCheck(result);
//Define the pixel shader input layout (will be fed by vertex shader layout)
static const D3D11_PARAMETER_DESC pixelInputDesc[] =
{
{"inputUV","TEXCOORD0",D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1,2,D3D_INTERPOLATION_UNDEFINED,D3D_PF_IN,0,0,0,0},
{"inputPosition","SV_POSITION",D3D_SVT_FLOAT,D3D_SVC_VECTOR,1,4,D3D_INTERPOLATION_UNDEFINED, D3D_PF_IN,0,0,0,0}
};
//Create pixel shader input node
ID3D11LinkingNode* pixelInputNode = nullptr;
result = pixelShaderGraph->SetInputSignature(pixelInputDesc, ARRAYSIZE(pixelInputDesc), &pixelInputNode);
EffectHelper::ErrorCheck(result, pixelShaderGraph);
//Create texture sample function node
ID3D11LinkingNode* textureSampleFunctionNode = nullptr;
result = pixelShaderGraph->CallFunction("", &myLibrary, "SampleTexture", &textureSampleFunctionNode);
EffectHelper::ErrorCheck(result, pixelShaderGraph);
//Pass value from input node to texture sample node
result = pixelShaderGraph->PassValue(pixelInputNode, 0, textureSampleFunctionNode, 0);
EffectHelper::ErrorCheck(result, pixelShaderGraph);
//Define the output parameters from the pixel shader
D3D11_PARAMETER_DESC outputParameterDesc[]=
{
{"outputColor","SV_TARGET",D3D_SVT_FLOAT,D3D_SVC_VECTOR,1,4,D3D_INTERPOLATION_UNDEFINED,D3D_PF_OUT,0,0,0,0}
};
//Set the output node (using the signature)
ID3D11LinkingNode* pixelOutputNode = nullptr;
result = pixelShaderGraph->SetOutputSignature(outputParameterDesc, ARRAYSIZE(outputParameterDesc), &pixelInputNode);
EffectHelper::ErrorCheck(result, pixelShaderGraph);
//Finalize the pixel shader graph
ID3D11ModuleInstance *pixelShaderInstance = nullptr;
result = pixelShaderGraph->CreateModuleInstance(&pixelShaderInstance, nullptr);
EffectHelper::ErrorCheck(result, pixelShaderGraph);
//Create a linker and hook up to library instance
ID3D11Linker *linker = nullptr;
result = D3DCreateLinker(&linker);
EffectHelper::ErrorCheck(result);
//Set library to use
result = linker->UseLibrary(&myLibraryInstance);
EffectHelper::ErrorCheck(result);
//Link the pixel shader
ID3DBlob* shaderBlob;
ID3DBlob* errorBlob;
//And also here
result = linker->Link(pixelShaderInstance, "main", (std::string("ps") + ShaderModelSuffix).c_str(), 0, &shaderBlob, &errorBlob);
EffectHelper::ErrorCheck(result, errorBlob);
//Compile the pixel shader
ID3D11PixelShader* pixelShader = nullptr;
result = MasterSingleton::GetInstance().Get3DEngine().GetFramework().GetDevice().CreatePixelShader(shaderBlob->GetBufferPointer(), shaderBlob->GetBufferSize(), nullptr, &pixelShader);
EffectHelper::ErrorCheck(result);
Related
I used DrawIconEx (GDI/D3D11 interoperability and CopyResource) to generate an ID3D11Texture2D which has many pixels with an alpha channel value of 0. this texture has been verified by D3D11_USAGE_STAGING/Map to view the pixel value and ScreenGrab save png (relevant code needs to be modified: DXGI_FORMAT_B8G8R8A8_UNORM->Use GUID_WICPixelFormat32bppBGRA instead of GUID_WICPixelFormat24bppBGR).
When I use the rendering texture method of Tutorial 5: Texturing, the alpha value of 0 pixels will be rendered as black, which is not what i want, I hope these pixels render to be transparent. What will be done to achieve the goal? Here is my relevant code:
HRESULT CGraphRender::Init()
{
...
// Create an alpha enabled blend state description.
_blend_state = nullptr;
D3D11_BLEND_DESC blendDesc;
ZeroMemory(&blendDesc, sizeof(D3D11_BLEND_DESC));
blendDesc.RenderTarget[0].BlendEnable = TRUE;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
hr = _d3d_device->CreateBlendState(&blendDesc, &_blend_state);
RETURN_ON_FAIL(hr);
....
}
HRESULT CGraphRender::Clear_3D(float color[])
{
ID3D11RenderTargetView* rtv[] = { _back_rendertarget_view };
_immediate_context->OMSetRenderTargets(_countof(rtv), rtv, nullptr);
_immediate_context->ClearRenderTargetView(_back_rendertarget_view, color);
float blendFactor[4] = { 1.f, 1.f, 1.f, 1.f };
_immediate_context->OMSetBlendState(_blend_state, blendFactor, 0xffffffff);
return S_OK;
}
The problem has been solved: Perform the OMGetBlendState(_blend_state... setting before rendering the "alpha" texture, and restore the default blendstate after rendered
HRESULT CGraphRender::DrawTexture(const std::shared_ptr<CDrawTextureShader>& texture, const RECT& dst_rect, const BOOL& is_blend_alpha)
{
CComPtr<ID3D11DeviceContext> immediate_context;
_d3d_device->GetImmediateContext(&immediate_context);
if (!immediate_context)
{
return E_UNEXPECTED;
}
if (is_blend_alpha)
{
CComPtr<ID3D11BlendState> old_blend_state;
FLOAT old_blend_factor[4] = { 0.f };
UINT old_sample_mask = 0;
immediate_context->OMGetBlendState(&old_blend_state, old_blend_factor, &old_sample_mask);
float blend_factor[4] = { 1.f, 1.f, 1.f, 1.f };
immediate_context->OMSetBlendState(_blend_state, blend_factor, 0xffffffff);
HRESULT hr = texture->Render(immediate_context, dst_rect);
immediate_context->OMSetBlendState(old_blend_state, old_blend_factor, old_sample_mask);
return hr;
}
else
{
return texture->Render(immediate_context, dst_rect);
}
}
I created a D3D11 device and can perform operations such as rendering pictures smoothly, but in order to also support GDI, I tried several methods:
Through swapchain -> GetBuffer(ID3D11Texture2D) -> CreateDxgiSurfaceRenderTarget -> ID2D1GdiInteropRenderTarget -> GetDC, finally get the DC. It runs normally on my Win10, but an exception report when running GetDC on Win7: _com_error.
Via swapchain -> GetBuffer(IDXGISurface1) -> GetDC, same as 1.
I suspect that the ID3D11Texture2D/IDXGISurface1 obtained by GetBuffer on Win7 will have some restrictions on the use of GDI, so I changed to dynamically create a new ID3D11Texture2D by myself, and now use DC alone/D3D11 drawing interface alone It works fine, but if I interoperate, I will find that gdi opertaion is drawn on the custom-created ID3D11Texture2D instead of the back_buffer of swapchain:
_d3d->Clear();
_d3d->DrawImage();
HDC hdc = _d3d->GetDC();
DrawRectangleByGDI(hdc);
_d3d->ReleaseDC();
_d3d->Present();
So how to do it: Whether the D3D or DC methods is drawn, they are all on the same ID3D11Texture2D? This way, it is also convenient for my CopyResource.
HRESULT CGraphRender::Resize(const UINT32& width, const UINT32& height)
{
_back_texture2d = nullptr;
_back_rendertarget_view = nullptr;
_dc_texture2d = nullptr;
_dc_render_target = nullptr;
float dpi = GetDpiFromD2DFactory(_d2d_factory);
//Backbuffer
HRESULT hr = _swap_chain->ResizeBuffers(2, width, height, DXGI_FORMAT_B8G8R8A8_UNORM, _is_gdi_compatible ? DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE : 0);
RETURN_ON_FAIL(hr);
hr = _swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&_back_texture2d);
RETURN_ON_FAIL(hr);
hr = CreateD3D11Texture2D(_d3d_device, width, height, &_dc_texture2d);
RETURN_ON_FAIL(hr);
D3D11_RENDER_TARGET_VIEW_DESC rtv;
rtv.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
rtv.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtv.Texture2D.MipSlice = 0;
hr = _d3d_device->CreateRenderTargetView(_back_texture2d, &rtv, &_back_rendertarget_view);
RETURN_ON_FAIL(hr);
...
}
HRESULT CGraphRender::Clear(float color[])
{
CComPtr<ID3D11DeviceContext> immediate_context;
_d3d_device->GetImmediateContext(&immediate_context);
if (!immediate_context)
{
return E_UNEXPECTED;
}
ID3D11RenderTargetView* ref_renderTargetView = _back_rendertarget_view;
immediate_context->OMSetRenderTargets(1, &ref_renderTargetView, nullptr);
immediate_context->ClearRenderTargetView(_back_rendertarget_view, color);
return S_OK;
}
HDC CGraphRender::GetDC()
{
if (_is_gdi_compatible)
{
CComPtr<IDXGISurface1> gdi_surface;
HRESULT hr = _dc_texture2d->QueryInterface(__uuidof(IDXGISurface1), (void**)&gdi_surface);
if (SUCCEEDED(hr))
{
HDC hdc = nullptr;
hr = gdi_surface->GetDC(TRUE, &hdc);
if (SUCCEEDED(hr))
{
return hdc;
}
}
}
return nullptr;
}
HRESULT CGraphRender::CopyTexture(ID3D11Texture2D* dst_texture, ID3D11Texture2D* src_texture, POINT* dst_topleft/* = nullptr*/, POINT* src_topleft/* = nullptr*/)
{
if (!dst_texture && !src_texture)
{
return E_INVALIDARG;
}
CComPtr<ID3D11DeviceContext> immediate_context;
_d3d_device->GetImmediateContext(&immediate_context);
if (!immediate_context)
{
return E_UNEXPECTED;
}
ID3D11Texture2D* dst_texture_real = dst_texture ? dst_texture : _dc_texture2d;
POINT dst_topleft_real = dst_topleft ? (*dst_topleft) : POINT{ 0, 0 };
ID3D11Texture2D* src_texture_real = src_texture ? src_texture : _dc_texture2d;
POINT src_topleft_real = src_topleft ? (*src_topleft) : POINT{ 0, 0 };
D3D11_TEXTURE2D_DESC src_desc = { 0 };
src_texture_real->GetDesc(&src_desc);
D3D11_TEXTURE2D_DESC dst_desc = { 0 };
dst_texture_real->GetDesc(&dst_desc);
if (!dst_topleft_real.x && !src_topleft_real.x && !dst_topleft_real.y && !src_topleft_real.y && dst_desc.Width == src_desc.Width && dst_desc.Height == src_desc.Height)
{
immediate_context->CopyResource(dst_texture_real, src_texture_real);
}
else
{
D3D11_BOX src_box;
src_box.left = min((UINT)src_topleft_real.x, (UINT)dst_topleft_real.x + dst_desc.Width);
src_box.top = min((UINT)src_topleft_real.y, (UINT)dst_topleft_real.y + dst_desc.Height);
src_box.right = min((UINT)src_box.left + src_desc.Width, (UINT)dst_topleft_real.x + dst_desc.Width);
src_box.bottom = min((UINT)src_box.top + src_desc.Height, (UINT)dst_topleft_real.y + dst_desc.Height);
src_box.front = 0;
src_box.back = 1;
ATLASSERT(src_box.left < src_box.right);
ATLASSERT(src_box.top < src_box.bottom);
immediate_context->CopySubresourceRegion(dst_texture_real, 0, dst_topleft_real.x, dst_topleft_real.y, 0, src_texture_real, 0, &src_box);
}
return S_OK;
}
I don’t think Windows 7 supports what you’re trying to do. Here’s some alternatives.
Switch from GDI to something else that can render 2D graphics with D3D11. Direct2D is the most straightforward choice here. And DirectWrite if you want text in addition to rectangles.
If your 2D content is static or only changes rarely, you can use GDI+ to render into in-memory RGBA device context, create Direct3D11 texture with that data, and render a full-screen triangle with that texture.
You can overlay another Win32 window on top of your Direct3D 11 rendering one, and use GDI to render into that one. The GDI window on top must have WS_EX_LAYERED expended style, and you must update it with UpdateLayeredWindow API. This method is the most complicated and least reliable, though.
I want implement Particle system based on stream out structure to my bigger project. I saw few articles about that method and I build one particle. It works almost correctly but in geometry shader with stream out i cant get value of InitVel.z and age because it always is 0. If i change order of age(for example age is before Position) it works fine for age but 6th float of order is still 0. It looks like he push only 5 first positions. I had no idea what i do wrong because i try change almost all(create input layout for vertex, the same like entry SO Declaration, change number of strides for static 28, change it to 32 but in this case he draw chaotic so size of strides is probably good). I think it is problem with limits of NumEntry in declaration Entry but on site msdn i saw the limit for directx is D3D11_SO_STREAM_COUNT(4)*D3D11_SO_OUTPUT_COMPONENT_COUNT(128) not 5. Pls can you look in this code and give me the way or hope of implement it correctly?? Thanks a lot for help.
Structure of particle
struct Particle{
Particle() {}
Particle(float x, float y, float z,float vx, float vy, float vz,float
l /*UINT typ*/)
:InitPos(x, y, z), InitVel(vx, vy, vz), Age(l) /*, Type(typ)*/{}
XMFLOAT3 InitPos;
XMFLOAT3 InitVel;
float Age;
//UINT Type;
};
SO Entry
D3D11_SO_DECLARATION_ENTRY PartlayoutSO[] =
{
{ 0,"POSITION", 0, 0 , 3, 0 }, // output all components of position
{ 0,"VELOCITY", 0, 0, 3, 0 },
{ 0,"AGE", 0, 0, 1, 0 }
//{ 0,"TYPE", 0, 0, 1, 0 }
};
Global Variables
//streamout shaders
ID3D11VertexShader* Part_VSSO;
ID3D11GeometryShader* Part_GSSO;
ID3DBlob *Part_GSSO_Buffer;
ID3DBlob *Part_VSSO_Buffer;
//normal shaders
ID3D11VertexShader* Part_VS;
ID3D11GeometryShader* Part_GS;
ID3DBlob *Part_GS_Buffer;
ID3D11PixelShader* Part_PS;
ID3DBlob *Part_VS_Buffer;
ID3DBlob *Part_PS_Buffer;
ID3D11Buffer* PartVertBufferInit;
//ID3D11Buffer* Popy;
ID3D11Buffer* mDrawVB;
ID3D11Buffer* mStreamOutVB;
ID3D11InputLayout* PartVertLayout;// I try to set input layout too
void ParticleSystem::InitParticles()
{
mFirstRun = true;
srand(time(NULL));
hr = D3DCompileFromFile(L"ParticleVertexShaderSO4.hlsl", NULL,
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "vs_5_0", NULL, NULL,
&Part_VSSO_Buffer, NULL);
hr = D3DCompileFromFile(L"ParticleGeometryShaderSO4.hlsl", NULL,
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "gs_5_0", NULL, NULL,
&Part_GSSO_Buffer, NULL);
UINT StrideArray[1] = { sizeof(Particle) };//I try to set static 28 bits-7*4
per float
hr = device->CreateVertexShader(Part_VSSO_Buffer->GetBufferPointer(),
Part_VSSO_Buffer->GetBufferSize(), NULL, &Part_VSSO);
hr = device->CreateGeometryShaderWithStreamOutput(Part_GSSO_Buffer-
>GetBufferPointer(), Part_GSSO_Buffer->GetBufferSize(), PartlayoutSO ,3/*
sizeof(PartlayoutSO)*/ , StrideArray, 1,D3D11_SO_NO_RASTERIZED_STREAM,
NULL,&Part_GSSO);
//Draw Shaders
hr = D3DCompileFromFile(L"ParticleVertexShaderDRAW4.hlsl", NULL,
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "vs_5_0", NULL, NULL,
&Part_VS_Buffer, NULL);
hr = D3DCompileFromFile(L"ParticleGeometryShaderDRAW4.hlsl", NULL,
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "gs_5_0", NULL, NULL,
&Part_GS_Buffer, NULL);
hr = D3DCompileFromFile(L"ParticlePixelShaderDRAW4.hlsl", NULL,
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "ps_5_0", NULL, NULL,
&Part_PS_Buffer, NULL);
hr = device->CreateVertexShader(Part_VS_Buffer->GetBufferPointer(),
Part_VS_Buffer->GetBufferSize(), NULL, &Part_VS);
hr = device->CreateGeometryShader(Part_GS_Buffer->GetBufferPointer(),
Part_GS_Buffer->GetBufferSize(), NULL, &Part_GS);
hr = device->CreatePixelShader(Part_PS_Buffer->GetBufferPointer(),
Part_PS_Buffer->GetBufferSize(), NULL, &Part_PS);
BuildVertBuffer();
}
void ParticleSystem::BuildVertBuffer()
{
D3D11_BUFFER_DESC vertexBufferDesc1;
ZeroMemory(&vertexBufferDesc1, sizeof(vertexBufferDesc1));
vertexBufferDesc1.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc1.ByteWidth = sizeof(Particle)*1; //*numParticles;
vertexBufferDesc1.BindFlags = D3D11_BIND_VERTEX_BUFFER;// |
D3D11_BIND_STREAM_OUTPUT;
vertexBufferDesc1.CPUAccessFlags = 0;
vertexBufferDesc1.MiscFlags = 0;
vertexBufferDesc1.StructureByteStride = 0;// I tried to comment this too
Particle p;
ZeroMemory(&p, sizeof(Particle));
p.InitPos = XMFLOAT3(0.0f, 0.0f, 0.0f);
p.InitVel = XMFLOAT3(0.0f, 0.0f, 0.0f);
p.Age = 0.0f;
//p.Type = 100.0f;
D3D11_SUBRESOURCE_DATA vertexBufferData1;
ZeroMemory(&vertexBufferData1, sizeof(vertexBufferData1));
vertexBufferData1.pSysMem = &p;//było &p
vertexBufferData1.SysMemPitch = 0;
vertexBufferData1.SysMemSlicePitch = 0;
hr = device->CreateBuffer(&vertexBufferDesc1, &vertexBufferData1,
&PartVertBufferInit);
ZeroMemory(&vertexBufferDesc1, sizeof(vertexBufferDesc1));
vertexBufferDesc1.ByteWidth = sizeof(Particle) * numParticles;
vertexBufferDesc1.BindFlags = D3D11_BIND_VERTEX_BUFFER |
D3D11_BIND_STREAM_OUTPUT;
hr = device->CreateBuffer(&vertexBufferDesc1, 0, &mDrawVB);
hr = device->CreateBuffer(&vertexBufferDesc1, 0, &mStreamOutVB);
}
void ParticleSystem::LoadDataParticles()
{
UINT stride = sizeof(Particle);
UINT offset = 0;
//Create the Input Layout
//device->CreateInputLayout(Partlayout, numElementsPart, Part_VSSO_Buffer-
//>GetBufferPointer(),
// Part_VSSO_Buffer->GetBufferSize(), &PartVertLayout);
//Set the Input Layout
//context->IASetInputLayout(PartVertLayout);
//Set Primitive Topology
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
if (mFirstRun)
{
// context->CopyResource(Popy, PartVertBufferInit);
context->IASetVertexBuffers(0, 1, &PartVertBufferInit, &stride,
&offset);
}
else
{
context->IASetVertexBuffers(0, 1, &mDrawVB, &stride, &offset);
}
context->SOSetTargets(1, &mStreamOutVB, &offset);
context->VSSetShader(Part_VSSO, NULL, 0);
context->GSSetShader(Part_GSSO, NULL, 0);
context->PSSetShader(NULL, NULL, 0);
//context->PSSetShader(Part_PS, NULL, 0);
ID3D11DepthStencilState* depthState;//disable depth
D3D11_DEPTH_STENCIL_DESC depthStateDesc;
depthStateDesc.DepthEnable = false;
depthStateDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
device->CreateDepthStencilState(&depthStateDesc, &depthState);
context->OMSetDepthStencilState(depthState, 0);
if (mFirstRun)
{
//mFirstRun;
context->Draw(1, 0);
mFirstRun = false;
}
else
{
context->DrawAuto();
}
//}
// done streaming-out--unbind the vertex buffer
ID3D11Buffer* bufferArray[1] = { 0 };
context->SOSetTargets(1, bufferArray, &offset);
// ping-pong the vertex buffers
std::swap(mStreamOutVB, mDrawVB);
// Draw the updated particle system we just streamed-out.
//Create the Input Layout
//device->CreateInputLayout(Partlayout, numElementsPart, Part_VS_Buffer-
//>GetBufferPointer(),
// Part_VS_Buffer->GetBufferSize(), &PartVertLayout);
//Set the normal Input Layout
//context->IASetInputLayout(PartVertLayout);
context->IASetVertexBuffers(0, 1, &mDrawVB, &stride, &offset);
ZeroMemory(&depthStateDesc, sizeof(depthStateDesc));
depthStateDesc.DepthEnable = true;
depthStateDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
device->CreateDepthStencilState(&depthStateDesc, &depthState);
context->OMSetDepthStencilState(depthState, 0);
//I tried add normal layout here the same like Entry SO but no changes
//Set Primitive Topology
//context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
context->VSSetShader(Part_VS, NULL, 0);
context->GSSetShader(Part_GS, NULL, 0);
context->PSSetShader(Part_PS, NULL, 0);
context->DrawAuto();
//mFirstRun = true;
context->GSSetShader(NULL, NULL, 0);
}
void ParticleSystem::RenderParticles()
{
//mFirstRun = true;
LoadDataParticles();
}
And the code of shaders:
VertexShader to stream out
struct Particle
{
float3 InitPos : POSITION;
float3 InitVel : VELOCITY;
float Age : AGE;
//uint Type : TYPE;
};
Particle main(Particle vin)
{
return vin;// just push data into geomtrywithso
}
GeometrywithSo
struct Particle
{
float3 InitPos : POSITION;
float3 InitVel : VELOCITY;
float Age : AGE;
//uint Type : TYPE;
};
float RandomPosition(float offset)
{
float u = Time + offset;// (Time + offset);
float v = ObjTexture13.SampleLevel(ObjSamplerState, u, 0).r;
return (v);
}
[maxvertexcount(6)]
void main(
point Particle gin[1],
inout PointStream< Particle > Output
)
{
//gin[0].Age = Time;
if ( StartPart == 1.0f )
{
//if (gin[0].Age < 100.0f)
//{
for (int i = 0; i < 6; i++)
{
float3 VelRandom; //= 5.0f * RandomPosition((float)i / 5.0f);
VelRandom.y = 10.0f+i;
VelRandom.x = 35 * i* RandomPosition((float)i / 5.0f);//+ offse;
VelRandom.z = 10.0f;//35*i * RandomPosition((float)i / 5.0f);
Particle p;
p.InitPos = VelRandom;//float3(0.0f, 5.0f, 0.0f); //+ VelRandom;
p.InitVel = float3(10.0f, 10.0f, 10.0f);
p.Age = 0.0f;//VelRandom.y;
//p.Type = PT_FLARE;
Output.Append(p);
}
Output.Append(gin[0]);
}
else if (StartPart == 0.0f)
{
if (gin[0].Age >= 0)
{
Output.Append(gin[0]);
}
}
}
If I change Age in geometry with so: for example Age += Time from const buffer
In geometry shader its fine once but in draw shader it is 0 and next time if it is reading in geometry with so it is 0 too.
Vertex shader to draw
struct VertexOut
{
float3 Pos : POSITION;
float4 Colour : COLOR;
//uint Type : TYPE;
};
struct Particle
{
float3 InitPos : POSITION;
float3 InitVel : VELOCITY;
float Age : AGE;
// uint Type : TYPE;
};
VertexOut main(Particle vin)
{
VertexOut vout;
float3 gAccelW = float3(0.0f, -0.98f, 0.0f);
float t = vin.Age;
//float b = Time/10000;
// constant Acceleration equation
vout.Pos = vin.InitVel+ (0.7f * gAccelW)*Time/100;
//vout.Pos.x = t;
vout.Colour = float4(1.0f, 0.0f, 0.0f, 1.0f);
//vout.Age = vout.Pos.y;
//vout.Type = vin.Type;
return vout;
}
Geometry shader to change point into line
struct VertexOut
{
float3 Pos : POSITION;
float4 Colour : COLOR;
//uint Type : TYPE;
};
struct GSOutput
{
float4 Pos : SV_POSITION;
float4 Colour : COLOR;
//float2 Tex : TEXCOORD;
};
[maxvertexcount(2)]
void main(
point VertexOut gin[1],
inout LineStream< GSOutput > Output
)
{
float3 gAccelW = float3(0.0f, -0.98f, 0.0f);
//if (gin[0].Type != PT_EMITTER)
{
float4 v[2];
v[0] = float4(gin[0].Pos, 1.0f);
v[1] = float4((gin[0].Pos + gAccelW), 1.0f);
GSOutput gout;
[unroll]
for (int i = 0; i < 2; ++i)
{
gout.Pos = mul(v[i], WVP);// mul(v[i], gViewProj);
gout.Colour = gin[0].Colour;
Output.Append(gout);
}
}
}
And pixel Shader
struct GSOutput
{
float4 Pos : SV_POSITION;
float4 Colour : COLOR;
};
float4 main(GSOutput pin) : SV_TARGET
{
return pin.Colour;
}
I create surface with following code:
const EGLint attrs[] = {
EGL_LEVEL, 0,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NATIVE_RENDERABLE, EGL_FALSE,
EGL_DEPTH_SIZE, EGL_DONT_CARE,
EGL_NONE
};
FDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
EGLint major = 0;
EGLint minor = 0;
if (!eglInitialize(FDisplay, &major, &minor))
return;
EGLConfig eglConfig;
// Obtain the first configuration with a depth buffer
EGLint numConfig = 0;
if (!eglChooseConfig(FDisplay, attrs, &eglConfig, 1, &numConfig))
return;
FSurface = eglCreateWindowSurface(FDisplay, eglConfig,
single_native_window: FNativeHwnd, NULL);
The problem is that eglCreateWindowSurface is not successful, returns EGL_NO_SURFACE when calling for second surface. I call it passing FDisplay which is same display as was used for the first surface. What i do wrong? Maybe there is another approach to create second surface?
I have made a container class that basicly contains all the information I need for rendering an animation. I'm using the Assimp library to load the animation. Then assigning the data from the scene->mVertices etc. to my array buffers, what I'm having trouble figuring out is how I'm supposed to get that data for other frames into my buffers!
I know that there is a function called HasAnimations(), and also a aiAnimation **mAnimations. But what I can't find any data in there that is relevant to getting the next set of vertex data.
I have managed to load a series of obj-files with it and draw them in order to comfirm that my class works correctly. But obviously I would prefer or actaully need to use something else when I want to expand to the real deal. As loading 250 frames individually takes a couple of minutes. (Loading a simple animation should be done in about 5 seconds tops, right?)
I'm open to using any kind of file format. But I need to know how to set it up in Blender so that the animations will get exported. As I also seem to fail horribly at for now, as I have little experience with Blender.
I've been searching for tutorials on this library and blender exporting for 2 days now, and found almost nothing useful. I did check out the documentation for Assimp as well, which took me so far, but doesn't explain a thing about how aiAnimation affects the vertices. Or how I can get the other frames of data I need.
Well, I did manage to make it work after endless hours! Sort of... I made a model that is transformed in a loop x+5, y+5, x-5, y-5...
What I ended up doing, well it was the only thing I could think of anyways. Is reading the data from the scene->mAnimations[] and this basicly consists of an array of the keyframes only. So I had to interpolate all the vertices myself, (which is always a funny task to approach!).
Effectivly:
You get the time the keyframe should have interpolated fully.
Then subtract where the object currently is to figure out how much you need to move.
Now you need to figure out how much to move each step, so I took the easiest solution, divided it by how many frames the movement should be splitted over.
Now it was just a matter of updating all my vertices before sending them to the VBO. (This step is probably a little varying depending on your data-setup)
After those steps, I got something that looks like this:
Header:
class AssimpMesh {
private:
struct ShaderProgram {
//Shader data
GLuint program;
string programName;
vector <GLuint> shaders, uniforms;
};
struct MeshData {
//Mesh data
GLuint meshArray;
vector <GLuint> buffers;
vector <string> bufferNames;
//Shader data
ShaderProgram *shader;
vector <aiVector3D> transedVertices;
int totalIndices;
};
struct Frame {
vector <MeshData*> meshes;
};
struct Animation {
string name;
vector <Frame*> frames;
};
//Global shader data
ShaderProgram *globalShader;
//Model data
Assimp::Importer importer;
const aiScene *scene;
//Mesh data
bool initialized, perMeshShading;
vector <Animation*> animations;
int currentFrame, currentAnimation;
Uint32 lastFrameTicks;
Transform *transform;
glm::mat4 projectionView;
aiVector3D lightPosition;
void loadScene(string filePath);
void loadAnimation(Animation *animation, int numFrames);
void initMesh(aiMesh *mesh, MeshData *data);
...
public:
AssimpMesh(string filePath);
~AssimpMesh();
void draw();
...
};
Source:
void AssimpMesh::loadScene(string filePath) {
//Load animation file
scene = importer.ReadFile(filePath.c_str(), aiProcessPreset_TargetRealtime_MaxQuality);
if (scene) {
if (scene->HasAnimations()) {
for (int i = 0; i < scene->mNumAnimations; i++) {
aiAnimation *anime = scene->mAnimations[i];
int framesInAnimation = ceil(anime->mDuration * ANIMATION_IMPORT_FPS);
Animation *animation = new Animation();
animation->name = anime->mName.C_Str();
loadAnimation(animation, framesInAnimation);
animations.push_back(animation);
}
}
else {
Animation *animation = new Animation();
animation->name = "Default";
loadAnimation(animation, 1);
animations.push_back(animation);
}
printf("Done loading '%s'\n", filePath.c_str());
}
else {
//Report error
printf("Assimp error: %s\n", importer.GetErrorString());
}
}
void AssimpMesh::loadAnimation(Animation *animation, int numFrames) {
int nextKeyframe = -1;
int nextKeyframeId = -1;
int transedFrames = 0;
aiVector3D transPos = aiVector3D();
aiVector3D transVec = aiVector3D();
for (int f = 0; f < numFrames; f++) {
Frame *frame = new Frame();
if (f > nextKeyframe && nextKeyframe < numFrames) {
//Get the new keyframe
aiAnimation *anime = scene->mAnimations[animations.size()];
aiNodeAnim *aniNode = anime->mChannels[0];
aiVectorKey key = aniNode->mPositionKeys[++nextKeyframeId];
nextKeyframe = ceil(key.mTime * ANIMATION_IMPORT_FPS);
if (!nextKeyframeId) {
transVec = key.mValue;
transPos = key.mValue;
}
else {
int transFrames = nextKeyframe - (f - 1);
aiVector3D transDir = key.mValue - transPos;
transPos = key.mValue;
transVec = transDir;
transVec /= transFrames;
transedFrames = 0;
}
}
if (scene->HasLights()) {
aiLight *light = scene->mLights[0];
//lightPosition = light->mPosition;
}
//Put data into vertex arrays
transedFrames++;
aiMesh *mesh;
MeshData *data;
for (int i = 0; i < scene->mNumMeshes; i++) {
mesh = scene->mMeshes[i];
data = new MeshData();
if (!i) {
for (int j = 0; j < mesh->mNumVertices; j++) {
if (!f) {
data->transedVertices.push_back(mesh->mVertices[j] + transVec);
}
else {
data->transedVertices.push_back(animation->frames[f-1]->meshes[i]->transedVertices[j] + transVec);
}
}
}
//Assign VBO
initMesh(mesh, data);
//Assign shader
if (perMeshShading) {
initShader(mesh, data);
setUniforms(mesh, data);
}
frame->meshes.push_back(data);
}
animation->frames.push_back(frame);
}
}
void AssimpMesh::initMesh(aiMesh *mesh, MeshData *data) {
//Buffer for temporary storage of new ids
GLuint id;
//Make vertex array
if (!initialized) {
glGenVertexArrays(1, &id);
}
data->meshArray = id;
//Tell OpenGL to use this array
glBindVertexArray(id);
//Assign vertices
if (mesh->HasPositions()) {
//Make buffer
if (!initialized) {
glGenBuffers(1, &id);
}
data->buffers.push_back(id);
data->bufferNames.push_back("Positions");
//Set buffer data
glBindBuffer(GL_ARRAY_BUFFER, id);
if (data->transedVertices.size()) {
glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * data->transedVertices.size(), &data->transedVertices[0], GL_STATIC_DRAW);
}
else {
glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * mesh->mNumVertices, &mesh->mVertices[0], GL_STATIC_DRAW);
}
//Set shader attribute data
glEnableVertexAttribArray(VBO_VERTEX);
glVertexAttribPointer(VBO_VERTEX, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
}
unsigned int matId = mesh->mMaterialIndex;
aiMaterial *material = scene->mMaterials[matId];
vector <aiColor3D> colors;
aiColor3D diffuse(0, 0, 0);
material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
for (int i = 0; i < mesh->mNumVertices; i++) {
colors.push_back(diffuse);
}
//Make buffer
if (!initialized) {
glGenBuffers(1, &id);
}
data->buffers.push_back(id);
data->bufferNames.push_back("Colors");
//Set buffer data
glBindBuffer(GL_ARRAY_BUFFER, id);
glBufferData(GL_ARRAY_BUFFER, sizeof(aiColor3D) * mesh->mNumVertices, &colors.front(), GL_STATIC_DRAW);
//Set shader attribute data
glEnableVertexAttribArray(VBO_COLOR);
glVertexAttribPointer(VBO_COLOR, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
//Assign texture coords
if (mesh->HasTextureCoords(0)) {
//Make buffer
if (!initialized) {
glGenBuffers(1, &id);
}
data->buffers.push_back(id);
data->bufferNames.push_back("TextureCoords");
//Set buffer data
glBindBuffer(GL_ARRAY_BUFFER, id);
glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * mesh->mNumVertices, &mesh->mTextureCoords[0], GL_STATIC_DRAW);
//Set shader attribute data
glEnableVertexAttribArray(VBO_TEXCORD);
glVertexAttribPointer(VBO_TEXCORD, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
}
//Assign colors
if (mesh->HasNormals()) {
//Make buffer
if (!initialized) {
glGenBuffers(1, &id);
}
data->buffers.push_back(id);
data->bufferNames.push_back("Normals");
//Set buffer data
glBindBuffer(GL_ARRAY_BUFFER, id);
glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * mesh->mNumVertices, &mesh->mNormals[0], GL_STATIC_DRAW);
//Set shader attribute data
glEnableVertexAttribArray(VBO_NORMAL);
glVertexAttribPointer(VBO_NORMAL, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
}
if (mesh->HasFaces()) {
vector <unsigned int> indices;
aiFace face;
for (int i = 0; i < mesh->mNumFaces; i++) {
face = mesh->mFaces[i];
for (int j = 0; j < face.mNumIndices; j++) {
indices.push_back(face.mIndices[j]);
}
}
data->totalIndices = indices.size();
//Make buffer
if (!initialized) {
glGenBuffers(1, &id);
}
data->buffers.push_back(id);
data->bufferNames.push_back("Faces");
//Set buffer data
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * indices.size(), &indices.front(), GL_STATIC_DRAW);
}
}
Of course, it doesn't work for everything yet. Actually only translation and the entire model. Apparently it doesn't read name values correctly so I can't which meshes the animation is meant for. But it got me going, maybe someone will find this helpful. =)