ฉันจะแก้ไขการจับคู่การทำแผนที่ UV ซิกซิกแซกบนตาข่ายที่สร้างขึ้นได้อย่างไร


10

ฉันกำลังสร้างตาข่ายแบบขั้นตอนตามเส้นโค้งและขนาดของตาข่ายจะเล็กลงตลอดทั้งเส้นโค้งตามที่คุณเห็นด้านล่าง

ป้อนคำอธิบายรูปภาพที่นี่

และปัญหาคือรังสียูวีได้รับซิกแซกเนื่องจากการเปลี่ยนแปลงขนาด (มันทำงานได้อย่างสมบูรณ์เมื่อขนาดของตาข่ายเท่ากันตลอดทั้งโค้ง)

ป้อนคำอธิบายรูปภาพที่นี่

 Vertices.Add(R);
 Vertices.Add(L);
 UVs.Add(new Vector2(0f, (float)id / count));
 UVs.Add(new Vector2(1f, (float)id / count));
 start = Vertices.Count - 4;
          Triangles.Add(start + 0);
                 Triangles.Add(start + 2);
                 Triangles.Add(start + 1);
                 Triangles.Add(start + 1);
                 Triangles.Add(start + 2);
                 Triangles.Add(start + 3);

 mesh.vertices = Vertices.ToArray();
         //mesh.normals = normales;
         mesh.uv = UVs.ToArray();
         mesh.triangles = Triangles.ToArray();

ฉันจะแก้ไขสิ่งนี้ได้อย่างไร


สิ่งที่เป็นidและcount? อะไรUVs.ToArray()ทำอย่างไร คุณกำลังอัปโหลดจุดยอดและพิกัดพื้นผิวไปยังการ์ดได้อย่างไร
user1118321

@ user1118321 จากบริบทidเป็นดัชนีของส่วนปัจจุบันจากแถบทั้งหมดที่อยู่ในแถบซึ่งมีcountทั้งหมด List<T>.ToArray()ส่งคืนอาร์เรย์ที่พิมพ์ของรายการทั้งหมดในรายการ (ดังนั้นที่นี่กVector2[]) บัฟเฟอร์ข้อมูลเหล่านี้พร้อมใช้งานสำหรับระบบการแสดงผลโดยกำหนดให้กับMeshอินสแตนซ์meshในสองสามบรรทัดสุดท้าย แต่สิ่งเหล่านี้ไม่ได้เป็นส่วนที่น่าสนใจอย่างยิ่งของรหัส: วิธีเลือกจุดยอด รายละเอียดเหล่านั้นจะมีประโยชน์มากขึ้นที่จะเห็น ;)
DMGregory

นั่นคือสมมติฐานของฉัน แต่ฉันขอคำชี้แจงเพราะบางครั้งสมมติฐานผิด ฉันเคยดูบางอย่างเช่นนั้นในรหัสของฉันในอดีตเท่านั้นที่จะตระหนักว่าcountจริงๆแล้วหมายถึงจุดยอดแทนที่จะเป็นรูปหลายเหลี่ยมหรือกลับกัน เพียงแค่ทำให้แน่ใจว่าทุกสิ่งที่เราคิดว่าเกิดขึ้นนั้นเป็นเรื่องจริง
user1118321

คำตอบ:


13

การทำแผนที่ UV โดยทั่วไปคือสิ่งที่เรียกว่าเปลี่ยนแปลงเลียนแบบ นั่นหมายถึงการแมปของสามเหลี่ยมแต่ละอันระหว่างพื้นที่ 3D กับพื้นที่พื้นผิวสามารถรวมถึงการหมุนการแปลการปรับ / สควอชและความลาดเอียง (เช่นอะไรก็ตามที่เราสามารถทำได้ด้วยการคูณเมทริกซ์เอกพันธ์)

สิ่งที่เกี่ยวกับการแปลงเลียนแบบคือพวกมันเหมือนกันทั่วทั้งโดเมน - การหมุนการแปลมาตราส่วนและความเบ้ที่เราใช้กับพื้นผิวที่อยู่ใกล้จุดสุดยอด A เหมือนกับสิ่งที่เราใช้ใกล้จุดยอด B ภายในสามเหลี่ยมใด ๆ เส้นที่ขนานกันในพื้นที่หนึ่งจะถูกแมปกับเส้นคู่ขนานในอีกช่องหนึ่งโดยไม่ต้องมาบรรจบกัน

แต่การเรียวแบบค่อยเป็นค่อยไปที่คุณพยายามจะใช้นั้นไม่เหมือนกัน - มันเป็นการจับคู่เส้นขนานในพื้นผิวเป็นการบรรจบเส้นบนตาข่าย นั่นหมายถึงขนาดของพื้นผิวที่วัดได้ทั่วทั้งวงนั้นมีการเปลี่ยนแปลงอย่างต่อเนื่องเมื่อเราเลื่อนแถบลง นั่นเป็นมากกว่าการแปลงเลียนแบบของการทำแผนที่ UV แบบ 2 มิติที่สามารถนำเสนอได้อย่างถูกต้อง: การประมาณค่าพิกัดยูวี 2 มิติระหว่างจุดยอดที่อยู่ติดกันจะได้สเกลที่สม่ำเสมอหนึ่งตลอดทั้งขอบแม้กระทั่งเส้นทแยงมุม ความไม่ตรงกันนั้นเป็นสิ่งที่สร้างซิกแซกที่กระจัดกระจาย

ปัญหานี้เกิดขึ้นเมื่อใดก็ตามที่เราต้องการแมปสี่เหลี่ยมกับสี่เหลี่ยมคางหมู - ด้านขนานกับการบรรจบกัน: ไม่มีการแปลงเลียนแบบที่ทำเช่นนี้ดังนั้นเราต้องประมาณมันทีละส่วนเพื่อนำไปสู่ตะเข็บที่มองเห็นได้

เพื่อวัตถุประสงค์ส่วนใหญ่คุณสามารถลดผลกระทบได้โดยการเพิ่มรูปทรงเรขาคณิตเพิ่มเติม การเพิ่มจำนวนเขตการปกครองตามความยาวของแถบและแยกแถบออกเป็นสองส่วนหรือมากกว่าตามความกว้างโดยมีเส้นทแยงมุมของรูปสามเหลี่ยมที่จัดในรูปแบบรูปแฉกแนวตั้งสามารถทำให้เอฟเฟ็กต์น้อยลง มันจะถูกนำเสนอในระดับหนึ่งเสมอตราบใดที่เราใช้การแปลงเลียนแบบ

แต่มีวิธีการอยู่รอบ ๆ เราสามารถใช้กลอุบายแบบเดียวกันกับที่เราใช้สำหรับการเรนเดอร์ 3D เพื่อวาดสี่เหลี่ยมคางหมูในมุมมองของผนังและพื้นรูปสี่เหลี่ยมผืนผ้า: เราใช้พิกัด projective !

เลียนแบบพื้นผิว: ตัวอย่างของการเลียนแบบพื้นผิวแบบปกติที่มีสิ่งประดิษฐ์ zig-zag

พื้นผิว Projective: ตัวอย่างของ textring projective การแก้ไขสิ่งประดิษฐ์

ในการทำเช่นนี้เราต้องเพิ่มพิกัดยูวีตัวที่สาม (uvw) และแก้ไขเฉดสีของเรา

เมื่อพิจารณาจากสเกลปัจจัยในแต่ละจุด (พูดเท่ากับความกว้างของแถบของคุณ ณ จุดนั้น) คุณสามารถสร้างพิกัดยูวีโปรเจ็กต์สามมิติจากพิกัดยูวี 2D ปกติของคุณด้วยวิธีนี้:

Vector3 uv3 = ((Vector3)uv2) * scale;
uv3.z = scale;

ในการใช้พิกัด uvw 3D เหล่านี้กับตาข่ายของคุณคุณจะต้องใช้ Vector3 เกินพิกัด Mesh.SetUVs (ช่องสัญญาณภายในรายการ uvs)

และให้แน่ใจว่าได้เปลี่ยนโครงสร้างอินพุตของ shader เพื่อคาดหวังพิกัดพื้นผิว 3 มิติ (แสดงไว้ที่นี่โดยใช้ shader ที่ไม่มีแสงสว่างดีฟอลต์)

struct appdata
{
    float4 vertex : POSITION;
    float3 uv : TEXCOORD0; // Change float2 to float 3.
};
// Also do this for the uv sent from the vertex shader to the fragment shader.

คุณจะต้องตัดมาโคร TRANSFORM_TEX ออกใน shader ที่จุดยอดเนื่องจากคาดว่าจะเป็น 2D uv:

// o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.uv = v.uv;
// If you define a float4 with the special name _MainTex_ST, 
// you can get the same effect the macro had by doing this:
o.uv.xy = o.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw;

ในที่สุดเมื่อต้องการกลับไปที่พิกัดพื้นผิว 2D สำหรับการสุ่มตัวอย่างพื้นผิวคุณเพียงแค่หารด้วยพิกัดที่สามในส่วนของส่วนย่อยของคุณ:

float2 uv = i.uv.xy / i.uv.z;

เนื่องจากเราได้สร้างพิกัดยูวี 3 มิติจากพิกัด 2D ที่เราต้องการโดยการคูณด้วยจำนวนเดียวกันการดำเนินการทั้งสองจึงยกเลิกและเรากลับไปที่พิกัด 2D ดั้งเดิมที่เราต้องการ แต่ตอนนี้มีการแก้ไขเชิงเส้นตรงระหว่างจุดยอด : D

เป็นสิ่งสำคัญที่จะทำหารนี้ต่อชิ้นส่วนและไม่ได้อยู่ในส่วนยอด หากทำต่อจุดสุดยอดแล้วเราจะกลับไปแก้ไขพิกัดที่เป็นเส้นตรงตามแนวขอบแต่ละเส้นและเราสูญเสียความไม่เชิงเส้นที่เราพยายามแนะนำกับพิกัดเชิง Projective!


สวัสดีฉันได้ต่อสู้กับปัญหาเดียวกันมาระยะหนึ่งแล้วและนี่ดูเหมือนว่าเกิดอะไรขึ้นกับฉัน ข้อแตกต่างเพียงอย่างเดียวคือฉันทำงานใน Threejs และไม่เป็นเอกภาพ เราจัดการเพื่อแก้ปัญหาโดยการเพิ่มจำนวนของรูปสามเหลี่ยม แต่ยังต้องการลองการทำพื้นผิวแบบ Projective คุณมีความคิดวิธีการเริ่มใช้ในสามjsหรือไม่ ขอบคุณ!
DživoJelić

1
ค่อนข้างเหมือนกัน คุณต้องมีการประสานงานพื้นผิวที่สามในการจัดเก็บตัวหารจากนั้นคุณดำเนินการหารในส่วนที่แตก หากคุณมีปัญหาในการใช้สิ่งนี้กับกรณีของคุณการถามคำถามใหม่จะช่วยให้คุณรวมตัวอย่างโค้ดแสดงวิธีการที่คุณวาดตาข่ายของคุณจนถึงตอนนี้คำตอบนั้นสามารถสร้างขึ้นมาได้
DMGregory

ฉันจำเป็นต้องจัดเก็บตัวหารเป็นพิกัดที่สาม (และเนื่องจากการเปลี่ยนแปลงนั้น struct และตัดออกจากแมโคร TRANSFORM_TEX ซึ่งฉันไม่รู้วิธีการทำใน threejs) หรือฉันสามารถส่งตัวหารเป็นแอตทริบิวต์ไปยังจุดสุดยอดได้ และจากนั้นก็เป็นส่วนต่าง ๆ ไปจนถึงส่วนที่สามารถใช้ในการแบ่งได้
DživoJelić

TRANSFORM_TEX เป็นมาโครแบบเอกภาพ คุณไม่มีในสาม.jsดังนั้นจึงไม่มีอะไรจะตัดออก ตราบใดที่พิกัดยูวีและตัวหารที่ผ่านการประมาณค่ามาถึงส่วนที่แยกส่วนมันก็ไม่สำคัญว่าคุณจะนำพวกมันไปที่นั่นได้อย่างไร คุณพบปัญหาในการระบุว่าเป็นคุณสมบัติ / เปลี่ยนแปลงหรือไม่?
DMGregory

ฉันยังไม่ได้ลองเพราะฉันไม่ต้องการเสียเวลาจนกว่าฉันจะตรวจสอบว่าเป็นไปได้ คำถามสุดท้ายเพียงหนึ่งตัวหารจะถูกแก้ไขเมื่อมันมาถึงชิ้นส่วนที่ถูกต้อง? หมายความว่าบนพิกเซลระหว่างจุดยอดสองจุดมันจะเป็นค่าที่ถูกประมาณค่าแล้วไม่ใช่ค่าดั้งเดิม? ฉันมีเวลายากที่จะพันหัวทำไมต้องคูณ UV แล้วหารด้วยมันช่วย แต่ฉันจะเอาคำของคุณมาลองดู : little_smiling_face: ขอบคุณมากสำหรับความช่วยเหลือของคุณ!
DživoJelić
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.