目录
前言
HTML部分
CSS部分
JS部分
效果图
总结
前言
无需多言,本文将详细介绍一段HTML代码,具体内容如下:
开始
首先新建文件夹,创建一个文本文档,两个文件夹,其中HTML的文件名改为[index.html];CSS的文件名改为[css],里面新建一个文本文档重命名为[normalize.min.css];JS的文件名改为[js],里面新建两个文本文档,分别重命名为 [script.js] [simplex-noise.min.js],创建好后右键用文本文档打开,再把下面相对应代码填入后保存即可。
HTML部分
这段HTML代码定义了一个基本的网页结构,包括了必要的文档类型声明、网页头部(head)和主体(body)部分。具体来说:
-
<!DOCTYPE html>
: 这是HTML5文档的声明,用于告诉浏览器这是一个HTML5文档。 -
<html lang="en">
: 根元素,定义了整个HTML文档,并设置页面的语言为英语。 -
<head>
: 包含了文档的元数据,不影响页面的可见内容,但对搜索引擎优化(SEO)和页面表现很重要。<meta charset="UTF-8">
: 设置字符编码为UTF-8,这是一种广泛使用的国际字符编码,可以显示几乎所有语言的字符。<title>雷神Leo</title>
: 设置了浏览器标签页上显示的标题,这里是“雷神Leo”。<link rel="stylesheet" href="css/normalize.min.css">
: 引入了一个外部CSS文件,用于样式重置和标准化不同浏览器间的默认样式差异,以确保网页的一致性。
-
<body>
: 包含了网页的所有可见内容。<script src='js/simplex-noise.min.js'></script>
: 引入了一个JavaScript库,用于生成简单的噪声效果,常用于创建视觉效果。<script src="js/script.js"></script>
: 引入了网页的主要JavaScript文件,负责处理网页的行为和交互逻辑。
这个网页模板是一个起点,开发者可以在此基础上添加更多的HTML元素、CSS样式和JavaScript代码,以创建具有丰富功能和吸引人设计的网页。需要注意的是,实际使用时,需要确保外部文件路径正确,并编写相应的CSS和JavaScript代码来实现所需的功能。
<!DOCTYPE html> <!-- 声明文档类型为HTML5 -->
<html lang="en" ><!-- 根元素,设置语言为英语 -->
<head>
<meta charset="UTF-8"> <!-- 设置字符编码为UTF-8,确保网页正确显示多语言字符 -->
<title>雷神Leo</title> <!-- 网页标题,将显示在浏览器标签页上 -->
<!-- 引入外部CSS样式表,用于网页的样式布局 -->
<link rel="stylesheet" href="css/normalize.min.css">
</head>
<body>
<!-- 页面的主体内容将会放在这里 -->
<!-- 引入外部JavaScript文件,用于网页的行为和动态效果 -->
<script src='js/simplex-noise.min.js'></script>
<script src="js/script.js"></script>
</body>
</html>
CSS部分
这段代码是一个CSS样式表的一部分,主要使用了Normalize.css,它是一个用于网页的CSS库,旨在创建一个更平滑的用户体验,同时保持不同浏览器和设备之间的一致性。以下是对这段代码的总结和注释:
-
button,hr,input{overflow:visible}
: 设置按钮、水平规则线(hr)和输入框的溢出内容为可见,以确保这些元素的溢出内容不会影响布局。 -
audio,canvas,progress,video{display:inline-block}
: 将音频、画布、进度条和视频等元素设置为内联块状元素,使它们既能像内联元素一样参与文本流,又能设置宽高。 -
progress,sub,sup{vertical-align:baseline}
: 设置进度条、下标和上标元素的垂直对齐方式为基线对齐,以确保它们与文本的基线对齐。 -
html{font-family:sans-serif;line-height:1.15;...}
: 设置默认的字体系列为无衬线字体,并设置行高为1.15倍,同时禁用了一些浏览器的默认文本大小调整功能。 -
body{margin:0}
: 设置页面主体的默认外边距为0,以避免浏览器的默认边距影响布局。 -
menu,article,aside,...{display:block}
: 将一些HTML5新增的语义化元素设置为块状元素,确保它们占据一整行。 -
h1{font-size:2em;margin:.67em 0}
: 设置一级标题的字体大小为2em,并设置上下外边距。 -
figcaption,figure,main{display:block}
: 设置图题、图形和主要内容区域为块状元素。 -
hr{box-sizing:content-box;height:0}
: 设置水平规则线的盒模型为内容盒模型,并将其高度设置为0。 -
code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}
: 设置代码、键盘输入、预格式化文本和样本文本的字体为等宽字体,并设置字体大小为1em。 -
a{background-color:transparent;...}
: 设置超链接的背景颜色为透明,并禁用了一些浏览器的默认文本装饰。 -
abbr[title]{...}
: 设置有标题属性的缩写词的文本装饰为下划线点状,以提供解释性的文本。 -
b,strong{font-weight:bolder}
: 设置加粗文本的字体权重更强。 -
small{font-size:80%}
: 设置小号文字的字体大小为80%。 -
sub,sup{...}
: 设置下标和上标的字体大小为75%,并设置行高为0,以及它们的相对位置。 -
audio:not([controls]){...}
: 隐藏没有控件的音频元素。 -
img{border-style:none}
: 设置图片的边框样式为无。 -
button,input,...{...}
: 设置一系列表单元素的字体系列、大小、外边距等。 -
fieldset{border:1px solid silver...}
: 设置字段集的边框样式、间距和填充。 -
legend{...}
: 设置图例的盒模型、颜色、显示方式和白空间。 -
progress{}
和textarea{overflow:auto}
: 为进度条和文本区域设置样式。 -
[type=checkbox],...{...}
: 设置复选框、单选按钮等表单元素的盒模型和样式。 -
summary{display:list-item}
: 设置摘要元素的显示方式为列表项。 -
[hidden],template{display:none}
: 隐藏隐藏元素和模板元素。
最后,/*# sourceMappingURL=normalize.min.css.map */
是一个注释,用于指示这个CSS文件的源映射文件的位置,便于开发者调试。
这段代码的目的是为网页提供一个统一的样式基础,减少浏览器之间的默认样式差异,使得开发者可以更轻松地创建一致且易于维护的网页。
button,hr,input{overflow:visible}audio,canvas,progress,video{display:inline-block}progress,sub,sup{vertical-align:baseline}html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0} menu,article,aside,details,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{}button,select{text-transform:none}[type=submit], [type=reset],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}[hidden],template{display:none}/*# sourceMappingURL=normalize.min.css.map */
JS部分
[script.js]
这段代码定义了几个类,用于生成随机数、颜色、处理向量运算、碰撞检测、计时、动画定时以及绘制分形图形。
-
Utils
类提供了一些静态方法,用于生成随机数、随机颜色值和渐变颜色。还包括一个计算当前帧率(FPS)的方法。 -
Vector2d
类表示二维向量,提供了一系列方法来执行向量运算,如缩放、加法、减法、取反、归一化、旋转和转换为字符串表示。 -
Collision
类用于处理对象之间的碰撞检测和碰撞反弹。它提供了一个collideAll
方法来检查所有对象对之间的碰撞,并调用bounce
方法来处理碰撞反弹。 -
Stopwatch
类用于计时,提供了开始、停止、获取经过时间、检查是否正在运行和重置计时器的方法。 -
AnimationTimer
类用于动画定时,它可以创建一个基于时间的动画效果,支持不同的缓动函数,如Ease-In、Ease-Out、Ease-In-Out、Elastic和Bounce。还包括一个线性缓动函数和一个方法来检查动画是否完成。 -
Angle
类用于表示角度,可以增加或减少角度值,并将角度值转换为弧度。 -
Canvas
类用于创建和管理分形图形的绘制。它提供了初始化、渲染、绘制帧率和响应窗口大小变化的方法。 -
PointObj
类表示一个二维点,包含 x 和 y 坐标。 -
FractalRoot
类用于生成分形的根节点,它初始化分形的结构并绘制形状。 -
Branch
类表示分形中的一个分支,它负责计算分支的中间点、结构点,并绘制分支。
最后,代码中的自执行函数用于初始化 Canvas
类,并设置窗口大小变化的事件监听器,以确保画布随着浏览器窗口的变化而调整大小。整个代码展示了一个分形动画的生成和渲染过程,包括碰撞检测和帧率显示。
class Utils {
static randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
static randomColorRGB() {
return (
"rgb(" +
this.randomNumber(0, 255) +
", " +
this.randomNumber(0, 255) +
", " +
this.randomNumber(0, 255) +
")"
);
}
static randomColorHSL(hue, saturation, lightness) {
return (
"hsl(" +
hue +
", " +
saturation +
"%, " +
lightness +
"%)"
);
}
static gradientColor(ctx, cr, cg, cb, ca, x, y, r) {
const col = cr + "," + cg + "," + cb;
const g = ctx.createRadialGradient(x, y, 0, x, y, r);
g.addColorStop(0, "rgba(" + col + ", " + (ca * 1) + ")");
g.addColorStop(0.5, "rgba(" + col + ", " + (ca * 0.5) + ")");
g.addColorStop(1, "rgba(" + col + ", " + (ca * 0) + ")");
return g;
}
static calcFPS() {
const now = (+new Date());
const fps = 1000 / (now - lastTime);
lastTime = now;
return fps.toFixed();
}
}
class Vector2d {
constructor(x, y) {
this.vx = x;
this.vy = y;
}
scale(scale) {
this.vx *= scale;
this.vy *= scale;
}
add(vec2) {
this.vx += vec2.vx;
this.vy += vec2.vy
}
sub(vec2) {
this.vx -= vec2.vx;
this.vy -= vec2.vy;
}
negate() {
this.vx = -this.vx;
this.vy = -this.vy;
}
length() {
return Math.sqrt(this.vx * this.vx + this.vy * this.vy);
}
lengthSquared() {
return this.vx * this.vx + this.vy * this.vy;
}
normalize() {
let len = Math.sqrt(this.vx * this.vx + this.vy * this.vy);
if (len) {
this.vx /= len;
this.vy /= len;
}
return len;
}
rotate(angle) {
let vx = this.vx;
let vy = this.vy;
let cosVal = Math.cos(angle);
let sinVal = Math.sin(angle);
this.vx = vx * cosVal - vy * sinVal;
this.vy = vx * sinVal + vy * cosVal;
}
toString() {
return '(' + this.vx.toFixed(3) + ',' + this.vy.toFixed(3) + ')';
}
}
class Collision {
constructor(targetArr) {
this.arr = targetArr;
}
collideAll() {
let vec = new Vector2d(0, 0);
let dist;
let obj1;
let obj2;
let c;
let i;
for (c = 0; c < this.arr.length; c++) {
obj1 = this.arr[c];
for (i = c + 1; i < this.arr.length; i++) {
obj2 = this.arr[i];
vec.vx = obj2.x - obj1.x;
vec.vy = obj2.y - obj1.y;
dist = vec.length();
if (dist < obj1.r + obj2.r) {
vec.normalize();
vec.scale(obj1.r + obj2.r - dist);
vec.negate();
obj1.x += vec.vx;
obj1.y += vec.vy;
this.bounce(obj1, obj2);
}
}
}
}
bounce(obj1, obj2) {
let colnAngle = Math.atan2(obj1.y - obj2.y, obj1.x - obj2.x);
let length1 = obj1.v.length();
let length2 = obj2.v.length();
let dirAngle1 = Math.atan2(obj1.v.vy, obj1.v.vx);
let dirAngle2 = Math.atan2(obj2.v.vy, obj2.v.vx);
let newVX1 = length1 * Math.cos(dirAngle1 - colnAngle);
let newVX2 = length2 * Math.cos(dirAngle2 - colnAngle);
obj1.v.vy = length1 * Math.sin(dirAngle1 - colnAngle);
obj2.v.vy = length2 * Math.sin(dirAngle2 - colnAngle);
obj1.v.vx = ((obj1.r - obj2.r) * newVX1 + (2 * obj2.r) * newVX2) / (obj1.r + obj2.r);
obj2.v.vx = ((obj2.r - obj1.r) * newVX2 + (2 * obj1.r) * newVX1) / (obj1.r + obj2.r);
obj1.v.rotate(colnAngle);
obj2.v.rotate(colnAngle);
}
}
class Stopwatch {
constructor(time) {
this.startTime = 0;
this.running = false;
this.elapsed = undefined;
}
start() {
this.startTime = +new Date();
this.elapsedTime = null;
this.running = true;
}
stop() {
this.elapsed = (+new Date()) - this.startTime;
this.running = false;
}
getElapsedTime() {
if (this.running) {
return (+new Date()) - this.startTime;
} else {
return this.elapsed;
}
}
isRunning() {
return this.running;
}
reset() {
this.elapsed = 0;
}
}
class AnimationTimer {
constructor(duration, timeWarp) {
if (duration !== undefined) this.duration = duration;
if (timeWarp !== undefined) this.timeWarp = timeWarp;
this.stopwatch = new Stopwatch();
}
start() {
this.stopwatch.start();
}
stop() {
this.stopwatch.stop();
}
getElapsedTime() {
const elapsedTime = this.stopwatch.getElapsedTime();
const percentComplete = elapsedTime / this.duration;
if (!this.stopwatch.running) return undefined;
if (this.timeWarp === undefined) return elapsedTime;
return elapsedTime * (this.timeWarp(percentComplete) / percentComplete);
}
isRunning() {
return this.stopwatch.running;
}
isOver() {
return this.stopwatch.getElapsedTime() > this.duration;
}
makeEaseIn(strength) {
return function(percentComplete) {
return Math.pow(percentComplete, strength * 2);
}
}
makeEaseOut(strength) {
return function(percentComplete) {
return 1 - Math.pow(1 - percentComplete, strength * 2);
}
}
makeEaseInOut() {
return function(percentComplete) {
return percentComplete - Math.sin(percentComplete * 2 * Math.PI) / (2 * Math.PI);
}
}
makeElastic(passes) {
passes = passes || default_elastic_passes;
return function(percentComplete) {
return ((1 - Math.cos(percentComplete * Math.PI * passes)) * (1 - percentComplete)) + percentComplete;
}
}
makeBounce(bounces) {
const fn = this.makeElastic(bounces);
return function(percentComplete) {
percentComplete = fn(percentComplete);
return percentComplete <= 1 ? percentComplete : 2 - percentComplete;
}
}
makeLinear() {
return function(percentComplete) {
return percentComplete;
}
}
}
class Angle {
constructor(angle) {
this.a = angle;
this.rad = this.a * Math.PI / 180;
}
incDec(num) {
this.a += num;
this.rad = this.a * Math.PI / 180;
return this.rad;
}
}
let canvas;
let lastTime = 0;
const simplex = new SimplexNoise();
class Canvas {
constructor(bool) {
this.canvas = document.createElement("canvas");
if (bool === true) {
this.canvas.style.position = 'relative';
this.canvas.style.display = 'block';
this.canvas.style.backgroundColor = 'black';
this.canvas.style.top = '0';
this.canvas.style.left = '0';
document.getElementsByTagName("body")[0].appendChild(this.canvas);
}
this.ctx = this.canvas.getContext("2d");
this.width = this.canvas.width = window.innerWidth;
this.height = this.canvas.height = window.innerHeight;
this.mouseX = null;
this.mouseY = null;
this.mouseZ = null;
this.number_of_shapes = 5;
this.shapes_array = [];
}
init() {
for (let i = 0; i < this.number_of_shapes; i++) {
const f = new FractalRoot(this.ctx, this.width / 2, this.height / 2, i);
this.shapes_array.push(f);
}
}
render() {
if (Math.random() < 0.001) this.ctx.clearRect(0, 0, this.width, this.height);
for (let i = 0; i < this.shapes_array.length; i++) {
this.shapes_array[i].drawShape();
}
window.requestAnimationFrame(() => {
this.render();
});
}
drawFPS() {
const ctx = this.ctx;
ctx.save();
ctx.fillStyle = 'white';
ctx.font = '16px sans-serif';
ctx.textAlign = 'right';
ctx.textBaseline = 'bottom';
ctx.fillText(Utils.calcFPS() + ' FPS', this.width, this.height);
ctx.restore();
}
resize() {
this.shapes_array = [];
this.width = this.canvas.width = window.innerWidth;
this.height = this.canvas.height = window.innerHeight;
this.init();
}
}
class PointObj {
constructor(ex, ey) {
this.x = ex;
this.y = ey;
}
}
class FractalRoot {
constructor(ctx, x, y, i) {
this.random = Math.random();
this.ctx = ctx;
this.x = x;
this.y = y;
this.i = i;
this.a = 0;
this.r = 100;
this.ri = this.r;
this.maxLevels = 4;
this.structFactor = null;
this.rootBranch = null;
this.numSlides = 5;
this.pointArr = new Array(this.numSlides);
this.angleStep = 360 / this.numSlides;
this.init();
}
init(time, noise) {
let count = 0;
for (let i = 0; i < 360; i += this.angleStep) {
let x = this.x + (this.r * Math.cos((this.a + i) * Math.PI / 180));
let y = this.y + (this.r * Math.sin((this.a + i) * Math.PI / 180));
this.pointArr[count] = new PointObj(x, y);
count++;
}
this.rootBranch = new Branch(
this.ctx,
0,
0,
this.pointArr,
this.structFactor,
this.maxLevels,
time,
noise
);
}
drawShape() {
const time = Date.now() / 5000 * this.random;
const noise = simplex.noise3D(this.x, this.y, time);
this.structFactor = Math.sin(time) * noise * 3;
this.r = Math.sin(time) * noise * this.ri + 100;
this.init(time, noise);
this.rootBranch.drawMe();
this.a += noise;
}
}
class Branch {
constructor(ctx, lev, n, points, factor, max, time, noise) {
this.ctx = ctx;
this.level = lev;
this.num = n;
this.outerPoints = points;
this.structFactor = factor;
this.maxLevels = max;
this.time = time;
this.noise = noise;
this.myBranches = [];
this.midPoints = this.calcMidPoints();
this.projPoints = this.calcStructPoints();
if (this.level + 1 < this.maxLevels) {
let childBranch = new Branch(
this.ctx,
this.level + 1,
0,
this.projPoints,
this.structFactor,
this.maxLevels,
this.time,
this.noise
);
this.myBranches.push(childBranch);
for (let i = 0; i < this.outerPoints.length; i++) {
let n = i - 1;
if (n < 0) {
n += this.outerPoints.length;
}
let newPoints = [
this.projPoints[i],
this.midPoints[i],
this.outerPoints[i],
this.midPoints[n],
this.projPoints[n]
];
let childBranch = new Branch(
this.ctx,
this.level + 1,
i + 1,
newPoints,
this.structFactor,
this.maxLevels,
this.time,
this.noise
);
this.myBranches.push(childBranch);
}
}
}
drawMe() {
const ctx = this.ctx;
ctx.save();
ctx.lineWidth = 0.1;
ctx.strokeStyle = 'hsl(' + 360 * (this.noise * 2) + ', 80% ,60%)';
ctx.beginPath();
ctx.moveTo(this.outerPoints[0].x,this.outerPoints[0].y);
for (let i = 1; i < this.outerPoints.length; i++) {
ctx.lineTo(this.outerPoints[i].x, this.outerPoints[i].y);
}
ctx.closePath();
ctx.stroke();
ctx.restore();
for (let i = 0; i < this.myBranches.length; i++) {
this.myBranches[i].drawMe();
}
}
calcMidPoints() {
let mpArray = [];
for (let i = 0; i < this.outerPoints.length; i++) {
let n = i + 1;
if (n === this.outerPoints.length) {
n = 0;
}
let thisMp = this.calcMidPoint(this.outerPoints[i], this.outerPoints[n]);
mpArray[i] = thisMp;
}
return mpArray;
}
calcMidPoint(end1, end2) {
let mx, my;
if (end1.x > end2.x) {
mx = end2.x + ((end1.x - end2.x) / 2);
} else {
mx = end1.x + ((end2.x - end1.x) / 2);
}
if (end1.y > end2.y) {
my = end2.y + ((end1.y - end2.y) / 2);
} else {
my = end1.y + ((end2.y - end1.y) / 2);
}
return new PointObj(mx, my);
}
calcStructPoints() {
let structArray = new Array(this.midPoints.length);
for (let i = 0; i < this.midPoints.length; i++) {
let n = i + 3;
if (n >= this.midPoints.length) {
n -= this.midPoints.length;
}
let thisSP = this.calcProjPoint(this.midPoints[i], this.outerPoints[n]);
structArray[i] = thisSP;
}
return structArray;
}
calcProjPoint(mp, op) {
let px, py, adj, opp;
if (op.x > mp.x) {
opp = op.x - mp.x;
} else {
opp = mp.x - op.x;
}
if (op.y > mp.y) {
adj = op.y - mp.y;
} else {
adj = mp.y - op.y;
}
if (op.x > mp.x) {
px = mp.x + (opp * this.structFactor);
} else {
px = mp.x - (opp * this.structFactor);
}
if (op.y > mp.y) {
py = mp.y + (adj * this.structFactor);
} else {
py = mp.y - (adj * this.structFactor);
}
return new PointObj(px, py);
}
}
(() => {
'use strict';
window.addEventListener('load', () => {
canvas = new Canvas(true);
canvas.init();
canvas.render();
window.addEventListener("resize", () => {
canvas.resize();
}, false);
}, false);
})();
[simplex-noise.min.js]
这段代码定义了一个名为 SimplexNoise
的 JavaScript 类,用于生成多维的简单噪声(Simplex Noise)。简单噪声是一种用于生成自然外观的纹理或形状的数学函数,常用于计算机图形学、游戏开发和数据可视化等领域。
以下是对代码中各个部分的总结:
-
初始化和配置:
- 定义了一系列的常量(如
r
,e
,t
,a
,o
),这些常量用于后续的噪声计算。 i
函数是一个工厂方法,用于创建SimplexNoise
实例。它接受一个参数,该参数可以是一个函数或者一个数字。如果参数是一个函数,它会调用该函数来生成随机数;如果参数是数字,它会使用这个数字来初始化噪声生成器的随机数种子。
- 定义了一系列的常量(如
-
Permutation Table(置换表):
n
函数用于生成置换表,这是一个包含随机排列的字节数组。置换表用于在噪声计算中引入随机性。i.prototype
对象包含了噪声生成的核心方法和数据,如grad3
和grad4
梯度数组,以及noise2D
、noise3D
和noise4D
方法,用于计算二维、三维和四维的简单噪声。
-
噪声计算方法:
noise2D
方法接受两个参数t
和a
,分别代表二维空间中的x
和y
坐标,返回一个介于-1
和1
之间的噪声值。noise3D
方法接受三个参数r
、e
和a
,分别代表三维空间中的x
、y
和z
坐标,同样返回一个介于-1
和1
之间的噪声值。noise4D
方法接受四个参数r
、e
、t
和i
,分别代表四维空间中的四个坐标轴,返回一个噪声值。
-
兼容性和模块导出:
- 代码的最后部分检查了
define
、exports
和window
对象是否存在,以确定如何导出SimplexNoise
类。如果使用 AMD(异步模块定义)规范,则通过define
函数导出;如果使用 CommonJS 规范(如 Node.js 环境),则通过module.exports
导出;如果运行在浏览器环境中,则将SimplexNoise
添加到window
对象上。
- 代码的最后部分检查了
总的来说,这段代码提供了一个完整的简单噪声生成器实现,可以用于各种需要自然随机性的场景。通过提供不同维度的噪声计算方法,它为开发者提供了灵活性,可以根据具体需求选择合适的噪声维度。
!function(){"use strict";var r=.5*(Math.sqrt(3)-1),e=(3-Math.sqrt(3))/6,t=1/6,a=(Math.sqrt(5)-1)/4,o=(5-Math.sqrt(5))/20;function i(r){var e;e="function"==typeof r?r:r?function(){var r=0,e=0,t=0,a=1,o=(i=4022871197,function(r){r=r.toString();for(var e=0;e<r.length;e++){var t=.02519603282416938*(i+=r.charCodeAt(e));t-=i=t>>>0,i=(t*=i)>>>0,i+=4294967296*(t-=i)}return 2.3283064365386963e-10*(i>>>0)});var i;r=o(" "),e=o(" "),t=o(" ");for(var n=0;n<arguments.length;n++)(r-=o(arguments[n]))<0&&(r+=1),(e-=o(arguments[n]))<0&&(e+=1),(t-=o(arguments[n]))<0&&(t+=1);return o=null,function(){var o=2091639*r+2.3283064365386963e-10*a;return r=e,e=t,t=o-(a=0|o)}}(r):Math.random,this.p=n(e),this.perm=new Uint8Array(512),this.permMod12=new Uint8Array(512);for(var t=0;t<512;t++)this.perm[t]=this.p[255&t],this.permMod12[t]=this.perm[t]%12}function n(r){var e,t=new Uint8Array(256);for(e=0;e<256;e++)t[e]=e;for(e=0;e<255;e++){var a=e+~~(r()*(256-e)),o=t[e];t[e]=t[a],t[a]=o}return t}i.prototype={grad3:new Float32Array([1,1,0,-1,1,0,1,-1,0,-1,-1,0,1,0,1,-1,0,1,1,0,-1,-1,0,-1,0,1,1,0,-1,1,0,1,-1,0,-1,-1]),grad4:new Float32Array([0,1,1,1,0,1,1,-1,0,1,-1,1,0,1,-1,-1,0,-1,1,1,0,-1,1,-1,0,-1,-1,1,0,-1,-1,-1,1,0,1,1,1,0,1,-1,1,0,-1,1,1,0,-1,-1,-1,0,1,1,-1,0,1,-1,-1,0,-1,1,-1,0,-1,-1,1,1,0,1,1,1,0,-1,1,-1,0,1,1,-1,0,-1,-1,1,0,1,-1,1,0,-1,-1,-1,0,1,-1,-1,0,-1,1,1,1,0,1,1,-1,0,1,-1,1,0,1,-1,-1,0,-1,1,1,0,-1,1,-1,0,-1,-1,1,0,-1,-1,-1,0]),noise2D:function(t,a){var o,i,n=this.permMod12,f=this.perm,s=this.grad3,v=0,h=0,l=0,u=(t+a)*r,d=Math.floor(t+u),p=Math.floor(a+u),M=(d+p)*e,m=t-(d-M),c=a-(p-M);m>c?(o=1,i=0):(o=0,i=1);var y=m-o+e,w=c-i+e,g=m-1+2*e,A=c-1+2*e,x=255&d,q=255&p,D=.5-m*m-c*c;if(D>=0){var S=3*n[x+f[q]];v=(D*=D)*D*(s[S]*m+s[S+1]*c)}var U=.5-y*y-w*w;if(U>=0){var b=3*n[x+o+f[q+i]];h=(U*=U)*U*(s[b]*y+s[b+1]*w)}var F=.5-g*g-A*A;if(F>=0){var N=3*n[x+1+f[q+1]];l=(F*=F)*F*(s[N]*g+s[N+1]*A)}return 70*(v+h+l)},noise3D:function(r,e,a){var o,i,n,f,s,v,h,l,u,d,p=this.permMod12,M=this.perm,m=this.grad3,c=(r+e+a)*(1/3),y=Math.floor(r+c),w=Math.floor(e+c),g=Math.floor(a+c),A=(y+w+g)*t,x=r-(y-A),q=e-(w-A),D=a-(g-A);x>=q?q>=D?(s=1,v=0,h=0,l=1,u=1,d=0):x>=D?(s=1,v=0,h=0,l=1,u=0,d=1):(s=0,v=0,h=1,l=1,u=0,d=1):q<D?(s=0,v=0,h=1,l=0,u=1,d=1):x<D?(s=0,v=1,h=0,l=0,u=1,d=1):(s=0,v=1,h=0,l=1,u=1,d=0);var S=x-s+t,U=q-v+t,b=D-h+t,F=x-l+2*t,N=q-u+2*t,C=D-d+2*t,P=x-1+.5,T=q-1+.5,_=D-1+.5,j=255&y,k=255&w,z=255&g,B=.6-x*x-q*q-D*D;if(B<0)o=0;else{var E=3*p[j+M[k+M[z]]];o=(B*=B)*B*(m[E]*x+m[E+1]*q+m[E+2]*D)}var G=.6-S*S-U*U-b*b;if(G<0)i=0;else{var H=3*p[j+s+M[k+v+M[z+h]]];i=(G*=G)*G*(m[H]*S+m[H+1]*U+m[H+2]*b)}var I=.6-F*F-N*N-C*C;if(I<0)n=0;else{var J=3*p[j+l+M[k+u+M[z+d]]];n=(I*=I)*I*(m[J]*F+m[J+1]*N+m[J+2]*C)}var K=.6-P*P-T*T-_*_;if(K<0)f=0;else{var L=3*p[j+1+M[k+1+M[z+1]]];f=(K*=K)*K*(m[L]*P+m[L+1]*T+m[L+2]*_)}return 32*(o+i+n+f)},noise4D:function(r,e,t,i){var n,f,s,v,h,l,u,d,p,M,m,c,y,w,g,A,x,q=this.perm,D=this.grad4,S=(r+e+t+i)*a,U=Math.floor(r+S),b=Math.floor(e+S),F=Math.floor(t+S),N=Math.floor(i+S),C=(U+b+F+N)*o,P=r-(U-C),T=e-(b-C),_=t-(F-C),j=i-(N-C),k=0,z=0,B=0,E=0;P>T?k++:z++,P>_?k++:B++,P>j?k++:E++,T>_?z++:B++,T>j?z++:E++,_>j?B++:E++;var G=P-(l=k>=3?1:0)+o,H=T-(u=z>=3?1:0)+o,I=_-(d=B>=3?1:0)+o,J=j-(p=E>=3?1:0)+o,K=P-(M=k>=2?1:0)+2*o,L=T-(m=z>=2?1:0)+2*o,O=_-(c=B>=2?1:0)+2*o,Q=j-(y=E>=2?1:0)+2*o,R=P-(w=k>=1?1:0)+3*o,V=T-(g=z>=1?1:0)+3*o,W=_-(A=B>=1?1:0)+3*o,X=j-(x=E>=1?1:0)+3*o,Y=P-1+4*o,Z=T-1+4*o,$=_-1+4*o,rr=j-1+4*o,er=255&U,tr=255&b,ar=255&F,or=255&N,ir=.6-P*P-T*T-_*_-j*j;if(ir<0)n=0;else{var nr=q[er+q[tr+q[ar+q[or]]]]%32*4;n=(ir*=ir)*ir*(D[nr]*P+D[nr+1]*T+D[nr+2]*_+D[nr+3]*j)}var fr=.6-G*G-H*H-I*I-J*J;if(fr<0)f=0;else{var sr=q[er+l+q[tr+u+q[ar+d+q[or+p]]]]%32*4;f=(fr*=fr)*fr*(D[sr]*G+D[sr+1]*H+D[sr+2]*I+D[sr+3]*J)}var vr=.6-K*K-L*L-O*O-Q*Q;if(vr<0)s=0;else{var hr=q[er+M+q[tr+m+q[ar+c+q[or+y]]]]%32*4;s=(vr*=vr)*vr*(D[hr]*K+D[hr+1]*L+D[hr+2]*O+D[hr+3]*Q)}var lr=.6-R*R-V*V-W*W-X*X;if(lr<0)v=0;else{var ur=q[er+w+q[tr+g+q[ar+A+q[or+x]]]]%32*4;v=(lr*=lr)*lr*(D[ur]*R+D[ur+1]*V+D[ur+2]*W+D[ur+3]*X)}var dr=.6-Y*Y-Z*Z-$*$-rr*rr;if(dr<0)h=0;else{var pr=q[er+1+q[tr+1+q[ar+1+q[or+1]]]]%32*4;h=(dr*=dr)*dr*(D[pr]*Y+D[pr+1]*Z+D[pr+2]*$+D[pr+3]*rr)}return 27*(n+f+s+v+h)}},i._buildPermutationTable=n,"undefined"!=typeof define&&define.amd&&define(function(){return i}),"undefined"!=typeof exports?exports.SimplexNoise=i:"undefined"!=typeof window&&(window.SimplexNoise=i),"undefined"!=typeof module&&(module.exports=i)}();
效果图
总结
-
HTML:
- 定义了一个网页的基本结构,包括DOCTYPE声明、html、head和body标签。
- 在head部分,设置了页面字符集为UTF-8,并定义了网页标题。
- 引入了一个外部CSS文件
normalize.min.css
用于样式重置,以及两个JavaScript文件simplex-noise.min.js
和script.js
,这些文件将用于网页的样式和行为。
-
CSS:
- 包含了一系列的CSS规则,用于重置和标准化HTML元素的默认样式,以确保在不同浏览器中具有一致的表现。
- 涉及的样式包括按钮、表单元素、媒体元素等的显示方式、字体、外边距、内边距和边框样式。
- 还包括了一些针对HTML5新语义元素的样式设置,如
article
、aside
、footer
等。
-
JavaScript:
- 定义了一系列的类和方法,用于生成随机数、颜色、渐变色、计算帧率(FPS)、处理向量运算、碰撞检测、计时和动画定时。
Utils
类提供了生成随机数和颜色的方法,以及创建渐变色和计算FPS的功能。Vector2d
类表示二维向量,提供了一系列向量运算的方法,如缩放、加法、减法、取反、归一化和旋转。Collision
类处理对象之间的碰撞检测和碰撞反弹。Stopwatch
类用于计时,提供了开始、停止、获取经过时间、检查是否正在运行和重置计时器的方法。AnimationTimer
类用于动画定时,支持不同的缓动函数,如Ease-In、Ease-Out、Ease-In-Out、Elastic和Bounce。Angle
类用于表示角度,可以增加或减少角度值,并将其转换为弧度。Canvas
类用于创建和管理分形图形的绘制,提供了初始化、渲染、绘制帧率和响应窗口大小变化的方法。PointObj
和FractalRoot
类用于生成分形图形的结构和绘制。Branch
类表示分形中的一个分支,负责计算分支的中间点、结构点,并绘制分支。- 最后,自执行函数用于初始化
Canvas
类,并设置窗口大小变化的事件监听器。 - 另外,还有一个SimplexNoise类,用于生成多维的简单噪声,这在计算机图形学中非常有用,可以用于创建自然纹理或形状。