Three.js SVGLoader: เปลี่ยนงานภาพแบนเป็นเมช 3 มิติ
โหลดพาธ SVG ใน Three.js รักษาช่องเปิดจริง แก้ทิศทางแนวตั้ง และกำหนดขนาดเมชที่อัดความลึกด้วยตัวอย่างเบราว์เซอร์เล็กที่ทำซ้ำได้
ในหน้านี้
หากต้องการเปลี่ยนงาน SVG แบนเป็นเมช Three.js ให้โหลด SVG แปลงพาธเป็นรูปทรง แล้วส่งรูปทรงให้ ExtrudeGeometry ตรวจช่องเปิด ทิศทางแนวตั้ง และขนาดก่อนเพิ่มเอฟเฟกต์ รูปเงาที่จำได้ยังอาจมีช่องภายในถูกเติมหรือมุมกลับหัว
คู่มือนี้ใช้ตราสัญลักษณ์ที่เขียนขึ้นเองพร้อมช่องเปิดสี่เหลี่ยมหนึ่งช่องและมุมบนขวาที่ตัดเฉียง ความไม่สมมาตรทำให้มองเห็นความผิดพลาดด้านทิศทาง นี่เป็นตัวอย่างรูปทรงในเบราว์เซอร์ ไม่ใช่ผลแปลง PerfectVector หรือการทดสอบการผลิต
เริ่มด้วยรูปทรงที่ต้องการเพิ่มความลึก
ใช้ SVG เล็กที่มีเส้นรอบรูปปิดและเติมสีสำหรับครั้งแรก บันทึกเป็น badge.svg:
<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>มีพาธย่อยปิดสองส่วนในองค์ประกอบพาธเดียว: ขอบภายนอกและสี่เหลี่ยมภายใน กฎเติม evenodd ทำให้พื้นที่ภายในเป็นช่องเปิด สี่เหลี่ยมสีขาวแยกจะเพียงปิดทับหน้าในภาพแบน ไม่ได้อธิบายพื้นที่ว่างแบบเดียวกัน
งานภาพกินพื้นที่ 200 คูณ 140 หน่วยพิกัดภายใน viewBox ขนาด 240 คูณ 180 อย่าลืมความต่างนั้นเมื่อกำหนดขนาดเมช ขอบว่างเป็นส่วนของวิวพอร์ต SVG ไม่ใช่รูปเงาที่อัดความลึก
หากมีเวกเตอร์ต้นฉบับที่แก้ไขได้อยู่แล้ว ให้ใช้มัน หาก PNG หรือ JPG เป็นแหล่งเดียว กระบวนการแปลงภาพเป็นเวกเตอร์ของ PerfectVector ช่วยเตรียมงานพาธ SVG ได้ ตรวจพรีวิวและเส้นรอบรูปที่ดาวน์โหลด โดยเฉพาะพื้นที่ว่างในรูป ก่อนโหลดเข้า Three.js การแปลงเป็นเวกเตอร์ให้งาน 2 มิติ ส่วนโค้ดด้านล่างให้ความลึก วัสดุ แสง และตำแหน่ง
โหลด SVG และเรนเดอร์เมช
ตัวอย่างทดสอบด้วย Three.js 0.186.0 ให้ไลบรารีหลักและ addon อยู่เวอร์ชันเดียวกัน ในโปรเจกต์เบราว์เซอร์ที่นำเข้าแพ็กเกจได้ ติดตั้ง three@0.186.0 ให้บริการไฟล์ผ่าน HTTP และสร้างคอนเทนเนอร์:
<div id="viewer"></div>
<script type="module" src="./main.js"></script>เครื่องมือบิลด์ต้องหา import three ได้ สำหรับหน้าเบราว์เซอร์ธรรมดาที่ไม่มีเครื่องมือบิลด์ ให้วาง import map นี้ก่อนสคริปต์โมดูล โดยใช้ไฟล์จากแพ็กเกจติดตั้งเดียวกัน:
<script type="importmap">
{
"imports": {
"three": "./node_modules/three/build/three.module.js",
"three/addons/": "./node_modules/three/examples/jsm/"
}
}
</script>วาง badge.svg ข้างหน้า HTML URL โหลดสัมพัทธ์ด้านล่างคำนวณจาก URL ของหน้านั้น จากนั้นบันทึกเป็น main.js:
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 เป็น addon ที่นำเข้าแยก loadAsync() อ่านไฟล์ ส่วน parse(svgText) เป็นทางเลือกเมื่อมีมาร์กอัป SVG เป็นสตริงแล้ว
ใน r186 ใช้ path.toShapes() ตัวอย่างเก่ามักเรียก SVGLoader.createShapes(path) ตัวช่วยนั้นถูกประกาศเลิกใช้ใน r185 และส่งงานต่อให้ toShapes() ในเวอร์ชันที่ทดสอบ ตรวจรุ่นติดตั้งก่อนผสมโค้ดจากบทเรียนต่างกัน
ลูปจงใจข้าม fill="none" มันจัดการสีเติมทึบในตัวอย่างนี้ ไม่ใช่ตัวเรนเดอร์ SVG เต็มรูปแบบ ไล่สี มาสก์ ภาพฝัง เส้นขอบ ความทึบ และชั้นสีซ้อนต้องตัดสินใจแยก แทนการสมมติว่ารูปลักษณ์แบนจะกลายเป็นรูปทรง 3 มิติที่เหมือนกัน

ตั้งทิศทางก่อนวัดและจัดศูนย์กลาง
พิกัดแนวตั้ง SVG เพิ่มลงล่าง ฉากนี้มองงานภาพโดยให้ y บวกชี้ขึ้น ดังนั้น artwork.scale.y = -1 คืนทิศทางที่คาดหวัง มุมตัดเป็นจุดตรวจ: ควรอยู่บนขวา
การเปลี่ยนเครื่องหมายนี้เป็นของการตั้งค่าพิกัดนี้ อย่าเพิ่มการกลับด้านครั้งที่สองเพราะเมชยังดูผิดหลังหมุนกล้องหรือวัตถุแม่ เปรียบเทียบรายละเอียดไม่สมมาตรที่รู้จากต้นฉบับกับฉากเรนเดอร์ก่อน
บรรทัดถัดไปวัดกลุ่มที่กลับด้าน คำนวณมาตราส่วนเท่ากัน และเลื่อนศูนย์กลางหลังปรับมาตราส่วนไปจุดกำเนิด Box3.setFromObject() วัดขอบเขตรวมวัตถุลูกและการแปลง ในที่นี้กลุ่มไม่มีวัตถุแม่ที่ผ่านการแปลงและไม่มีการหมุนงานขณะวัด
รูปทรงอัดความลึกเดิมมีขนาด 200 คูณ 140 คูณ 20 การตั้งความกว้างเป็น 4 ให้มาตราส่วน 4 / 200 หรือ 0.02 เพราะใช้กับทั้งสามแกน ขอบเขตผลลัพธ์จึงเป็น 4 คูณ 2.8 คูณ 0.4 ความลึก 20 ในตัวสร้างไม่คงเป็น 20 หลังปรับมาตราส่วนกลุ่ม
นี่เป็นหน่วยฉาก ตัวอย่างไม่ได้อ้างว่าหนึ่งหน่วยคือหนึ่งมิลลิเมตร หากแอปต้องมีความหมายทางกายภาพเฉพาะ ให้กำหนดชัดและตรวจผ่านกระบวนการปลายทาง
ยืนยันช่องเปิดก่อนตกแต่งพื้นผิว
การทดสอบได้พาธที่โหลดหนึ่งพาธ รูปทรงหนึ่งรูป และช่องเปิดหนึ่งช่อง เรายิงรังสีผ่านช่องสี่เหลี่ยมและผ่านพื้นที่ทึบด้วย: ช่องเปิดไม่พบการชนเมช ส่วนทึบพบการชน รังสีผ่านมุมบนขวาที่ตัดและมุมล่างขวาทึบยืนยันทิศทางแนวตั้งโดยไม่พึ่งมุมมองเฉียง
คุณเริ่มด้วยการตรวจภาพง่ายกว่าในฉากตัวเองได้: ดูหน้าตรง แล้วดูมุมเฉียงบนพื้นหลังตัดกัน ช่องเปิดควรเผยพื้นหลัง และควรเห็นผนังข้างเมื่อกล้องเคลื่อน หน้าสีขาวที่ปิดพื้นที่นั้นเป็นคนละผล
หากช่องภายในถูกเติม ให้แยกรูปทรงนั้น ตรวจว่าต้นฉบับใช้พาธย่อย วัตถุเติมแยก พาธตัดภาพ หรือมาสก์ อย่าพยายามซ่อนปัญหาด้วยสีวัสดุ คู่มือช่องเปิด SVG ที่ถูกเติม อธิบายความต่างไฟล์ต้นทาง ส่วน การวินิจฉัยการอัดความลึก ครอบคลุมการซ่อมเส้นรอบรูปเมื่องานพื้นฐานเสีย
เพิ่มเอฟเฟกต์ความลึกหลังรูปทรงธรรมดาทำงานแล้ว
ตัวอย่างปิด bevel เพื่อให้ตรวจขนาดเริ่มต้นง่าย ตัวเลือก ExtrudeGeometry ควบคุมความลึก ขนาด bevel ความหนา bevel และการเก็บตัวอย่างจุดบนเส้นโค้งแยกกัน ตรวจช่องเปิดเล็กและขอบเขตใหม่เมื่อเปิด bevel ขอบตกแต่งเปลี่ยนรูปทรงที่เพิ่งวัด
สำหรับงานโค้ง ตรวจรูปเงาเมชตามขนาดและระยะกล้องที่จะใช้ในแอป เพิ่มการเก็บตัวอย่างจุดบนเส้นโค้งเฉพาะเมื่อเหลี่ยมที่เห็นต้องการ การลดโหนดอินพุตที่ไม่จำเป็นเป็นงานแก้ไขแยก ทั้งสองการตั้งค่าไม่คืนรายละเอียดที่ไม่มีในต้นฉบับ
ภาพวาดที่มีเพียงเส้นขอบต้องตัดสินใจต่างกันด้วย ตัวโหลดมี pointsToStroke() สำหรับรูปทรงเส้นขอบ แต่ลูปรูปเติมด้านบนจงใจละพาธเหล่านั้น หากเส้นที่เห็นควรกลายเป็นแถบอัดความลึก ให้ตัดสินใจก่อนว่าเส้นรอบรูปปิดใดกำหนดแถบนั้น หากควรคงเป็นเส้นในฉาก ให้สร้างรูปแบบเส้นหรือเส้นขอบแทน
สำหรับแอป React รันงานโหลดและเรนเดอร์ที่ใช้ได้เฉพาะเบราว์เซอร์บนไคลเอนต์ และกำจัด geometry วัสดุ และตัวเรนเดอร์ที่คุณเป็นเจ้าของเมื่อถอดมุมมองออก ตัวอย่างย่อเรนเดอร์ครั้งเดียวที่ขนาดคงที่ ตัวดูจริงต้องจัดการการเปลี่ยนขนาดและวงจรทรัพยากรด้วย
แยกการตรวจต้นฉบับกับปลายทาง
เมชในเบราว์เซอร์มีประโยชน์กับตราสัญลักษณ์โต้ตอบ พรีวิวโลโก้ หรือของตกแต่งฉาก ไม่ได้ยืนยันว่าผลเป็นชิ้นส่วนปิดสนิทและมีขนาดเหมาะสม หากปลายทางคือการผลิต ให้ใช้ กระบวนการภาพเป็น SVG สำหรับพิมพ์ 3 มิติ แยกและตรวจโมเดลที่นำเข้าในนั้น
สำหรับงานบนหน้าจอ ให้แยกสามไฟล์หรือขั้นตอน: SVG ต้นฉบับที่แก้ไขได้ เมชที่สร้างต่อ และการนำเสนอฉาก ทำให้แยกได้ง่ายว่าผลผิดมาจากรูปทรงพาธ การสร้างเมช หรือกล้องกับแสง คู่มือกระบวนการ SVG เพิ่มเติมครอบคลุมฝั่งต้นฉบับเมื่อต้องซ่อมงานก่อนโหลด
คำถามที่พบบ่อย
ทำไม SVG กลับหัวใน Three.js? พิกัดแนวตั้ง SVG เพิ่มลงล่าง ในฉากที่ใช้ y บวกขึ้นและดูด้านหน้างานภาพ การกลับมาตราส่วน y ของกลุ่มอาจคืนทิศทางต้นฉบับ ตรวจรายละเอียดไม่สมมาตรก่อนเพิ่มการกลับด้านหรือหมุนอีกครั้ง
ควรใช้ createShapes หรือ toShapes? ตัวอย่างนี้ใช้ path.toShapes() กับ Three.js 0.186.0 SVGLoader.createShapes() ถูกประกาศเลิกใช้ใน r185 ใช้ API ที่มีเอกสารสำหรับเวอร์ชันติดตั้ง โดยให้แพ็กเกจหลักกับ addon อยู่รุ่นเดียวกัน
SVGLoader เปลี่ยน PNG ใน SVG เป็นเมชหรือไม่? ภาพราสเตอร์ฝังไม่มีเส้นรอบรูปเติมที่ตัวอย่างนี้ใช้ เตรียมงานพาธที่เหมาะก่อน หรือใช้ภาพเป็นเท็กซ์เจอร์เมื่อเป้าหมายจริงคือรักษารูปลักษณ์
การอัดความลึกรักษาความหนาเส้นขอบ SVG หรือไม่? ตัวอย่างนี้อัดความลึกรูปเติมและข้ามพาธที่ fill เป็น none รูปทรงเส้นขอบต้องใช้กระบวนการแยก เส้นหนาที่วาดไม่ได้เป็นเส้นรอบรูปปิดของแถบอัดความลึกโดยอัตโนมัติ
แหล่งอ้างอิง
- Three.js — SVGLoader — อธิบายการนำเข้า addon เมธอดแยกวิเคราะห์และโหลด ตัวช่วยเส้นขอบ และการเลิกใช้ createShapes
- Three.js — ShapePath — อธิบายการแปลงชุดพาธเป็นรูปทรงด้วย toShapes
- Three.js — ExtrudeGeometry — นิยามการอัดความลึกรูปทรง ความลึก bevel และตัวเลือกการเก็บตัวอย่างจุดบนเส้นโค้ง
- Three.js — Box3 — อธิบายการวัดขอบเขตวัตถุที่ผ่านการแปลงและหาขนาดกับศูนย์กลาง
ทำจากตราสัญลักษณ์ที่มีเพียงราสเตอร์หรือ? เตรียม SVG สำหรับประเมิน ตรวจเส้นรอบรูปเติมและช่องเปิด แล้วทดสอบไฟล์นั้นในฉากเล็กนี้ก่อนสร้างตัวดูเต็มรูปแบบ
เพิ่มเติมจากบล็อก

นำเข้า SVG ใน Unreal Engine: ตรวจรูปทรง Motion Design
เตรียม SVG สำหรับ Motion Design ของ Unreal Engine ตรวจช่องเปิดและชิ้นแยก และแยกรูปทรงฉากจากเท็กซ์เจอร์หรือกระบวนการภาพ UI ขณะรัน

นำเข้า SVG ใน Rhino: เลือกเส้นโค้ง Hatch หรือพื้นผิว
เลือกตัวเลือกนำเข้า SVG ใน Rhino 8 ให้เหมาะ ตรวจชนิดวัตถุและรู และตัดสินว่าโลโก้แรสเตอร์ต้องแปลงเป็นพาธเมื่อใดก่อนเริ่มสร้างแบบจำลอง