Skip to content

Commit

Permalink
core: 考虑到美观程度去掉了定时更换控制点的代码
Browse files Browse the repository at this point in the history
core: 整理了随机控制点生成器代码
  • Loading branch information
Steve-xmh committed Feb 11, 2025
1 parent 9424b18 commit bbcc4c9
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 275 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"@biomejs/biome": "^1.9.4",
"lerna": "^8.1.9",
"typescript": "^5.7.3"
}
}
},
"packageManager": "[email protected]+sha512.398035c7bd696d0ba0b10a688ed558285329d27ea994804a52bad9167d8e3a72bcb993f9699585d3ca25779ac64949ef422757a6c31102c12ab932e5cbe5cc92"
}
214 changes: 214 additions & 0 deletions packages/core/src/bg-render/mesh-renderer/cp-generate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/**
* @fileoverview
* 实验性的随机控制点生成函数算法
* 目的是取代原先大量的预设控制点代码
*/

import {
type ControlPointConf,
type ControlPointPreset,
p,
preset,
} from "./cp-presets.ts";

const randomRange = (min: number, max: number): number =>
Math.random() * (max - min) + min;

function clamp(x: number, min: number, max: number): number {
return Math.min(Math.max(x, min), max);
}

function smoothstep(edge0: number, edge1: number, x: number): number {
const t = clamp((x - edge0) / (edge1 - edge0), 0, 1);
return t * t * (3 - 2 * t);
}

function smoothifyControlPoints(
conf: ControlPointConf[],
w: number,
h: number,
iterations = 2,
factor = 0.5,
factorIterationModifier = 0.1,
): void {
let grid: ControlPointConf[][] = [];
let f = factor;

for (let j = 0; j < h; j++) {
grid[j] = [];
for (let i = 0; i < w; i++) {
grid[j][i] = conf[j * w + i];
}
}

const kernel = [
[1, 2, 1],
[2, 4, 2],
[1, 2, 1],
];
const kernelSum = 16;

for (let iter = 0; iter < iterations; iter++) {
const newGrid: ControlPointConf[][] = [];
for (let j = 0; j < h; j++) {
newGrid[j] = [];
for (let i = 0; i < w; i++) {
if (i === 0 || i === w - 1 || j === 0 || j === h - 1) {
newGrid[j][i] = grid[j][i];
continue;
}
let sumX = 0;
let sumY = 0;
let sumUR = 0;
let sumVR = 0;
let sumUP = 0;
let sumVP = 0;
for (let dj = -1; dj <= 1; dj++) {
for (let di = -1; di <= 1; di++) {
const weight = kernel[dj + 1][di + 1];
const nb = grid[j + dj][i + di];
sumX += nb.x * weight;
sumY += nb.y * weight;
sumUR += nb.ur * weight;
sumVR += nb.vr * weight;
sumUP += nb.up * weight;
sumVP += nb.vp * weight;
}
}
const avgX = sumX / kernelSum;
const avgY = sumY / kernelSum;
const avgUR = sumUR / kernelSum;
const avgVR = sumVR / kernelSum;
const avgUP = sumUP / kernelSum;
const avgVP = sumVP / kernelSum;

const cur = grid[j][i];
const newX = cur.x * (1 - f) + avgX * f;
const newY = cur.y * (1 - f) + avgY * f;
const newUR = cur.ur * (1 - f) + avgUR * f;
const newVR = cur.vr * (1 - f) + avgVR * f;
const newUP = cur.up * (1 - f) + avgUP * f;
const newVP = cur.vp * (1 - f) + avgVP * f;
newGrid[j][i] = p(i, j, newX, newY, newUR, newVR, newUP, newVP);
}
}
grid = newGrid;
f = Math.min(1, Math.max(f + factorIterationModifier, 0));
}

for (let j = 0; j < h; j++) {
for (let i = 0; i < w; i++) {
conf[j * w + i] = grid[j][i];
}
}
}

function noise(x: number, y: number): number {
return fract(Math.sin(x * 12.9898 + y * 78.233) * 43758.5453);
}

function fract(x: number): number {
return x - Math.floor(x);
}

function smoothNoise(x: number, y: number): number {
const x0 = Math.floor(x);
const y0 = Math.floor(y);
const x1 = x0 + 1;
const y1 = y0 + 1;

const xf = x - x0;
const yf = y - y0;

const u = xf * xf * (3 - 2 * xf);
const v = yf * yf * (3 - 2 * yf);

const n00 = noise(x0, y0);
const n10 = noise(x1, y0);
const n01 = noise(x0, y1);
const n11 = noise(x1, y1);

const nx0 = n00 * (1 - u) + n10 * u;
const nx1 = n01 * (1 - u) + n11 * u;

return nx0 * (1 - v) + nx1 * v;
}

function computeNoiseGradient(
perlinFn: (x: number, y: number) => number,
x: number,
y: number,
epsilon = 0.001,
): [number, number] {
const n1 = perlinFn(x + epsilon, y);
const n2 = perlinFn(x - epsilon, y);
const n3 = perlinFn(x, y + epsilon);
const n4 = perlinFn(x, y - epsilon);
const dx = (n1 - n2) / (2 * epsilon);
const dy = (n3 - n4) / (2 * epsilon);
const len = Math.sqrt(dx * dx + dy * dy) || 1;
return [dx / len, dy / len];
}

export function generateControlPoints(
width: number,
height: number,
variationFraction = randomRange(0.4, 0.6), // = 0.2,
normalOffset = randomRange(0.3, 0.6), // = 0.3,
blendFactor = 0.8,
smoothIters = Math.floor(randomRange(3, 5)), // = 3,
smoothFactor = randomRange(0.2, 0.3), // = 0.3,
smoothModifier = randomRange(-0.1, -0.05), // = -0.05,
): ControlPointPreset {
const w = width ?? Math.floor(randomRange(3, 6));
const h = height ?? Math.floor(randomRange(3, 6));

const conf: ControlPointConf[] = [];
const dx = w === 1 ? 0 : 2 / (w - 1);
const dy = h === 1 ? 0 : 2 / (h - 1);

for (let j = 0; j < h; j++) {
for (let i = 0; i < w; i++) {
const baseX = (w === 1 ? 0 : i / (w - 1)) * 2 - 1;
const baseY = (h === 1 ? 0 : j / (h - 1)) * 2 - 1;

const isBorder = i === 0 || i === w - 1 || j === 0 || j === h - 1;
const pertX = isBorder
? 0
: randomRange(-variationFraction * dx, variationFraction * dx);
const pertY = isBorder
? 0
: randomRange(-variationFraction * dy, variationFraction * dy);
let x = baseX + pertX;
let y = baseY + pertY;

const ur = isBorder ? 0 : randomRange(-60, 60);
const vr = isBorder ? 0 : randomRange(-60, 60);
const up = isBorder ? 1 : randomRange(0.8, 1.2);
const vp = isBorder ? 1 : randomRange(0.8, 1.2);

if (!isBorder) {
const uNorm = (baseX + 1) / 2;
const vNorm = (baseY + 1) / 2;

const [nx, ny] = computeNoiseGradient(smoothNoise, uNorm, vNorm, 0.001);
let offsetX = nx * normalOffset;
let offsetY = ny * normalOffset;

const distToBorder = Math.min(uNorm, 1 - uNorm, vNorm, 1 - vNorm); // in [0,0.5]

const weight = smoothstep(0, 1.0, distToBorder);
offsetX *= weight;
offsetY *= weight;

x = x * (1 - blendFactor) + (x + offsetX) * blendFactor;
y = y * (1 - blendFactor) + (y + offsetY) * blendFactor;
}
conf.push(p(i, j, x, y, ur, vr, up, vp));
}
}

smoothifyControlPoints(conf, w, h, smoothIters, smoothFactor, smoothModifier);

return preset(w, h, conf);
}
Loading

0 comments on commit bbcc4c9

Please sign in to comment.