WebGL-размеры массива переменных над вызовами вершинных шейдеров
контекст
Я пытаюсь нарисовать кривые Безье на холсте. Мне удалось нарисовать квадратичные и кубические кривые внутри шейдера, но у меня была равномерная переменная для каждой контрольной точки.
Итак, я нажимаю на свой холст, добавляю точки и когда у меня достаточно (соответственно 3 и 4), я рисую свою кривую.
теперь я пытаюсь обобщить кривые Безье. Хотя я достиг этого на стороне JavaScript, я чувствую, что это было бы лучше сделать это со стороны шейдера, так как скорость рендеринга будет значительно увеличена.
Итак, я хотел бы нарисовать свою кривую, как только у меня будет хотя бы две точки. Но я мог бы продолжать добавлять точки и рисовать свою кривую, используя каждую точку в качестве контрольных точек.
объяснение
поэтому я знаю, что невозможно установить динамический массив в GLSL, но возможно ли динамически объявить массив GLSL на основе переменной JS ?
Если мой вопрос неясен (я знаю, что у меня проблемы с формулировкой вещей сразу), позвольте мне объяснить на примере.
uniform vec2 uMyPoints[<length>];
Итак, это то, чего я хотел бы достичь, но, конечно, размер массива должен быть постоянным, согласно спецификациям glsl.
однако, с моей точки зрения, я чувствую, что я должен быть в состоянии создать length
из переменной JS. Моя интуиция заключается в том, что размер массива в GLSL будет постоянным в течение выполнение различных шейдеров во время рендеринга, но может меняться от одного перевода к другому.
вопрос
Итак, мой вопрос к вам: основываясь на них, знаете ли вы какой-либо хороший способ или трюки, чтобы иметь возможность установить константу в GLSL из переменной javascript ?
Если это представляется возможным, это очень помогло бы мне. Спасибо за внимание.
для сравнения: как мы могли бы установить"numLights " в этом пример из JS ?
ответ
string substitution хорошо подходит для моих нужд. Хотя это немного сложно, это будет просто прекрасно. Дальнейшие исследования привели меня к тому, что размер неявного массива доступен Open GL ES версии 3, который должен использоваться будущими версиями WebGL, но не сейчас.
С другой стороны, второе предложение не соответствует моим потребностям, поскольку я точно хотел избежать наличия N точек в шейдере, так как это количество точки могут меняться.
Спасибо за ответ ;)
1 ответов
работает подстановка строк
<script id="vs" type="notjs">
uniform vec2 uMyPoints[<length>];
...
</script>
js
var numPoints = 10;
var vSrc = document.getElementById("vs").text;
vSrc = vSrc.replace(/<length>/g, numPoints);
это то, что большинство сложных программ делают для шейдеров. Они генерируют шейдеры со строковыми манипуляциями.
конечно, вы можете использовать более приятную функцию для замены строки. Например, может быть что-то вроде
/**
* Replace %(id)s in strings with values in objects(s)
*
* Given a string like `"Hello %(name)s from $(user.country)s"`
* and an object like `{name:"Joe",user:{country:"USA"}}` would
* return `"Hello Joe from USA"`.
*
* @function
* @param {string} str string to do replacements in
* @param {Object|Object[]} params one or more objects.
* @returns {string} string with replaced parts
* @memberOf module:Strings
*/
var replaceParams = (function() {
var replaceParamsRE = /%\(([^\)]+)\)s/g;
return function(str, params) {
if (!params.length) {
params = [params];
}
return str.replace(replaceParamsRE, function(match, key) {
var keys = key.split('.');
for (var ii = 0; ii < params.length; ++ii) {
var obj = params[ii];
for (var jj = 0; jj < keys.length; ++jj) {
var part = keys[jj];
obj = obj[part];
if (obj === undefined) {
break;
}
}
if (obj !== undefined) {
return obj;
}
}
console.error("unknown key: " + key);
return "%(" + key + ")s";
});
};
}());
теперь, если вы шейдер выглядит так
uniform Lights u_lights[%(numLights)s];
uniform vec2 u_points[%(numPoints)s];
можно заменить на
vSrc = replaceParams(vsrc, {
numLights: 4,
numPoints: 10,
});
вы также можете в использование курса ' #define в шейдере
#define NUM_LIGHTS %(numLights)s
#define NUM_POINTS %(numPoints)s
uniform Lights u_lights[NUM_LIGHTS];
uniform vec2 u_points[NUM_POINTS];
void main() {
for (int i = 0; i < NUM_LIGHTS; ++i) {
...
}
}
etc..
но, честно говоря, большинство людей не прошли бы контрольные точки Безье в качестве униформы, потому что существует серьезное ограничение на количество униформы. Большинство людей прошли бы контрольные точки Безье в атрибутах. Вероятно, вы даже можете установить шаг и смещение при вызове gl.vertexAttribPointer
так что если ваши очки идут
[pt0, pt1, pt2, pt3, pt4, pt5, pt6, pt7, pt8, ..]
вы можете сделать 4 атрибуты
attribute vec2 p0;
attribute vec2 p1;
attribute vec2 p2;
attribute vec2 p3;
и указать все из них с смещение и шаг, чтобы установить свои 4 атрибута, чтобы точки вытащили
p0 = pt0, p1 = pt1, p2 = pt2, p3 = pt3,
p0 = pt1, p1 = pt2, p2 = pt3, p3 = pt4,
p0 = pt2, p1 = pt3, p2 = pt4, p3 = pt5,
p0 = pt3, p1 = pt4, p2 = pt5, p3 = pt6,
etc..