Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
const float size = 0.1f; // размер конченого квадрата
Вместо геометрических шейдеров и structured буфера — инстансинг.
… что для тех кто хочет миллионы частиц без DirectX 10 и выше — все прекрасно (практически с идентичной производительностью) делается на DX9
Ну и по поводу шейдеров. Поскольку у нас частицы ориентированы на нас, то data.Position = mul(data.Position, Projection); в геометрическом шейдере не нужен.
Так же размер частицы можно посчитать в вертексном, а в геометрическом делать только сдвиг
Проверьте (касаемо «практические идентичной производительности»)? Сделайте систему на один миллион частиц на DX9 через рендер в текстуру и VFetch (еще и с инстансингом), и потом сравните с CS, GS. Когда уже дадут умереть DX9? :)Спасибо, проверял уже в те времена, когда производительность GF550 Ti была чем-то очень крутым: habrahabr.ru/post/151821/
Попробуйте сделать сдвиг вертекса во ViewSpace и ProjectionSpace, ну как?Легко. Вам шейдер запилить в качестве доказательства? Мы можем такое делать, потому что частица всегда ориентирована на нас и перспективных искажений нет => интерполятор даст идентичные результаты.
Вы думаете в копилированном варианте шейдера есть такое понятие — как функции? В геометрическом не считается размер частиц и делается только сдвиг.Вы size не считате, потому что вы 4 раза умножаете на матрицу проекции. Я же говорю, что лучше умножать на матрицу проекции в вершинном, там же считать Size и передавать его в геометрический.
Вон выше в комментариях уже обсуждали, что DX11 возможности сегодня далеко не везде есть. Если можно обойтись без них — почему бы это не сделать (особенно это касается OpenGL)?
А так же, сделайте геометрический шейдер с вашей оптимизацией, я посмотрю как это будет работать (скачайте исходник и сделайте).К сожалению вы не залили проект на git, сделал бы пуллреквест… так что шейдер под спойлером:
struct Particle
{
float3 Position;
float3 Velocity;
};
StructuredBuffer<Particle> Particles : register(t0);
Texture2D<float> ParticleTexture : register(t1);
SamplerState ParticleSampler : register(s1);
cbuffer Params : register(b0)
{
float4x4 ViewProjection;
float4x4 Projection;
};
struct VertexInput
{
uint VertexID : SV_VertexID;
};
struct GeometryInput
{
float4 Position : SV_POSITION;
float3 PositionTWS : TEXCOORD0;
float2 Size : SIZE;
};
struct PixelInput
{
float4 Position : SV_POSITION;
float2 UV : TEXCOORD0;
float3 PositionTWS : TEXCOORD1;
};
struct PixelOutput
{
float4 Color : SV_TARGET0;
};
GeometryInput TriangleVS(VertexInput input)
{
GeometryInput output = (GeometryInput)0;
Particle particle = Particles[input.VertexID];
output.Position = mul(float4(particle.Position, 1), ViewProjection);
float size = 0.1;
output.Size = size * float2(Projection[0][0], Projection[1][1]);
float speedLength = length(particle.Velocity);
//float magnitude = saturate(length(worldPosition.xyz) * 0.1);
output.PositionTWS = float3(lerp(float3(0.1, 0.5, 1.0), float3(1.0, 0.5, 0.1), speedLength * 0.1));
return output;
}
void FillQuadVertex(inout PixelInput data, in float2 NewXY, in float2 UV)
{
data.Position.xy = NewXY;
data.UV = UV;
}
[maxvertexcount(4)]
void TriangleGS( point GeometryInput input[1], inout TriangleStream<PixelInput> stream )
{
PixelInput Out;
Out.Position.zw = input[0].Position.zw;
Out.PositionTWS = input[0].PositionTWS;
FillQuadVertex(Out, input[0].Position.xy + float2(-1,-1) * input[0].Size, float2(0, 0)); stream.Append(Out);
FillQuadVertex(Out, input[0].Position.xy + float2(-1, 1) * input[0].Size, float2(0, 1)); stream.Append(Out);
FillQuadVertex(Out, input[0].Position.xy + float2( 1,-1) * input[0].Size, float2(1, 0)); stream.Append(Out);
FillQuadVertex(Out, input[0].Position.xy + float2( 1, 1) * input[0].Size, float2(1, 1)); stream.Append(Out);
stream.RestartStrip();
}
PixelOutput TrianglePS(PixelInput input)
{
PixelOutput output = (PixelOutput)0;
float particle = ParticleTexture.Sample(ParticleSampler, input.UV).x * 0.3;
float3 speedColor = input.PositionTWS;
output.Color = float4(speedColor * particle, 1);
return output;
}
technique ParticleRender
{
pass DefaultPass
{
Profile = 10.0;
VertexShader = TriangleVS;
GeometryShader = TriangleGS;
PixelShader = TrianglePS;
}
}
С радостью увижу шейдер (а еще лучше скомпилированный экзешник) с инстансингом (quadbillboard) и vfetch миллиона партиклов с FPS на GeForce 550 Ti в 110.Может быть как-нибудь позже, но не обещаю. Времени требует много.
Так и пишите на ассемблере, у всех будет работать, в чем проблема? У DX10+ есть режим совместимости с feature level 9.1-9.3. DX10 карта сейчас есть практически у всех, DX9 (и всякие мертвые WinXP) — поддерживать смысла нет.Я сейчас говорю не столько о самом DX9, сколько об аппаратных возможностях. Компьют и геометрические шейдера с feature level 9 не взлетят.
И да, если вы пишите игры для «офисных» компьютеров — использовать DX смысла вообще нет, используйте OpenGL.Вот уж не могу согласится. «Офисные» компьютеры часто с дефолтными драйверами после установки Win, и с OGL там вообще печаль. Вон даже хром «эмулирует» OGL через DirectX.
С радостью увижу шейдер (а еще лучше скомпилированный экзешник) с инстансингом (quadbillboard) и vfetch миллиона партиклов с FPS на GeForce 550 Ti в 110 (при реализации с FL9.3 у меня вышло 59 FPS).
Убрал умножение на матрицу проекции в геометрическом шейдере. Поскольку все умножения теперь в вертексном, то делаю одно умножение на ViewProjection. Поэтому не забудьте изменить в GPUParticlesHandler.cs установку матрицы вида на _particlesRender.Parameters[«ViewProjection»].SetValue(camera.ViewProjection);
Но как я и говорил, прирост фпс после данной «оптимизации» сложно заметить, потому что узко на филлрейте.
Может быть как-нибудь позже, но не обещаю. Времени требует много.
Я сейчас говорю не столько о самом DX9, сколько об аппаратных возможностях. Компьют и геометрические шейдера с feature level 9 не взлетят.
10 000 000 частиц, фуллскрин, разрешение 1920x1080, камера на всю сцену:Я же говорю, узко на филлрейте. Упирается в запись в память. Если оптимзировать запись в память, то 10кк частиц можно выжать с гораздо большим фпс, и эта оптимизация уже будет иметь смысл. А сейчас чтобы заметить эту оптимизацию — камеру отворачивайте, чтобы частицы в кадр не попадали, и отключите резолв.
с «оптимизацией» — FPS: 9, Draw time: прыгает в районе 0.02s с максимальным отклонением 0.0052s.
без «оптимизации» — FPS: 9, Draw time: прыгает в районе 0.02s с максимальным отклонением 0.0049s.
Оптимизация говорите?
GPU Particles с использованием Compute и Geometry шейдеров