我是webgl世界的新手所以表示怜悯;)
我希望沿着色带的x轴有一个线性渐变。 沿着y轴,我发现了渐变材料,但沿着x轴,我还没有找到任何东西。
在此示例中,您可以找到我想要应用渐变的功能区。
https://www.babylonjs-playground.com/#E6IX1#137
类似的东西:
https://doc.babylonjs.com/extensions/gradient
但沿着x轴
答案 0 :(得分:2)
不幸的是,它看起来并不简单。
真正定义的渐变素材here在世界空间中使用渐变(对我来说似乎没那么有用,但我知道的是什么)。这意味着当您移动对象时,渐变将保持在世界的中心。
我可以通过更改此{/ 3}}中的此行来将其切换到纹理空间
float h = normalize(vPositionW).y + offset;
到这个
float h = normalize(vDiffuseUV).y + offset;
这样可以通过更改模型的纹理坐标来设置方向。它会让你在色带周围流动渐变,沿着更多的色带向下流动。
不幸的是AFAIK Babylon需要一个纹理才能使用纹理坐标,至少在那里查看代码,你可以看到只有在设置DIFFUSE
时才包含纹理坐标,然后假设需要一个纹理< / p>
#ifdef DIFFUSE
varying vec2 vDiffuseUV;
uniform sampler2D diffuseSampler;
uniform vec2 vDiffuseInfos;
#endif
您可以在巴比伦制作自定义着色器并提供您自己的数据,但这超出了我的巴比伦技能。我能找到的所有教程都需要安装一个大型环境并从typescript构建。
更简单的解决方案可能只是使用您的2种颜色创建一个小渐变纹理,并设置vScale
和vOffset
以扩展UV坐标。
// Using a Canvas because Babylon doesn't support all texture features
// on all types of textures :(
const rampWidth = 1;
const rampHeight = 2;
const tex = new BABYLON.DynamicTexture("dyntex", {width:rampWidth, height:rampHeight}, scene, true);
const ctx = tex.getContext();
ctx.fillStyle = "#15A4FA";
ctx.fillRect(0, 0, 1, 1);
ctx.fillStyle = "blue";
ctx.fillRect(0, 1, 1, 1);
tex.vOffset = .5 / (rampHeight);
tex.vScale = (rampHeight - 1) / rampHeight;
tex.update(false);
mat.diffuseTexture = tex;
现在它在UV空间中你可以the fragment shader这不是你想要的,但它是功能区的默认UV坐标。
要解决此问题,您需要调整UV坐标。
var sphere = BABYLON.MeshBuilder.CreateRibbon("sph", {pathArray: paths}, scene);
// get the positions so we can compute the extents
{
const positions = sphere.getVerticesData(BABYLON.VertexBuffer.PositionKind);
let min = positions.slice(0, 3);
let max = positions.slice(0, 3);
const numVerts = positions.length / 3;
for (let i = 1; i < numVerts; ++i) {
const offset = i * 3;
for (let j = 0; j < 3; ++j) {
min[j] = Math.min(min[j], positions[offset + j]);
max[j] = Math.max(max[j], positions[offset + j]);
}
}
// now update the UVs
const range = [
max[0] - min[0],
max[1] - min[1],
max[2] - min[2],
];
const uvs = new Float32Array(numVerts * 2);
for (let i = 0; i < numVerts; ++i) {
const positionOffset = i * 3;
const uvOffset = i * 2;
for (let j = 0; j < 2; ++j) {
uvs[uvOffset + j] = (positions[positionOffset + j] - min[j]) / range[j];
}
}
sphere.setVerticesData(BABYLON.VertexBuffer.UVKind, uvs);
}
我还将纹理切换为水平
// Using a Canvas because Babylon doesn't support all texture features
// on all types of textures :(
const rampWidth = 2;
const rampHeight = 1;
const tex = new BABYLON.DynamicTexture("dyntex", {width:rampWidth, height:rampHeight}, scene, true);
const ctx = tex.getContext();
ctx.fillStyle = "#15A4FA";
ctx.fillRect(0, 0, 1, 1);
ctx.fillStyle = "blue";
ctx.fillRect(1, 0, 1, 1);
tex.uOffset = 0.5 / (rampWidth);
tex.uScale = (rampWidth - 1) / rampWidth;
tex.update(false);
mat.diffuseTexture = tex;
see it follows the contours of the ribbon
请注意,因为我们将纹理用作渐变,所以我们需要缩放和偏移UV坐标。在BABYLON中,可以选择使用texture.uScale
,texture.uOffset
和相应的v
版本来完成此操作。这些设置有效地操纵着色器内的纹理坐标
coordToUse = coordFromBuffer * scale + offset;
我们需要这样做的原因是WebGL的纹理坐标引用像素的边缘,所以想象你有2x1像素的纹理。 0和1引用纹理的这一部分。
0 1
| |
V v
+-------+-------+
| | |
| | |
| | |
+-------+-------+
当您将纹理用作渐变时,假设左侧像素为红色且右侧像素为蓝色
+-------+-------+
| | |
|rrrr...|...bbbb|
| | |
+-------+-------+
r
为红色,b
为蓝色,....
为2之间混合的区域。我们只想使用2之间的区域,因为那个&#39; s 渐变。
此代码
tex.vOffset = .5 / (rampHeight);
tex.vScale = (rampHeight - 1) / rampHeight;
是缩放UV坐标的因子,因此它们仅使用该中间部分。基本上我们减去1个像素并移动半个像素。如果你注释掉那两行,你会看到形状边缘有一个纯色边框,rrrr和bbbb部分。
如果BABYLON没有提供该选项,我们必须编写自己的着色器来添加它,或者在制作我们放入缓冲区的UV坐标时更改我们的计算。在着色器(BABYLON方式或自定义着色器)中进行此操作的优点是偏移和比例需要根据纹理的大小而有所不同,因此我们必须更新所有的UV我们的缓冲区,如果我们没有调整着色器中的UV坐标,我们就改变了渐变纹理的大小
不是,如果您不熟悉WebGL主题,我建议您阅读https://www.babylonjs-playground.com/#QS8RP8#2。然后,如果你深入挖掘babylon.js来源,希望它会更清楚发生了什么。