2D-освещение от нескольких точечных источников на GLSL ES 2.0 в iPhone

Так как я полный новичок с шейдерами, у меня возникли некоторые проблемы, когда я пытался заставить работать 2D-систему освещения, которая в основном покрывает экран 2D-текстурой черного цвета с прозрачными отверстиями в местах, где есть светлые области.

Поскольку я использую только одну текстуру, я думаю, что я должен сделать это в фрагментном шейдере, верно?

Фрагмент шейдера:

#ifdef GL_ES
precision mediump float;
#endif

// Texture, coordinates and size
uniform sampler2D u_texture;
varying vec2 v_texCoord;
uniform vec2 textureSize;

uniform int lightCount;

struct LightSource
{
vec2 position;
float radius;
float strength;
};

uniform LightSource lights[10];

void main()
{
float alpha = 1.0;

vec2 pos = vec2(v_texCoord.x * textureSize.x, v_texCoord.y * textureSize.y);

int i;
for (i = 0; i < lightCount; i++)
{
LightSource source = lights[i];

float distance = distance(source.position, pos);

if (distance < source.radius)
{
alpha -= mix(source.strength, 0.0, distance/source.radius);
}
}

gl_FragColor = vec4(0.0, 0.0, 0.0, alpha);
}

Проблема в том, что производительность действительно ужасна (не может работать при 60 кадрах в секунду с 2 лампами и ничего больше на экране), какие-либо предложения по улучшению или даже другие способы решения этой проблемы?

Кстати, я делаю это из cocos2d-x, так что если у кого-то есть идеи, использующие элементы cocos2d, то это тоже будет приветствоваться 🙂

1

Решение

Я полностью согласен с Тимом. Если вы хотите улучшить общую скорость, вам следует избегать петель. Я рекомендую вам, если размер массива lights всегда равен десяти, поменяйте местами оператор цикла с десятью копиями содержимого цикла. Вы должны знать, что любая переменная, которую вы объявляете в операторе цикла, будет освобождена в конце цикла! Так что хорошая идея разбить цикл на десять частей (некрасиво, но это уловка старой школы;))))

Кроме того, я также рекомендую вам помещать некоторые println в каждое утверждение, чтобы увидеть, какие инструкции не работают. Могу поспорить, что операция смешивания является виновником. Я ничего не знаю о cocos2d, но можно ли сделать уникальный вызов для микширования в конце процесса с суммированием расстояний и сил? Кажется, что в какой-то момент происходит довольно раздражающая операция

2

Другие решения

Две вещи, которые я бы попробовал (не гарантировано, чтобы помочь)

  1. Удалите цикл for и просто жестко закодируйте в двух источниках. Поскольку петли могут быть дорогими, если они не обрабатываются водителем должным образом. Было бы хорошо знать, если это замедляет вас.

  2. Если заявления могут быть дорогими, и я не думаю, что это хорошее применение mix (вы делаете a*(1-c) + 0.0 * cи вторая половина этого термина бессмысленна). Я мог бы попробовать заменить это если утверждение:

    if (distance < source.radius)
    {
    alpha -= mix(source.strength, 0.0, distance/source.radius);
    }
    

    С этой единственной строкой:

    alpha -= (1.0-min(distance/source.radius, 1.0)) * source.strength;
    
1

По вопросам рекламы [email protected]