Three.js: 用一种颜色填充网格 shaderMaterial 到特定位置
Three.js: Fill mesh shaderMaterial with one color up to certain position
我在理解 Three.js 着色器时遇到一些问题。我正在尝试用一种颜色为网格着色,但仅限于某个位置。到目前为止,这是我最接近实现的目标。
- 我需要让绿色“停止”在网格高度的 50% 处
- 对于网格的其余部分(50% 以上),要么用另一种颜色填充,要么根本不填充(这两种情况都适用)
着色器代码:
const _VS = `
uniform vec3 bboxMin;
uniform vec3 bboxMax;
varying vec2 vUv;
void main() {
vUv.x = (position.x - bboxMin.x) / (bboxMax.x - bboxMin.x);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const _FS = `
uniform vec3 incompleteColor;
uniform vec3 completenessColor;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(mix(incompleteColor, completenessColor, vUv.x), 1.0);
}
`;
Javascript代码:
let geometries = element.geometry.clone(); // Inherits geometries from parent element
let wall = new THREE.Mesh(
geometries,
new THREE.ShaderMaterial({
uniforms: {
incompleteColor: {
value: new THREE.Color('red')
},
completenessColor: {
value: new THREE.Color('green')
},
bboxMin: {
value: element.geometry.boundingBox.min
},
bboxMax: {
value: element.geometry.boundingBox.max
}
},
vertexShader: _VS,
fragmentShader: _FS,
})
);
wall.castShadow = true;
wall.position.setFromMatrixPosition(element.matrixWorld);
wall.rotation.setFromRotationMatrix(element.matrixWorld, 'XYZ');
scene.add(wall);
这张图片有助于说明我想要实现的目标:
LEFT: 我发布的代码看起来如何(Three.js 场景)
右:我想达到的目标
我花了几个小时研究这个问题,但我似乎找不到能为我指明正确方向的例子。
您需要使用 GLSL step()
函数。你可以 read about it here.
void main() {
// First, create a hard step when UV crosses the 0.5 threshold
float switch = step(0.5, vUv.x);
// Then use that hard step on your mix function
gl_FragColor = vec4(mix(incompleteColor, completenessColor, switch), 1.0);
}
我在理解 Three.js 着色器时遇到一些问题。我正在尝试用一种颜色为网格着色,但仅限于某个位置。到目前为止,这是我最接近实现的目标。
- 我需要让绿色“停止”在网格高度的 50% 处
- 对于网格的其余部分(50% 以上),要么用另一种颜色填充,要么根本不填充(这两种情况都适用)
着色器代码:
const _VS = `
uniform vec3 bboxMin;
uniform vec3 bboxMax;
varying vec2 vUv;
void main() {
vUv.x = (position.x - bboxMin.x) / (bboxMax.x - bboxMin.x);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const _FS = `
uniform vec3 incompleteColor;
uniform vec3 completenessColor;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(mix(incompleteColor, completenessColor, vUv.x), 1.0);
}
`;
Javascript代码:
let geometries = element.geometry.clone(); // Inherits geometries from parent element
let wall = new THREE.Mesh(
geometries,
new THREE.ShaderMaterial({
uniforms: {
incompleteColor: {
value: new THREE.Color('red')
},
completenessColor: {
value: new THREE.Color('green')
},
bboxMin: {
value: element.geometry.boundingBox.min
},
bboxMax: {
value: element.geometry.boundingBox.max
}
},
vertexShader: _VS,
fragmentShader: _FS,
})
);
wall.castShadow = true;
wall.position.setFromMatrixPosition(element.matrixWorld);
wall.rotation.setFromRotationMatrix(element.matrixWorld, 'XYZ');
scene.add(wall);
这张图片有助于说明我想要实现的目标:
LEFT: 我发布的代码看起来如何(Three.js 场景)
右:我想达到的目标
我花了几个小时研究这个问题,但我似乎找不到能为我指明正确方向的例子。
您需要使用 GLSL step()
函数。你可以 read about it here.
void main() {
// First, create a hard step when UV crosses the 0.5 threshold
float switch = step(0.5, vUv.x);
// Then use that hard step on your mix function
gl_FragColor = vec4(mix(incompleteColor, completenessColor, switch), 1.0);
}