Three.js 美丽的魔鬼之花罂粟

文化   2024-10-05 09:25   河南  

使用 Three.js 的 WebGL 小实验。美丽的魔鬼之花罂粟。

实现代码

HTML:

<script type="importmap">  {    "imports": {      "three": "https://unpkg.com/three@0.168.0/build/three.module.js",      "three/addons/": "https://unpkg.com/three@0.168.0/examples/jsm/"    }  }</script><canvas id="cnv"></canvas>
CSS:
body{  overflow: hidden;  margin: 0;  background-color: black;}

canvas { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); /*border: 1px solid red;*/}

JAVASCRIPT:

import {Vector2, Color, Clock} from 'three';import {SimplexNoise} from "three/addons/math/SimplexNoise.js";

console.clear();

let simplex = new SimplexNoise();

// https://www.color-meanings.com/neon-color-palettes/let palettes = [ ["#FC1FF9", "#BC0EEF", "#443061", "#E42536", "#FC5E31"], ["#B7239B", "#ED3DC6", "#FFE91A", "#FE5700", "#EA1104"], ["#FE02FF", "#DF21FF", "#8407CE", "#5F03BD", "#2F0049"].reverse(), ["#463F9E", "#F354A9", "#84F5D5", "#9B62E5", "#9D2EB0"], ["#221EB8", "#861CFF", "#EC14EE", "#1ECDE6", "#FB7443"].reverse(), ["#1B37AA", "#2572D9", "#A83A96", "#F0533C", "#DB3836"]]let basePalette = palettes[5];

let ctx = cnv.getContext("2d");let unit = 0;let u = val => unit * val;let resize = () => { let minVal = Math.min(innerWidth, innerHeight); cnv.width = cnv.height = minVal * 0.95; unit = cnv.height * 0.01;}window.addEventListener("resize", resize);resize();

let color = new Color();const palette = basePalette.map(pal => { let res = {h:0, s:0, l:0}; color.set(pal).getHSL(res); return res;});

const layersAmount = palette.length;const amountPerLayer = 30;const center = new Vector2();const ctxCenter = new Vector2(50, 50);let points = Array.from({length: amountPerLayer}, (_, pIdx) => { let v = new Vector2( Math.cos(pIdx * Math.PI / (amountPerLayer * 0.5)), Math.sin(pIdx * Math.PI / (amountPerLayer * 0.5)) ); return v;});let noisyPoints = Array.from({length: amountPerLayer}, () => {return new Vector2()});let layers = Array.from({length: layersAmount}, (_, layerIdx) => { return { layerIdx: layerIdx, radius: (50 / (layersAmount)) * (layerIdx + 1) }}).reverse();

let mediators = { temp: new Vector2()}

let clock = new Clock();let t = 0;

draw();

function draw(){ requestAnimationFrame(draw); let dt = clock.getDelta(); t += dt * 0.25; ctx.clearRect(0, 0, cnv.width, cnv.height); ctx.save(); { ctx.translate(u(ctxCenter.x), u(ctxCenter.y)); let rrSize = 85; ctx.beginPath(); ctx.roundRect(-u(rrSize * 0.5), -u(rrSize * 0.5), u(rrSize), u(rrSize), u(rrSize * 0.1)); ctx.strokeStyle = basePalette[1]; ctx.lineWidth = u(2); let bckGrd = ctx.createLinearGradient(0, -u(rrSize * 0.5), 0, u(rrSize * 0.5)); basePalette.forEach((pal, palIdx) => { bckGrd.addColorStop(palIdx / (basePalette.length - 1), pal); }) ctx.fillStyle = bckGrd; ctx.stroke(); ctx.fill(); layers.forEach((layer) => { // pre-compute noise let layerPlus = ((layer.layerIdx + 1) * 0.75) ** 2.7; noisyPoints.forEach((np, pIdx) => { np.copy(points[pIdx]); let noise = simplex.noise3d(np.x * layerPlus, np.y * layerPlus, t * (layerPlus ** 0.27)) * 0.5 + 0.5; np.setLength(u((1 + noise) * 0.5 * layer.radius)); }) let pal = palette[layer.layerIdx]; ctx.strokeStyle = `hsl(${360 * pal.h}, ${100 * pal.s}%, ${100 * (pal.l + 0.125)}%)`; ctx.fillStyle = `hsl(${360 * pal.h}, ${100 * pal.s}%, ${100 * pal.l}%)`; ctx.lineWidth = u(0.5); let r = u(0.5); ctx.beginPath(); let pMinusOne = noisyPoints[noisyPoints.length - 1]; let pZero = noisyPoints[0]; ctx.moveTo((pMinusOne.x + pZero.x) * 0.5, (pMinusOne.y + pZero.y) * 0.5); noisyPoints.forEach((p, pIdx) => { let pNext = noisyPoints[(pIdx + 1) % noisyPoints.length]; ctx.quadraticCurveTo(p.x, p.y, (p.x + pNext.x) * 0.5, (p.y + pNext.y) * 0.5); }) ctx.fill(); ctx.stroke(); }) } ctx.restore();}



源码:

https://codepen.io/prisoner849/pen/oNrOErX


体验:

https://codepen.io/prisoner849/full/oNrOErX



感谢您的阅读      

在看点赞 好文不断  

初识Threejs
初识 Three.js 的奇妙世界,走进三维空间,与小编一起拥抱前端技术,涉及WebGL、WebGPU、Threejs、Shader、GIS、VR/AR、数字孪生、3D图形学等。
 最新文章