2015-10-24 3 views
0

Я пытаюсь сделать лампочку, которая светится немного, а затем она становится менее интенсивной. Также по краям немного тусклее. Я нашел код, который, как я думаю, создает эффект, который я хочу создать, но я, похоже, не очень хорошо его понимаю. Вот код:Объяснение кода WebGL - почему это так работает

mat2 rotate2d(float angle){ 
return mat2(cos(angle),-sin(angle), 
      sin(angle),cos(angle)); 
    } 

float variation(vec2 v1, vec2 v2, float strength, float speed) { 
    return sin(
     dot(normalize(v1), normalize(v2)) * strength + iGlobalTime * speed 
    )/100.0; 
} 

vec3 paintCircle (vec2 uv, vec2 center, float rad, float width) { 

    vec2 diff = center-uv; 
    float len = length(diff); 

    len += variation(diff, vec2(0.0, 1.0), 5.0, 2.0); 
    len -= variation(diff, vec2(1.0, 0.0), 5.0, 2.0); 

    float circle = smoothstep(rad-width, rad, len) - smoothstep(rad, rad+width, len); 
    return vec3(circle); 
} 


void mainImage(out vec4 fragColor, in vec2 fragCoord) 
{ 
    vec2 uv = fragCoord.xy/iResolution.xy; 
    uv.x *= 1.5; 
    uv.x -= 0.25; 

    vec3 color; 
    float radius = 0.35; 
    vec2 center = vec2(0.5); 


    //paint color circle 
    color = paintCircle(uv, center, radius, 0.1); 

    //color with gradient 
    vec2 v = rotate2d(iGlobalTime) * uv; 
    color *= vec3(v.x, v.y, 0.7-v.y*v.x); 

    //paint white circle 
    color += paintCircle(uv, center, radius, 0.01); 


    fragColor = vec4(color, 1.0); 
} 

Я не понимаю, почему мы должны скалярное произведение нормированных векторов и как он выбрал exacly:

len += variation(diff, vec2(0.0, 1.0), 5.0, 2.0); 
len -= variation(diff, vec2(1.0, 0.0), 5.0, 2.0); 

Я имею в виду - почему там первое добавление, то вычитание ? Тогда почему это:

vec2 uv = fragCoord.xy/iResolution.xy; 
uv.x *= 1.5; 
uv.x -= 0.25; 

и как это vec2 v = rotate2d(iGlobalTime) * uv; color *= vec3(v.x, v.y, 0.7-v.y*v.x);

сделать градиент цвета? Вот ссылка кода, если кто-то предпочитает смотреть его там и что он делает: https://www.shadertoy.com/view/ltBXRc. Я, очевидно, не очень хорошо разбираюсь в геометрии. Если бы кто-то мог мне помочь, я был бы признателен :)

ответ

2

Если бы мы хотели нарисовать идеальный круг, мы бы просто построили все точки, расположенные на некотором расстоянии от центра сцены. Говоря процедурно, мы начинаем с центра, выбираем любое случайное направление, идем на некотором расстоянии r в этом направлении и строим точку. Затем вернитесь в центр, выберите другое направление, пройдете то же расстояние r, и заведите еще одну точку. И так далее, пока мы не гладкий круг: r = 1

Чтобы построить искаженный круг можно изменять расстояние r в зависимости от направления мы столкнулись. Если мы выражаем направление как угол в радианах (theta), то r будет некоторой функцией этого угла. Какая функция в точности? Попробуем сначала что-то простое: r = theta

Нешумное то, что мы хотим, оно должно быть больше похоже на круг (r = 1), но с немного волнистостью (r = 1 + волнистость). Самая простая волнистая функция - sin(x). Попробуем добавить его: r = 1 + 0.1 * sin(5 * theta)

Изменяя числа, мы можем манипулировать амплитудой и частотой волн. Но есть слишком большая симметрия, чтобы сломать ее, нам нужно что-то более сложное, чем синусоидальная волна.

Как насчет этого монстра sin(5 * sin(x)) - sin(5 * cos(x))

Давайте добавим его к кругу r = 1 + 0.1 * sin(5 * sin(theta)) - 0.1 * sin(5 * cos(theta))

Выглядит довольно хорошо для меня.

Шейдер выполняет именно это искажение, но по-другому. Взятие точечного произведения со стандартным базисным вектором просто дает вам координату X или Y вектора. Мы можем переписать этот бит как:

len += 0.02 * sin(normalize(diff).y * 5.0 + 2.0 * iGlobalTime); 
len -= 0.02 * sin(normalize(diff).x * 5.0 + 2.0 * iGlobalTime); 

X и Y координаты нормализованного вектора являются лишь sin и cos угла, представленного этим вектором. Итак, normalize(diff).y дает вам синус угла, а normalize(diff).x дает вам косинус.

Надеюсь, это немного прояснит ситуацию.

+0

Да, это так. Спасибо :) – vixenn

Смежные вопросы