沿着色带的x轴的线性梯度

时间:2017-08-16 17:08:41

标签: webgl babylonjs

我是webgl世界的新手所以表示怜悯;)

我希望沿着色带的x轴有一个线性渐变。 沿着y轴,我发现了渐变材料,但沿着x轴,我还没有找到任何东西。

在此示例中,您可以找到我想要应用渐变的功能区。

https://www.babylonjs-playground.com/#E6IX1#137

如果游乐场不起作用: Screen_Shot_2017-08-17_at_09.06.00.png

类似的东西:

https://doc.babylonjs.com/extensions/gradient

但沿着x轴

1 个答案:

答案 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种颜色创建一个小渐变纹理,并设置vScalevOffset以扩展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.uScaletexture.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来源,希望它会更清楚发生了什么。