Комментарии 44
А какие аналоги этих типов шейдеров существуют в OpenGL?
ARB_compute_shader, к сожалению, доступен только для OpenGL 4.3.
Но в качестве альтернативы можно использовать «Transform feedback». Он доступен с версии 3.0.
Но в качестве альтернативы можно использовать «Transform feedback». Он доступен с версии 3.0.
Почему «к сожалению»? На десктопах OpenGL 4.3 сейчас не поддерживает только Intel под линуксом, потому что работает через Mesa.
В OpenGL ES 3 compute shaders тоже есть, хотя вряд ли кто захочет симулировать 1М частиц на мобильном устройстве.
А вот OpenCL как раз Nvidia не поддерживает дальше версии 1.1, что значительно ограничевает возможности.
В OpenGL ES 3 compute shaders тоже есть, хотя вряд ли кто захочет симулировать 1М частиц на мобильном устройстве.
А вот OpenCL как раз Nvidia не поддерживает дальше версии 1.1, что значительно ограничевает возможности.
Сейчас 3 основные десктоп платформы. Винда, Линукс, МакОС.
Под макам версия GL традиционно отстает. ref support.apple.com/en-us/HT202823
Текущий максимум под OSX — это GL 4.1
UPD: если верить табличке www.g-truc.net/post-0702.html#menu — то и 4.1 Apple поддерживает на 83%
Под макам версия GL традиционно отстает. ref support.apple.com/en-us/HT202823
Текущий максимум под OSX — это GL 4.1
UPD: если верить табличке www.g-truc.net/post-0702.html#menu — то и 4.1 Apple поддерживает на 83%
«К сожалению» — потому что ни моя домашняя, ни офисная видеокарты OpenGL 4.3 не поддерживают.
И таких людей довольно много, чтобы сбрасывать их со счетов.
И таких людей довольно много, чтобы сбрасывать их со счетов.
Да, ещё для вычислений вполне можно использовать OpenCL. Там есть возможность использовать контекст и буферы OpenGL.
Спасибо за статью.
Правда проект просто так нельзя взять и запустить, тем кто не работает с SharpDX:
Cannot process file '\GPUParticlesSources\GPUParticles\Content\ParticleSolver.fx': Could not load file or assembly 'SharpDX.D3DCompiler,
Было бы здорово иметь самодостаточный солюшен.
Правда проект просто так нельзя взять и запустить, тем кто не работает с SharpDX:
Cannot process file '\GPUParticlesSources\GPUParticles\Content\ParticleSolver.fx': Could not load file or assembly 'SharpDX.D3DCompiler,
Было бы здорово иметь самодостаточный солюшен.
Извините, но с какого перепугу GeForce 550 Ti вдруг стала бюджетной видеокартой. Начнем с того, что это карта из линейки GTX а не GT, и по умолчанию является игровой. Более того, на момент появления была топовой картой и мечтой каждого игромана. Да, сегодня она по номеру устарела но по прежнему выдает достаточную производительность в играх, так как по сути в новых моделях ничего толкового не появилось.
А в чём противоречие? 550 Ti — самая дешёвая игровая видеокарта из 500-й линейки. Ниже — офисные, выше — средне-бюджетная 560, более дорогие 570, 580-я и топовая 590-я.
По видимому у нас с вами разная шкала оценки, мне всегда казалось что бюджетная и оффисная это одно и тоже. Но это мое личное мнение, спасибо за ответ.
Спасибо за статью)
На GTX770 полет отличный (скачал исходник, сбилдил). Показывает 61 fps, хотя мне кажется циферка врет немного).
На GTX770 полет отличный (скачал исходник, сбилдил). Показывает 61 fps, хотя мне кажется циферка врет немного).
Она не врет, FPS ограничен — 60 кадров в секунду, отключите (поставьте false) в конструкторе класса Logic -> SynchronizeWithVerticalRetrace и IsFixedTimeStep, увидите максимальное кол-во FPS. На GTX 770, думаю, будет около 220.
Спасибо за ответ.
Выдает 440-453
Выдает 440-453
Ну поэкспериментируйте еще и с кол-вом частиц: класс GPUParticlesHandler, константа — PARTICLES_COUNT, достаточно изменить значение — а уж исходя из этого построится нужный буфер на нужное кол-во частиц в этом буфере.
Можно узнать частоты вашей карточки? Просто моя 770 (ядро/память: 1058/7010 МГц) выдает 380-420 :)
Gigabyte GeForce GTX 770
AIDA64 показывает:
Частота- 1189 МГц
Частота памяти — 3505
c2n.me/3b9VuYb
Не разгонял.
AIDA64 показывает:
Частота- 1189 МГц
Частота памяти — 3505
c2n.me/3b9VuYb
Не разгонял.
Это все очень неоднозначно, потому что в частицах тормозить начинает уже на филлрейте. Открыли окно на весь экран или подлетели камерой поближе, и минус 50% FPS.
Нужно делать динамический LOD-инг чтобы выжать еще больше попугаев.
Нужно делать динамический LOD-инг чтобы выжать еще больше попугаев.
Не могу скачать демо — пишет превышен лимит скачивания файлов.
В полноэкранный режим не переключается по альт-энтер: экран мигает на секунду и все возвращается. Или просто нет такой опции?
В статье вовсю Compute шейдера, но в требованиях упоминается только DirectX 10.
В статью неплохо было бы добавить, что для тех кто хочет миллионы частиц без DirectX 10 и выше — все прекрасно (практически с идентичной производительностью) делается на DX9. Вместо геометрических шейдеров и structured буфера — инстансинг. Вместо Compute шейдеров — рендер в текстуру.
Ну и по поводу шейдеров. Поскольку у нас частицы ориентированы на нас, то data.Position = mul(data.Position, Projection); в геометрическом шейдере не нужен. Так же размер частицы можно посчитать в вертексном, а в геометрическом делать только сдвиг. Оптимизация.
p.s. Знаю, что о опечатках принято в личку, но не удержался:
В статью неплохо было бы добавить, что для тех кто хочет миллионы частиц без DirectX 10 и выше — все прекрасно (практически с идентичной производительностью) делается на DX9. Вместо геометрических шейдеров и structured буфера — инстансинг. Вместо Compute шейдеров — рендер в текстуру.
Ну и по поводу шейдеров. Поскольку у нас частицы ориентированы на нас, то data.Position = mul(data.Position, Projection); в геометрическом шейдере не нужен. Так же размер частицы можно посчитать в вертексном, а в геометрическом делать только сдвиг. Оптимизация.
p.s. Знаю, что о опечатках принято в личку, но не удержался:
const float size = 0.1f; // размер конченого квадрата
Вместо геометрических шейдеров и structured буфера — инстансинг.
… что для тех кто хочет миллионы частиц без DirectX 10 и выше — все прекрасно (практически с идентичной производительностью) делается на DX9
Проверьте (касаемо «практические идентичной производительности»)? Сделайте систему на один миллион частиц на DX9 через рендер в текстуру и VFetch (еще и с инстансингом), и потом сравните с CS, GS. Когда уже дадут умереть DX9? :)
Ну и по поводу шейдеров. Поскольку у нас частицы ориентированы на нас, то data.Position = mul(data.Position, Projection); в геометрическом шейдере не нужен.
Попробуйте сделать сдвиг вертекса во ViewSpace и ProjectionSpace, ну как?
Так же размер частицы можно посчитать в вертексном, а в геометрическом делать только сдвиг
Вы думаете в копилированном варианте шейдера есть такое понятие — как функции? В геометрическом не считается размер частиц и делается только сдвиг.
Это ответ на этот комментарий.
Проверьте (касаемо «практические идентичной производительности»)? Сделайте систему на один миллион частиц на DX9 через рендер в текстуру и VFetch (еще и с инстансингом), и потом сравните с CS, GS. Когда уже дадут умереть DX9? :)Спасибо, проверял уже в те времена, когда производительность GF550 Ti была чем-то очень крутым: habrahabr.ru/post/151821/
Все свободно крутилось на очень дохлых встроенных видеокартах. А в моем случае частицы еще и создавались динамически, и кол-во частиц в сцене могло скакать очень сильно. CS тогда еще в зачатках не было, а GS только только анонсировали. Вон выше в комментариях уже обсуждали, что DX11 возможности сегодня далеко не везде есть. Если можно обойтись без них — почему бы это не сделать (особенно это касается OpenGL)?
Попробуйте сделать сдвиг вертекса во ViewSpace и ProjectionSpace, ну как?Легко. Вам шейдер запилить в качестве доказательства? Мы можем такое делать, потому что частица всегда ориентирована на нас и перспективных искажений нет => интерполятор даст идентичные результаты.
Вы думаете в копилированном варианте шейдера есть такое понятие — как функции? В геометрическом не считается размер частиц и делается только сдвиг.Вы size не считате, потому что вы 4 раза умножаете на матрицу проекции. Я же говорю, что лучше умножать на матрицу проекции в вершинном, там же считать Size и передавать его в геометрический.
upd. Ответ на комментарий выше habrahabr.ru/post/248755/#comment_8243109
С радостью увижу шейдер (а еще лучше скомпилированный экзешник) с инстансингом (quadbillboard) и vfetch миллиона партиклов с FPS на GeForce 550 Ti в 110 (при реализации с FL9.3 у меня вышло 59 FPS).
А так же, сделайте геометрический шейдер с вашей оптимизацией, я посмотрю как это будет работать (скачайте исходник и сделайте).
Потом:
Так и пишите на ассемблере, у всех будет работать, в чем проблема? У DX10+ есть режим совместимости с feature level 9.1-9.3. DX10 карта сейчас есть практически у всех, DX9 (и всякие мертвые WinXP) — поддерживать смысла нет.
И да, если вы пишите игры для «офисных» компьютеров — использовать DX смысла вообще нет, используйте OpenGL.
А так же, сделайте геометрический шейдер с вашей оптимизацией, я посмотрю как это будет работать (скачайте исходник и сделайте).
Потом:
Вон выше в комментариях уже обсуждали, что DX11 возможности сегодня далеко не везде есть. Если можно обойтись без них — почему бы это не сделать (особенно это касается OpenGL)?
Так и пишите на ассемблере, у всех будет работать, в чем проблема? У DX10+ есть режим совместимости с feature level 9.1-9.3. DX10 карта сейчас есть практически у всех, DX9 (и всякие мертвые WinXP) — поддерживать смысла нет.
И да, если вы пишите игры для «офисных» компьютеров — использовать DX смысла вообще нет, используйте OpenGL.
А так же, сделайте геометрический шейдер с вашей оптимизацией, я посмотрю как это будет работать (скачайте исходник и сделайте).К сожалению вы не залили проект на git, сделал бы пуллреквест… так что шейдер под спойлером:
ParticleRender.fx
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;
}
}
Убрал умножение на матрицу проекции в геометрическом шейдере. Поскольку все умножения теперь в вертексном, то делаю одно умножение на ViewProjection. Поэтому не забудьте изменить в GPUParticlesHandler.cs установку матрицы вида на _particlesRender.Parameters[«ViewProjection»].SetValue(camera.ViewProjection);
Но как я и говорил, прирост фпс после данной «оптимизации» сложно заметить, потому что узко на филлрейте.
С радостью увижу шейдер (а еще лучше скомпилированный экзешник) с инстансингом (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).
mrdoob.com/lab/javascript/webgl/particles/particles_zz85_2m.html
И т.п. — гугл в помощь. 59 фпс — очень похоже на vsync (в webgl скорее всего тоже около 60 фпс покажет).
Убрал умножение на матрицу проекции в геометрическом шейдере. Поскольку все умножения теперь в вертексном, то делаю одно умножение на ViewProjection. Поэтому не забудьте изменить в GPUParticlesHandler.cs установку матрицы вида на _particlesRender.Parameters[«ViewProjection»].SetValue(camera.ViewProjection);
Но как я и говорил, прирост фпс после данной «оптимизации» сложно заметить, потому что узко на филлрейте.
10 000 000 частиц, фуллскрин, разрешение 1920x1080, камера на всю сцену:
с «оптимизацией» — FPS: 9, Draw time: прыгает в районе 0.02s с максимальным отклонением 0.0052s.
без «оптимизации» — FPS: 9, Draw time: прыгает в районе 0.02s с максимальным отклонением 0.0049s.
Оптимизация говорите?
Может быть как-нибудь позже, но не обещаю. Времени требует много.
Я же говорю, я делал сначала на Feature Level 9.3, через две текстуры R32, G32, B32 формата и временного буфера с таким же форматом, через RTсчитал частицы, с обычным (!) point-рендером, было 59 fps. В то же время, CS + GS (конечный продукт — quadbillboard) — 110 fps, а вы говорите такой же FPS: проиграл по FPS, качеству, еще и памяти больше нужно.
Я сейчас говорю не столько о самом DX9, сколько об аппаратных возможностях. Компьют и геометрические шейдера с feature level 9 не взлетят.
Так не используйте FL9.x, это же по сути эмулятор фиксированного мамонта. DX10 карта сейчас (кто интересует играми хотя-бы чуть-чуть) есть у всех, а Windows XP как таргет-платформу рассматривать вообще не стоит, через год вы о ней уже забудете.
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 шейдеров