From e9b8f3194c8604f5d0826df1b1e6a17cf27f68f7 Mon Sep 17 00:00:00 2001 From: Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> Date: Sun, 4 Oct 2026 00:54:43 +0900 Subject: bluebey-studio: 髪の生え際をなめらかにし、カーブとわけめを作り直す MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 髪のテクスチャを2倍解像度・曲線の分割を細かくして生え際のギザつきを解消。カーブを深い丸カバーに。わけめは正面側だけで非対称にし、継ぎ目で戻すことで背中の段差を解消。分け目はギャップで表現。 --- public/bluebey-studio/src/face.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'public/bluebey-studio/src/face.js') diff --git a/public/bluebey-studio/src/face.js b/public/bluebey-studio/src/face.js index e3063f2..f2440d3 100644 --- a/public/bluebey-studio/src/face.js +++ b/public/bluebey-studio/src/face.js @@ -1,6 +1,12 @@ import * as THREE from 'three'; import { drawEyes, drawMouth, drawHeadCoverWrap, canvasLayout } from './faceArt.js'; +// The hair plate's texture is drawn at this multiple of the plate's natural UV +// size. The hairline crosses the head over only a fraction of that height, so at +// 1x its edge comes out visibly jagged; doubling it (with the finer curve +// subdivision in `drawHeadCoverWrap`) keeps the edge smooth. +const HAIR_SCALE = 2; + /** * Owns the two procedural textures (eyes and mouth) and keeps them in sync with * the face parameters. @@ -48,7 +54,7 @@ export class Face { this.beardImages = {}; this.eyeCanvas = makeCanvas(this.eyeLayout); this.mouthCanvas = makeCanvas(this.mouthLayout); - this.hairCanvas = this.hairLayout ? makeCanvas(this.hairLayout) : null; + this.hairCanvas = this.hairLayout ? makeCanvas(this.hairLayout, HAIR_SCALE) : null; this.eyeCtx = this.eyeCanvas.getContext('2d'); this.mouthCtx = this.mouthCanvas.getContext('2d'); this.hairCtx = this.hairCanvas ? this.hairCanvas.getContext('2d') : null; @@ -264,10 +270,13 @@ export class Face { this.hairMesh.renderOrder = p.eyes.headMark?.overEyes === false ? 0 : 3; const layout = this.hairLayout; const ctx = this.hairCtx; - ctx.clearRect(0, 0, layout.width, layout.height); + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(0, 0, layout.width * HAIR_SCALE, layout.height * HAIR_SCALE); + ctx.scale(HAIR_SCALE, HAIR_SCALE); // `drawHeadCoverWrap` works in canvas coordinates (its x axis is the UV // angle already normalised), so it is not shifted by the window offset. drawHeadCoverWrap(ctx, p.eyes.headMark ?? {}, layout); + ctx.setTransform(1, 0, 0, 1, 0, 0); this.hairTexture.needsUpdate = true; } @@ -275,10 +284,10 @@ export class Face { } } -function makeCanvas({ width, height }) { +function makeCanvas({ width, height }, scale = 1) { const canvas = document.createElement('canvas'); - canvas.width = width; - canvas.height = height; + canvas.width = Math.round(width * scale); + canvas.height = Math.round(height * scale); return canvas; } -- cgit v1.3.1