THREE.js 旋转烟雾效果仅适用于一个元素,而不适用于所有元素
THREE.js revolving smoke effect works only for one element instead of applying to all elements
我正在尝试为论坛网站创建自定义 post 页眉背景。但是因为我总是想让我的生活变得更加艰难,所以我试图让它变得花哨。我还需要 link 每个 post.
中的那个脚本
当我复制 post(或仅通过 ctrl+a ctrl+c ctrl+v ctrl+v HTMP 代码模拟它)时,只有最后一个 post 获得任何烟雾效果背景。我试图在初始化时将函数添加到 window 并使用 SiffrinSmoke class 为每个元素循环它,但仍然只显示一根烟雾 - 在底部。
HTML:
<div class="SiffrinBody">
<div class="SiffrinHeader">
<div class="SiffrinSmoke">
<!--h1>Siffrin<br>Drauglir</h1-->
<h1 data-heading="Siffrin
Drauglir"></h1>
</div>
<div class="SiffrinCanvasBackground" id="SiffrinCanvasBackground"></div>
<div class="SiffrinCanvasForeground" id="SiffrinCanvasForeground"></div>
<img id="SiffrinHeaderBackground" src="https://i.imgur.com/iYnkBdZ.jpg">
<img id="SiffrinWolf" src="https://i.imgur.com/MBLqG00.png">
</div>
</div>
CSS:
@import url('https://fonts.googleapis.com/css2?family=Arvo:ital@0;1&family=Carter+One&family=Dosis:wght@400;500;600&display=swap');
.SiffrinBody .SiffrinHeader .SiffrinCanvasBackground{
height: 330px;
width: 656px;
position: absolute;
left: inherit;
top: inherit;
z-index: 5;
}
.SiffrinBody .SiffrinHeader .SiffrinCanvasForeground{
height: 330px;
width: 656px;
position: absolute;
left: inherit;
top: inherit;
z-index: 7;
}
.SiffrinBody .SiffrinHeader img{
position: absolute;
height: 330px;
width: 656px;
grid-row: 1;
}
.SiffrinBody .SiffrinHeader .SiffrinSmoke{
width: 328px;
height: 330px;
position: relative;
z-index: 6;
float: right;
display: block;
}
.SiffrinBody .SiffrinHeader .SiffrinSmoke canvas{
position: absolute;
top: 0;
left: 0;
z-index: -4;
}
.SiffrinBody .SiffrinHeader #SiffrinHeaderBackground{
z-index: 4;
}
.SiffrinBody .SiffrinHeader #SiffrinWolf{
z-index: 6;
}
.SiffrinBody .SiffrinHeader h1{
font-family: Carter One;
z-index: 1000;
color: white;
grid-column: 2;
font-size: 50;
margin-top: 32%;
text-align: center;
background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/209981/6963bbf342d87b3a2150bd8f59682b89.jpg);
-webkit-background-clip: text;
background-size: cover;
width: 100%;
color: transparent;
font-weight: 900;
display: block;
white-space: pre-wrap !important;
line-height: 1.1em;
text-shadow: 2px 2px 6px rgba(46,146,211,0.8);
}
.SiffrinBody .SiffrinHeader h1::before{
content: attr(data-heading);
position: relative;
left: 0;
top: 0;
width: 100%;
background: linear-gradient(45deg, rgba(255,255,255,0) 45%,rgba(255,255,255,0.8) 50%,rgba(255,255,255,0) 55%,rgba(255,255,255,0) 100%);
-webkit-background-clip: text;
color: transparent;
mix-blend-mode: screen;
animation: SiffrinShine 15s infinite linear;
background-size: 200%;
}
.SiffrinBody .SiffrinHeader #SiffrinName{
z-index: 22;
transform: scale(0.8);
left: 150px;
}
.SiffrinBody .SiffrinHeader{
grid-row: 1;
mask-image: linear-gradient(
to top,
rgba(255, 255, 255, 0) 0,
rgba(255, 255, 255, 1) 15px
);
}
.SiffrinBody .SiffrinHeader > *{
user-select: none;
}
.SiffrinBody{
color: white;
display: grid;
grid-template-rows: 330px auto auto;
grid-template-columns: 1fr;
margin: 0;
padding: 0;
width: 656px;
/*background-image: linear-gradient(#bad4eb, #bad4eb, #a7c8e7, #4789c6, #037ccf);*/
background-image: url("https://i.imgur.com/UqFcRzS.jpg");
background-repeat: repeat;
}
.SiffrinBody *::selection{
background: rgba(225, 0, 255, 0.3);
color: inherit;
}
.SiffrinBody .SiffrinHeader{
/*
z-index: 7;
text-align: center;
font-family: Oleo Script;
margin: auto;
font-size: 30px;
transition-duration: 2s;
transition-timing-function: ease-in-out;
background-image: radial-gradient(#0e111800, #232b3e00, #24212a00, #403b6600);
user-select: none;
*/
}
.SiffrinBody .SiffrinBody:hover .SiffrinHeader{
/*
letter-spacing: 0.35em;
transition-duration: 3s;
transition-timing-function: ease-in-out;
transform: translate(0px, 40px);
*/
}
.SiffrinBody .SiffrinText{
z-index: 7;
margin: 10px 50px;
padding: 20px;
background-color: rgba(0, 0, 0, 0.5);
font-family: Dosis;
font-size: 17px;
margin-bottom: 0;
line-height: 1.235em;
font-weight: 500;
}
.SiffrinBody .SiffrinText::before{
border-top: 3px solid blue;
border-right: 3px solid blue;
}
.SiffrinBody .SiffrinText::after{
border-bottom: 3px solid orange;
border-left: 3px solid orange;
}
.SiffrinBody .SiffrinText p{
padding: 0;
margin-bottom: 1em;
}
.SiffrinBody .SiffrinText p u,
.SiffrinBody .SiffrinText p i,
.SiffrinBody .SiffrinText p q{
font-family: Arvo;
font-size: 16px;
}
.SiffrinBody .SiffrinText p u{
text-decoration: none;
color:rgb(250, 210, 255);
}
.SiffrinBody .SiffrinText p u::before {
content: "“"
}
.SiffrinBody.SiffrinText p u::after {
content: "”"
}
.SiffrinBody .SiffrinText p i{
font-family: Arvo;
color:rgb(250, 210, 255);
font-style: italic;
}
.SiffrinBody .SiffrinText p q{
text-decoration: none;
color:rgb(219, 223, 255);
}
.SiffrinBody .SiffrinText p:last-child{
margin: 0;
}
.SiffrinBody .SiffrinText p:first-child{
margin-top: 0;
}
.SiffrinBody .SiffrinFooter{
display: flex;
align-items: center;
justify-content: center;
padding: 10px;
margin: 0;
}
.SiffrinBody .SiffrinFooter p{
text-align: center;
font-size: 20px;
color: #f8f7fd;
text-align: center;
}
@keyframes SiffrinShine {
0% {background-position: 110%;}
60% {background-position: -90%;}
100% {background-position: -90%;}
}
导入三个:
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>
JS:
function initiateSmoke() {
smokeBackgrounds = document.getElementsByClassName('SiffrinSmoke');
clock = new THREE.Clock();
renderW = smokeBackgrounds[0].offsetWidth;
renderH = smokeBackgrounds[0].offsetHeight;
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize( renderW, renderH );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, renderW / renderH , 1, 10000 );
camera.position.z = 1300;
scene.add( camera );
geometry = new THREE.CubeGeometry( 200, 200, 200 );
material = new THREE.MeshLambertMaterial( { color: 0xaa6666, wireframe: false } );
mesh = new THREE.Mesh( geometry, material );
cubeSineDriver = 0;
textGeo = new THREE.PlaneGeometry(300,300);
THREE.ImageUtils.crossOrigin = ''; //Need this to pull in crossdomain images from AWS
light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(-1,0,1);
scene.add(light);
smokeTexture = THREE.ImageUtils.loadTexture('https://s3-us-west-2.amazonaws.com/s.cdpn.io/95637/Smoke-Element.png');
smokeMaterial = new THREE.MeshLambertMaterial({color: 0x333333, opacity: 1, map: smokeTexture, transparent: true});
smokeGeo = new THREE.PlaneGeometry(650,650);
smokeParticles = [];
for (p = 0; p < 36; p++) {
particle = new THREE.Mesh(smokeGeo,smokeMaterial);
particle.position.set(Math.random() * 950 - 500, Math.random() * 620 - 300, Math.random() * 200 - 100);
particle.rotation.z = Math.random() * 360;
particle.scale.set(2,2,2);
scene.add(particle);
smokeParticles.push(particle);
}
for(i = 0; i < smokeBackgrounds.length; i++) {
smokeBackgrounds[i].appendChild( renderer.domElement );
}
}
function animateSmoke() {
// note: three.js includes requestAnimationFrame shim
delta = clock.getDelta();
requestAnimationFrame( animateSmoke );
evolveSmoke();
render();
}
function evolveSmoke() {
var sp = smokeParticles.length;
while(sp--) {
smokeParticles[sp].rotation.z += (delta * 0.2);
}
}
function render() {
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
cubeSineDriver += .01;
mesh.position.z = 100 + (Math.sin(cubeSineDriver) * 500);
renderer.render( scene, camera );
}
window.onload = function Snowfall(){
initiateSmoke();
animateSmoke();
}
您知道如何为具有 class 的每个元素应用与背景相同的效果吗?也许另一个工具更适合这项工作?
编辑:解决方案
Smoke init函数接受之前的背景元素和returns个相关对象
function initiateSmoke(smokeBackground) {
[...]
return({
"renderer": renderer,
"scene": scene,
"camera": camera,
"mesh": mesh,
"cubeSineDriver": cubeSineDriver,
"smokeParticles": smokeParticles
})
}
然后在window.onloadI有这个循环
smokeBackgrounds = document.getElementsByClassName('SiffrinSmoke');
for(i = 0; i < smokeBackgrounds.length; i++) {
smokeScenes[i] = initiateSmoke(smokeBackgrounds[i]);
smokeBackgrounds[i].appendChild(smokeScenes[i]['renderer'].domElement);
}
animateSmoke();
我还编辑了动画函数
function animateSmoke() {
delta = clock.getDelta();
requestAnimationFrame(animateSmoke);
evolveSmoke();
render();
}
function evolveSmoke() {
for(i = 0; i < smokeScenes.length; i++) {
smokeScene = smokeScenes[i];
var sp = smokeScene['smokeParticles'].length;
while(sp--) {
smokeScene['smokeParticles'][sp].rotation.z += (delta * 0.2);
}
}
}
function render() {
for(i = 0; i < smokeScenes.length; i++) {
smokeScene = smokeScenes[i];
smokeScene['mesh'].rotation.x += 0.005;
smokeScene['mesh'].rotation.y += 0.01;
smokeScene['cubeSineDriver'] += .01;
smokeScene['mesh'].position.z = 100 + (Math.sin(smokeScene['cubeSineDriver']) * 500);
smokeScene['renderer'].render( smokeScene['scene'], smokeScene['camera']);
}
}
let smokeScenes = []
let clock = new THREE.Clock();
这很有效!
这是因为您只创建了一个 canvas,并将其附加到循环中的每个“smokeBackgrounds”。但是每一个都会覆盖最后一个,因为只有一个 canvas (renderer.domElement).
有几种方法可以解决它:
- 在此代码之外创建一个循环,循环通过 smokeBackgrounds,并调用 initiateSmoke(smokeBackgrounds[i]),然后将该循环更改为使用 passed-in dom元素。
- 克隆 canvas 本身,并为每个新实例分配一个 smokeBackgrounds。
- (困难)在代码中创建多个 threejs 场景,并在页面上为每个场景分配一个位置。通过这种方式,您可以将 canvas 拉伸到 full-page,只需移动烟雾位置即可与 HTML 元素所在的位置相关联。这样做的好处是它更轻,因为你不会有多个 canvas 的 运行.
我正在尝试为论坛网站创建自定义 post 页眉背景。但是因为我总是想让我的生活变得更加艰难,所以我试图让它变得花哨。我还需要 link 每个 post.
中的那个脚本当我复制 post(或仅通过 ctrl+a ctrl+c ctrl+v ctrl+v HTMP 代码模拟它)时,只有最后一个 post 获得任何烟雾效果背景。我试图在初始化时将函数添加到 window 并使用 SiffrinSmoke class 为每个元素循环它,但仍然只显示一根烟雾 - 在底部。
HTML:
<div class="SiffrinBody">
<div class="SiffrinHeader">
<div class="SiffrinSmoke">
<!--h1>Siffrin<br>Drauglir</h1-->
<h1 data-heading="Siffrin
Drauglir"></h1>
</div>
<div class="SiffrinCanvasBackground" id="SiffrinCanvasBackground"></div>
<div class="SiffrinCanvasForeground" id="SiffrinCanvasForeground"></div>
<img id="SiffrinHeaderBackground" src="https://i.imgur.com/iYnkBdZ.jpg">
<img id="SiffrinWolf" src="https://i.imgur.com/MBLqG00.png">
</div>
</div>
CSS:
@import url('https://fonts.googleapis.com/css2?family=Arvo:ital@0;1&family=Carter+One&family=Dosis:wght@400;500;600&display=swap');
.SiffrinBody .SiffrinHeader .SiffrinCanvasBackground{
height: 330px;
width: 656px;
position: absolute;
left: inherit;
top: inherit;
z-index: 5;
}
.SiffrinBody .SiffrinHeader .SiffrinCanvasForeground{
height: 330px;
width: 656px;
position: absolute;
left: inherit;
top: inherit;
z-index: 7;
}
.SiffrinBody .SiffrinHeader img{
position: absolute;
height: 330px;
width: 656px;
grid-row: 1;
}
.SiffrinBody .SiffrinHeader .SiffrinSmoke{
width: 328px;
height: 330px;
position: relative;
z-index: 6;
float: right;
display: block;
}
.SiffrinBody .SiffrinHeader .SiffrinSmoke canvas{
position: absolute;
top: 0;
left: 0;
z-index: -4;
}
.SiffrinBody .SiffrinHeader #SiffrinHeaderBackground{
z-index: 4;
}
.SiffrinBody .SiffrinHeader #SiffrinWolf{
z-index: 6;
}
.SiffrinBody .SiffrinHeader h1{
font-family: Carter One;
z-index: 1000;
color: white;
grid-column: 2;
font-size: 50;
margin-top: 32%;
text-align: center;
background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/209981/6963bbf342d87b3a2150bd8f59682b89.jpg);
-webkit-background-clip: text;
background-size: cover;
width: 100%;
color: transparent;
font-weight: 900;
display: block;
white-space: pre-wrap !important;
line-height: 1.1em;
text-shadow: 2px 2px 6px rgba(46,146,211,0.8);
}
.SiffrinBody .SiffrinHeader h1::before{
content: attr(data-heading);
position: relative;
left: 0;
top: 0;
width: 100%;
background: linear-gradient(45deg, rgba(255,255,255,0) 45%,rgba(255,255,255,0.8) 50%,rgba(255,255,255,0) 55%,rgba(255,255,255,0) 100%);
-webkit-background-clip: text;
color: transparent;
mix-blend-mode: screen;
animation: SiffrinShine 15s infinite linear;
background-size: 200%;
}
.SiffrinBody .SiffrinHeader #SiffrinName{
z-index: 22;
transform: scale(0.8);
left: 150px;
}
.SiffrinBody .SiffrinHeader{
grid-row: 1;
mask-image: linear-gradient(
to top,
rgba(255, 255, 255, 0) 0,
rgba(255, 255, 255, 1) 15px
);
}
.SiffrinBody .SiffrinHeader > *{
user-select: none;
}
.SiffrinBody{
color: white;
display: grid;
grid-template-rows: 330px auto auto;
grid-template-columns: 1fr;
margin: 0;
padding: 0;
width: 656px;
/*background-image: linear-gradient(#bad4eb, #bad4eb, #a7c8e7, #4789c6, #037ccf);*/
background-image: url("https://i.imgur.com/UqFcRzS.jpg");
background-repeat: repeat;
}
.SiffrinBody *::selection{
background: rgba(225, 0, 255, 0.3);
color: inherit;
}
.SiffrinBody .SiffrinHeader{
/*
z-index: 7;
text-align: center;
font-family: Oleo Script;
margin: auto;
font-size: 30px;
transition-duration: 2s;
transition-timing-function: ease-in-out;
background-image: radial-gradient(#0e111800, #232b3e00, #24212a00, #403b6600);
user-select: none;
*/
}
.SiffrinBody .SiffrinBody:hover .SiffrinHeader{
/*
letter-spacing: 0.35em;
transition-duration: 3s;
transition-timing-function: ease-in-out;
transform: translate(0px, 40px);
*/
}
.SiffrinBody .SiffrinText{
z-index: 7;
margin: 10px 50px;
padding: 20px;
background-color: rgba(0, 0, 0, 0.5);
font-family: Dosis;
font-size: 17px;
margin-bottom: 0;
line-height: 1.235em;
font-weight: 500;
}
.SiffrinBody .SiffrinText::before{
border-top: 3px solid blue;
border-right: 3px solid blue;
}
.SiffrinBody .SiffrinText::after{
border-bottom: 3px solid orange;
border-left: 3px solid orange;
}
.SiffrinBody .SiffrinText p{
padding: 0;
margin-bottom: 1em;
}
.SiffrinBody .SiffrinText p u,
.SiffrinBody .SiffrinText p i,
.SiffrinBody .SiffrinText p q{
font-family: Arvo;
font-size: 16px;
}
.SiffrinBody .SiffrinText p u{
text-decoration: none;
color:rgb(250, 210, 255);
}
.SiffrinBody .SiffrinText p u::before {
content: "“"
}
.SiffrinBody.SiffrinText p u::after {
content: "”"
}
.SiffrinBody .SiffrinText p i{
font-family: Arvo;
color:rgb(250, 210, 255);
font-style: italic;
}
.SiffrinBody .SiffrinText p q{
text-decoration: none;
color:rgb(219, 223, 255);
}
.SiffrinBody .SiffrinText p:last-child{
margin: 0;
}
.SiffrinBody .SiffrinText p:first-child{
margin-top: 0;
}
.SiffrinBody .SiffrinFooter{
display: flex;
align-items: center;
justify-content: center;
padding: 10px;
margin: 0;
}
.SiffrinBody .SiffrinFooter p{
text-align: center;
font-size: 20px;
color: #f8f7fd;
text-align: center;
}
@keyframes SiffrinShine {
0% {background-position: 110%;}
60% {background-position: -90%;}
100% {background-position: -90%;}
}
导入三个:
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>
JS:
function initiateSmoke() {
smokeBackgrounds = document.getElementsByClassName('SiffrinSmoke');
clock = new THREE.Clock();
renderW = smokeBackgrounds[0].offsetWidth;
renderH = smokeBackgrounds[0].offsetHeight;
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize( renderW, renderH );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, renderW / renderH , 1, 10000 );
camera.position.z = 1300;
scene.add( camera );
geometry = new THREE.CubeGeometry( 200, 200, 200 );
material = new THREE.MeshLambertMaterial( { color: 0xaa6666, wireframe: false } );
mesh = new THREE.Mesh( geometry, material );
cubeSineDriver = 0;
textGeo = new THREE.PlaneGeometry(300,300);
THREE.ImageUtils.crossOrigin = ''; //Need this to pull in crossdomain images from AWS
light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(-1,0,1);
scene.add(light);
smokeTexture = THREE.ImageUtils.loadTexture('https://s3-us-west-2.amazonaws.com/s.cdpn.io/95637/Smoke-Element.png');
smokeMaterial = new THREE.MeshLambertMaterial({color: 0x333333, opacity: 1, map: smokeTexture, transparent: true});
smokeGeo = new THREE.PlaneGeometry(650,650);
smokeParticles = [];
for (p = 0; p < 36; p++) {
particle = new THREE.Mesh(smokeGeo,smokeMaterial);
particle.position.set(Math.random() * 950 - 500, Math.random() * 620 - 300, Math.random() * 200 - 100);
particle.rotation.z = Math.random() * 360;
particle.scale.set(2,2,2);
scene.add(particle);
smokeParticles.push(particle);
}
for(i = 0; i < smokeBackgrounds.length; i++) {
smokeBackgrounds[i].appendChild( renderer.domElement );
}
}
function animateSmoke() {
// note: three.js includes requestAnimationFrame shim
delta = clock.getDelta();
requestAnimationFrame( animateSmoke );
evolveSmoke();
render();
}
function evolveSmoke() {
var sp = smokeParticles.length;
while(sp--) {
smokeParticles[sp].rotation.z += (delta * 0.2);
}
}
function render() {
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
cubeSineDriver += .01;
mesh.position.z = 100 + (Math.sin(cubeSineDriver) * 500);
renderer.render( scene, camera );
}
window.onload = function Snowfall(){
initiateSmoke();
animateSmoke();
}
您知道如何为具有 class 的每个元素应用与背景相同的效果吗?也许另一个工具更适合这项工作?
编辑:解决方案 Smoke init函数接受之前的背景元素和returns个相关对象
function initiateSmoke(smokeBackground) {
[...]
return({
"renderer": renderer,
"scene": scene,
"camera": camera,
"mesh": mesh,
"cubeSineDriver": cubeSineDriver,
"smokeParticles": smokeParticles
})
}
然后在window.onloadI有这个循环
smokeBackgrounds = document.getElementsByClassName('SiffrinSmoke');
for(i = 0; i < smokeBackgrounds.length; i++) {
smokeScenes[i] = initiateSmoke(smokeBackgrounds[i]);
smokeBackgrounds[i].appendChild(smokeScenes[i]['renderer'].domElement);
}
animateSmoke();
我还编辑了动画函数
function animateSmoke() {
delta = clock.getDelta();
requestAnimationFrame(animateSmoke);
evolveSmoke();
render();
}
function evolveSmoke() {
for(i = 0; i < smokeScenes.length; i++) {
smokeScene = smokeScenes[i];
var sp = smokeScene['smokeParticles'].length;
while(sp--) {
smokeScene['smokeParticles'][sp].rotation.z += (delta * 0.2);
}
}
}
function render() {
for(i = 0; i < smokeScenes.length; i++) {
smokeScene = smokeScenes[i];
smokeScene['mesh'].rotation.x += 0.005;
smokeScene['mesh'].rotation.y += 0.01;
smokeScene['cubeSineDriver'] += .01;
smokeScene['mesh'].position.z = 100 + (Math.sin(smokeScene['cubeSineDriver']) * 500);
smokeScene['renderer'].render( smokeScene['scene'], smokeScene['camera']);
}
}
let smokeScenes = []
let clock = new THREE.Clock();
这很有效!
这是因为您只创建了一个 canvas,并将其附加到循环中的每个“smokeBackgrounds”。但是每一个都会覆盖最后一个,因为只有一个 canvas (renderer.domElement).
有几种方法可以解决它:
- 在此代码之外创建一个循环,循环通过 smokeBackgrounds,并调用 initiateSmoke(smokeBackgrounds[i]),然后将该循环更改为使用 passed-in dom元素。
- 克隆 canvas 本身,并为每个新实例分配一个 smokeBackgrounds。
- (困难)在代码中创建多个 threejs 场景,并在页面上为每个场景分配一个位置。通过这种方式,您可以将 canvas 拉伸到 full-page,只需移动烟雾位置即可与 HTML 元素所在的位置相关联。这样做的好处是它更轻,因为你不会有多个 canvas 的 运行.