Cru*_*leZ 6 javascript arrays glsl webgl vertex-shader
上下文
我试图在画布上绘制贝塞尔曲线.我实现了从着色器中绘制二次曲线和三次曲线,但到目前为止我确实为每个控制点都有一个统一变量.
所以,我点击我的画布,添加点,当我有足够的(分别为3和4)时,我画出我的曲线.
现在我试图推广Bezier曲线.虽然我在JavaScript方面实现了这一目标,但我觉得从着色器方面做到这一点会更好,因为渲染速度会大大提高.
所以,一旦我至少得到两分,我想画出我的曲线.但我可以继续添加点并使用每个点绘制我的曲线,以作为控制点.
说明
所以我知道在GLSL中设置动态数组是不可能的,但是可以根据JS变量动态声明一个GLSL数组吗?
如果我的问题不清楚(我知道我有麻烦直接制定事情),让我用一个例子来解释.
uniform vec2 uMyPoints[<length>];
Run Code Online (Sandbox Code Playgroud)
所以这就是我想要实现的,但是当然,根据glsl规范,数组大小必须是常量.
但是,从我的角度来看,我觉得我应该能够length从JS变量进行设置.我的直觉是GLSL中的数组大小在渲染期间执行不同着色器的持续时间内是恒定的,但可能会从一个渲染更改为另一个渲染.
题
所以我的问题是:基于这些,您是否知道能从javascript变量在GLSL中设置常量的任何好方法或技巧?
如果看起来有可能,这对我有很大的帮助.谢谢你的考虑.
作为比较:我们如何在这个例子中从JS 设置" numLights"?
回答
字符串替换非常适合我的需求.虽然它有点棘手,但它会做得很好.进一步的研究使我知道隐式数组大小是可用的Open GL ES版本3,它应该被未来版本的WebGL使用,但现在不是.
另一方面,第二个建议不适合我的需要,因为我确实想避免在着色器中有N个点,因为点的数量可能会改变.
谢谢你的回答 ;)
字符串替换有效
<script id="vs" type="notjs">
uniform vec2 uMyPoints[<length>];
...
</script>
Run Code Online (Sandbox Code Playgroud)
js
var numPoints = 10;
var vSrc = document.getElementById("vs").text;
vSrc = vSrc.replace(/<length>/g, numPoints);
Run Code Online (Sandbox Code Playgroud)
这就是大多数复杂程序为着色器所做的事情。他们通过字符串操作生成着色器。
当然,您可能想使用更好的函数来进行字符串替换。例如也许像
/**
* 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";
});
};
}());
Run Code Online (Sandbox Code Playgroud)
现在如果你是着色器看起来像这样
uniform Lights u_lights[%(numLights)s];
uniform vec2 u_points[%(numPoints)s];
Run Code Online (Sandbox Code Playgroud)
你可以用
vSrc = replaceParams(vsrc, {
numLights: 4,
numPoints: 10,
});
Run Code Online (Sandbox Code Playgroud)
当然你也可以在着色器中使用`#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) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
ETC..
但是,老实说,大多数人不会将贝塞尔曲线控制点作为制服通过,因为制服的数量有严格的限制。大多数人都会通过属性中的贝塞尔曲线控制点。您甚至可以在调用时设置步幅和偏移量,gl.vertexAttribPointer这样如果您的点去
[pt0, pt1, pt2, pt3, pt4, pt5, pt6, pt7, pt8, ..]
Run Code Online (Sandbox Code Playgroud)
可以设置4个属性
attribute vec2 p0;
attribute vec2 p1;
attribute vec2 p2;
attribute vec2 p3;
Run Code Online (Sandbox Code Playgroud)
并用偏移量和步幅来指向所有这些点以设置您的 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,
Run Code Online (Sandbox Code Playgroud)
ETC..