aboutsummaryrefslogtreecommitdiffhomepage
path: root/public/bluebey-studio/src/styles.js
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-06 09:56:21 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-06 09:56:21 +0900
commit8f39a174d6c4415c7a4df418187090fb5e061983 (patch)
treedbd3cf1e4f67393f029a455c4226479fbefe4804 /public/bluebey-studio/src/styles.js
parent63c1a9dfa8b04ab9725a9a49ef34cd3fc6ade56c (diff)
bluebey-studio: ボーンのたて回転・縦書きと吹き出しの形・線画の帽子小物・光の色
ボーンのたてスライダーが±180°で暴れる問題を修正。セリフの縦書きを禁則込みで直し、「ささやき」「思考」の吹き出しを追加。帽子・小物の輪郭線を線画のみにし、線画で帯や芯の境目が読めるよう調整。眼鏡の左右レンズ間隔、光と環境光の色を追加。ハートの下まぶた、レンズが濃いときのまばたきを修正。口メニューの項目名を整理。「顔/すべてをランダム」に眼鏡・Oの口・ひげの大きさ・目の左右位置などを追加。
Diffstat (limited to 'public/bluebey-studio/src/styles.js')
-rw-r--r--public/bluebey-studio/src/styles.js60
1 files changed, 48 insertions, 12 deletions
diff --git a/public/bluebey-studio/src/styles.js b/public/bluebey-studio/src/styles.js
index 8efdf71..2e4f62d 100644
--- a/public/bluebey-studio/src/styles.js
+++ b/public/bluebey-studio/src/styles.js
@@ -112,9 +112,13 @@ export class Styles {
this.paperMaterial = new THREE.MeshBasicMaterial({ color: paper, toneMapped: false });
// A hat is not flat: in a line drawing a white hat on a white head merges
// into one shape, so hats get a light tone instead of paper (see addMesh).
- this.toneMaterial = new THREE.MeshBasicMaterial({ color: toneOf(paper), toneMapped: false });
- /** Runtime meshes that want the tone fill rather than paper in 線画. */
- this.toneMeshes = new Set();
+ // The tone is per-mesh (`toneMeshes`, mesh -> material) and the amount it
+ // steps from the paper towards the ink is cached by strength in
+ // `toneMaterials`, so a part on a same-coloured neighbour (a hat band, a
+ // pencil's lead) can ask for a darker fill and its seam then reads.
+ this.toneMaterials = new Map();
+ /** Runtime meshes that want a tone fill rather than paper in 線画. */
+ this.toneMeshes = new Map();
this.invisibleMaterial = new THREE.MeshBasicMaterial({ colorWrite: false, depthWrite: true });
this.outlineWidth = outlineWidth;
@@ -159,6 +163,25 @@ export class Styles {
return entry.material;
}
+ /**
+ * The flat fill a runtime mesh wears instead of paper in 線画, cached by how far
+ * it steps from the paper towards the ink. `userData.tone` on the mesh (set by
+ * the builder) carries the amount; the hat default comes from `options.tone`.
+ */
+ toneMaterialFor(strength = DEFAULT_TONE) {
+ const key = String(strength);
+ let material = this.toneMaterials.get(key);
+ if (!material) {
+ material = new THREE.MeshBasicMaterial({
+ color: toneOf(this.paper, strength),
+ toneMapped: false,
+ });
+ material.userData.tone = strength;
+ this.toneMaterials.set(key, material);
+ }
+ return material;
+ }
+
createOutlines() {
const hulls = [];
for (const mesh of this.meshes) {
@@ -193,13 +216,20 @@ export class Styles {
* styles and gets an outline hull like the GLB parts. `removeMesh` undoes it.
*
* `options.tone` gives the mesh the light tone fill in 線画 instead of paper,
- * for parts whose shape would otherwise merge with the body (the hats).
+ * for parts whose shape would otherwise merge with the body (the hats). A
+ * number instead of `true` picks how far to step towards the ink, and the
+ * builder can override it per mesh with `userData.tone` - which is how a part
+ * draws its seam against a same-coloured neighbour.
+ *
+ * `options.lineOnly` keeps the hull to the line-art styles, so a runtime mesh
+ * (a hat, a prop) gets its ink outline in 線画 but none in リアル / フラット.
*/
addMesh(mesh, options = {}) {
if (!mesh || this.originals.has(mesh)) return;
this.originals.set(mesh, mesh.material);
this.meshes.push(mesh);
- if (options.tone) this.toneMeshes.add(mesh);
+ const tone = mesh.userData.tone ?? options.tone;
+ if (tone) this.toneMeshes.set(mesh, this.toneMaterialFor(tone === true ? DEFAULT_TONE : tone));
const kind = this.kindOf(mesh);
if (!OUTLINE_SKIP.has(kind)) {
const overlay = OUTLINE_SILHOUETTE_ONLY.has(kind);
@@ -214,7 +244,7 @@ export class Styles {
if (overlay) hull.renderOrder = -1;
hull.userData.kind = kind;
hull.userData.source = mesh;
- hull.userData.lineOnly = OUTLINE_LINE_ONLY.has(kind);
+ hull.userData.lineOnly = options.lineOnly === true || OUTLINE_LINE_ONLY.has(kind);
hull.userData.shadedOnly = OUTLINE_SHADED_ONLY.has(kind);
mesh.parent?.add(hull);
this.outlineMeshes.push(hull);
@@ -264,7 +294,7 @@ export class Styles {
// the leaves - is drawn by the screen-space outline, so no part needs a
// material trick of its own any more.
material = value === 'lineart'
- ? (this.toneMeshes.has(mesh) ? this.toneMaterial : this.paperMaterial)
+ ? (this.toneMeshes.get(mesh) ?? this.paperMaterial)
: this.invisibleMaterial;
} else if (value === 'flat') {
material = this.toonFor(original);
@@ -325,7 +355,9 @@ export class Styles {
setPaper(color) {
this.paper = color;
this.paperMaterial.color.set(color);
- this.toneMaterial.color.copy(toneOf(color));
+ for (const material of this.toneMaterials.values()) {
+ material.color.copy(toneOf(color, material.userData.tone));
+ }
}
setOutlineVisible(visible) {
@@ -379,7 +411,8 @@ export class Styles {
for (const entry of this.hullMaterials.values()) entry.material.dispose();
this.hullMaterials.clear();
this.paperMaterial.dispose();
- this.toneMaterial.dispose();
+ for (const material of this.toneMaterials.values()) material.dispose();
+ this.toneMaterials.clear();
this.invisibleMaterial.dispose();
this.gradientMap.dispose();
for (const material of this.toonMaterials.values()) material.dispose();
@@ -387,9 +420,12 @@ export class Styles {
}
}
-/** A step towards the ink, for the light fill a hat gets in 線画. */
-function toneOf(paper) {
- return new THREE.Color(paper).lerp(new THREE.Color('#2a1e33'), 0.14);
+/** How far the hat default steps from the paper towards the ink in 線画. */
+const DEFAULT_TONE = 0.14;
+
+/** A step towards the ink, for the flat fill a runtime mesh gets in 線画. */
+function toneOf(paper, strength = DEFAULT_TONE) {
+ return new THREE.Color(paper).lerp(new THREE.Color('#2a1e33'), strength);
}
/** A 3-step ramp gives crisper cartoon bands than the shader's default. */