Files
WickedEngine/WickedEngine/wiHairParticle.cpp
T
Turanszki Janos fa267b0e7d large refactor
2019-12-12 22:15:16 +00:00

390 lines
11 KiB
C++

#include "wiHairParticle.h"
#include "wiRenderer.h"
#include "wiResourceManager.h"
#include "wiMath.h"
#include "wiIntersect.h"
#include "wiRandom.h"
#include "ResourceMapping.h"
#include "wiArchive.h"
#include "ShaderInterop.h"
#include "wiTextureHelper.h"
#include "wiScene.h"
#include "ShaderInterop_HairParticle.h"
#include "wiBackLog.h"
using namespace std;
using namespace wiGraphics;
namespace wiScene
{
static VertexShader vs;
static PixelShader ps_alphatestonly;
static PixelShader ps_deferred;
static PixelShader ps_forward;
static PixelShader ps_forward_transparent;
static PixelShader ps_tiledforward;
static PixelShader ps_tiledforward_transparent;
static PixelShader ps_simplest;
static ComputeShader cs_simulate;
static DepthStencilState dss_default, dss_equal, dss_rejectopaque_keeptransparent;
static RasterizerState rs, ncrs, wirers;
static BlendState bs[2];
static PipelineState PSO[RENDERPASS_COUNT][2];
static PipelineState PSO_wire;
void wiHairParticle::UpdateCPU(const TransformComponent& transform, const MeshComponent& mesh, float dt)
{
world = transform.world;
XMFLOAT3 _min = mesh.aabb.getMin();
XMFLOAT3 _max = mesh.aabb.getMax();
_max.x += length;
_max.y += length;
_max.z += length;
_min.x -= length;
_min.y -= length;
_min.z -= length;
aabb = AABB(_min, _max);
aabb = aabb.transform(world);
if (dt > 0)
{
_flags &= ~REGENERATE_FRAME;
if (cb == nullptr || (strandCount * segmentCount) != particleBuffer->GetDesc().ByteWidth / sizeof(Patch))
{
_flags |= REGENERATE_FRAME;
cb.reset(new GPUBuffer);
particleBuffer.reset(new GPUBuffer);
simulationBuffer.reset(new GPUBuffer);
GPUBufferDesc bd;
bd.Usage = USAGE_DEFAULT;
bd.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
bd.CPUAccessFlags = 0;
bd.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
if (strandCount*segmentCount > 0)
{
bd.StructureByteStride = sizeof(Patch);
bd.ByteWidth = bd.StructureByteStride * strandCount * segmentCount;
wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, particleBuffer.get());
bd.StructureByteStride = sizeof(PatchSimulationData);
bd.ByteWidth = bd.StructureByteStride * strandCount * segmentCount;
wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, simulationBuffer.get());
}
bd.Usage = USAGE_DEFAULT;
bd.ByteWidth = sizeof(HairParticleCB);
bd.BindFlags = BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, cb.get());
}
}
}
void wiHairParticle::UpdateGPU(const MeshComponent& mesh, const MaterialComponent& material, CommandList cmd) const
{
if (strandCount == 0 || particleBuffer == nullptr)
{
return;
}
GraphicsDevice* device = wiRenderer::GetDevice();
device->EventBegin("HairParticle - UpdateRenderData", cmd);
device->BindComputeShader(&cs_simulate, cmd);
HairParticleCB hcb;
hcb.xWorld = world;
hcb.xColor = material.baseColor;
hcb.xHairRegenerate = (_flags & REGENERATE_FRAME) ? 1 : 0;
hcb.xLength = length;
hcb.xStiffness = stiffness;
hcb.xHairRandomness = randomness;
hcb.xHairStrandCount = strandCount;
hcb.xHairSegmentCount = std::max(segmentCount, 1u);
hcb.xHairParticleCount = hcb.xHairStrandCount * hcb.xHairSegmentCount;
hcb.xHairRandomSeed = randomSeed;
hcb.xHairViewDistance = viewDistance;
hcb.xHairBaseMeshIndexCount = (uint)mesh.indices.size();
hcb.xHairBaseMeshVertexPositionStride = sizeof(MeshComponent::Vertex_POS);
// segmentCount will be loop in the shader, not a threadgroup so we don't need it here:
hcb.xHairNumDispatchGroups = (uint)ceilf((float)strandCount / (float)THREADCOUNT_SIMULATEHAIR);
device->UpdateBuffer(cb.get(), &hcb, cmd);
device->BindConstantBuffer(CS, cb.get(), CB_GETBINDSLOT(HairParticleCB), cmd);
GPUResource* uavs[] = {
particleBuffer.get(),
simulationBuffer.get()
};
device->BindUAVs(CS, uavs, 0, arraysize(uavs), cmd);
GPUResource* res[] = {
mesh.indexBuffer.get(),
mesh.streamoutBuffer_POS != nullptr ? mesh.streamoutBuffer_POS.get() : mesh.vertexBuffer_POS.get(),
};
device->BindResources(CS, res, TEXSLOT_ONDEMAND0, arraysize(res), cmd);
device->Dispatch(hcb.xHairNumDispatchGroups, 1, 1, cmd);
device->UnbindUAVs(0, arraysize(uavs), cmd);
device->UnbindResources(TEXSLOT_ONDEMAND0, arraysize(res), cmd);
device->EventEnd(cmd);
}
void wiHairParticle::Draw(const CameraComponent& camera, const MaterialComponent& material, RENDERPASS renderPass, bool transparent, CommandList cmd) const
{
if (strandCount == 0 || cb == nullptr)
{
return;
}
GraphicsDevice* device = wiRenderer::GetDevice();
device->EventBegin("HairParticle - Draw", cmd);
device->BindStencilRef(STENCILREF_DEFAULT, cmd);
if (wiRenderer::IsWireRender())
{
if (transparent || renderPass == RENDERPASS_DEPTHONLY)
{
return;
}
device->BindPipelineState(&PSO_wire, cmd);
device->BindResource(VS, wiTextureHelper::getWhite(), TEXSLOT_ONDEMAND0, cmd);
}
else
{
device->BindPipelineState(&PSO[renderPass][transparent], cmd);
const GPUResource* res[] = {
material.GetBaseColorMap()
};
device->BindResources(PS, res, TEXSLOT_ONDEMAND0, arraysize(res), cmd);
device->BindResources(VS, res, TEXSLOT_ONDEMAND0, arraysize(res), cmd);
}
device->BindConstantBuffer(VS, cb.get(), CB_GETBINDSLOT(HairParticleCB), cmd);
device->BindResource(VS, particleBuffer.get(), 0, cmd);
device->Draw(strandCount * 12 * std::max(segmentCount, 1u), 0, cmd);
device->EventEnd(cmd);
}
void wiHairParticle::Serialize(wiArchive& archive, uint32_t seed)
{
if (archive.IsReadMode())
{
archive >> _flags;
wiECS::SerializeEntity(archive, meshID, seed);
archive >> strandCount;
archive >> segmentCount;
archive >> randomSeed;
archive >> length;
archive >> stiffness;
archive >> randomness;
archive >> viewDistance;
}
else
{
archive << _flags;
wiECS::SerializeEntity(archive, meshID, seed);
archive << strandCount;
archive << segmentCount;
archive << randomSeed;
archive << length;
archive << stiffness;
archive << randomness;
archive << viewDistance;
}
}
void wiHairParticle::LoadShaders()
{
std::string path = wiRenderer::GetShaderPath();
wiRenderer::LoadVertexShader(vs, "hairparticleVS.cso");
wiRenderer::LoadPixelShader(ps_simplest, "hairparticlePS_simplest.cso");
wiRenderer::LoadPixelShader(ps_alphatestonly, "hairparticlePS_alphatestonly.cso");
wiRenderer::LoadPixelShader(ps_deferred, "hairparticlePS_deferred.cso");
wiRenderer::LoadPixelShader(ps_forward, "hairparticlePS_forward.cso");
wiRenderer::LoadPixelShader(ps_forward_transparent, "hairparticlePS_forward_transparent.cso");
wiRenderer::LoadPixelShader(ps_tiledforward, "hairparticlePS_tiledforward.cso");
wiRenderer::LoadPixelShader(ps_tiledforward_transparent, "hairparticlePS_tiledforward_transparent.cso");
wiRenderer::LoadComputeShader(cs_simulate, "hairparticle_simulateCS.cso");
GraphicsDevice* device = wiRenderer::GetDevice();
for (int i = 0; i < RENDERPASS_COUNT; ++i)
{
if (i == RENDERPASS_DEPTHONLY || i == RENDERPASS_DEFERRED || i == RENDERPASS_FORWARD || i == RENDERPASS_TILEDFORWARD)
{
for (int j = 0; j < 2; ++j)
{
if ((i == RENDERPASS_DEPTHONLY || i == RENDERPASS_DEFERRED) && j == 1)
{
continue;
}
PipelineStateDesc desc;
desc.vs = &vs;
desc.bs = &bs[j];
desc.rs = &ncrs;
desc.dss = &dss_default;
switch (i)
{
case RENDERPASS_DEPTHONLY:
desc.ps = &ps_alphatestonly;
break;
case RENDERPASS_DEFERRED:
desc.ps = &ps_deferred;
break;
case RENDERPASS_FORWARD:
if (j == 0)
{
desc.ps = &ps_forward;
desc.dss = &dss_equal;
}
else
{
desc.ps = &ps_forward_transparent;
}
break;
case RENDERPASS_TILEDFORWARD:
if (j == 0)
{
desc.ps = &ps_tiledforward;
desc.dss = &dss_equal;
}
else
{
desc.ps = &ps_tiledforward_transparent;
}
break;
}
if (j == 1)
{
desc.dss = &dss_rejectopaque_keeptransparent; // transparent
}
device->CreatePipelineState(&desc, &PSO[i][j]);
}
}
}
{
PipelineStateDesc desc;
desc.vs = &vs;
desc.ps = &ps_simplest;
desc.bs = &bs[0];
desc.rs = &wirers;
desc.dss = &dss_default;
device->CreatePipelineState(&desc, &PSO_wire);
}
}
void wiHairParticle::Initialize()
{
RasterizerStateDesc rsd;
rsd.FillMode = FILL_SOLID;
rsd.CullMode = CULL_BACK;
rsd.FrontCounterClockwise = true;
rsd.DepthBias = 0;
rsd.DepthBiasClamp = 0;
rsd.SlopeScaledDepthBias = 0;
rsd.DepthClipEnable = true;
rsd.MultisampleEnable = false;
rsd.AntialiasedLineEnable = false;
wiRenderer::GetDevice()->CreateRasterizerState(&rsd, &rs);
rsd.FillMode = FILL_SOLID;
rsd.CullMode = CULL_NONE;
rsd.FrontCounterClockwise = true;
rsd.DepthBias = 0;
rsd.DepthBiasClamp = 0;
rsd.SlopeScaledDepthBias = 0;
rsd.DepthClipEnable = true;
rsd.MultisampleEnable = false;
rsd.AntialiasedLineEnable = false;
wiRenderer::GetDevice()->CreateRasterizerState(&rsd, &ncrs);
rsd.FillMode = FILL_WIREFRAME;
rsd.CullMode = CULL_NONE;
rsd.FrontCounterClockwise = true;
rsd.DepthBias = 0;
rsd.DepthBiasClamp = 0;
rsd.SlopeScaledDepthBias = 0;
rsd.DepthClipEnable = true;
rsd.MultisampleEnable = false;
rsd.AntialiasedLineEnable = false;
wiRenderer::GetDevice()->CreateRasterizerState(&rsd, &wirers);
DepthStencilStateDesc dsd;
dsd.DepthEnable = true;
dsd.DepthWriteMask = DEPTH_WRITE_MASK_ALL;
dsd.DepthFunc = COMPARISON_GREATER;
dsd.StencilEnable = true;
dsd.StencilReadMask = 0xFF;
dsd.StencilWriteMask = 0xFF;
dsd.FrontFace.StencilFunc = COMPARISON_ALWAYS;
dsd.FrontFace.StencilPassOp = STENCIL_OP_REPLACE;
dsd.FrontFace.StencilFailOp = STENCIL_OP_KEEP;
dsd.FrontFace.StencilDepthFailOp = STENCIL_OP_KEEP;
dsd.BackFace.StencilFunc = COMPARISON_ALWAYS;
dsd.BackFace.StencilPassOp = STENCIL_OP_REPLACE;
dsd.BackFace.StencilFailOp = STENCIL_OP_KEEP;
dsd.BackFace.StencilDepthFailOp = STENCIL_OP_KEEP;
wiRenderer::GetDevice()->CreateDepthStencilState(&dsd, &dss_default);
dsd.DepthWriteMask = DEPTH_WRITE_MASK_ZERO;
dsd.DepthFunc = COMPARISON_EQUAL;
wiRenderer::GetDevice()->CreateDepthStencilState(&dsd, &dss_equal);
dsd.DepthFunc = COMPARISON_GREATER;
wiRenderer::GetDevice()->CreateDepthStencilState(&dsd, &dss_rejectopaque_keeptransparent);
BlendStateDesc bld;
bld.RenderTarget[0].BlendEnable = false;
bld.AlphaToCoverageEnable = false; // maybe for msaa
wiRenderer::GetDevice()->CreateBlendState(&bld, &bs[0]);
bld.RenderTarget[0].SrcBlend = BLEND_SRC_ALPHA;
bld.RenderTarget[0].DestBlend = BLEND_INV_SRC_ALPHA;
bld.RenderTarget[0].BlendOp = BLEND_OP_ADD;
bld.RenderTarget[0].SrcBlendAlpha = BLEND_ONE;
bld.RenderTarget[0].DestBlendAlpha = BLEND_ONE;
bld.RenderTarget[0].BlendOpAlpha = BLEND_OP_ADD;
bld.RenderTarget[0].BlendEnable = true;
bld.RenderTarget[0].RenderTargetWriteMask = COLOR_WRITE_ENABLE_ALL;
bld.AlphaToCoverageEnable = false;
bld.IndependentBlendEnable = false;
wiRenderer::GetDevice()->CreateBlendState(&bld, &bs[1]);
LoadShaders();
wiBackLog::post("wiHairParticle Initialized");
}
}