沿着色带 x-axis 的线性渐变
linear gradient along the x-axis of a ribbon
我是 webgl 世界的新手所以手下留情 ;)
我想要沿着色带 x-axis 的线性渐变。
沿着 y-axis 我找到了 gradientMaterial 但是沿着 x-axis 我还没有找到任何东西。
在此示例中,您可以找到我想要应用渐变的色带。
https://www.babylonjs-playground.com/#E6IX1#137
类似的东西:
https://doc.babylonjs.com/extensions/gradient
但沿着 x-axis
不幸的是,这似乎不是一件简单的事情。
真正定义here的渐变material正在使用世界space中的渐变(对我来说似乎没那么有用,但我知道什么)。这意味着当您移动对象时,渐变将保持在世界中心。
我会将 the fragment shader 中的这一行从
更改为纹理 space
float h = normalize(vPositionW).y + offset;
至此
float h = normalize(vDiffuseUV).y + offset;
这样您就可以通过更改模型的纹理坐标来设置方向。它会让你在色带周围流动渐变,沿着更多色带之类的东西向下流动。
不幸的是,AFAIK Babylon 需要纹理才能使用纹理坐标,至少查看那里的代码您可以看到只有在设置 DIFFUSE
时才会包含纹理坐标,然后假定需要纹理
#ifdef DIFFUSE
varying vec2 vDiffuseUV;
uniform sampler2D diffuseSampler;
uniform vec2 vDiffuseInfos;
#endif
您可以在 Babylon 中制作自定义着色器并提供您自己的数据,但这超出了我的 babylon 技能范围。我能找到的所有教程都需要安装大型环境并从打字稿构建。
一个更简单的解决方案可能只是用您的 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 space 中,您可以 see it follows the contours of the ribbon 这不是您想要的,但这是色带的默认 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;
https://www.babylonjs-playground.com/#QS8RP8#2
请注意,因为我们将纹理用作渐变,所以我们需要稍微缩放和偏移 UV 坐标。在 BABYLON 中,有一个选项可以使用 texture.uScale
、texture.uOffset
和相应的 v
版本。这些设置有效地操纵着色器内的纹理坐标
coordToUse = coordFromBuffer * scale + offset;
我们需要这样做的原因是 WebGL 的纹理坐标参考了像素的边缘,因此假设您有一个 2x1 像素的纹理。 0 和 1 引用了这部分纹理。
0 1
| |
V v
+-------+-------+
| | |
| | |
| | |
+-------+-------+
假设当您将纹理用作渐变时,您将获得的左像素为红色,右像素为蓝色
+-------+-------+
| | |
|rrrr...|...bbbb|
| | |
+-------+-------+
其中 r
是红色,b
是蓝色,....
是两者之间的混合区域。我们只想使用 2 之间的区域,因为那是 梯度.
这个代码
tex.vOffset = .5 / (rampHeight);
tex.vScale = (rampHeight - 1) / rampHeight;
缩放 UV 坐标,因此它们只使用中间部分。基本上我们减去 1 个像素并移动半个像素。如果您注释掉这两行,您会看到形状的边缘、rrrr 和 bbbb 部分有纯色边框。
如果 BABYLON 没有提供该选项,我们要么必须编写自己的着色器来添加它,要么在制作我们放入缓冲区的 UV 坐标时更改我们的计算。在着色器中执行此操作(使用 BABYLON 方式或使用自定义着色器)的优点是偏移量和比例需要根据纹理的大小而不同,因此我们必须更新缓冲区中的所有 UV如果我们没有在着色器中调整 UV 坐标,我们随时更改渐变纹理的大小
不,如果您不熟悉 WebGL 主题,我建议您阅读 these tutorials。然后,如果你深入研究 babylon.js 来源,希望它会更清楚发生了什么。
我是 webgl 世界的新手所以手下留情 ;)
我想要沿着色带 x-axis 的线性渐变。 沿着 y-axis 我找到了 gradientMaterial 但是沿着 x-axis 我还没有找到任何东西。
在此示例中,您可以找到我想要应用渐变的色带。
https://www.babylonjs-playground.com/#E6IX1#137
类似的东西:
https://doc.babylonjs.com/extensions/gradient
但沿着 x-axis
不幸的是,这似乎不是一件简单的事情。
真正定义here的渐变material正在使用世界space中的渐变(对我来说似乎没那么有用,但我知道什么)。这意味着当您移动对象时,渐变将保持在世界中心。
我会将 the fragment shader 中的这一行从
更改为纹理 spacefloat h = normalize(vPositionW).y + offset;
至此
float h = normalize(vDiffuseUV).y + offset;
这样您就可以通过更改模型的纹理坐标来设置方向。它会让你在色带周围流动渐变,沿着更多色带之类的东西向下流动。
不幸的是,AFAIK Babylon 需要纹理才能使用纹理坐标,至少查看那里的代码您可以看到只有在设置 DIFFUSE
时才会包含纹理坐标,然后假定需要纹理
#ifdef DIFFUSE
varying vec2 vDiffuseUV;
uniform sampler2D diffuseSampler;
uniform vec2 vDiffuseInfos;
#endif
您可以在 Babylon 中制作自定义着色器并提供您自己的数据,但这超出了我的 babylon 技能范围。我能找到的所有教程都需要安装大型环境并从打字稿构建。
一个更简单的解决方案可能只是用您的 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 space 中,您可以 see it follows the contours of the ribbon 这不是您想要的,但这是色带的默认 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;
https://www.babylonjs-playground.com/#QS8RP8#2
请注意,因为我们将纹理用作渐变,所以我们需要稍微缩放和偏移 UV 坐标。在 BABYLON 中,有一个选项可以使用 texture.uScale
、texture.uOffset
和相应的 v
版本。这些设置有效地操纵着色器内的纹理坐标
coordToUse = coordFromBuffer * scale + offset;
我们需要这样做的原因是 WebGL 的纹理坐标参考了像素的边缘,因此假设您有一个 2x1 像素的纹理。 0 和 1 引用了这部分纹理。
0 1
| |
V v
+-------+-------+
| | |
| | |
| | |
+-------+-------+
假设当您将纹理用作渐变时,您将获得的左像素为红色,右像素为蓝色
+-------+-------+
| | |
|rrrr...|...bbbb|
| | |
+-------+-------+
其中 r
是红色,b
是蓝色,....
是两者之间的混合区域。我们只想使用 2 之间的区域,因为那是 梯度.
这个代码
tex.vOffset = .5 / (rampHeight);
tex.vScale = (rampHeight - 1) / rampHeight;
缩放 UV 坐标,因此它们只使用中间部分。基本上我们减去 1 个像素并移动半个像素。如果您注释掉这两行,您会看到形状的边缘、rrrr 和 bbbb 部分有纯色边框。
如果 BABYLON 没有提供该选项,我们要么必须编写自己的着色器来添加它,要么在制作我们放入缓冲区的 UV 坐标时更改我们的计算。在着色器中执行此操作(使用 BABYLON 方式或使用自定义着色器)的优点是偏移量和比例需要根据纹理的大小而不同,因此我们必须更新缓冲区中的所有 UV如果我们没有在着色器中调整 UV 坐标,我们随时更改渐变纹理的大小
不,如果您不熟悉 WebGL 主题,我建议您阅读 these tutorials。然后,如果你深入研究 babylon.js 来源,希望它会更清楚发生了什么。