Использование языка шейдеров WebGL (GLSL) для произвольной векторной математики в JavaScript - PullRequest
27 голосов
/ 24 марта 2011

Язык шейдеров WebGL (GLSL) - очень мощный инструмент для многомерной векторной математики.

Есть ли возможность использовать эту мощь из JavaScript (работающую в веб-браузере) для частных не 3D-вычислений? Получение данных возможно, но есть ли способ вывести данные в JavaScript после выполнения вычислений шейдера?

Фактическое рисование не требуется, только вычисления векторов. (Я играю за идею аппаратного ускоренного гравитационного симулятора, написанного на JavaScript.)

Спасибо!


В новостях: кажется, что Khronos разрабатывает WebCL , которая будет доступной для JavaScript версией OpenCL . Это именно то, что я ищу, но это займет некоторое время ...

Ответы [ 3 ]

17 голосов
/ 24 марта 2011

Насколько я вижу из spec WebGL поддерживает объекты кадрового буфера и операции чтения.Этого достаточно для того, чтобы вы преобразовали данные и вернули их в пространство клиента.Вот последовательность операций:

  1. Создание FBO с буферами рендеринга вложений, которые необходимы для сохранения результата;привязать его
  2. Загрузить все входные данные в текстуры (одинакового размера).
  3. Создать шейдер обработки GLSL, который будет производить вычисления внутри части фрагмента, считывая ввод из текстур и записывая выводв целевой буфер рендеринга;свяжи это
  4. Нарисуй четырехугольник;читать обратно буферы рендеринга через glReadPixels.
6 голосов
/ 12 марта 2014

Получение плавающих значений из шейдера в браузере на самом деле довольно легко, хотя ограничение составляет 1 плавающее число на пиксель.

Мы конвертируем 4 ints в 1 float (r: int, g: int, b: int, a: int) -> (rgba: float).

Спасибо IEEE

float random(vec2 seed) { 
    return fract(cos(mod(123456780., 1024. * dot(seed / time, vec2(23.1406926327792690, 2.6651441426902251))))); 
}
float shift_right(float v, float amt) { 
    v = floor(v) + 0.5; return floor(v / exp2(amt)); 
}
float shift_left(float v, float amt) { 
    return floor(v * exp2(amt) + 0.5); 
}
float mask_last(float v, float bits) { 
    return mod(v, shift_left(1.0, bits)); 
}
float extract_bits(float num, float from, float to) { 
    from = floor(from + 0.5); to = floor(to + 0.5); 
    return mask_last(shift_right(num, from), to - from); 
}
vec4 encode_float(float val) { 
    if (val == 0.0) return vec4(0, 0, 0, 0); 
    float sign = val > 0.0 ? 0.0 : 1.0; 
    val = abs(val); 
    float exponent = floor(log2(val)); 
    float biased_exponent = exponent + 127.0; 
    float fraction = ((val / exp2(exponent)) - 1.0) * 8388608.0; 
    float t = biased_exponent / 2.0; 
    float last_bit_of_biased_exponent = fract(t) * 2.0; 
    float remaining_bits_of_biased_exponent = floor(t); 
    float byte4 = extract_bits(fraction, 0.0, 8.0) / 255.0; 
    float byte3 = extract_bits(fraction, 8.0, 16.0) / 255.0; 
    float byte2 = (last_bit_of_biased_exponent * 128.0 + extract_bits(fraction, 16.0, 23.0)) / 255.0; 
    float byte1 = (sign * 128.0 + remaining_bits_of_biased_exponent) / 255.0; 
    return vec4(byte4, byte3, byte2, byte1); 
}

Использование:

Shader:

outputcolor = encode_float(420.420f);

JavaScript:

// convert output to floats
output = new Float32Array(output.buffer);
2 голосов
/ 24 марта 2011

Да, это выполнимо - есть старое демо (может потребоваться несколько настроек, чтобы заставить его работать со спецификацией 1.0 WebGL) Аарона Бабкока здесь .

...