Спавн партиклей сферой.

svk

1,185
3
Что я не так делаю, мало того что лаги, так ещё и пластиной спавнятся.
Код:
        for(int i = 0; i < 90; i++)
            for(int i2 = 0; i2 < 90;i2++)
                for(int i3 = 0; i3 < 90;i3++)
                {
                     double x = Math.toRadians(i);
                     double y = Math.toRadians(i2);
                     double z = Math.toRadians(i3);
                     
                     world.spawnParticle("explode", entity.posX + 10*Math.cos(x), entity.posY + 10*Math.cos(y), entity.posZ + 10*Math.cos(z), 0, 0, 0);
                }

Формула [центр сферы] + [R] * [cos(угол)]
 
Скриншот дай.Тебе сферой или кубом?(у самого 3 по геометрии).Тема была
 
Dovakin написал(а):
Скриншот дай.Тебе сферой или кубом?(у самого 3 по геометрии).Тема была
Скрин-шот чего? Сфера нужна, как у взрыва.
Пытался у взрыва партиклы повзаимствовать, но там 3-4 диска спавнятся, формирующи сферу, в общем не очень выглядит.
[merge_posts_bbcode]Добавлено: 19.03.2015 20:55:31[/merge_posts_bbcode]

Знаю, дали в зубы параметрическое уравнение сферы, с тета и фи, которые х*р знает что значат.
 
И ещё, как заспавнить цветные партиклы? Самому делать?
+Я вижу, что разные партиклы, рендерятся на разном расстоянии, это тоже надо делать свой партикл?
 
А насчёт партиклов? Можно-ли сделать изменение цвета/дальности прорисовки не создавая свой?
 
Ну если нужно простое решение для "рандомной" сферы, то проще всего сделать случайный вектор, нормализовать его и сдвинуть частицу на этот вектор от центра взрыва. Что-то вроде:
Код:
Random rand = new Random();
Vector3f randVec = new Vector3f(rand.nextFloat()-0.5F, rand.nextFloat()-0.5F, rand.nextFloat()-0.5F);
randVec.normalise();
float particleX = centerX + randVec.x;
//TODO y и z

Если нужно равномерное расстояние между партиклами (имхо не лучший выбор для взрыва), то как-то так:
Код:
//число сегментов по вертикали стоит сделать вдвое меньше числа сегментов по горизонтали
for (int vert = 0; vert < NUM_VERTICAL_SEGMENTS; vert++){
  for (int hor = 0; hor < NUM_HORIZONTAL_SEGMENTS; hor++){
    //угол от 0 до 2Pi
    float angleH = (float)hor/NUM_HORIZONTAL_SEGMENTS * 2 * (float)Math.PI;
    //угол от -Pi/2 до Pi/2
    float angleV = (float)vert/NUM_VERTICAL_SEGMENTS * (float)Math.PI - (float)Math.PI/2;
    float particleY = centerY + MathHelper.sin(angleV);
    float particleX = centerX + MathHelper.cos(angleH) * MathHelper.cos(angleV);
    float particleZ = centerZ + MathHelper.sin(angleH) * MathHelper.cos(angleV);
  }
}
P.S: весь код писался сейчас из головы и без проверки, так что поправьте, если оно не работает.
P.P.S: поправил некоторые моменты, первый вариант точно бы не работал :D
P.P.P.S: ну теперь-то уже точно должно работать
 
GloomyFolken написал(а):
Ну если нужно простое решение для "рандомной" сфера, то проще всего сделать случайный вектор, номализовать его и частицу на этот вектор от центра взрыва. Что-то вроде
Спасибо, решила частично свою проблему)))
 
GloomyFolken написал(а):
Ну если нужно простое решение для "рандомной" сферы, то проще всего сделать случайный вектор, нормализовать его и сдвинуть частицу на этот вектор от центра взрыва. Что-то вроде:
Код:
Random rand = new Random();
Vector3f randVec = new Vector3f(rand.nextFloat()-0.5F, rand.nextFloat()-0.5F, rand.nextFloat()-0.5F);
randVec.normalise();
float particleX = centerX + randVec.x;
//TODO y и z

Если нужно равномерное расстояние между партиклами (имхо не лучший выбор для взрыва), то как-то так:
Код:
//число сегментов по вертикали стоит сделать вдвое меньше числа сегментов по горизонтали
for (int vert = 0; vert < NUM_VERTICAL_SEGMENTS; vert++){
  for (int hor = 0; hor < NUM_HORIZONTAL_SEGMENTS; hor++){
    //угол от 0 до 2Pi
    float angleH = (float)hor/NUM_HORIZONTAL_SEGMENTS * 2 * (float)Math.PI;
    float particleX = centerX + MathHelper.cos(angleH);
    float particleZ = centerZ + MathHelper.sin(angleH);
    //угол от -Pi/2 до Pi/2
    float angleV = (float)vert/NUM_VERTICAL_SEGMENTS * (float)Math.PI - (float)Math.PI/2;
    float particleY = centerY + MathHelper.sin(angleV);
    particleX *= MathHelper.cos(angleV);
    particleZ *= MathHelper.cos(angleV);
  }
}
P.S: весь код писался сейчас из головы и без проверки, так что поправьте, если оно не работает.
P.P.S: поправил некоторые моменты, первый вариант точно бы не работал :D
Не работает 2 вариант.
 
Ну а что второй вариант делает? Мне лень проверять.
И проверь, что пытался использовать код после последней правки, потому что их было штук 5 :D
[merge_posts_bbcode]Добавлено: 20.03.2015 21:52:05[/merge_posts_bbcode]

а, точно, там фейл небольшой, ща перепишу.. done
 
GloomyFolken написал(а):
Ну а что второй вариант делает? Мне лень проверять.
И проверь, что пытался использовать код после последней правки, потому что их было штук 5 :D
[merge_posts_bbcode]Добавлено: 20.03.2015 21:52:05[/merge_posts_bbcode]

а, точно, там фейл небольшой, ща перепишу
Оно то рыбной палочкой спавнит, то несколько сфер в той-же форме.
 
Да йопт, ща сам чекну
[merge_posts_bbcode]Добавлено: 20.03.2015 22:03:34[/merge_posts_bbcode]

Неправда, пашет последний вариант.
h_1426874617_6314584_5d7ee5013c.png


[merge_posts_bbcode]Добавлено: 20.03.2015 22:09:14[/merge_posts_bbcode]

Только одна проблемка остается, у "полюсов" сразу пачка партиклов кучкуется, а "на экваторе" - ничего. Исправить это несложно. Нужно просто делать количество сегментов по горизонтали не константным, а зависящим от текущего вертикального сегмента. Например:
Код:
if (vert < NUM_VERTICAL_SEGMENTS / 2)
  numHorizontalParticles = vert * 2;
else
  numHorizontalParticles = (NUM_VERTICAL_SEGMENTS - vert) * 2;
Короче, дальше сам справишься.
 
А еще стоит делать или так (нестрогое неравенство, тогда партиклы на полюсах будут):
Код:
for (int vert = 0; vert <= NUM_VERTICAL_SEGMENTS; vert++)

или так (начиная с 1, тогда их не будет):
Код:
for (int vert = 1; vert < NUM_VERTICAL_SEGMENTS; vert++)
[merge_posts_bbcode]Добавлено: 20.03.2015 22:17:27[/merge_posts_bbcode]

Dovakin написал(а):
Научишь делать партиклы,глуми?
Два варианта.
1) Берешь, делаешь свой класс extends EntityFX и страдаешь (а еще больше страдают владельцы калькуляторов, на которых этот код будет выполняться).
2) Начинаешь пилить свою либу для партиклов и в этот раз еще больше страдаешь сам. По ходу дела наверняка придется неплохо разобраться в openGL :D
Свою либу для частиц я не кину (мне кушать хочется, я не могу плод своих трудов всем конкурентам дарить). Задавать движение частиц относительно несложно, нужно просто немного понимать, как выглядят графики простейших функций вроде параболы/гиперболы/синусоиды.
 
GloomyFolken написал(а):
Два варианта.
1) Берешь, делаешь свой класс extends EntityFX и страдаешь (а еще больше страдают владельцы калькуляторов, на которых этот код будет выполняться).
2) Начинаешь пилить свою либу для партиклов и в этот раз еще больше страдаешь сам. По ходу дела наверняка придется неплохо разобраться в openGL :D
Свою либу для частиц я не кину (мне кушать хочется, я не могу плод своих трудов всем конкурентам дарить). Задавать движение частиц относительно несложно, нужно просто немного понимать, как выглядят графики простейших функций вроде параболы/гиперболы/синусоиды.
Саша, ты сколько Java учил?!?!
 
GloomyFolken написал(а):
Да йопт, ща сам чекну
[merge_posts_bbcode]Добавлено: 20.03.2015 22:03:34[/merge_posts_bbcode]

Неправда, пашет последний вариант.
h_1426874617_6314584_5d7ee5013c.png


[merge_posts_bbcode]Добавлено: 20.03.2015 22:09:14[/merge_posts_bbcode]

Только одна проблемка остается, у "полюсов" сразу пачка партиклов кучкуется, а "на экваторе" - ничего. Исправить это несложно. Нужно просто делать количество сегментов по горизонтали не константным, а зависящим от текущего вертикального сегмента. Например:
Код:
if (vert < NUM_VERTICAL_SEGMENTS / 2)
  numHorizontalParticles = vert * 2;
else
  numHorizontalParticles = (NUM_VERTICAL_SEGMENTS - vert) * 2;
Короче, дальше сам справишься.
Слушай, можешь полный код дать? :)
 
Код:
public static final int NUM_VERTICAL_SEGMENTS = 20;

private void spawnSphere(float centerX, float centerY, float centerZ){
    for (int vert = 0; vert < NUM_VERTICAL_SEGMENTS; vert++){
           int numHorizontalParticles =  vert < NUM_VERTICAL_SEGMENTS / 2 ? vert * 4 : (NUM_VERTICAL_SEGMENTS - vert)*4;
            for (int hor = 0; hor < numHorizontalParticles; hor++){
                float angleH = (float)hor/numHorizontalParticles * 2 * (float)Math.PI;
                float angleV = (float)vert/NUM_VERTICAL_SEGMENTS * (float)Math.PI - (float)Math.PI/2;
                float particleY = centerY + MathHelper.sin(angleV);
                float particleX = centerX + MathHelper.cos(angleH) * MathHelper.cos(angleV);
                float particleZ = centerZ + MathHelper.sin(angleH) * MathHelper.cos(angleV);
//код для моей либы партиклов, мне лень вспоминать, как спавнить партиклы майна. Перепиши уж.
                TestParticle particle = new TestParticle(this, AnomalyIconList.funnelEyeIcon);
                particle.setPosition(particleX, particleY, particleZ);
                particles.add(particle);
            }
        }
}
h_1426876296_2731243_07a8a42c13.png

P.S: сначала забыл убрать двойку из строки, где вычисляется particleY (была для теста).
 
Аня,причем тут джава?! Это рендеры
Глуми,я сделаю через тесселератор. Или кастомныц ентити+рендер
 
Чтобы не тратить по рендер коллу на каждую частицу, стоит создавать по "эмиттеру" (например, сущности) для каждого источника частиц (в данном случае - эмиттер для взрыва) и рендерить его так:
Код:
mc.renderEngine.bindTexture(emitterTexture);
tessellator.startDrawingQuads();
//particlesComparator должен сортировать по расстоянию до камеры
Collections.sort(particles, particlesComparator);
for (Particle particle : particles){
  //рисуем частицу, пример кода есть в ванильном майне
}
tesselator.draw();
Сравнение с моим путём - глобальным списком частиц (точнее, эмиттеры у меня тоже есть, но все партиклы все равно объединяются в одну кучу, которая рендерится за один draw call)
Преимущества метода:
  • Быстро кодить
  • Быстрее сортировка. Отсортировать 100 раз по 100 элементов намного быстрее, чем один раз 10000 элементов.
  • Не нужно париться со склеиванием атласа частиц, на каждый эмиттер по своему атласу
Недостатки метода:
  • Если много эмиттеров, то много draw call'ов.
  • На пересечении эмиттеров партиклы не будут корректно смешиваться, один эмиттер будет перед другим.
  • (продолжение предыдущего) Затруднительно использовать два режима смешивания одновременно => сложно сделать комбинированные эффекты (например, огонь вперемешку с дымом). Однако, я сказал "затруднительно", а не "невозможно". Есть замечательное решение, хоть и со своими проблемами. Если рендерить через тесселлатор (без шейдера), то их две: очень непросто (хоть и возможно) приспособить это решение к тесселлатору и теряется цвет текстуры при больших значениях прозрачности. Второй недостаток есть у меня в моей версии рендера без шейдеров, но это особенности реализации - мб можно обойти эту проблему. Если рендерить через шейдер, то обе проблемы отпадают. Вот статейка по этому поводу. Читать раздел "Enhanced blending".
 
Назад
Сверху