如何使用three.js/dat.gui使Canvas动画背景透明
How to make Canvas animation Background tranparent using three.js/dat.gui
我想把这个canvas做成背景动画。但是 three.js 将背景渲染为黑色。我想让它透明。我试图通过 css background-color:transparent;
来更改它 我在 Whosebug 中寻找其他类似的问题,但没有任何帮助。我该怎么做?这些是我的 html、css 和 js。
提前致谢。
这是 codepen link.
我的 HTML:
<canvas id="webgl-canvas"></canvas>
<!-- vertexShader -->
<script id="js-vertex-shader" type="x-shader/x-vertex">
attribute vec3 position;
void main() {
gl_Position = vec4(position, 1.0);
}
</script>
<!-- fragmentShader -->
<script id="js-fragment-shader" type="x-shader/x-fragment">
precision highp float;
uniform vec2 resolution;
uniform float time;
uniform float xScale;
uniform float yScale;
uniform float distortion;
void main() {
vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
float d = length(p) * distortion;
float rx = p.x * (1.0 + d);
float gx = p.x;
float bx = p.x * (1.0 - d);
float r = 0.05 / abs(p.y + sin((rx + time) * xScale) * yScale);
float g = 0.05 / abs(p.y + sin((gx + time) * xScale) * yScale);
float b = 0.05 / abs(p.y + sin((bx + time) * xScale) * yScale);
gl_FragColor = vec4(r, g, b, 1.0);
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r124/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
我的CSS:
#webgl-canvas{
width: 20% !important;
height:10% !important;
background: null !important;
}
我的 JS:
class Stage {
constructor() {
this.renderParam = {
clearColor: 0xffffff,
width: window.innerWidth,
height: window.innerHeight
};
this.cameraParam = {
left: -1,
right: 1,
top: 1,
bottom: 1,
near: 0,
far: -1
};
this.scene = null;
this.camera = null;
this.renderer = null;
this.geometry = null;
this.material = null;
this.mesh = null;
this.isInitialized = false;
}
init() {
this._setScene();
this._setRender();
this._setCamera();
this.isInitialized = true;
}
_setScene() {
this.scene = new THREE.Scene();
}
_setRender() {
this.renderer = new THREE.WebGLRenderer({
canvas: document.getElementById("webgl-canvas")
});
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setClearColor(new THREE.Color(this.renderParam.clearColor));
this.renderer.setSize(this.renderParam.width, this.renderParam.height);
}
_setCamera() {
if (!this.isInitialized) {
this.camera = new THREE.OrthographicCamera(
this.cameraParam.left,
this.cameraParam.right,
this.cameraParam.top,
this.cameraParam.bottom,
this.cameraParam.near,
this.cameraParam.far
);
}
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
this.camera.aspect = windowWidth / windowHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(windowWidth, windowHeight);
}
_render() {
this.renderer.render(this.scene, this.camera);
}
onResize() {
this._setCamera();
}
onRaf() {
this._render();
}
}
class Mesh {
constructor(stage) {
this.canvas = document.getElementById("webgl-canvas");
this.canvasWidth = this.canvas.width;
this.canvasHeight = this.canvas.height;
this.uniforms = {
resolution: { type: "v2", value: [ this.canvasWidth, this.canvasHeight ] },
time: { type: "f", value: 0.0 },
xScale: { type: "f", value: 1.0 },
yScale: { type: "f", value: 0.5 },
distortion: { type: "f", value: 0.050 }
};
this.stage = stage;
this.mesh = null;
this.xScale = 1.0;
this.yScale = 0.5;
this.distortion = 0.050;
}
init() {
this._setMesh();
// this._setGui();
}
_setMesh() {
const position = [
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, 1.0, 0.0
];
const positions = new THREE.BufferAttribute(new Float32Array(position), 3);
const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", positions);
const material = new THREE.RawShaderMaterial({
vertexShader: document.getElementById("js-vertex-shader").textContent,
fragmentShader: document.getElementById("js-fragment-shader").textContent,
uniforms: this.uniforms,
side: THREE.DoubleSide
});
this.mesh = new THREE.Mesh(geometry, material);
this.stage.scene.add(this.mesh);
}
_diffuse() {
}
_render() {
this.uniforms.time.value += 0.01;
}
_setGui() {
const parameter = {
xScale: this.xScale,
yScale: this.yScale,
distortion: this.distortion
}
const gui = new dat.GUI();
gui.add(parameter, "xScale", 0.00, 5.00, 0.01).onChange((value) => {
this.mesh.material.uniforms.xScale.value = value;
});
gui.add(parameter, "yScale", 0.00, 1.00, 0.01).onChange((value) => {
this.mesh.material.uniforms.yScale.value = value;
});
gui.add(parameter, "distortion", 0.001, 0.100, 0.001).onChange((value) => {
this.mesh.material.uniforms.distortion.value = value;
});
}
onRaf() {
this._render();
}
}
(() => {
const stage = new Stage();
stage.init();
const mesh = new Mesh(stage);
mesh.init();
window.addEventListener("resize", () => {
stage.onResize();
});
window.addEventListener("load", () => {
setTimeout(() => {
mesh._diffuse();
}, 1000);
});
const _raf = () => {
window.requestAnimationFrame(() => {
stage.onRaf();
mesh.onRaf();
_raf();
});
};
_raf();
})();
为了能够通过 three.js 的 WebGLRenderer
获得 alpha 支持,您需要通过在初始化时将 alpha
选项设置为 true 来激活它的 alpha 缓冲区。
this.renderer = new THREE.WebGLRenderer({
alpha: true,
canvas: document.getElementById("webgl-canvas")
});
由于您使用 RawShaderMaterial
,纹理像素不透明度的来源 是 片段着色器。
如果我们看一下
gl_FragColor = vec4(r, g, b, 1.0);
我们意识到无论一个像素有什么颜色,它总是不透明的。这意味着您需要在片段着色器中进行 alpha 计算。一种可能的方法是使用阈值,例如如果red+green+blue小于0.5就完全透明
float a = 1.0;
if (r + g + b < 0.5) {
a = 0.0;
}
gl_FragColor = vec4(r, g, b, a);
除此之外,您还需要摆脱您的自定义透明颜色:
this.renderer.setClearColor(new THREE.Color(this.renderParam.clearColor));
并为您的 RawShaderMaterial 提供额外的选项 transparent: true, opacity: 1
这是一个例子:
class Stage {
constructor() {
this.renderParam = {
width: window.innerWidth,
height: window.innerHeight
};
this.cameraParam = {
left: -1,
right: 1,
top: 1,
bottom: 1,
near: 0,
far: -1
};
this.scene = null;
this.camera = null;
this.renderer = null;
this.geometry = null;
this.material = null;
this.mesh = null;
this.isInitialized = false;
}
init() {
this._setScene();
this._setRender();
this._setCamera();
this.isInitialized = true;
}
_setScene() {
this.scene = new THREE.Scene();
}
_setRender() {
this.renderer = new THREE.WebGLRenderer({
alpha: true,
canvas: document.getElementById("webgl-canvas")
});
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(this.renderParam.width, this.renderParam.height);
}
_setCamera() {
if (!this.isInitialized) {
this.camera = new THREE.OrthographicCamera(
this.cameraParam.left,
this.cameraParam.right,
this.cameraParam.top,
this.cameraParam.bottom,
this.cameraParam.near,
this.cameraParam.far
);
}
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
this.camera.aspect = windowWidth / windowHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(windowWidth, windowHeight);
}
_render() {
this.renderer.render(this.scene, this.camera);
}
onResize() {
this._setCamera();
}
onRaf() {
this._render();
}
}
class Mesh {
constructor(stage) {
this.canvas = document.getElementById("webgl-canvas");
this.canvasWidth = this.canvas.width;
this.canvasHeight = this.canvas.height;
this.uniforms = {
resolution: {
type: "v2",
value: [this.canvasWidth, this.canvasHeight]
},
time: {
type: "f",
value: 0.0
},
xScale: {
type: "f",
value: 1.0
},
yScale: {
type: "f",
value: 0.5
},
distortion: {
type: "f",
value: 0.050
}
};
this.stage = stage;
this.mesh = null;
this.xScale = 1.0;
this.yScale = 0.5;
this.distortion = 0.050;
}
init() {
this._setMesh();
// this._setGui();
}
_setMesh() {
const position = [
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, 1.0, 0.0
];
const positions = new THREE.BufferAttribute(new Float32Array(position), 3);
const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", positions);
const material = new THREE.RawShaderMaterial({
vertexShader: document.getElementById("js-vertex-shader").textContent,
fragmentShader: document.getElementById("js-fragment-shader").textContent,
uniforms: this.uniforms,
transparent: true,
opacity: 1,
side: THREE.DoubleSide
});
this.mesh = new THREE.Mesh(geometry, material);
this.stage.scene.add(this.mesh);
}
_diffuse() {
// gsap.to(this.mesh.material.uniforms.xScale, {
// value: 2,
// duration: 0.1,
// ease: 'power2.inOut',
// repeat: -1,
// yoyo: true
// });
// gsap.to(this.mesh.material.uniforms.yScale, {
// value: 1,
// duration: 0.1,
// ease: 'power2.inOut',
// repeat: -1,
// yoyo: true
// });
}
_render() {
this.uniforms.time.value += 0.01;
}
_setGui() {
const parameter = {
xScale: this.xScale,
yScale: this.yScale,
distortion: this.distortion
}
const gui = new dat.GUI();
gui.add(parameter, "xScale", 0.00, 5.00, 0.01).onChange((value) => {
this.mesh.material.uniforms.xScale.value = value;
});
gui.add(parameter, "yScale", 0.00, 1.00, 0.01).onChange((value) => {
this.mesh.material.uniforms.yScale.value = value;
});
gui.add(parameter, "distortion", 0.001, 0.100, 0.001).onChange((value) => {
this.mesh.material.uniforms.distortion.value = value;
});
}
onRaf() {
this._render();
}
}
(() => {
const stage = new Stage();
stage.init();
const mesh = new Mesh(stage);
mesh.init();
window.addEventListener("resize", () => {
stage.onResize();
});
window.addEventListener("load", () => {
setTimeout(() => {
mesh._diffuse();
}, 1000);
});
const _raf = () => {
window.requestAnimationFrame(() => {
stage.onRaf();
mesh.onRaf();
_raf();
});
};
_raf();
})();
body {
margin: 0;
overflow: hidden;
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r124/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
<canvas id="webgl-canvas"></canvas>
<!-- vertexShader -->
<script id="js-vertex-shader" type="x-shader/x-vertex">
attribute vec3 position;
void main() {
gl_Position = vec4(position, 1.0);
}
</script>
<!-- fragmentShader -->
<script id="js-fragment-shader" type="x-shader/x-fragment">
precision highp float;
uniform vec2 resolution;
uniform float time;
uniform float xScale;
uniform float yScale;
uniform float distortion;
void main() {
vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
float d = length(p) * distortion;
float rx = p.x * (1.0 + d);
float gx = p.x;
float bx = p.x * (1.0 - d);
float r = 0.05 / abs(p.y + sin((rx + time) * xScale) * yScale);
float g = 0.05 / abs(p.y + sin((gx + time) * xScale) * yScale);
float b = 0.05 / abs(p.y + sin((bx + time) * xScale) * yScale);
float a = 1.0;
if(r+g+b<0.5)
{
a=0.0;
}
gl_FragColor = vec4(r, g, b, a);
}
</script>
我想把这个canvas做成背景动画。但是 three.js 将背景渲染为黑色。我想让它透明。我试图通过 css background-color:transparent;
来更改它 我在 Whosebug 中寻找其他类似的问题,但没有任何帮助。我该怎么做?这些是我的 html、css 和 js。
提前致谢。
这是 codepen link.
我的 HTML:
<canvas id="webgl-canvas"></canvas>
<!-- vertexShader -->
<script id="js-vertex-shader" type="x-shader/x-vertex">
attribute vec3 position;
void main() {
gl_Position = vec4(position, 1.0);
}
</script>
<!-- fragmentShader -->
<script id="js-fragment-shader" type="x-shader/x-fragment">
precision highp float;
uniform vec2 resolution;
uniform float time;
uniform float xScale;
uniform float yScale;
uniform float distortion;
void main() {
vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
float d = length(p) * distortion;
float rx = p.x * (1.0 + d);
float gx = p.x;
float bx = p.x * (1.0 - d);
float r = 0.05 / abs(p.y + sin((rx + time) * xScale) * yScale);
float g = 0.05 / abs(p.y + sin((gx + time) * xScale) * yScale);
float b = 0.05 / abs(p.y + sin((bx + time) * xScale) * yScale);
gl_FragColor = vec4(r, g, b, 1.0);
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r124/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
我的CSS:
#webgl-canvas{
width: 20% !important;
height:10% !important;
background: null !important;
}
我的 JS:
class Stage {
constructor() {
this.renderParam = {
clearColor: 0xffffff,
width: window.innerWidth,
height: window.innerHeight
};
this.cameraParam = {
left: -1,
right: 1,
top: 1,
bottom: 1,
near: 0,
far: -1
};
this.scene = null;
this.camera = null;
this.renderer = null;
this.geometry = null;
this.material = null;
this.mesh = null;
this.isInitialized = false;
}
init() {
this._setScene();
this._setRender();
this._setCamera();
this.isInitialized = true;
}
_setScene() {
this.scene = new THREE.Scene();
}
_setRender() {
this.renderer = new THREE.WebGLRenderer({
canvas: document.getElementById("webgl-canvas")
});
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setClearColor(new THREE.Color(this.renderParam.clearColor));
this.renderer.setSize(this.renderParam.width, this.renderParam.height);
}
_setCamera() {
if (!this.isInitialized) {
this.camera = new THREE.OrthographicCamera(
this.cameraParam.left,
this.cameraParam.right,
this.cameraParam.top,
this.cameraParam.bottom,
this.cameraParam.near,
this.cameraParam.far
);
}
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
this.camera.aspect = windowWidth / windowHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(windowWidth, windowHeight);
}
_render() {
this.renderer.render(this.scene, this.camera);
}
onResize() {
this._setCamera();
}
onRaf() {
this._render();
}
}
class Mesh {
constructor(stage) {
this.canvas = document.getElementById("webgl-canvas");
this.canvasWidth = this.canvas.width;
this.canvasHeight = this.canvas.height;
this.uniforms = {
resolution: { type: "v2", value: [ this.canvasWidth, this.canvasHeight ] },
time: { type: "f", value: 0.0 },
xScale: { type: "f", value: 1.0 },
yScale: { type: "f", value: 0.5 },
distortion: { type: "f", value: 0.050 }
};
this.stage = stage;
this.mesh = null;
this.xScale = 1.0;
this.yScale = 0.5;
this.distortion = 0.050;
}
init() {
this._setMesh();
// this._setGui();
}
_setMesh() {
const position = [
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, 1.0, 0.0
];
const positions = new THREE.BufferAttribute(new Float32Array(position), 3);
const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", positions);
const material = new THREE.RawShaderMaterial({
vertexShader: document.getElementById("js-vertex-shader").textContent,
fragmentShader: document.getElementById("js-fragment-shader").textContent,
uniforms: this.uniforms,
side: THREE.DoubleSide
});
this.mesh = new THREE.Mesh(geometry, material);
this.stage.scene.add(this.mesh);
}
_diffuse() {
}
_render() {
this.uniforms.time.value += 0.01;
}
_setGui() {
const parameter = {
xScale: this.xScale,
yScale: this.yScale,
distortion: this.distortion
}
const gui = new dat.GUI();
gui.add(parameter, "xScale", 0.00, 5.00, 0.01).onChange((value) => {
this.mesh.material.uniforms.xScale.value = value;
});
gui.add(parameter, "yScale", 0.00, 1.00, 0.01).onChange((value) => {
this.mesh.material.uniforms.yScale.value = value;
});
gui.add(parameter, "distortion", 0.001, 0.100, 0.001).onChange((value) => {
this.mesh.material.uniforms.distortion.value = value;
});
}
onRaf() {
this._render();
}
}
(() => {
const stage = new Stage();
stage.init();
const mesh = new Mesh(stage);
mesh.init();
window.addEventListener("resize", () => {
stage.onResize();
});
window.addEventListener("load", () => {
setTimeout(() => {
mesh._diffuse();
}, 1000);
});
const _raf = () => {
window.requestAnimationFrame(() => {
stage.onRaf();
mesh.onRaf();
_raf();
});
};
_raf();
})();
为了能够通过 three.js 的 WebGLRenderer
获得 alpha 支持,您需要通过在初始化时将 alpha
选项设置为 true 来激活它的 alpha 缓冲区。
this.renderer = new THREE.WebGLRenderer({
alpha: true,
canvas: document.getElementById("webgl-canvas")
});
由于您使用 RawShaderMaterial
,纹理像素不透明度的来源 是 片段着色器。
如果我们看一下
gl_FragColor = vec4(r, g, b, 1.0);
我们意识到无论一个像素有什么颜色,它总是不透明的。这意味着您需要在片段着色器中进行 alpha 计算。一种可能的方法是使用阈值,例如如果red+green+blue小于0.5就完全透明
float a = 1.0;
if (r + g + b < 0.5) {
a = 0.0;
}
gl_FragColor = vec4(r, g, b, a);
除此之外,您还需要摆脱您的自定义透明颜色:
this.renderer.setClearColor(new THREE.Color(this.renderParam.clearColor));
并为您的 RawShaderMaterial 提供额外的选项 transparent: true, opacity: 1
这是一个例子:
class Stage {
constructor() {
this.renderParam = {
width: window.innerWidth,
height: window.innerHeight
};
this.cameraParam = {
left: -1,
right: 1,
top: 1,
bottom: 1,
near: 0,
far: -1
};
this.scene = null;
this.camera = null;
this.renderer = null;
this.geometry = null;
this.material = null;
this.mesh = null;
this.isInitialized = false;
}
init() {
this._setScene();
this._setRender();
this._setCamera();
this.isInitialized = true;
}
_setScene() {
this.scene = new THREE.Scene();
}
_setRender() {
this.renderer = new THREE.WebGLRenderer({
alpha: true,
canvas: document.getElementById("webgl-canvas")
});
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(this.renderParam.width, this.renderParam.height);
}
_setCamera() {
if (!this.isInitialized) {
this.camera = new THREE.OrthographicCamera(
this.cameraParam.left,
this.cameraParam.right,
this.cameraParam.top,
this.cameraParam.bottom,
this.cameraParam.near,
this.cameraParam.far
);
}
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
this.camera.aspect = windowWidth / windowHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(windowWidth, windowHeight);
}
_render() {
this.renderer.render(this.scene, this.camera);
}
onResize() {
this._setCamera();
}
onRaf() {
this._render();
}
}
class Mesh {
constructor(stage) {
this.canvas = document.getElementById("webgl-canvas");
this.canvasWidth = this.canvas.width;
this.canvasHeight = this.canvas.height;
this.uniforms = {
resolution: {
type: "v2",
value: [this.canvasWidth, this.canvasHeight]
},
time: {
type: "f",
value: 0.0
},
xScale: {
type: "f",
value: 1.0
},
yScale: {
type: "f",
value: 0.5
},
distortion: {
type: "f",
value: 0.050
}
};
this.stage = stage;
this.mesh = null;
this.xScale = 1.0;
this.yScale = 0.5;
this.distortion = 0.050;
}
init() {
this._setMesh();
// this._setGui();
}
_setMesh() {
const position = [
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, 1.0, 0.0
];
const positions = new THREE.BufferAttribute(new Float32Array(position), 3);
const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", positions);
const material = new THREE.RawShaderMaterial({
vertexShader: document.getElementById("js-vertex-shader").textContent,
fragmentShader: document.getElementById("js-fragment-shader").textContent,
uniforms: this.uniforms,
transparent: true,
opacity: 1,
side: THREE.DoubleSide
});
this.mesh = new THREE.Mesh(geometry, material);
this.stage.scene.add(this.mesh);
}
_diffuse() {
// gsap.to(this.mesh.material.uniforms.xScale, {
// value: 2,
// duration: 0.1,
// ease: 'power2.inOut',
// repeat: -1,
// yoyo: true
// });
// gsap.to(this.mesh.material.uniforms.yScale, {
// value: 1,
// duration: 0.1,
// ease: 'power2.inOut',
// repeat: -1,
// yoyo: true
// });
}
_render() {
this.uniforms.time.value += 0.01;
}
_setGui() {
const parameter = {
xScale: this.xScale,
yScale: this.yScale,
distortion: this.distortion
}
const gui = new dat.GUI();
gui.add(parameter, "xScale", 0.00, 5.00, 0.01).onChange((value) => {
this.mesh.material.uniforms.xScale.value = value;
});
gui.add(parameter, "yScale", 0.00, 1.00, 0.01).onChange((value) => {
this.mesh.material.uniforms.yScale.value = value;
});
gui.add(parameter, "distortion", 0.001, 0.100, 0.001).onChange((value) => {
this.mesh.material.uniforms.distortion.value = value;
});
}
onRaf() {
this._render();
}
}
(() => {
const stage = new Stage();
stage.init();
const mesh = new Mesh(stage);
mesh.init();
window.addEventListener("resize", () => {
stage.onResize();
});
window.addEventListener("load", () => {
setTimeout(() => {
mesh._diffuse();
}, 1000);
});
const _raf = () => {
window.requestAnimationFrame(() => {
stage.onRaf();
mesh.onRaf();
_raf();
});
};
_raf();
})();
body {
margin: 0;
overflow: hidden;
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r124/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
<canvas id="webgl-canvas"></canvas>
<!-- vertexShader -->
<script id="js-vertex-shader" type="x-shader/x-vertex">
attribute vec3 position;
void main() {
gl_Position = vec4(position, 1.0);
}
</script>
<!-- fragmentShader -->
<script id="js-fragment-shader" type="x-shader/x-fragment">
precision highp float;
uniform vec2 resolution;
uniform float time;
uniform float xScale;
uniform float yScale;
uniform float distortion;
void main() {
vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
float d = length(p) * distortion;
float rx = p.x * (1.0 + d);
float gx = p.x;
float bx = p.x * (1.0 - d);
float r = 0.05 / abs(p.y + sin((rx + time) * xScale) * yScale);
float g = 0.05 / abs(p.y + sin((gx + time) * xScale) * yScale);
float b = 0.05 / abs(p.y + sin((bx + time) * xScale) * yScale);
float a = 1.0;
if(r+g+b<0.5)
{
a=0.0;
}
gl_FragColor = vec4(r, g, b, a);
}
</script>