PerfectVector
Yazan Irene Kim8 dk okuma

Three.js SVGLoader: Düz çizimden 3B mesh oluşturun

SVG yollarını Three.js'e yükleyin, gerçek bir boşluğu koruyun, dikey yönü düzeltin ve küçük, tekrarlanabilir bir tarayıcı örneğiyle derinlik verilen mesh'i boyutlandırın.

Bu sayfada

Düz SVG çizimini bir Three.js mesh'ine dönüştürmek için SVG'yi yükleyin, yollarını şekillere dönüştürün ve ardından bu şekilleri ExtrudeGeometry'ye aktarın. Efekt eklemeden önce boşlukları, dikey yönü ve boyutları kontrol edin. Silüet tanınabilir olsa bile bir iç boşluk dolmuş veya bir köşe ters dönmüş olabilir.

Bu uygulamada, kare bir boşluğu ve sağ üst köşesinde kesik bir bölümü olan, elle hazırlanmış özgün bir rozet kullanılıyor. Asimetri, yön hatasını görünür kılıyor. Bu, tarayıcıda çalışan bir geometri örneğidir; PerfectVector dönüştürme sonucu veya üretim testi değildir.

Derinlik vermek istediğiniz şekillerle başlayın

İlk denemede kapalı, dolgulu konturlar içeren küçük bir SVG kullanın. Bunu badge.svg olarak kaydedin:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 180">
  <path fill="#e64b35" fill-rule="evenodd"
    d="M20 20H160L220 80V160H20Z M65 60H115V110H65Z"/>
</svg>

Tek bir yol öğesinde iki kapalı alt yol vardır: bir dış sınır ve bir iç kare. evenodd dolgu kuralı, bu iç bölgeyi boşluk haline getirir. Ayrı bir beyaz dikdörtgen, düz bir resimde yalnızca yüzeyi örter; aynı boş bölgeyi tanımlamaz.

Çizim, 240 × 180 boyutundaki viewBox içinde 200 × 140 koordinat birimlik alan kaplar. Mesh'i boyutlandırırken bu farkı aklınızda tutun. Boş kenar payları SVG görüntüleme alanının parçasıdır; derinlik verilen silüetin parçası değildir.

Elinizde zaten düzenlenebilir bir vektör orijinali varsa onu kullanın. Tek kaynağınız PNG veya JPG ise PerfectVector'ın görselden vektöre dönüştürme iş akışı, SVG yol çizimini hazırlamanıza yardımcı olabilir. Dosyayı Three.js'e yüklemeden önce önizlemeyi ve indirdiğiniz konturları, özellikle de negatif alanları inceleyin. Vektörleştirme 2B çizimi sağlar; aşağıdaki kod ise derinliği, malzemeleri, aydınlatmayı ve yerleşimi sağlar.

SVG'yi yükleyin ve mesh'i render edin

Örnek Three.js 0.186.0 ile test edildi. Çekirdek kitaplığı ve eklentiyi aynı sürümde tutun. Paket içe aktarımları kullanan bir tarayıcı projesinde three@0.186.0 kurun, dosyaları HTTP üzerinden sunun ve bir kapsayıcı oluşturun:

<div id="viewer"></div>
<script type="module" src="./main.js"></script>

Derleme aracınız three içe aktarımlarını çözümlemelidir. Derleme aracı olmayan sade bir tarayıcı sayfası için, aynı kurulu paketin dosyalarını kullanarak bu import map'i modül betiğinin önüne yerleştirin:

<script type="importmap">
{
  "imports": {
    "three": "./node_modules/three/build/three.module.js",
    "three/addons/": "./node_modules/three/examples/jsm/"
  }
}
</script>

badge.svg dosyasını HTML sayfasının yanına yerleştirin. Aşağıdaki göreli yükleme URL'si, o sayfanın URL'sine göre çözümlenir. Ardından bunu main.js olarak kaydedin:

import * as THREE from 'three';
import { SVGLoader } from 'three/addons/loaders/SVGLoader.js';
 
const data = await new SVGLoader().loadAsync('./badge.svg');
const artwork = new THREE.Group();
for (const path of data.paths) {
  if (path.userData.style.fill === 'none') continue;
  for (const shape of path.toShapes()) {
    const geometry = new THREE.ExtrudeGeometry(shape, {
      depth: 20, bevelEnabled: false, steps: 1
    });
    const material = new THREE.MeshStandardMaterial({
      color: path.color, roughness: 0.65, metalness: 0
    });
    artwork.add(new THREE.Mesh(geometry, material));
  }
}
if (!artwork.children.length) throw new Error('No filled shapes found');
 
// SVG y grows down; this scene uses y up.
artwork.scale.y = -1;
const bounds = new THREE.Box3().setFromObject(artwork);
const size = bounds.getSize(new THREE.Vector3());
const center = bounds.getCenter(new THREE.Vector3());
const scale = 4 / size.x;
artwork.scale.multiplyScalar(scale);
artwork.position.copy(center).multiplyScalar(-scale);
 
const scene = new THREE.Scene();
scene.background = new THREE.Color('#f1f3f5');
scene.add(artwork);
scene.add(new THREE.HemisphereLight(0xffffff, 0x596477, 2));
const light = new THREE.DirectionalLight(0xffffff, 3);
light.position.set(-3, 5, 7);
scene.add(light);
const camera = new THREE.PerspectiveCamera(35, 800 / 600, 0.1, 100);
camera.position.set(4, 3, 9);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(800, 600);
document.querySelector('#viewer').append(renderer.domElement);
renderer.render(scene, camera);

SVGLoader, ayrı içe aktarılan bir eklentidir. loadAsync() dosyayı okur; SVG işaretlemesi zaten bir metin dizgesi olarak elinizdeyse alternatif olarak parse(svgText) kullanabilirsiniz.

r186'da path.toShapes() kullanın. Eski örnekler sıklıkla SVGLoader.createShapes(path) çağırır. Bu yardımcı işlevin kullanımı r185'ten itibaren artık önerilmiyor (deprecated); test edilen sürümde işlemi toShapes()'e devreder. Farklı eğitimlerden kod parçalarını birleştirmeden önce kurulu sürümünüzü kontrol edin.

Döngü, fill="none" değerini bilinçli olarak atlar. Bu örnekteki düz renk dolgularını işler; tam kapsamlı bir SVG render aracı değildir. Degradeler, maskeler, gömülü görseller, kontur çizgileri, opaklık ve üst üste binen renk katmanları için ayrı kararlar gerekir. Düz görünümün birebir aynı 3B geometriye dönüşeceğini varsaymayın.

Kare boşluğu ve kesik sağ üst köşesi olan özgün SVG rozeti, Three.js ile derinlik verilmiş mesh'iyle karşılaştıran gerçek tarayıcı görüntüsü
Elle hazırlanmış test çiziminin Three.js r186'daki gerçek WebGL render'ı. Boşluk açık kalır, kesik köşe sağ üstte kalır ve eşit oranlı ölçekleme 4 × 2.8 × 0.4 boyutunda bir mesh oluşturur.

Ölçme ve merkezleme işlemlerinden önce yönü ayarlayın

SVG'nin dikey koordinatları aşağı doğru artar. Bu sahnede çizime bakılırken pozitif y yukarıyı gösterir; dolayısıyla artwork.scale.y = -1 beklenen yönü geri getirir. Kontrol noktası kesik köşedir: sağ üstte bulunmalıdır.

Bu işaret değişikliği, bu koordinat düzenine özgüdür. Kamerayı veya üst nesneyi döndürdükten sonra mesh hâlâ yanlış görünüyorsa ikinci bir ters çevirme eklemeyin. Önce kaynaktaki bilinen bir asimetrik özelliği render edilen sahneyle karşılaştırın.

Sonraki satırlar, ters çevrilmiş grubu ölçer, eşit oranlı bir ölçek hesaplar ve ölçeklenmiş merkezini orijine taşır. Box3.setFromObject(), alt nesneler ve onların dönüşümleri dahil sınırları ölçer. Burada ölçüm sırasında grubun dönüşüm uygulanmış bir üst nesnesi yoktur ve çizim döndürülmemiştir.

Başlangıçtaki derinlik verilmiş geometrinin boyutları 200 × 140 × 20'dir. Genişliği 4 olarak ayarlamak 4 / 200, yani 0.02 ölçek katsayısını verir. Bu ölçek üç eksene de uygulandığı için ortaya çıkan sınırlar 4 × 2.8 × 0.4 olur. Oluşturucuda verilen 20 derinliği, grup ölçeklendikten sonra 20 olarak kalmaz.

Bunlar sahne birimleridir. Örnek, bir birimin bir milimetre olduğunu iddia etmez. Uygulamanızın belirli bir fiziksel karşılığa ihtiyacı varsa bunu açıkça tanımlayın ve hedef iş akışında doğrulayın.

Yüzeyi süslemeden önce boşluğu doğrulayın

Testte bir yol yüklendi, bir şekil ve bir boşluk oluştu. Ayrıca kare boşluktan bir ışın, dolu alandan da başka bir ışın gönderdik: boşluk herhangi bir mesh kesişimi döndürmezken dolu alan bir kesişim döndürdü. Kesik sağ üst köşeden ve dolu sağ alt köşeden geçen ışınlar, açılı görünümden bağımsız olarak dikey yönü doğruladı.

Kendi sahnenizde daha basit bir görsel kontrolle başlayabilirsiniz: yüzeye önce tam karşıdan, sonra zıt renkli bir arka plan önünde açılı olarak bakın. Boşluktan arka plan görünmeli ve kamera hareket ettiğinde boşluğun yan duvarları ortaya çıkmalıdır. Bölgeyi örten beyaz bir yüzey farklı bir sonuçtur.

Bir iç boşluk doluyorsa o şekli tek başına inceleyin. Kaynağın alt yollar mı, ayrı dolgulu nesneler mi, kırpma yolu mu yoksa maske mi kullandığını kontrol edin. Sorunu malzeme rengiyle gizlemeye çalışmayın. Dolup kapanan SVG boşlukları kılavuzu, kaynak dosyadaki farkları açıklar; derinlik verme sorunlarının teşhisi ise temel çizim bozuk olduğunda konturların onarılmasını ele alır.

Sade geometri çalıştıktan sonra derinlik efektlerini ekleyin

Örnek, başlangıç boyutlarını kolayca inceleyebilmeniz için bevel işlemini kapatır. ExtrudeGeometry seçenekleri, derinliği, bevel boyutunu, bevel kalınlığını ve eğri örneklemesini ayrı ayrı kontrol eder. Bevel işlemini etkinleştirdiğinizde küçük boşlukları ve sınırları yeniden kontrol edin. Dekoratif bir kenar, az önce ölçtüğünüz geometriyi değiştirir.

Eğrili çizimlerde mesh silüetini, uygulamanızın kullanacağı boyutta ve kamera uzaklığında inceleyin. Eğri örneklemesini yalnızca köşeli görünüm gerektiriyorsa artırın; girdideki gereksiz düğümleri azaltmak ayrı bir düzenleme işidir. Bu iki ayar da kaynakta bulunmayan ayrıntıları geri getirmez.

Yalnızca kontur çizgilerinden oluşan bir çizim için de farklı bir karar gerekir. Yükleyici, kontur geometrisi için pointsToStroke() sunar; ancak yukarıdaki dolgulu şekil döngüsü bu yolları bilinçli olarak dışarıda bırakır. Görünen çizgi, derinlik verilen bir şeride dönüşecekse önce o şeridi hangi kapalı sınırın tanımlayacağına karar verin. Sahnede çizgi olarak kalacaksa bir çizgi veya kontur temsili oluşturun.

React uygulamalarında yalnızca tarayıcıda çalışabilen yükleme ve render işlemlerini istemci tarafında yürütün. Görünüm kaldırıldığında ona ait geometriyi, malzemeleri ve renderer'ı serbest bırakın. Bu kısa örnek sabit boyutta bir kez render eder; üretimde kullanılacak bir görüntüleyici, yeniden boyutlandırmayı ve kendi kaynak yaşam döngüsünü de yönetmelidir.

Kaynak ve hedef kontrollerini ayrı tutun

Tarayıcı mesh'i, etkileşimli bir rozet, logo önizlemesi veya sahne süslemesi için kullanışlıdır. Sonucun açık yüzeyleri olmayan kapalı bir geometriye sahip, boyutsal olarak uygun bir parça olduğunu kanıtlamaz. Hedefiniz fiziksel üretimse ayrı 3B baskı için görselden SVG'ye dönüştürme iş akışını kullanın ve içe aktarılan modeli orada inceleyin.

Ekranda kullanım için üç dosyayı veya aşamayı ayrı tutun: düzenlenebilir kaynak SVG, ondan türetilen mesh ve sahne sunumu. Böylece kötü bir sonucun yol geometrisinden mi, mesh oluşturulmasından mı yoksa kamera ve aydınlatmadan mı kaynaklandığını daha kolay ayırt edebilirsiniz. Daha fazla SVG iş akışı kılavuzu, çizimin yüklemeden önce onarılması gerektiğinde kaynak tarafını ele alır.

Sık sorulan sorular

SVG'm Three.js'te neden ters duruyor? SVG'nin dikey koordinatları aşağı doğru artar. Pozitif y'nin yukarıyı gösterdiği ve çizimin ön yüzüne bakılan bir sahnede, çizim grubunun y ölçeğini ters çevirmek kaynağın yönünü geri getirebilir. Başka bir ters çevirme veya döndürme eklemeden önce asimetrik bir özelliği kontrol edin.

createShapes mı, toShapes mı kullanmalıyım? Bu örnek Three.js 0.186.0 ile path.toShapes() kullanır. SVGLoader.createShapes() kullanımı, r185'ten itibaren artık önerilmiyor (deprecated). Çekirdek paket ve eklentiyi aynı sürümde tutarak projenizde kurulu sürüm için belgelenen API'yi kullanın.

SVGLoader, SVG içindeki bir PNG'yi mesh'e dönüştürür mü? Gömülü bir raster görüntü, bu örneğin kullandığı dolgulu konturları sağlamaz. Önce uygun yol çizimini elde edin veya asıl hedef görünümü korumaksa görseli doku olarak kullanın.

Derinlik verme işlemi SVG kontur kalınlığını korur mu? Bu örnek dolgulu şekillere derinlik verir ve fill değeri none olan yolları atlar. Kontur geometrisi ayrı bir iş akışı gerektirir; kalın boyanmış bir çizgi, otomatik olarak derinlik verilen bir şeridin kapalı sınırına dönüşmez.

Kaynaklar

  1. Three.js — SVGLoader — Eklenti içe aktarımını, ayrıştırma ve yükleme yöntemlerini, kontur yardımcı işlevini ve createShapes kullanımının artık önerilmemesini belgeler.
  2. Three.js — ShapePath — Yol koleksiyonlarının toShapes ile şekillere dönüştürülmesini belgeler.
  3. Three.js — ExtrudeGeometry — Şekillere derinlik verme, derinlik, bevel ve eğri örnekleme seçeneklerini tanımlar.
  4. Three.js — Box3 — Dönüşüm uygulanmış nesnelerin sınırlarını ölçmeyi, boyutlarını ve merkezlerini elde etmeyi belgeler.

Yalnızca raster görüntü biçiminde bulunan bir amblemle mi çalışıyorsunuz? Bir SVG adayı hazırlayın, dolgulu konturlarını ve boşluklarını inceleyin; ardından tam görüntüleyiciyi oluşturmadan önce bu dosyayı küçük sahnede test edin.

Bloga daha fazlası

Düzenlemesi daha kolay,
daha temiz bir SVG ile başlayın