使用 OGL Flowmap 效果为此 WebGL 设置透明背景?
Setting transparent background to this WebGL with OGL Flowmap effect?
我正在尝试从 OGL examples 创建 Flowmap 效果,但使用部分透明的 PNG 图像。我在这个问题上苦苦挣扎了好几个小时,我什至不知道是纹理的错误、流图效果还是其他任何事情。如何将背景设置为透明而不是黑色?
渲染方式canvas看起来
const vertex = /* glsl */ `
attribute vec2 uv;
attribute vec2 position;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 0, 1);
}
`
const fragment = /* glsl */ `
precision highp float;
precision highp int;
uniform sampler2D texture;
uniform sampler2D tFlow;
uniform float uTime;
varying vec2 vUv;
uniform vec4 res;
void main() {
// R and G values are velocity in the x and y direction
// B value is the velocity length
vec3 flow = texture2D(tFlow, vUv).rgb;
// Use flow to adjust the uv lookup of a texture
vec2 uv = .5 * gl_FragCoord.xy / res.xy ;
uv += flow.xy * 0.05;
vec3 tex = texture2D(texture, uv).rgb;
gl_FragColor.rgb = tex;
gl_FragColor.a = 1.0;
}
`
{
const renderer = new Renderer({
dpr: 2,
alpha: true,
premultiplyAlpha: false,
})
const gl = renderer.gl
const canvas = document.body.appendChild(gl.canvas)
gl.clearColor(1, 1, 1, 1)
// Variable inputs to control flowmap
let aspect = 1
const mouse = new Vec2(-1)
const velocity = new Vec2()
let imgSize = [600, 600]
const flowmap = new Flowmap(gl, { falloff: 0.2, dissipation: 0.9 })
// Triangle that includes -1 to 1 range for 'position', and 0 to 1 range for 'uv'.
const geometry = new Geometry(gl, {
position: { size: 2, data: new Float32Array([-1, -1, 3, -1, -1, 3]) },
uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) },
})
const texture = new Texture(gl, {
minFilter: gl.LINEAR,
magFilter: gl.LINEAR,
premultiplyAlpha: true,
})
const img = new Image()
img.onload = () => (texture.image = img)
img.src = "/static/sowa@2x-863f69426831e1cc05d417dc45111419.png"
let a1, a2
var imageAspect = imgSize[1] / imgSize[0]
if (imgSize[1] / imgSize[0] < imageAspect) {
a1 = 1
a2 = imgSize[1] / imgSize[0] / imageAspect
} else {
a1 = (imgSize[0] / imgSize[1]) * imageAspect
a2 = 1
}
const program = new Program(gl, {
vertex,
fragment,
uniforms: {
uTime: { value: 0 },
texture: { value: texture },
res: {
value: new Vec4(imgSize[0], imgSize[1], a1, a2),
},
// Note that the uniform is applied without using an object and value property
// This is because the class alternates this texture between two render targets
// and updates the value property after each render.
tFlow: flowmap.uniform,
},
})
const mesh = new Mesh(gl, { geometry, program })
// Create handlers to get mouse position and velocity
const isTouchCapable = "ontouchstart" in window
if (isTouchCapable) {
window.addEventListener("touchstart", updateMouse, false)
window.addEventListener("touchmove", updateMouse, false)
} else {
window.addEventListener("mousemove", updateMouse, false)
}
let lastTime
const lastMouse = new Vec2()
function resize() {
renderer.setSize(imgSize[0], imgSize[1])
aspect = imgSize[0] / imgSize[1]
}
window.addEventListener("resize", resize, false)
resize()
function updateMouse(e) {
if (e.changedTouches && e.changedTouches.length) {
e.x = e.changedTouches[0].pageX
e.y = e.changedTouches[0].pageY
}
const positionX = e.x - canvas.getBoundingClientRect().x
const positionY = e.y - canvas.getBoundingClientRect().y
// Get mouse value in 0 to 1 range, with y flipped
mouse.set(
positionX / gl.renderer.width,
1.0 - positionY / gl.renderer.height
)
// Calculate velocity
if (!lastTime) {
// First frame
lastTime = performance.now()
lastMouse.set(positionX, positionY)
}
const deltaX = positionX - lastMouse.x
const deltaY = positionY - lastMouse.y
lastMouse.set(positionX, positionY)
let time = performance.now()
// Avoid dividing by 0
let delta = Math.max(14, time - lastTime)
lastTime = time
velocity.x = deltaX / delta
velocity.y = deltaY / delta
// Flag update to prevent hanging velocity values when not moving
velocity.needsUpdate = true
}
requestAnimationFrame(update)
function update(t) {
requestAnimationFrame(update)
// Reset velocity when mouse not moving
if (!velocity.needsUpdate) {
mouse.set(-1)
velocity.set(0)
}
velocity.needsUpdate = false
// Update flowmap inputs
flowmap.aspect = aspect
flowmap.mouse.copy(mouse)
// Ease velocity input, slower when fading out
flowmap.velocity.lerp(velocity, velocity.len ? 0.5 : 0.1)
flowmap.update()
program.uniforms.uTime.value = t * 0.01
renderer.render({ scene: mesh })
}
}
我应该在哪里寻找答案?这是 OGL 内部的东西吗?
您需要进行两项更改。
- 在您的程序声明中,您需要添加
transparent: true
- 在片段着色器中,将输出更改为
gl_FragColor = texture2D(texture, uv);
第一个更改是将混合类型更改为使用 alpha - 默认情况下在 WebGL 中禁用混合。
第二个使用纹理的 alpha 通道。在原始示例中,仅使用 rgb
(红色、绿色、蓝色)通道。
我正在尝试从 OGL examples 创建 Flowmap 效果,但使用部分透明的 PNG 图像。我在这个问题上苦苦挣扎了好几个小时,我什至不知道是纹理的错误、流图效果还是其他任何事情。如何将背景设置为透明而不是黑色?
渲染方式canvas看起来
const vertex = /* glsl */ `
attribute vec2 uv;
attribute vec2 position;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 0, 1);
}
`
const fragment = /* glsl */ `
precision highp float;
precision highp int;
uniform sampler2D texture;
uniform sampler2D tFlow;
uniform float uTime;
varying vec2 vUv;
uniform vec4 res;
void main() {
// R and G values are velocity in the x and y direction
// B value is the velocity length
vec3 flow = texture2D(tFlow, vUv).rgb;
// Use flow to adjust the uv lookup of a texture
vec2 uv = .5 * gl_FragCoord.xy / res.xy ;
uv += flow.xy * 0.05;
vec3 tex = texture2D(texture, uv).rgb;
gl_FragColor.rgb = tex;
gl_FragColor.a = 1.0;
}
`
{
const renderer = new Renderer({
dpr: 2,
alpha: true,
premultiplyAlpha: false,
})
const gl = renderer.gl
const canvas = document.body.appendChild(gl.canvas)
gl.clearColor(1, 1, 1, 1)
// Variable inputs to control flowmap
let aspect = 1
const mouse = new Vec2(-1)
const velocity = new Vec2()
let imgSize = [600, 600]
const flowmap = new Flowmap(gl, { falloff: 0.2, dissipation: 0.9 })
// Triangle that includes -1 to 1 range for 'position', and 0 to 1 range for 'uv'.
const geometry = new Geometry(gl, {
position: { size: 2, data: new Float32Array([-1, -1, 3, -1, -1, 3]) },
uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) },
})
const texture = new Texture(gl, {
minFilter: gl.LINEAR,
magFilter: gl.LINEAR,
premultiplyAlpha: true,
})
const img = new Image()
img.onload = () => (texture.image = img)
img.src = "/static/sowa@2x-863f69426831e1cc05d417dc45111419.png"
let a1, a2
var imageAspect = imgSize[1] / imgSize[0]
if (imgSize[1] / imgSize[0] < imageAspect) {
a1 = 1
a2 = imgSize[1] / imgSize[0] / imageAspect
} else {
a1 = (imgSize[0] / imgSize[1]) * imageAspect
a2 = 1
}
const program = new Program(gl, {
vertex,
fragment,
uniforms: {
uTime: { value: 0 },
texture: { value: texture },
res: {
value: new Vec4(imgSize[0], imgSize[1], a1, a2),
},
// Note that the uniform is applied without using an object and value property
// This is because the class alternates this texture between two render targets
// and updates the value property after each render.
tFlow: flowmap.uniform,
},
})
const mesh = new Mesh(gl, { geometry, program })
// Create handlers to get mouse position and velocity
const isTouchCapable = "ontouchstart" in window
if (isTouchCapable) {
window.addEventListener("touchstart", updateMouse, false)
window.addEventListener("touchmove", updateMouse, false)
} else {
window.addEventListener("mousemove", updateMouse, false)
}
let lastTime
const lastMouse = new Vec2()
function resize() {
renderer.setSize(imgSize[0], imgSize[1])
aspect = imgSize[0] / imgSize[1]
}
window.addEventListener("resize", resize, false)
resize()
function updateMouse(e) {
if (e.changedTouches && e.changedTouches.length) {
e.x = e.changedTouches[0].pageX
e.y = e.changedTouches[0].pageY
}
const positionX = e.x - canvas.getBoundingClientRect().x
const positionY = e.y - canvas.getBoundingClientRect().y
// Get mouse value in 0 to 1 range, with y flipped
mouse.set(
positionX / gl.renderer.width,
1.0 - positionY / gl.renderer.height
)
// Calculate velocity
if (!lastTime) {
// First frame
lastTime = performance.now()
lastMouse.set(positionX, positionY)
}
const deltaX = positionX - lastMouse.x
const deltaY = positionY - lastMouse.y
lastMouse.set(positionX, positionY)
let time = performance.now()
// Avoid dividing by 0
let delta = Math.max(14, time - lastTime)
lastTime = time
velocity.x = deltaX / delta
velocity.y = deltaY / delta
// Flag update to prevent hanging velocity values when not moving
velocity.needsUpdate = true
}
requestAnimationFrame(update)
function update(t) {
requestAnimationFrame(update)
// Reset velocity when mouse not moving
if (!velocity.needsUpdate) {
mouse.set(-1)
velocity.set(0)
}
velocity.needsUpdate = false
// Update flowmap inputs
flowmap.aspect = aspect
flowmap.mouse.copy(mouse)
// Ease velocity input, slower when fading out
flowmap.velocity.lerp(velocity, velocity.len ? 0.5 : 0.1)
flowmap.update()
program.uniforms.uTime.value = t * 0.01
renderer.render({ scene: mesh })
}
}
我应该在哪里寻找答案?这是 OGL 内部的东西吗?
您需要进行两项更改。
- 在您的程序声明中,您需要添加
transparent: true
- 在片段着色器中,将输出更改为
gl_FragColor = texture2D(texture, uv);
第一个更改是将混合类型更改为使用 alpha - 默认情况下在 WebGL 中禁用混合。
第二个使用纹理的 alpha 通道。在原始示例中,仅使用 rgb
(红色、绿色、蓝色)通道。