Checkpoint curve-origin book shape lab
This commit is contained in:
@@ -100,14 +100,14 @@ function rebuildBook() {
|
|||||||
const fullBlock = 0.41;
|
const fullBlock = 0.41;
|
||||||
const leftThickness = THREE.MathUtils.lerp(sheetTick, fullBlock, readingProgress);
|
const leftThickness = THREE.MathUtils.lerp(sheetTick, fullBlock, readingProgress);
|
||||||
const rightThickness = THREE.MathUtils.lerp(fullBlock, sheetTick, readingProgress);
|
const rightThickness = THREE.MathUtils.lerp(fullBlock, sheetTick, readingProgress);
|
||||||
const foldX = clothFoldX(gutter);
|
|
||||||
const spineWidth = fullBlock;
|
const spineWidth = fullBlock;
|
||||||
|
const fold = spineCurvePoint(readingProgress, spineWidth);
|
||||||
|
|
||||||
addCoverAssembly(pageWidth, coverDepth, coverThickness, spineWidth);
|
addCoverAssembly(pageWidth, coverDepth, coverThickness, spineWidth);
|
||||||
addSplinePageBlock(-1, pageWidth, pageDepth, leftThickness, foldX);
|
addSplinePageBlock(-1, pageWidth, pageDepth, leftThickness, fold, spineWidth);
|
||||||
addSplinePageBlock(1, pageWidth, pageDepth, rightThickness, foldX);
|
addSplinePageBlock(1, pageWidth, pageDepth, rightThickness, fold, spineWidth);
|
||||||
addPageLayerLines(-1, pageWidth, pageDepth, leftThickness, foldX);
|
addPageLayerLines(-1, pageWidth, pageDepth, leftThickness, spineWidth, fold);
|
||||||
addPageLayerLines(1, pageWidth, pageDepth, rightThickness, foldX);
|
addPageLayerLines(1, pageWidth, pageDepth, rightThickness, spineWidth, fold);
|
||||||
addClothSpine(pageDepth, spineWidth);
|
addClothSpine(pageDepth, spineWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,45 +185,38 @@ function createCoverAssemblyGeometry(pageWidth, depth, thickness, spineWidth) {
|
|||||||
return geometry;
|
return geometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSplinePageBlock(side, width, depth, thickness, foldX) {
|
function addSplinePageBlock(side, width, depth, thickness, fold, spineWidth) {
|
||||||
const block = new THREE.Mesh(createSplinePageBlockGeometry(side, width, depth, thickness, foldX), side < 0 ? materials.pagesLeft : materials.pagesRight);
|
const block = new THREE.Mesh(createSplinePageBlockGeometry(side, width, depth, thickness, fold, spineWidth), side < 0 ? materials.pagesLeft : materials.pagesRight);
|
||||||
book.add(block);
|
book.add(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPageLayerLines(side, width, depth, thickness, foldX) {
|
function addPageLayerLines(side, width, depth, thickness, spineWidth, fold) {
|
||||||
const material = new THREE.LineBasicMaterial({ color: 0x8f7750, transparent: true, opacity: 0.55 });
|
const material = new THREE.LineBasicMaterial({ color: 0x8f7750, transparent: true, opacity: 0.55 });
|
||||||
const z = depth * 0.5 + 0.006;
|
const z = depth * 0.5 + 0.006;
|
||||||
const lineCount = Math.max(1, Math.round(thickness / 0.018));
|
const lineCount = Math.max(1, Math.round(thickness / 0.018));
|
||||||
for (let layer = 1; layer < lineCount; layer += 1) {
|
for (let layer = 1; layer < lineCount; layer += 1) {
|
||||||
const t = layer / lineCount;
|
const t = layer / lineCount;
|
||||||
|
const curveT = side < 0
|
||||||
|
? THREE.MathUtils.lerp(0, readingProgress, t)
|
||||||
|
: THREE.MathUtils.lerp(1, readingProgress, t);
|
||||||
|
const lineFold = spineCurvePoint(curveT, spineWidth);
|
||||||
const points = [];
|
const points = [];
|
||||||
for (let i = 0; i <= 40; i += 1) {
|
for (let i = 0; i <= 40; i += 1) {
|
||||||
const u = 0.04 + 0.96 * (i / 40);
|
const u = i / 40;
|
||||||
const top = pageBlockTopY(thickness, u, 0.5);
|
const top = pageBlockTopY(side, thickness, u, 0.5, lineFold, spineWidth);
|
||||||
const bottom = pageBlockBottomY(thickness, u, 0.5);
|
const bottom = pageBlockBottomY(side, thickness, u, 0.5, lineFold, spineWidth);
|
||||||
points.push(new THREE.Vector3(pageX(side, foldX, width, u, 0.5), bottom + (top - bottom) * t, z));
|
points.push(new THREE.Vector3(pageX(side, lineFold, spineWidth, width, u, 0.5), bottom + (top - bottom) * t, z));
|
||||||
}
|
}
|
||||||
book.add(new THREE.Line(new THREE.BufferGeometry().setFromPoints(points), material));
|
book.add(new THREE.Line(new THREE.BufferGeometry().setFromPoints(points), material));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clothFoldX(gutter) {
|
|
||||||
const spineTravel = gutter * 0.52;
|
|
||||||
return THREE.MathUtils.lerp(-spineTravel, spineTravel, readingProgress);
|
|
||||||
}
|
|
||||||
|
|
||||||
function addClothSpine(depth, spineWidth) {
|
function addClothSpine(depth, spineWidth) {
|
||||||
const material = new THREE.LineBasicMaterial({ color: 0xb51f1f });
|
const material = new THREE.LineBasicMaterial({ color: 0xb51f1f });
|
||||||
const radiusX = spineWidth * 0.42;
|
|
||||||
const radiusY = 0.018;
|
|
||||||
const baseY = BOOK_PROFILE.tableY + BOOK_PROFILE.coverThickness + 0.002;
|
|
||||||
const profile = [];
|
const profile = [];
|
||||||
for (let i = 0; i <= 32; i += 1) {
|
for (let i = 0; i <= 32; i += 1) {
|
||||||
const u = i / 32;
|
const u = i / 32;
|
||||||
const theta = Math.PI * (1 - u);
|
profile.push(spineCurvePoint(u, spineWidth));
|
||||||
const x = Math.cos(theta) * radiusX;
|
|
||||||
const y = baseY + Math.sin(theta) * radiusY;
|
|
||||||
profile.push({ x, y });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[depth * 0.5 + 0.008, -depth * 0.5 - 0.008].forEach((z) => {
|
[depth * 0.5 + 0.008, -depth * 0.5 - 0.008].forEach((z) => {
|
||||||
@@ -232,26 +225,42 @@ function addClothSpine(depth, spineWidth) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function pageBlockTopY(thickness, u, v) {
|
function spineCurvePoint(t, spineWidth) {
|
||||||
|
const radiusX = spineWidth * 0.42;
|
||||||
|
const radiusY = 0.018;
|
||||||
|
const baseY = BOOK_PROFILE.tableY + BOOK_PROFILE.coverThickness + 0.002;
|
||||||
|
const theta = Math.PI * (1 - THREE.MathUtils.clamp(t, 0, 1));
|
||||||
|
return {
|
||||||
|
t: THREE.MathUtils.clamp(t, 0, 1),
|
||||||
|
x: Math.cos(theta) * radiusX,
|
||||||
|
y: baseY + Math.sin(theta) * radiusY
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function pageBlockTopY(side, thickness, u, v, fold, spineWidth) {
|
||||||
const hingeWidth = 0.105;
|
const hingeWidth = 0.105;
|
||||||
const hinge = THREE.MathUtils.clamp(u / hingeWidth, 0, 1);
|
const hinge = THREE.MathUtils.clamp(u / hingeWidth, 0, 1);
|
||||||
const t = easeOutCubic(hinge);
|
const t = easeOutCubic(hinge);
|
||||||
const sewnY = 0.066;
|
const sewnY = fold.y + 0.002;
|
||||||
const stackY = pageBlockBottomY(thickness, u, v) + thickness;
|
const stackY = pageBlockBottomY(side, thickness, u, v, fold, spineWidth) + thickness;
|
||||||
const flatCrown = 0.006 * Math.sin(Math.PI * v);
|
const flatCrown = 0.006 * Math.sin(Math.PI * v);
|
||||||
const foreCurl = 0.006 * smoothstep(THREE.MathUtils.clamp((u - 0.88) / 0.12, 0, 1));
|
const foreCurl = 0.006 * smoothstep(THREE.MathUtils.clamp((u - 0.88) / 0.12, 0, 1));
|
||||||
return sewnY * (1 - t) + (stackY + flatCrown + foreCurl) * t;
|
return sewnY * (1 - t) + (stackY + flatCrown + foreCurl) * t;
|
||||||
}
|
}
|
||||||
|
|
||||||
function pageBlockBottomY(thickness, u, v) {
|
function pageBlockBottomY(side, thickness, u, v, fold, spineWidth) {
|
||||||
const supportY = coverSupportTopY(u);
|
const curveEnd = 0.34;
|
||||||
return supportY + BOOK_PROFILE.paperContactOffset;
|
if (u <= curveEnd) {
|
||||||
|
return pageCurvePoint(side, fold, spineWidth, u, curveEnd).y;
|
||||||
|
}
|
||||||
|
const flatY = BOOK_PROFILE.coverThickness + BOOK_PROFILE.paperContactOffset;
|
||||||
|
return flatY;
|
||||||
}
|
}
|
||||||
|
|
||||||
function coverSupportTopY(u) {
|
function pageCurvePoint(side, fold, spineWidth, u, curveEnd) {
|
||||||
const hingeSpan = 0.14;
|
const along = THREE.MathUtils.clamp(u / curveEnd, 0, 1);
|
||||||
const t = THREE.MathUtils.clamp((u - hingeSpan) / (1 - hingeSpan), 0, 1);
|
const targetT = side < 0 ? 0 : 1;
|
||||||
return THREE.MathUtils.lerp(BOOK_PROFILE.raisedHingeY, BOOK_PROFILE.coverThickness, t);
|
return spineCurvePoint(THREE.MathUtils.lerp(fold.t, targetT, along), spineWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
function smoothstep(value) {
|
function smoothstep(value) {
|
||||||
@@ -266,12 +275,18 @@ function pageWidthAtDepth(width, v) {
|
|||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
function pageX(side, foldX, width, u, v = 0.5) {
|
function pageX(side, fold, spineWidth, width, u, v = 0.5) {
|
||||||
|
const curveEnd = 0.34;
|
||||||
|
if (u <= curveEnd) {
|
||||||
|
return pageCurvePoint(side, fold, spineWidth, u, curveEnd).x;
|
||||||
|
}
|
||||||
|
const outerT = THREE.MathUtils.clamp((u - curveEnd) / (1 - curveEnd), 0, 1);
|
||||||
|
const curveEndX = spineCurvePoint(side < 0 ? 0 : 1, spineWidth).x;
|
||||||
const foreX = side * pageWidthAtDepth(width, v);
|
const foreX = side * pageWidthAtDepth(width, v);
|
||||||
return foldX * (1 - u) + foreX * u;
|
return curveEndX * (1 - outerT) + foreX * outerT;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSplinePageBlockGeometry(side, width, depth, thickness, foldX) {
|
function createSplinePageBlockGeometry(side, width, depth, thickness, fold, spineWidth) {
|
||||||
const columns = 36;
|
const columns = 36;
|
||||||
const rows = 36;
|
const rows = 36;
|
||||||
const positions = [];
|
const positions = [];
|
||||||
@@ -294,8 +309,8 @@ function createSplinePageBlockGeometry(side, width, depth, thickness, foldX) {
|
|||||||
for (let column = 0; column <= columns; column += 1) {
|
for (let column = 0; column <= columns; column += 1) {
|
||||||
const u = column / columns;
|
const u = column / columns;
|
||||||
const z = (v - 0.5) * depth;
|
const z = (v - 0.5) * depth;
|
||||||
top[row][column] = push(pageX(side, foldX, width, u, v), pageBlockTopY(thickness, u, v), z, u, v);
|
top[row][column] = push(pageX(side, fold, spineWidth, width, u, v), pageBlockTopY(side, thickness, u, v, fold, spineWidth), z, u, v);
|
||||||
bottom[row][column] = push(pageX(side, foldX, width, u, v), pageBlockBottomY(thickness, u, v), z, u, v);
|
bottom[row][column] = push(pageX(side, fold, spineWidth, width, u, v), pageBlockBottomY(side, thickness, u, v, fold, spineWidth), z, u, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user