Alpha 通道淡入淡出动画
Alpha channel fade animation
我对着色器还很陌生,我一直在尝试创建一个着色器来执行纹理的 alpha 狂欢,我已经接近了,但我很确定有更好的方法。
这就是我所要做的https://codepen.io/tkmoney/pen/REYrpV
varying vec2 vUv;
precision highp float;
precision highp int;
uniform sampler2D texture;
uniform float mask_position;
uniform float fade_size;
void main(void) {
float mask_starting_point = (0.0 - fade_size);
float mask_ending_point = (1.0 - fade_size);
vec4 orig_color = texture2D(texture, vUv);
vec4 color = texture2D(texture, vUv);
float mask_p = smoothstep(mask_starting_point, mask_ending_point, mask_position);
//color.a *= (distance(vUv.x, split_center_point));
vec2 p = vUv;
if (p.x > (mask_p)){
color.a = 0.0;
}else{
color.a *= (smoothstep(mask_position, (mask_position - fade_size), p.x ));
}
gl_FragColor = color;
}
如您所见,淡入并没有完全显示整个图像。任何有关解决此问题的更好方法的见解都会很棒。谢谢!
你想做的是让 mask_position
左边的区域可见,但你想隐藏右边的区域。这可以通过 step
:
来实现
color.a *= 1.0 - step(fade_size, p);
如果你想从可见区域平滑过渡到不可见区域,那么你必须使用smoothstep
。衰落的开始是在 mask_position
之前的一定量,在 mask_position
之后的一定量结束:
float start_p = mask_position-fade_size;
float end_p = mask_position+fade_size;
color.a *= 1.0 - smoothstep(start_p, end_p, vUv.x);
这将导致图像的开头和结尾永远不会完全淡入。为了弥补这一点,[vUV.x] 必须从范围 [0.0, 1.0] 映射到范围 [fade_size
, 1.0-fade_size
]。这可以通过 mix
轻松计算:
float p = vUv.x * (1.0-2.0*fade_size) + fade_size;
color.a *= 1.0 - smoothstep(start_p, end_p, p;
如果最终剔除器的 alpha 通道低于一个微小的阈值,则可以丢弃片段:
if ( color.a < 0.01 )
discard;
最终着色器:
varying vec2 vUv;
precision highp float;
precision highp int;
uniform sampler2D texture;
uniform float mask_position;
uniform float fade_size;
void main(void) {
vec4 color = texture2D(texture, vUv);
float start_p = mask_position-fade_size;
float end_p = mask_position+fade_size;
float p = mix(fade_size, 1.0-fade_size, vUv.x);
color.a *= 1.0 - smoothstep(start_p, end_p, p);
if ( color.a < 0.01 )
discard;
gl_FragColor = color;
}
看例子:
var container;
var camera, scene, renderer;
var uniforms;
init();
animate();
function init() {
container = document.getElementById( 'container' );
camera = new THREE.Camera();
camera.position.z = 1;
scene = new THREE.Scene();
var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
var texture = new THREE.TextureLoader().load( 'https://raw.githubusercontent.com/Rabbid76/graphics-snippets/master/resource/texture/background.jpg' );
uniforms = {
u_time: { type: "f", value: 1.0 },
u_resolution: { type: "v2", value: new THREE.Vector2() },
u_mouse: { type: "v2", value: new THREE.Vector2() },
texture: {type: 't', value: texture},
fade_size: { type: 'f', value: 0.2 },
mask_position: { type: 'f', value: 0 }
};
var material = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer( {alpha : true} );
renderer.setClearColor(0xffffff, 0.0);
renderer.setPixelRatio( window.devicePixelRatio );
container.appendChild( renderer.domElement );
onWindowResize();
window.addEventListener( 'resize', onWindowResize, false );
document.onmousemove = function(e){
uniforms.u_mouse.value.x = e.pageX
uniforms.u_mouse.value.y = e.pageY
}
}
function onWindowResize( event ) {
renderer.setSize( window.innerWidth, window.innerHeight );
uniforms.u_resolution.value.x = renderer.domElement.width;
uniforms.u_resolution.value.y = renderer.domElement.height;
}
function animate() {
requestAnimationFrame( animate );
render();
}
var mask_step = 0.01;
var mask_val = 0.0;
function render() {
if ( mask_val >= 1.0) { mask_val = 1.0; mask_step = -0.01; }
else if ( mask_val <= -0.0) { mask_val = 0.0; mask_step = 0.01; }
mask_val += mask_step;
uniforms.mask_position.value = mask_val;
uniforms.u_time.value += 0.05;
renderer.render( scene, camera );
}
<script id="vertexShader" type="x-shader/x-vertex">
void main() {
gl_Position = vec4( position, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec2 u_resolution;
uniform float u_time;
uniform sampler2D texture;
uniform float fade_size;
uniform float mask_position;
void main() {
vec2 vUv = gl_FragCoord.xy/u_resolution.xy;
vec4 color = texture2D(texture, vUv);
float start_p = mask_position-fade_size;
float end_p = mask_position+fade_size;
float p = mix(fade_size, 1.0-fade_size, vUv.x);
color.rgba *= 1.0 - smoothstep(start_p, end_p, p);
if ( color.a < 0.01 )
discard;
gl_FragColor = color;
}
</script>
<div id="container"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/100/three.min.js"></script>
我对着色器还很陌生,我一直在尝试创建一个着色器来执行纹理的 alpha 狂欢,我已经接近了,但我很确定有更好的方法。
这就是我所要做的https://codepen.io/tkmoney/pen/REYrpV
varying vec2 vUv;
precision highp float;
precision highp int;
uniform sampler2D texture;
uniform float mask_position;
uniform float fade_size;
void main(void) {
float mask_starting_point = (0.0 - fade_size);
float mask_ending_point = (1.0 - fade_size);
vec4 orig_color = texture2D(texture, vUv);
vec4 color = texture2D(texture, vUv);
float mask_p = smoothstep(mask_starting_point, mask_ending_point, mask_position);
//color.a *= (distance(vUv.x, split_center_point));
vec2 p = vUv;
if (p.x > (mask_p)){
color.a = 0.0;
}else{
color.a *= (smoothstep(mask_position, (mask_position - fade_size), p.x ));
}
gl_FragColor = color;
}
如您所见,淡入并没有完全显示整个图像。任何有关解决此问题的更好方法的见解都会很棒。谢谢!
你想做的是让 mask_position
左边的区域可见,但你想隐藏右边的区域。这可以通过 step
:
color.a *= 1.0 - step(fade_size, p);
如果你想从可见区域平滑过渡到不可见区域,那么你必须使用smoothstep
。衰落的开始是在 mask_position
之前的一定量,在 mask_position
之后的一定量结束:
float start_p = mask_position-fade_size;
float end_p = mask_position+fade_size;
color.a *= 1.0 - smoothstep(start_p, end_p, vUv.x);
这将导致图像的开头和结尾永远不会完全淡入。为了弥补这一点,[vUV.x] 必须从范围 [0.0, 1.0] 映射到范围 [fade_size
, 1.0-fade_size
]。这可以通过 mix
轻松计算:
float p = vUv.x * (1.0-2.0*fade_size) + fade_size;
color.a *= 1.0 - smoothstep(start_p, end_p, p;
如果最终剔除器的 alpha 通道低于一个微小的阈值,则可以丢弃片段:
if ( color.a < 0.01 )
discard;
最终着色器:
varying vec2 vUv;
precision highp float;
precision highp int;
uniform sampler2D texture;
uniform float mask_position;
uniform float fade_size;
void main(void) {
vec4 color = texture2D(texture, vUv);
float start_p = mask_position-fade_size;
float end_p = mask_position+fade_size;
float p = mix(fade_size, 1.0-fade_size, vUv.x);
color.a *= 1.0 - smoothstep(start_p, end_p, p);
if ( color.a < 0.01 )
discard;
gl_FragColor = color;
}
看例子:
var container;
var camera, scene, renderer;
var uniforms;
init();
animate();
function init() {
container = document.getElementById( 'container' );
camera = new THREE.Camera();
camera.position.z = 1;
scene = new THREE.Scene();
var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
var texture = new THREE.TextureLoader().load( 'https://raw.githubusercontent.com/Rabbid76/graphics-snippets/master/resource/texture/background.jpg' );
uniforms = {
u_time: { type: "f", value: 1.0 },
u_resolution: { type: "v2", value: new THREE.Vector2() },
u_mouse: { type: "v2", value: new THREE.Vector2() },
texture: {type: 't', value: texture},
fade_size: { type: 'f', value: 0.2 },
mask_position: { type: 'f', value: 0 }
};
var material = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer( {alpha : true} );
renderer.setClearColor(0xffffff, 0.0);
renderer.setPixelRatio( window.devicePixelRatio );
container.appendChild( renderer.domElement );
onWindowResize();
window.addEventListener( 'resize', onWindowResize, false );
document.onmousemove = function(e){
uniforms.u_mouse.value.x = e.pageX
uniforms.u_mouse.value.y = e.pageY
}
}
function onWindowResize( event ) {
renderer.setSize( window.innerWidth, window.innerHeight );
uniforms.u_resolution.value.x = renderer.domElement.width;
uniforms.u_resolution.value.y = renderer.domElement.height;
}
function animate() {
requestAnimationFrame( animate );
render();
}
var mask_step = 0.01;
var mask_val = 0.0;
function render() {
if ( mask_val >= 1.0) { mask_val = 1.0; mask_step = -0.01; }
else if ( mask_val <= -0.0) { mask_val = 0.0; mask_step = 0.01; }
mask_val += mask_step;
uniforms.mask_position.value = mask_val;
uniforms.u_time.value += 0.05;
renderer.render( scene, camera );
}
<script id="vertexShader" type="x-shader/x-vertex">
void main() {
gl_Position = vec4( position, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec2 u_resolution;
uniform float u_time;
uniform sampler2D texture;
uniform float fade_size;
uniform float mask_position;
void main() {
vec2 vUv = gl_FragCoord.xy/u_resolution.xy;
vec4 color = texture2D(texture, vUv);
float start_p = mask_position-fade_size;
float end_p = mask_position+fade_size;
float p = mix(fade_size, 1.0-fade_size, vUv.x);
color.rgba *= 1.0 - smoothstep(start_p, end_p, p);
if ( color.a < 0.01 )
discard;
gl_FragColor = color;
}
</script>
<div id="container"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/100/three.min.js"></script>