feat(stereo3d): Фаза 4 — визуал (подписи осей, свечение вершин, контраст рёбер)

- подписи осей X/Y/Z цветами AxesHelper
- мягкое additive-свечение вершин (без текстур), вершины поверх рёбер
- рёбра контрастнее (opacity 0.9, renderOrder над полупрозрачным телом)
- bump stereo.js?v=7

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-30 11:32:21 +03:00
parent dbb6a6fa11
commit b46c761373
3 changed files with 31 additions and 6 deletions
+25 -2
View File
@@ -917,6 +917,16 @@ class StereoSim {
axes.material.transparent = true;
axes.material.opacity = 0.4;
this._gridGroup.add(axes);
// axis letters, coloured to match AxesHelper (X red, Y green, Z blue)
const axLabel = (txt, color, pos) => {
const s = this._makeTextSprite(txt, color, 38);
s.position.copy(pos);
s.scale.multiplyScalar(0.85);
this._gridGroup.add(s);
};
axLabel('X', '#ff5b5b', new THREE.Vector3(6.5, 0.15, 0));
axLabel('Y', '#5bff8d', new THREE.Vector3(0, 6.6, 0));
axLabel('Z', '#5b9bff', new THREE.Vector3(0, 0.15, 6.5));
}
this._invalidate();
}
@@ -1432,13 +1442,15 @@ class StereoSim {
this._figGroup.add(new THREE.Mesh(geo, mat));
}
_addEdges(opac = 0.8) {
_addEdges(opac = 0.9) {
if (!this.showEdges) return;
for (const e of this._edges) {
const pts = [e.from, e.to];
const geo = new THREE.BufferGeometry().setFromPoints(pts);
const mat = new THREE.LineBasicMaterial({ color: 0xFFFFFF, transparent: true, opacity: opac, linewidth: 2 });
this._figGroup.add(new THREE.Line(geo, mat));
const line = new THREE.Line(geo, mat);
line.renderOrder = 2; // draw over the translucent solid for crisp contrast
this._figGroup.add(line);
if (this.showEdgeLengths) {
const len = e.from.distanceTo(e.to);
@@ -1454,10 +1466,21 @@ class StereoSim {
_addVerticesAndLabels() {
for (const v of this._vertices) {
if (this.showVertices) {
// soft additive glow halo (texture-free → safe with _clearGroup disposal)
const gGeo = new THREE.SphereGeometry(0.17, 12, 12);
const gMat = new THREE.MeshBasicMaterial({
color: 0x9B5DE5, transparent: true, opacity: 0.16,
blending: THREE.AdditiveBlending, depthWrite: false,
});
const glow = new THREE.Mesh(gGeo, gMat);
glow.position.copy(v.pos);
this._figGroup.add(glow);
const sGeo = new THREE.SphereGeometry(0.08, 12, 12);
const sMat = new THREE.MeshBasicMaterial({ color: 0xFFFFFF });
const sphere = new THREE.Mesh(sGeo, sMat);
sphere.position.copy(v.pos);
sphere.renderOrder = 3;
this._figGroup.add(sphere);
}
+1 -1
View File
@@ -4819,7 +4819,7 @@
<script src="/js/labs/flask.js"></script>
<script src="/js/labs/redox.js"></script>
<script src="/js/labs/ionexchange.js"></script>
<script src="/js/labs/stereo.js?v=6"></script>
<script src="/js/labs/stereo.js?v=7"></script>
<script src="/js/notifications.js"></script>
<script src="/js/search.js"></script>
<script src="/js/mobile.js"></script>
+5 -3
View File
@@ -36,10 +36,12 @@
Бэклог: полное «построение сечения по следам» (продление рёбер, след на грани); readout углов (двугранный/линия-плоскость) — сейчас угол только в 3D-метке.
## Фаза 4 — Визуал
## Фаза 4 — Визуал — ГОТОВО (см. бэклог)
- [ ] 4.1 Материалы: рёбра с anti-alias, подсветка активной грани, свечение вершин.
- [ ] 4.2 Аккуратные оси X/Y/Z с подписями, опциональный фон (тёмный/бумага).
- [x] 4.1 Свечение вершин (мягкий additive-ореол без текстур, безопасно с `_clearGroup`); рёбра контрастнее (opacity 0.9, `renderOrder` поверх полупрозрачного тела), вершины поверх рёбер. _(Подсветка грани по ховеру отложена — текущий centroid-пикинг граней грубоват для плавного hover.)_
- [x] 4.2 Подписи осей X/Y/Z, цвета совпадают с AxesHelper (X крас., Y зел., Z син.).
Бэклог: подсветка грани по ховеру (нужен точный raycast по логическим граням); градиентный/бумажный фон (учесть захват в скриншоте).
## Фаза 5 — Интеграция и архитектура