上下文
我正在尝试在 Canvas 中绘制贝塞尔曲线。 我实现了从着色器中绘制二次和三次曲线,但到目前为止我确实为每个控制点设置了统一变量。
因此,我在 Canvas 上单击,添加点,当我有足够的点(分别为 3 和 4)时,我绘制曲线。
现在我正在尝试概括贝塞尔曲线。虽然我在 JavaScript 端实现了这一点,但我觉得从着色器端完成它会更好,因为渲染速度会大大提高。
因此,我想在至少有两个点后立即绘制曲线。但我可以继续添加点并使用每个点绘制曲线,以作为控制点。
解释
所以我知道在 GLSL 中设置动态数组是不可能的,但是是否可以基于 JS 变量动态声明 GLSL 数组?
如果我的问题不清楚(我知道我很难马上表述清楚),让我用一个例子来解释。
uniform vec2 uMyPoints[<length>];
所以这就是我想要实现的,但是当然,根据 glsl 规范,数组大小必须是常量。
但是,从我的 Angular 来看,我觉得我应该能够从 JS 变量设置 length。我的直觉是,在渲染期间不同着色器的执行期间,GLSL 中的数组大小将保持不变,但可以从一个渲染更改为另一个渲染。
问题
所以我要问你的问题是:基于这些,你是否知道能够从 javascript 变量在 GLSL 中设置常量的任何好方法或技巧?
如果这似乎是可能的,这将对我有很大帮助。感谢您的考虑。
作为比较:我们如何从 JS 设置“numLights" in this example”?
回答
字符串替换非常适合我的需要。虽然这有点棘手,但它会做得很好。进一步的研究让我知道隐式数组大小在 Open GL ES 版本 3 中可用, future 版本的 WebGL 应该会使用它,但不是现在。
另一方面,第二个建议不符合我的需要,因为我正是想避免在着色器中有 N 个点,因为点的数量可能会改变。
感谢您的回答;)
最佳答案
字符串替换有效
<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) {
...
}
}
等..
但是,老实说,大多数人不会通过贝塞尔曲线控制点作为制服,因为对制服的数量有严格的限制。大多数人会通过属性中的贝塞尔曲线控制点。你甚至可以在调用 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,
等..
关于javascript - WebGL - 顶点着色器调用的变量数组大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33299796/
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby数组,我们在StackOverflow上找到一
我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat