admin管理员组文章数量:1357312
I have this scene and for the half transparent box geometry I want to create a shader that gradually reduced the alpha value of gl_FragColor going over the long axis (in this case the z axis in three js).
I am a bit at a loss on how to do that. I thought I could do that with UVs but they run along the wrong axis.
I basically need a way to find out at which percentage point I am on the z axis relative to the mesh size.
Is that even possible in a shader?
I could also send the length size via a uniform. But then again, I missing the overall concept on how to reach the goal. Any help would be greatly appreciated.
I have this scene and for the half transparent box geometry I want to create a shader that gradually reduced the alpha value of gl_FragColor going over the long axis (in this case the z axis in three js).
I am a bit at a loss on how to do that. I thought I could do that with UVs but they run along the wrong axis.
I basically need a way to find out at which percentage point I am on the z axis relative to the mesh size.
Is that even possible in a shader?
I could also send the length size via a uniform. But then again, I missing the overall concept on how to reach the goal. Any help would be greatly appreciated.
Share Improve this question asked Mar 27 at 20:56 Johannes KlaußJohannes Klauß 11.1k18 gold badges71 silver badges127 bronze badges 1 |2 Answers
Reset to default 2Yes it is possible to be done with shaders, here is function which will return material which you can set for your mesh to achieve effect you want:
function materialGradientByAxis(mesh, color = 0xff_ff_00, axis = 0, reverse = false) {
/*- mesh: must be instanceof THREE.Mesh
mesh must have geometry (mesh.geometry)
expected static geometry attribute, but dynamic transform matrix
- axis: 0: x , 1: y, 2: z (in mesh.geometry space)
- reverse:
false: axis local min: alpha = 0, max: alpha = 1
true: axis local min: alpha = 1, max: alpha = 0
*/
if ( !(mesh?.geometry?.boundingBox instanceof THREE.Box3) ) {
mesh.geometryputeBoundingBox()
}
const shaderMaterial = new THREE.ShaderMaterial({
uniforms: {
u_bboxMin: { value: mesh.geometry.boundingBox.min },
u_bboxDelta: { value: mesh.geometry.boundingBox.max.clone().sub(mesh.geometry.boundingBox.min) },
u_axisIndex: { value: axis },
u_reverse: { value: reverse },
u_color: { value: new THREE.Color(color) }
},
vertexShader:`
varying vec3 vPosition;
void main() {
vPosition = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}`,
fragmentShader:`
varying vec3 vPosition;
uniform vec3 u_bboxMin;
uniform vec3 u_bboxDelta;
uniform int u_axisIndex;
uniform bool u_reverse;
uniform vec3 u_color;
void main() {
float pos = ((vPosition - u_bboxMin)/u_bboxDelta)[u_axisIndex];
vec4 color = vec4(
u_color,
u_reverse ? 1.0 - pos : pos
);
gl_FragColor = color;
}`
});
shaderMaterial.transparent = true;
shaderMaterial.side = THREE.DoubleSide;
shaderMaterial.depthWrite = false;
return shaderMaterial;
}
you can use it like this:
const geometry = new THREE.BoxGeometry( 2, 2, 2 );
const cube = new THREE.Mesh( geometry );
cube.material = materialGradientByAxis( cube, 0xff_ff_00, 0, false )
and here is a result: and without box helper: you can check full code and view result from different angles here: https://codepen.io/andromeda2/full/LEYJMEN
You can control each pixel via transparency of box or any geometry, by smoothstep
function you can calculate transparency based on x-coords
of the fragment
. Then alpha
value determines transparency of fragment
.
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 3;
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const geometry = new THREE.BoxGeometry(2, 1, 1);
const settings = {
fade: 1.0,
fadePoint: 0.0
};
const material = new THREE.ShaderMaterial({
uniforms: {
uFade: {
value: settings.fade
},
uFadePoint: {
value: settings.fadePoint
},
uFadeRange: {
value: 1.0
}
},
vertexShader: `
varying vec3 vPosition;
void main() {
vPosition = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform float uFade;
uniform float uFadePoint;
uniform float uFadeRange;
varying vec3 vPosition;
void main() {
float alpha = smoothstep(uFadePoint, uFadePoint + uFadeRange, vPosition.x) * uFade;
gl_FragColor = vec4(0.0, 0.5, 1.0, alpha);
}
`,
transparent: true,
depthWrite: false
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
const gui = new GUI();
gui.add(settings, 'fade', 0, 1).name('Fade Strength').onChange(value => {
material.uniforms.uFade.value = value;
});
gui.add(settings, 'fadePoint', -3, 3).name('Fade Point (World X)').onChange(value => {
material.uniforms.uFadePoint.value = value;
});
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
https://codepen.io/Lucas_Mas/full/yyLxWEM
本文标签: threejsAlpha Gradient over mesh geometry in shader codeStack Overflow
版权声明:本文标题:three.js - Alpha Gradient over mesh geometry in shader code - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744068023a2585367.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
float
attribute for each vertex, which is 0 on one end of the z-axis and 1 on the other end. Set thisfloat
as output for the VS and input for the FS, where these will arrive interpolated (from 0 to 1) along the z-axis and could then be used as the alpha value. Depending on how the geometry (i.e. positions) of the box are defined, you could also use the position's z-values in the VS directly to set the outputfloat
. Does this answer your question? – Yun Commented Mar 28 at 4:11