うにょうにょ動かす(HTML/CSS/JS)
前書き
うにょうにょ動かす方法を掲載しています。
目次
- 波線(平面)
- 波(平面)
- 丸
- 丸(重ねる)
- 波線(立体)
- 波(立体)
- 球
- 参考
波線
2つのパスを用意して、svgのanimate要素を使って動かしています。
2つのパス
<svg class="svg" width="720" height="10">
<path d="M 0 5 Q 10 10 20 5 Q 30 0 40 5" fill="none" stroke="#845080" stroke-width="2" />
</svg>
<svg class="svg" width="720" height="10">
<path d="M 0 5 Q 10 0 20 5 Q 30 10 40 5" fill="none" stroke="#845080" stroke-width="2" />
</svg>
.svg{ max-width: 100%; }
動かす
<svg class="svg" width="720" height="10">
<path d="M 0 5 Q 10 10 20 5 Q 30 0 40 5" fill="none" stroke="#845080" stroke-width="2">
<!-- d属性の値を変化させる -->
<animate
attributeName="d"
dur="2s"
repeatCount="indefinite"
values="M 0 5 Q 10 10 20 5 Q 30 0 40 5;
M 0 5 Q 10 0 20 5 Q 30 10 40 5;
M 0 5 Q 10 10 20 5 Q 30 0 40 5" />
</path>
</svg>
繰り返し
<svg class="svg" width="720" height="10">
<!-- パターンを定義 -->
<defs>
<pattern id="ptn_nami11" x="0" y="0" width="40" height="10" patternUnits="userSpaceOnUse">
<path d="M 0 5 Q 10 10 20 5 Q 30 0 40 5" fill="none" stroke="#845080" stroke-width="2">
<animate
attributeName="d"
dur="2s"
repeatCount="indefinite"
values="M 0 5 Q 10 10 20 5 Q 30 0 40 5;
M 0 5 Q 10 0 20 5 Q 30 10 40 5;
M 0 5 Q 10 10 20 5 Q 30 0 40 5" />
</path>
</pattern>
</defs>
<!-- パターンで塗りつぶす -->
<rect x="0" y="0" width="100%" height="100%" fill="url(#ptn_nami11)"></rect>
</svg>
左右に動かす
<svg class="svg" width="720" height="30">
<defs>
<!-- パス共通(左右に広げている) -->
<path d="中略" id="path_nami12" fill="none" stroke-width="2">
<animate
attributeName="d"
dur="2s"
repeatCount="indefinite"
values="M -40 5 Q -30 10 -20 5 Q -10 0 0 5 Q 10 10 20 5 Q 30 0 40 5 Q 50 10 60 5 Q 70 0 80 5;
M -40 5 Q -30 0 -20 5 Q -10 10 0 5 Q 10 0 20 5 Q 30 10 40 5 Q 50 0 60 5 Q 70 10 80 5;
M -40 5 Q -30 10 -20 5 Q -10 0 0 5 Q 10 10 20 5 Q 30 0 40 5 Q 50 10 60 5 Q 70 0 80 5;" />
</path>
<!-- パターン(use属性でパスを使い回す。パターンのx属性の値を変化させる) -->
<!-- 一つ目(右に移動) -->
<pattern id="ptn_nami12_a" x="0" y="0" width="40" height="10" patternUnits="userSpaceOnUse">
<use href="#path_nami12" stroke="#a675a5" />
<animate
attributeName="x"
dur="2s"
repeatCount="indefinite"
values="0; 40"/>
</pattern>
<!-- 二つ目(左に移動) -->
<pattern id="ptn_nami12_b" x="0" y="0" width="40" height="10" patternUnits="userSpaceOnUse">
<use href="#path_nami12" stroke="#845080" />
<animate
attributeName="x"
dur="2s"
repeatCount="indefinite"
values="0; -40"/>
</pattern>
<!-- 三つ目(行ったり来たり) -->
<pattern id="ptn_nami12_c" x="0" y="0" width="40" height="10" patternUnits="userSpaceOnUse">
<use href="#path_nami12" stroke="#a675a5" />
<animate
attributeName="x"
dur="4s"
repeatCount="indefinite"
values="0; 40; 0"/>
</pattern>
</defs>
<!-- パターンで塗りつぶす -->
<rect x="0" y="0" width="720" height="10" fill="url(#ptn_nami12_a)"></rect>
<rect x="0" y="10" width="720" height="10" fill="url(#ptn_nami12_b)"></rect>
<rect x="0" y="20" width="720" height="10" fill="url(#ptn_nami12_c)"></rect>
</svg>
波(平面)
2つのパスを用意して、svgのanimate要素を使って動かしています。
2つのパス
<svg class="svg" width="720" height="30">
<path d="M 0 10 Q 10 20 20 10 Q 30 0 40 10 V 30 H 0 Z" fill="#845080" />
</svg>
<svg class="svg" width="720" height="30">
<path d="M 0 10 Q 10 0 20 10 Q 30 20 40 10 V 30 H 0 Z" fill="#845080" />
</svg>
動かす
<svg class="svg" width="720" height="30">
<!-- d属性の値を変化させる -->
<path d="M 0 10 Q 10 20 20 10 Q 30 0 40 10 V 30 H 0 Z" fill="#845080" >
<animate
attributeName="d"
dur="2s"
repeatCount="indefinite"
values="M 0 10 Q 10 20 20 10 Q 30 0 40 10 V 30 H 0 Z;
M 0 10 Q 10 0 20 10 Q 30 20 40 10 V 30 H 0 Z;
M 0 10 Q 10 20 20 10 Q 30 0 40 10 V 30 H 0 Z" />
</path>
</svg>
繰り返し
<svg class="svg" width="720" height="30">
<!-- パターンを定義 -->
<defs>
<pattern id="ptn_nami21" x="0" y="0" width="40" height="50" patternUnits="userSpaceOnUse">
<path d="M 0 10 Q 10 20 20 10 Q 30 0 40 10 V 30 H 0 Z" fill="#845080" >
<animate
attributeName="d"
dur="2s"
repeatCount="indefinite"
values="M 0 10 Q 10 20 20 10 Q 30 0 40 10 V 30 H 0 Z;
M 0 10 Q 10 0 20 10 Q 30 20 40 10 V 30 H 0 Z;
M 0 10 Q 10 20 20 10 Q 30 0 40 10 V 30 H 0 Z" />
</path>
</pattern>
</defs>
<!-- パターンで塗りつぶす -->
<rect x="0" y="0" width="100%" height="100%" fill="url(#ptn_nami21)"></rect>
</svg>
左右に動かす
<svg class="svg" width="720" height="50">
<defs>
<!-- パス共通(左右に広げている。微調整) -->
<path id="path_nami22" d="中略">
<animate id="animate_nami22"
attributeName="d"
dur="2s"
repeatCount="indefinite"
values="M -40 10 Q -30 20 -20 10 Q -10 0 0 10 Q 10 20 20 10 Q 30 0 40 10 Q 50 20 60 10 Q 70 20 80 10 V 29 H -40 Z;
M -40 10 Q -30 0 -20 10 Q -10 20 0 10 Q 10 0 20 10 Q 30 20 40 10 Q 50 0 60 10 Q 70 0 80 10 V 29 H -40 Z;
M -40 10 Q -30 20 -20 10 Q -10 0 0 10 Q 10 20 20 10 Q 30 0 40 10 Q 50 20 60 10 Q 70 20 80 10 V 29 H -40 Z;" />
</path>
<!-- 奥(行ったり来たり) -->
<pattern id="ptn_nami22_a" x="0" y="0" width="40" height="30" patternUnits="userSpaceOnUse" >
<use href="#path_nami22" fill="#e7d4e3" />
<animate
attributeName="x"
dur="4s"
repeatCount="indefinite"
values="0; 40; 0"/>
</pattern>
<!-- 中(左に移動) -->
<pattern id="ptn_nami22_b" x="0" y="10" width="40" height="40" patternUnits="userSpaceOnUse">
<use href="#path_nami22" fill="#a675a5" />
<animate
attributeName="x"
dur="2s"
repeatCount="indefinite"
values="0; -40"/>
</pattern>
<!-- 手前(右に移動) -->
<pattern id="ptn_nami22_c" x="0" y="20" width="40" height="50" patternUnits="userSpaceOnUse">
<use href="#path_nami22" fill="#845080" />
<animate
attributeName="x"
dur="2s"
repeatCount="indefinite"
values="0; 40"/>
</pattern>
</defs>
<!-- パターンで塗りつぶす、大きさ調整 -->
<rect x="0" y="0" width="720" height="30" fill="url(#ptn_nami22_a)"></rect>
<rect x="0" y="0" width="480" height="40" fill="url(#ptn_nami22_b)" transform="scale(1.5,1)"></rect>
<rect x="0" y="0" width="360" height="50" fill="url(#ptn_nami22_c)" transform="scale(2,1)"></rect>
</svg>
丸
SVG
3つのパスを用意して、svgのanimate要素でpathを変化させています。また、要素を回転させています。
<svg class="svg" viewBox="0 0 500 500">
<!-- グラデーション -->
<defs>
<radialGradient id="svg03_gradient">
<stop offset="0%" stop-color = "#e7d4e3"></stop>
<stop offset="100%" stop-color = "#845080"></stop>
</radialGradient >
</defs>
<!-- パス d属性を変化させる。回転させる。 -->
<path d="中略" fill="url(#svg03_gradient)">
<animate
attributeName="d"
dur="20s"
repeatCount="indefinite"
values="中略; 中略; 中略; 中略;" />
<animateTransform
attributeName="transform"
type="rotate"
dur="12s"
repeatCount="indefinite"
from="0,250,250"
to="360,250,250"/>
</path>
</svg>
CSS
cssで角丸の値を変化させています。また、要素を回転させています。
<div class="css-circle"></div>
.css-circle{
border-radius: 55% 45% 74% 26% / 66% 32% 68% 34%;
background-image: radial-gradient(#e7d4e3 0%, 845080 100%);
animation-name: corners, rotate;
animation-duration: 20s, 12s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
@keyframes corners {
0% { border-radius: 55% 45% 74% 26% / 66% 32% 68% 34%; }
25% { border-radius: 33% 67% 44% 56% / 28% 56% 44% 72%; }
50% { border-radius: 29% 71% 37% 63% / 55% 40% 60% 45%; }
75% { border-radius: 53% 47% 53% 47% / 49% 63% 37% 51%; }
100% { border-radius: 55% 45% 74% 26% / 66% 32% 68% 34%; }
}
@keyframes rotate {
0% { transform: rotate(0deg);}
100% { transform: rotate(360deg)}
}
丸(重ねる)
SVG
丸を3つ重ねて、各々を回転させています。描画モードは乗算にしています。
<svg class="svg" viewBox="0 0 500 500">
<!-- パスを定義 d属性を変化させる -->
<defs>
<path id="path_circle01" d="中略">
<animate
attributeName="d"
dur="20s"
repeatCount="indefinite"
values="中略; 中略; 中略; 中略;" />
</path>
</defs>
<!-- 回転をそれぞれ設定 -->
<use class="use-circle01" href="#path_circle01">
<animateTransform
attributeName="transform"
type="rotate"
dur="12s"
repeatCount="indefinite"
from="0,250,250"
to="360,250,250"/>
</use>
<use class="use-circle01" href="#path_circle01">
<animateTransform
attributeName="transform"
type="rotate"
dur="12s"
repeatCount="indefinite"
from="60,250,250"
to="-300,250,250"/>
</use>
<use class="use-circle01" href="#path_circle01">
<animateTransform
attributeName="transform"
type="rotate"
dur="12s"
repeatCount="indefinite"
from="-60,250,250"
to="300,250,250"/>
</use>
</svg>
.use-circle01{
fill: #e7d4e3; mix-blend-mode: multiply;
}
CSS
丸を3つ重ねて、各々を回転させています。描画モードは乗算にしています。
<div class="css-circle-wrap">
<div class="css-circle-b css-circle-b01"></div>
<div class="css-circle-b css-circle-b02"></div>
<div class="css-circle-b css-circle-b03"></div>
</div>
.css-circle-wrap{
position: relative;
}
.css-circle-b{
border-radius: 55% 45% 74% 26% / 66% 32% 68% 34%;
background: #e7d4e3; mix-blend-mode: multiply;
animation-name: corners, rotate;
animation-duration: 20s, 12s;
animation-timing-function: linear;
animation-iteration-count: infinite;
&02{
position: absolute; top: 0; left: 0; right: 0; margin: auto;
animation-name: corners, rotate02;
}
&03{
position: absolute; top: 0; left: 0; right: 0; margin: auto;
animation-name: corners, rotate03;
}
}
@keyframes corners {
0% { border-radius: 55% 45% 74% 26% / 66% 32% 68% 34%; }
25% { border-radius: 33% 67% 44% 56% / 28% 56% 44% 72%; }
50% { border-radius: 29% 71% 37% 63% / 55% 40% 60% 45%; }
75% { border-radius: 53% 47% 53% 47% / 49% 63% 37% 51%; }
100% { border-radius: 55% 45% 74% 26% / 66% 32% 68% 34%; }
}
@keyframes rotate {
0% { transform: rotate(0deg);}
100% { transform: rotate(360deg);}
}
@keyframes rotate02 {
0% { transform: rotate(60deg);}
100% { transform: rotate(-300deg);}
}
@keyframes rotate03 {
0% { transform: rotate(-60deg);}
100% { transform: rotate(300deg);}
}
波線(立体)
下記ページを参考にthree.jsを使って表示しています。
Three.jsでラインアニメーション
概要
- 線を作成する
- 各頂点において、パーリンノイズを生成して、y座標を変化させる
見本
<div class="wrap js-wrap-c">
<canvas class="canvas js-canvas03"></canvas>
</div>
<script src="./perlin.js"></script>
.wrap{
position: relative; padding: 50% 0 0; overflow: hidden;
}
.canvas{
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
}
import * as THREE from './three_r127/build/three.module.js';
import { OrbitControls } from './three_r127/examples/jsm/controls/OrbitControls.js';
// サイズ------------------
const wrap = document.querySelector(".js-wrap-c");
let wrapWidth = wrap.clientWidth;
let wrapHeight = wrap.clientHeight;
// レンダラー------------------
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector(".js-canvas03"),
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(wrapWidth, wrapHeight);
// シーン------------------
const scene = new THREE.Scene();
scene.background = new THREE.Color( 0xf5edf3 ); //背景色
// カメラ------------------
const camera = new THREE.PerspectiveCamera(45, wrapWidth / wrapHeight);
camera.position.set(-100, 50, 200);
camera.lookAt(new THREE.Vector3(0, 0, 0));
// カメラコントローラーを作成
const controls = new OrbitControls( camera, renderer.domElement );
// 線------------------
const lineNum = 30; //線の数
const lineLength = 500; //線の長さ
const lineSegment = 100; //線の分割数
const lineSpace = 15 //線の間隔
const noiseScale = 5 / 100; //ノイズの大きさ
const amplitude = 100; //振り幅
//グループを作成
const lineGroup = new THREE.Group();
lineGroup.position.x = - lineLength / 2; //中心に寄せる
lineGroup.position.z = - lineNum * lineSpace / 2; //中心に寄せる
scene.add(lineGroup);
for(let i = 0; i < lineNum; i++){
//頂点
const points = [];
for(let j = 0; j <= lineSegment; j++){
const x = j / lineSegment * lineLength;
const y = 0;
const z = i * lineSpace;
const p = new THREE.Vector3(x,y,z);
points.push(p);
}
const line = new THREE.Line(
new THREE.BufferGeometry().setFromPoints(points),
new THREE.LineBasicMaterial()
);
// 色
const h = 305 / 360; //色相
const s = 100 / 100; //彩度
const l = Math.round((lineNum - i) / lineNum * 60 + 20 ) / 100; //輝度(20~80)
line.material.color.setHSL(h, s, l);
lineGroup.add( line );//グループに追加
}
// 頂点の位置を変える------------------
const positionUpdate = () =>{
const time = performance.now() * 0.00025;
for(let i = 0; i < lineNum; i++){
const line = lineGroup.children[i];
const positions = line.geometry.attributes.position.array;
for(let j = 0; j <= lineSegment; j++){
const pn = noise.perlin2( i * noiseScale + time , j * noiseScale + time); //パーリンノイズ
positions[j * 3 + 1] = amplitude * pn; //y座標(振り幅 × パーリンノイズ)
}
line.geometry.attributes.position.needsUpdate = true;
}
}
//リサイズ------------------
const wrapResize = () =>{
wrapWidth = wrap.clientWidth;
wrapHeight = wrap.clientHeight;
renderer.setSize(wrapWidth, wrapHeight);
// camera.aspect = wrapWidth / wrapHeight;
// camera.updateProjectionMatrix();
}
//一定時間毎に処理------------------
let tick;
const switching = (e) => {
if( e[0].isIntersecting ){ //見えてる時
tick = () => {
wrapResize(); //リサイズ
positionUpdate(); //頂点の位置を更新
renderer.render(scene, camera); //レンダリング
requestAnimationFrame( tick ); //繰り返し
}
requestAnimationFrame( tick );
}else{ //見えてない時
tick = () => {
cancelAnimationFrame( tick )
}
}
}
//見えているかどうか(Intersection Observer API)------------------
const createObserver = () => {
let observer;
const options = { root: null, rootMargin: "0%", threshold: 0 };
observer = new IntersectionObserver(switching, options); //コールバック関数とオプションを渡す
observer.observe(wrap); //要素の監視を開始
}
createObserver();
波(立体)
下記ページを参考にthree.jsを使って表示しています。
three.js の PlaneGeometry で地形を作る
概要
- 平面を作成する
- canvasでグラデーションを作成して、平面に貼り付ける
- 各頂点において、パーリンノイズを生成して、z座標を変化させる
見本
<div class="wrap js-wrap-b">
<canvas class="canvas js-canvas02"></canvas>
</div>
<script src="./perlin.js"></script>
.wrap{
position: relative; padding: 50% 0 0; overflow: hidden;
}
.canvas{
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
}
import * as THREE from './three_r127/build/three.module.js';
import { OrbitControls } from './three_r127/examples/jsm/controls/OrbitControls.js';
// サイズ------------------
const wrap = document.querySelector(".js-wrap-b");
let wrapWidth = wrap.clientWidth;
let wrapHeight = wrap.clientHeight;
// レンダラー------------------
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector(".js-canvas02"),
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(wrapWidth, wrapHeight);
// シーン------------------
const scene = new THREE.Scene();
scene.background = new THREE.Color( 0xf5edf3 ); //背景色
// カメラ------------------
const camera = new THREE.PerspectiveCamera(45, wrapWidth / wrapHeight);
camera.position.set(-100, 150, 500);
camera.lookAt(new THREE.Vector3(0, 0, 0));
// カメラコントローラーを作成
const controls = new OrbitControls( camera, renderer.domElement );
controls.minPolarAngle = 0;
controls.maxPolarAngle = Math.PI / 2;
// 光源------------------
const dLight = new THREE.DirectionalLight(0xffffff, 1); // 平行光源
scene.add(dLight);
// 波 ------------------
//グラデーションの準備
const canvas = document.createElement("canvas");
canvas.width = 100;
canvas.height = 100;
const context = canvas.getContext("2d");
context.beginPath();
const grad = context.createLinearGradient(0,0,0,100);
grad.addColorStop(0,"rgba(231,212,227,1)");
grad.addColorStop(0.7,"rgba(57,7,53,1)");
grad.addColorStop(1,"rgba(57,7,53,1)");
context.fillStyle = grad;
context.rect(0,0,100,100);
context.fill();
const texture = new THREE.CanvasTexture(canvas);
//メッシュ
const ground = new THREE.Mesh(
new THREE.PlaneGeometry(4000, 4000, 75, 75),
new THREE.MeshStandardMaterial( { map: texture } ),
);
ground.rotation.x = Math.PI / -2;
scene.add( ground );
// 頂点の位置を変える------------------
const count = ground.geometry.attributes.position.count; //頂点の数
const positions = ground.geometry.attributes.position.array; //頂点の座標
const noiseScale = 10 / 4000; //ノイズの大きさ
const unevenness = 150; //凸凹の大きさ
const positionUpdate = () =>{
const time = performance.now() * 0.0005;
for(let i = 0; i < count; i++){
const x = positions[i*3]; //x座標
const y = positions[i*3+1]; //y座標
const pn = noise.perlin2( x * noiseScale + time , y * noiseScale + time); // パーリンノイズ
positions[i*3+2] = unevenness * pn; //z座標(凸凹の大きさ×パーリンノイズ)
}
ground.geometry.attributes.position.needsUpdate = true;
ground.geometry.computeVertexNormals();
}
//リサイズ------------------
const wrapResize = () =>{
wrapWidth = wrap.clientWidth;
wrapHeight = wrap.clientHeight;
renderer.setSize(wrapWidth, wrapHeight);
// camera.aspect = wrapWidth / wrapHeight;
// camera.updateProjectionMatrix();
}
//一定時間毎に処理------------------
let tick;
const switching = (e) => {
if( e[0].isIntersecting ){ //見えてる時
tick = () => {
wrapResize(); //リサイズ
positionUpdate(); //頂点の位置を更新
renderer.render(scene, camera); //レンダリング
requestAnimationFrame( tick ); //繰り返し
}
requestAnimationFrame( tick );
}else{ //見えてない時
tick = () => {
cancelAnimationFrame( tick )
}
}
}
//見えているかどうか(Intersection Observer API)------------------
const createObserver = () => {
let observer;
const options = { root: null, rootMargin: "0%", threshold: 0 };
observer = new IntersectionObserver(switching, options); //コールバック関数とオプションを渡す
observer.observe(wrap); //要素の監視を開始
}
createObserver();
球
下記ページを参考にthree.jsを使って表示しています。
球体の頂点アニメーション
概要
- 球体を作成する
- 各頂点において、パーリンノイズを生成して、x,y,z座標を変化させる
見本
<div class="wrap js-wrap-a">
<canvas class="canvas js-canvas"></canvas>
</div>
<script src="./perlin.js"></script>
.wrap{
position: relative; padding: 50% 0 0; overflow: hidden;
}
.canvas{
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
}
import * as THREE from './three_r127/build/three.module.js';
import { OrbitControls } from './three_r127/examples/jsm/controls/OrbitControls.js';
// サイズ------------------
const wrap = document.querySelector(".js-wrap-a");
let wrapWidth = wrap.clientWidth;
let wrapHeight = wrap.clientHeight;
// レンダラー------------------
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector(".js-canvas"),
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(wrapWidth, wrapHeight);
// シーン------------------
const scene = new THREE.Scene();
scene.background = new THREE.Color( 0xf5edf3 ); //背景色
scene.fog = new THREE.Fog(0xf5edf3, 500, 2200); //フォグ
// カメラ------------------
const camera = new THREE.PerspectiveCamera(45, wrapWidth / wrapHeight);
camera.position.set(250, 250, 250);
// カメラコントローラーを作成
const controls = new OrbitControls( camera, renderer.domElement );
// 光源------------------
const dLight = new THREE.DirectionalLight(0xffffff, 1); // 平行光源
dLight.position.set(1, 1, 1);
scene.add(dLight);
const hLight = new THREE.HemisphereLight(0xffffff, 0.5); // 半球光源
scene.add(hLight);
// 物体------------------
//地面
const ground = new THREE.LineSegments(
new THREE.WireframeGeometry(
new THREE.PlaneGeometry(4000, 4000, 75, 75),
),
new THREE.LineBasicMaterial({color: 0x845080, transparent:true, opacity:0.25}),
);
ground.rotation.x = Math.PI / -2;
scene.add( ground );
//球体
const radius = 100; //球体の半径
const ball = new THREE.Mesh(
new THREE.SphereGeometry(radius, 60, 40),
new THREE.MeshPhongMaterial( { color: 0x845080 ,transparent:true, opacity:0.75} ),
);
ball.position.y = 125;
scene.add(ball);
camera.lookAt(ball.position); //カメラの向き
controls.target.set( ball.position.x, ball.position.y, ball.position.z); //カメラコントローラーの向き
// 頂点の位置を変える------------------
const count = ball.geometry.attributes.position.count; //頂点の数
const positions = ball.geometry.attributes.position.array; //頂点の座標
const noiseScale = 1.2; //ノイズの大きさ
const unevenness = radius * 0.1; //凸凹の大きさ
const positionUpdate = () =>{
const time = performance.now() * 0.0005;
for(let i = 0; i < count; i++){
const p = new THREE.Vector3(
positions[i*3],
positions[i*3+1],
positions[i*3+2]
);
// 単位ベクトルに変換
p.normalize();
// パーリンノイズ
const pn = noise.perlin3( p.x * noiseScale + time, p.y * noiseScale + time, p.z * noiseScale + time);
// 拡縮( 半径 + 凹凸の大きさ * パーリンノイズ )
p.multiplyScalar( radius + unevenness * pn );
positions[i*3] = p.x
positions[i*3+1] = p.y
positions[i*3+2] = p.z;
}
ball.geometry.attributes.position.needsUpdate = true;
ball.geometry.computeVertexNormals();
}
//リサイズ------------------
const wrapResize = () =>{
wrapWidth = wrap.clientWidth;
wrapHeight = wrap.clientHeight;
renderer.setSize(wrapWidth, wrapHeight);
// camera.aspect = wrapWidth / wrapHeight;
// camera.updateProjectionMatrix();
}
//一定時間毎に処理------------------
let tick;
const switching = (e) => {
if( e[0].isIntersecting ){ //見えてる時
tick = () => {
wrapResize(); //リサイズ
positionUpdate(); //頂点の位置を更新
renderer.render(scene, camera); //レンダリング
requestAnimationFrame( tick ); //繰り返し
}
requestAnimationFrame( tick );
}else{ //見えてない時
tick = () => {
cancelAnimationFrame( tick )
}
}
}
//見えているかどうか(Intersection Observer API)------------------
const createObserver = () => {
let observer;
const options = { root: null, rootMargin: "0%", threshold: 0 };
observer = new IntersectionObserver(switching, options); //コールバック関数とオプションを渡す
observer.observe(wrap); //要素の監視を開始
}
createObserver();
参考
CSSアニメーションで実現!コピペで使えるマイクロインタラクション
three.js の PlaneGeometry で地形を作る
[threejs] CanvasTextureでグラデーションテクスチャを貼る(1)
関連記事
マウスの位置に合わせて要素を動かす(HTML/CSS/JS)
この記事は役に立ちましたか?
送信中