plakátok, részecskerendszerek szécsi lászló. copy-paste-rename gg009-gui folder (sok zsiráf...
TRANSCRIPT
GraphGamegg011-Particles
Plakátok, részecskerendszerek
Szécsi László
gg011-Particles project
• copy-paste-rename gg009-Gui folder (sok zsiráf nem kell ide)
• vcxproj, filters átnevezés• solution/add existing project• rename project• working dir: $(SolutionDir)• Project Properties/Configuration
Properties/Debugging/Command Arguments--solutionPath:"$(SolutionDir)" --projectPath:"$(ProjectDir)"
• build, run
Particle osztály#include "Math/math.h"class Particle{ friend class Game; Egg::Math::float3 position; Egg::Math::float3 velocity; float lifespan; float age;public:};
Particle osztályvoid reborn() { using namespace Egg::Math; position = float3::random(-1,1); velocity = position * 5; age = 0; lifespan = float1::random(2,5);}Particle(){ reborn(); }
Particle buffer, input layout és pass
• Lehetne ezeket kézzel létrehozni– ugyanúgy, ahogy a háromszögrajzolásnál az elején– csak a shader az effect fileból jön
• D3DX11_PASS_DESC billboardPassDesc;• effect->GetTechniqueByName("billboard")->
GetPassByName("fire")->GetDesc(&billboardPassDesc);
– és a VB használati módja dinamikus– rajzoláskor
• context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
• effect->GetTechniqueByName("billboard")-> GetPassByName("fire")->Apply(0, context);
• context->Draw(particles.size(), 0);
Egg::Mesh-t használva
• Mesh::VertexStream a buffer• Effect pass-ra Mesh::Material• InputLayout gyártása a Mesh::Binder feladata• a végén kapunk egy Mesh::Shaded-et amit
csak ki kell rajzolni– beállítja az effect pass-t– az input layoutot– a vertex buffert– rajzol
Game.h#include "Particle.h"#include <vector>
Game.hclass Game : public Egg::Sas::SasApp
{ std::vector<Particle> particles; Egg::Mesh::Shaded::P fireBillboardSet;
createResourcesfor(int i=0; i<40; i++) particles.push_back(Particle());
createResourcesD3D11_INPUT_ELEMENT_DESC particleElements[3];particleElements[0].AlignedByteOffset = offsetof(Particle, position);particleElements[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;particleElements[0].InputSlot = 0;particleElements[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;particleElements[0].InstanceDataStepRate = 0;particleElements[0].SemanticIndex = 0;particleElements[0].SemanticName = "POSITION";particleElements[1].AlignedByteOffset = offsetof(Particle, lifespan);particleElements[1].Format = DXGI_FORMAT_R32_FLOAT;particleElements[1].InputSlot = 0;particleElements[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;particleElements[1].InstanceDataStepRate = 0;particleElements[1].SemanticIndex = 0;particleElements[1].SemanticName = "LIFESPAN";particleElements[2].AlignedByteOffset = offsetof(Particle, age);particleElements[2].Format = DXGI_FORMAT_R32_FLOAT;particleElements[2].InputSlot = 0;particleElements[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;particleElements[2].InstanceDataStepRate = 0;particleElements[2].SemanticIndex = 0;particleElements[2].SemanticName = "AGE";
createResourcesEgg::Mesh::VertexStreamDesc particleBufferDesc;
particleBufferDesc.elements = particleElements;particleBufferDesc.nElements = 3;particleBufferDesc.nVertices = particles.size();
particleBufferDesc.vertexStride = sizeof(Particle);
particleBufferDesc.vertexData = &particles.at(0);
particleBufferDesc.cpuAccessFlags = D3D11_CPU_ACCESS_WRITE;
particleBufferDesc.usage = D3D11_USAGE_DYNAMIC;
createResourcesEgg::Mesh::VertexStream::P particleVertexStream = Egg::Mesh::VertexStream::create( device, particleBufferDesc);
createResourcesID3DX11EffectPass* billboardPass = effect-> GetTechniqueByName("billboard")-> GetPassByName("fire");Egg::Mesh::Material::P fireMaterial = Egg::Mesh::Material::create( billboardPass, 0);fireBillboardSet = binder->bindMaterial( fireMaterial, particleVertexStream);
releaseResourcesfireBillboardSet.reset();
renderfireBillboardSet->draw(context);
Új fx file
• solution fx folderbe• billboard.fx
fx/main.fx#include <envmapped.fx>#include <billboard.fx>
#9.0
fx/billboard.fxstruct IaosBillboard{ float3 pos : POSITION; float lifespan : LIFESPAN; float age : AGE;};
typedef IaosBillboard VsosBillboard;
VsosBillboard vsBillboard(IaosBillboard input){ return input;}
#9.0
fx/billboard.fxstruct GsosBillboard{ float4 pos : SV_Position; float2 tex : TEXCOORD;};
float billboardWidth = 0.1;float billboardHeight = 0.1;
#9.0
fx/billboard.fx[maxvertexcount(4)]void gsBillboard( point VsosBillboard input[1], inout TriangleStream<GsosBillboard> stream) { float4 hndcPos = mul(float4(input[0].pos, 1), modelViewProjMatrix); GsosBillboard output; output.pos = hndcPos; output.pos.x += billboardWidth; output.pos.y += billboardHeight; output.tex = float2(1, 0); stream.Append(output);output.pos = hndcPos;
output.pos.x += billboardWidth;
output.pos.y -= billboardHeight;
output.tex = float2(1, 1);
stream.Append(output);
output.pos = hndcPos;
output.pos.x -= billboardWidth;
output.pos.y += billboardHeight;
output.tex = float2(0, 0);
stream.Append(output);
output.pos = hndcPos;
output.pos.x -= billboardWidth;
output.pos.y -= billboardHeight;
output.tex = float2(0, 1);
stream.Append(output); }
#9.0
fx/billboard.fxfloat4 psFire(GsosBillboard input) : SV_Target{ return input.tex.xyyy;}technique11 billboard { pass fire { SetVertexShader ( CompileShader( vs_5_0, vsBillboard() ) ); SetGeometryShader ( CompileShader( gs_5_0, gsBillboard() ) ); SetPixelShader( CompileShader( ps_5_0, psFire() ) ); }}
#9.0
Színes plakátok
Textúra
• particle.dds letöltése• Projects/gg011-Particles/Media folderbe
Game classclass Game : public Egg::Sas::SasApp
{
ID3D11ShaderResourceView* billboardSrv;
createResourcesD3DX11CreateShaderResourceViewFromFileA( device, systemEnvironment.resolveMediaPath( "particle.dds" ).c_str(), NULL, NULL, &billboardSrv, NULL);effect-> GetVariableByName("billboardTexture") ->AsShaderResource(billboardSrv);
releaseResourcesbillboardSrv->Release();
fx/billboard.fxTexture2D billboardTexture;
float4 psFire(GsosBillboard input) : SV_Target{ return billboardTexture.Sample( linearSampler, input.tex.xy);}
#9.0
Textúrázott, de viewporthoz torzuló
createSwapChainResourcesusing namespace Egg::Math;
float4 worldBillboardSize(0.2, 0.2, 0, 0);float4 screenBillboardSize = worldBillboardSize * firstPersonCam->getProjMatrix();
effect-> GetVariableByName("billboardWidth")-> AsScalar()-> SetFloat(screenBillboardSize.x);effect-> GetVariableByName("billboardHeight")-> AsScalar()-> SetFloat(screenBillboardSize.y);
Állandó méretű plakátok
Alpha blending
• BlendState-et kell definiálni, pass-ban kiválasztani
• a többi pass-ban viszont vissza kéne állítani• legyen a blendStates.fx, amibe az összes
BlendState-et gyűjtjük• legyen akkor már– rasterizerStates.fx– depthStencilStates.fx
fx/blendStates.fxBlendState defaultBlender{};
BlendState additiveBlender{BlendEnable[0] = true;SrcBlend = src_alpha;DestBlend = one;BlendOp = add;SrcBlendAlpha = one;DestBlendAlpha = one;BlendOpAlpha = add;
};
#9.0
fx/blendStates.fxRasterizerState defaultRasterizer{};
RasterizerState noCullRasterizer{
CullMode = none;FillMode = solid;
};
RasterizerState backfaceRasterizer{
CullMode = front;FillMode = solid;
};
RasterizerState wireframeRasterizer{
CullMode = none;FillMode = wireFrame;
};
#9.0
depthStencilStates.fxDepthStencilState defaultCompositor{};
DepthStencilState noDepthTestCompositor{
DepthEnable = false;DepthWriteMask = zero;
};
DepthStencilState noDepthWriteCompositor{ DepthEnable = true; DepthWriteMask = zero;};
#9.0
fx/basic.fx#include <blendStates.fx>#include <rasterizerStates.fx>#include <depthStencilStates.fx>
...
technique11 basic{
pass basic{ SetVertexShader ( CompileShader( vs_5_0, vsTrafo() ) ); SetGeometryShader( NULL ); SetRasterizerState( defaultRasterizer ); SetPixelShader( CompileShader( ps_5_0, psBasic() ) ); SetDepthStencilState( defaultCompositor, 0 ); SetBlendState( defaultBlender,
float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); }
}
#9.0
Minden pass legyen teljes
• textured/textured• shaded/diffuse, shaded/specular• envmapped/envmapped,
envmapped/background
fx/billboard.fxtechnique11 billboard { pass fire { SetVertexShader ( CompileShader( vs_5_0, vsBillboard() ) ); SetGeometryShader ( CompileShader( gs_5_0, gsBillboard() ) ); SetRasterizerState( defaultRasterizer ); SetPixelShader( CompileShader( ps_5_0, psFire() ) ); SetDepthStencilState( defaultCompositor, 0 ); SetBlendState( defaultBlender, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); }}
#9.0
Ugyanaz
fx/billboard.fxtechnique11 billboard { pass fire { SetVertexShader ( CompileShader( vs_5_0, vsBillboard() ) ); SetGeometryShader ( CompileShader( gs_5_0, gsBillboard() ) ); SetRasterizerState( defaultRasterizer ); SetPixelShader( CompileShader( ps_5_0, psFire() ) ); SetDepthStencilState( defaultCompositor, 0 ); SetBlendState( additiveBlender, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); }}
#9.0
Blending van… de z-teszt is
fx/billboard.fxtechnique11 billboard { pass fire { SetVertexShader ( CompileShader( vs_5_0, vsBillboard() ) ); SetGeometryShader ( CompileShader( gs_5_0, gsBillboard() ) ); SetRasterizerState( defaultRasterizer ); SetPixelShader( CompileShader( ps_5_0, psFire() ) ); SetDepthStencilState( noDepthTestCompositor, 0 ); SetBlendState( additiveBlender, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); }}
#9.0
Nem depth test – zsiráf sem takar
fx/billboard.fxtechnique11 billboard { pass fire { SetVertexShader ( CompileShader( vs_5_0, vsBillboard() ) ); SetGeometryShader ( CompileShader( gs_5_0, gsBillboard() ) ); SetRasterizerState( defaultRasterizer ); SetPixelShader( CompileShader( ps_5_0, psFire() ) ); SetDepthStencilState( noDepthWriteCompositor, 0 ); SetBlendState( additiveBlender, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); }}
#9.0
Zsiráf takar, plakát nem
fx/billboard.fxtechnique11 billboard { pass fire { SetVertexShader ( CompileShader( vs_5_0, vsBillboard() ) ); SetGeometryShader ( CompileShader( gs_5_0, gsBillboard() ) ); SetRasterizerState( defaultRasterizer ); SetPixelShader( CompileShader( ps_5_0, psFire() ) ); SetDepthStencilState( noDepthWriteCompositor, 0 ); SetBlendState( transparencyBlender, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); }}
#9.0
Rossz a sorrend… hátsók takarnak előbbiekre
Ehhez rendezni kellene a plakátokat mélység szerint…
egyelőre inkább vissza az additívhoz!
Legyen színesebbfloat4 psFire(GsosBillboard input) : SV_Target{ float4 color = billboardTexture.Sample(linearSampler,
input.tex.xy); color.rgb = float3( color.a, pow(color.a, 4), pow(color.a, 10)); return color;}
#9.0
worldBillboardSize (1, 1)
Nagyobb tűzusing namespace Egg::Math;firstPersonCam = Egg::Cam::FirstPerson::create()
->setView( float3(0, 0, 200), float3(0, 0, -1)) ->setProj(1.2, 1, 1, 1000) ->setSpeed(50);
float4 worldBillboardSize(50.0, 50.0, 0, 0);
Particlevoid move(float dt){ position +=velocity * dt; age += dt; if(age > lifespan) reborn();}
Game::animatefor(int i = 0; i < particles.size(); i++)
particles.at(i).move(dt);
Game::animateID3D11Buffer* vertexBuffer = fireBillboardSet->getGeometry()-> getPrimaryBuffer();
ID3D11DeviceContext* context;device->GetImmediateContext(&context);D3D11_MAPPED_SUBRESOURCE mappedVertexData;context->Map(vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedVertexData);
memcpy(mappedVertexData.pData, &particles.at(0), sizeof(Particle) * particles.size());context->Unmap(vertexBuffer, 0);context->Release();
Hirtelen tűnnek el
Megoldás
• Korfüggő méret, intenzitás és átlátszóság
gsBillboardstruct GsosBillboard{ float4 pos : SV_Position; float2 tex : TEXCOORD; float opacity : OPACITY;};
float s = input[0].age / input[0].lifespan;...output.opacity = 1 - abs(s*2-1);
// és mindenhol szorozzuk s-sel a szélességet és magasságot
#9.0
psFirefloat4 psFire(GsosBillboard input) : SV_Target{ float4 color = billboardTexture.Sample(linearSampler,
input.tex.xy); color.rgb = float3(color.a, pow(color.a, 4), pow(color.a, 10)); color.a *= input.opacity; return color;}
#9.0
Simább tűz
fx/billboard.fxtechnique11 billboard { pass fire { SetVertexShader ( CompileShader( vs_5_0, vsBillboard() ) ); SetGeometryShader ( CompileShader( gs_5_0, gsBillboard() ) ); SetRasterizerState( defaultRasterizer ); SetPixelShader( CompileShader( ps_5_0, psFire() ) ); SetDepthStencilState( noDepthWriteCompositor, 0 ); SetBlendState( transparencyBlender, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); }}
#9.0
animate - rendezésusing namespace Egg::Math;struct CameraDepthComparator { float3 ahead; bool operator()(const Particle& a, const Particle& b) { return a.position.dot(ahead) > b.position.dot(ahead) + 0.01; }} comp = { firstPersonCam->getAhead() };std::sort(particles.begin(), particles.end(), comp);
Rendezéssel szép
400 részecske, kisebb alfa