ผลวัตถุเค้าร่าง


26

ฉันจะทำให้เอฟเฟกต์เค้าร่างคล้ายกับที่พบใน League of Legends หรือ Diablo III ได้อย่างไร

ร่าง League of Legends ร่าง League of Legends ร่าง Diablo III

มันใช้ shader หรือไม่? อย่างไร?
ฉันต้องการคำตอบที่ไม่เชื่อมโยงกับเอ็นจินใด ๆ โดยเฉพาะ แต่เป็นคำตอบที่ฉันสามารถปรับให้เข้ากับเอนจินที่ฉันกำลังทำงาน

คำตอบ:


19

คุณจะต้องแสดงวัตถุสองครั้งในบางจุด คุณสามารถหลีกเลี่ยงการแสดงผลเพียงใบหน้าที่หันหน้าเข้าหากล้องหนึ่งครั้งและหันหน้าออกจากกล้องเพียงครั้งเดียว แต่มีการแลกเปลี่ยนกัน

วิธีแก้ปัญหาที่ง่ายที่สุดที่พบได้บ่อยที่สุดคือการแสดงวัตถุสองครั้งในบัตรเดียวกัน:

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

นี่ง่ายพอที่จะสร้างและนำไปใช้และหลีกเลี่ยงกลวิธีการแสดงผลต่อพื้นผิวใด ๆ แต่มีข้อบกพร่องเล็กน้อยที่สังเกตได้:

  • ขนาดเค้าร่างหากคุณไม่ปรับขนาดตามระยะทางจากกล้องจะแตกต่างกันไป วัตถุที่อยู่ไกลออกไปจะมีโครงร่างเล็กกว่าวัตถุที่อยู่ใกล้เคียง ของหลักสูตรนี้อาจจะมีสิ่งที่คุณจริงต้องการ
  • จุดยอดยอด "ระเบิด" ไม่ทำงานได้ดีนักสำหรับวัตถุที่ซับซ้อนเช่นโครงกระดูกในตัวอย่างของคุณแนะนำสิ่งประดิษฐ์ z-fighting อย่างง่ายสำหรับการเรนเดอร์ การแก้ไขมันต้องการให้คุณแสดงวัตถุเป็นสองรอบ แต่ช่วยให้คุณไม่กลับสู่บรรทัดฐาน
  • เค้าโครงและวัตถุอาจทำงานได้ไม่ดีนักเมื่อวัตถุอื่นครอบครองพื้นที่เดียวกันและโดยทั่วไปแล้วความเจ็บปวดที่จะเกิดขึ้นเมื่อรวมกับการสะท้อนและการหักเหของแสง

แนวคิดพื้นฐานสำหรับ shader นั้นมีลักษณะเช่นนี้ (Cg, สำหรับ Unity - รหัสเป็น shader toon ที่ได้รับการแก้ไขเล็กน้อยที่ฉันพบที่ไหนสักแห่งและไม่ได้สังเกตแหล่งที่มา การใช้งาน Shader):

Shader "Basic Outline" {
    Properties {
        _Color ("Main Color", Color) = (.5,.5,.5,1)
        _OutlineColor ("Outline Color", Color) = (1,0.5,0,1)
        _Outline ("Outline width", Range (0.0, 0.1)) = .05
        _MainTex ("Base (RGB)", 2D) = "white" { }
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        Pass {
            Name "OUTLINE"
            Tags { "LightMode" = "Always" }
CGPROGRAM
#pragma exclude_renderers gles
#pragma exclude_renderers xbox360
#pragma vertex vert

struct appdata {
    float4 vertex;
    float3 normal;
};

struct v2f
{
    float4 pos : POSITION;
    float4 color : COLOR;
    float fog : FOGC;
};
float _Outline;
float4 _OutlineColor;
v2f vert(appdata v)
{
    v2f o;
    o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    float3 norm = mul ((float3x3)UNITY_MATRIX_MV, v.normal);
    norm.x *= UNITY_MATRIX_P[0][0];
    norm.y *= UNITY_MATRIX_P[1][1];
    o.pos.xy += norm.xy * _Outline;
    o.fog = o.pos.z;
    o.color = _OutlineColor;
    return o;
}
ENDCG
            Cull Front
            ZWrite On
            ColorMask RGB
            Blend SrcAlpha OneMinusSrcAlpha
            SetTexture [_MainTex] { combine primary }
        }
        Pass {
        Name "BASE"
        Tags {"LightMode" = "Always"}
CGPROGRAM
#pragma fragment frag
#pragma vertex vert
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"

struct v2f {
    float4 pos : SV_POSITION;
    float2    uv            : TEXCOORD0;
    float3    viewDir        : TEXCOORD1;
    float3    normal        : TEXCOORD2;
}; 

v2f vert (appdata_base v)
{
    v2f o;
    o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    o.normal = v.normal;
    o.uv = TRANSFORM_UV(0);
    o.viewDir = ObjSpaceViewDir( v.vertex );
    return o;
}

uniform float4 _Color;

uniform sampler2D _MainTex;
float4 frag (v2f i)  : COLOR
{
    half4 texcol = tex2D( _MainTex, i.uv );

    half3 ambient = texcol.rgb * (UNITY_LIGHTMODEL_AMBIENT.rgb);
    return float4( ambient, texcol.a * _Color.a );
}
ENDCG
    }
    }
    FallBack "Diffuse"
}

วิธีการทั่วไปอื่น ๆ ทำให้วัตถุสองครั้งเช่นกัน แต่หลีกเลี่ยงจุดยอดอย่างเต็มที่ ในทางกลับกันมันไม่สามารถทำได้อย่างง่ายดายในการส่งครั้งเดียวและต้องการแสดงผลเป็นพื้นผิว: แสดงวัตถุอีกครั้งด้วย shader ชิ้นส่วนโครงร่าง "แบน" และใช้เบลอ (ถ่วงน้ำหนัก) บนเรนเดอร์นี้พื้นที่หน้าจอจากนั้นแสดงวัตถุตามปกติด้านบนของมัน

นอกจากนี้ยังมีวิธีที่สามและอาจใช้วิธีที่ง่ายที่สุดแม้ว่าจะเก็บภาษี GPU เพิ่มอีกเล็กน้อยและจะทำให้ศิลปินของคุณต้องการฆ่าคุณในโหมดสลีปเว้นแต่คุณจะทำให้มันง่ายสำหรับพวกเขาในการสร้าง: ให้วัตถุมีเค้าโครงแยกจากกัน ตาข่ายตลอดเวลาเพียงแค่โปร่งใสอย่างเต็มที่หรือย้ายบางแห่งที่ไม่เห็น (เช่นใต้ดินลึก) จนกว่าคุณจะต้องการมัน


บัฟเฟอร์ stencil ไม่ใช่วิธีการที่ใช้กันทั่วไปหรือไม่?
edA-qa mort-ora-y

1
@ edA-qamort-ora-y: มันสามารถใช้ได้เช่นกัน แต่ฉันไม่เคยลองวิธีการดังกล่าวดังนั้นจึงไม่สามารถแสดงความคิดเห็นได้ :) หากคุณมีอัลกอริทึมที่ใช้งานได้โปรดอย่าลังเลที่จะเพิ่มวิธีนี้เป็นคำตอบอื่นเช่นกัน
Martin Sojka

ฉันไม่รู้อะไรเพิ่มเติมเกี่ยวกับมันด้วยตัวเองเพียงแค่มีการพูดถึงโครงร่างที่กล่าวถึงบ่อยครั้งในการอ้างอิงถึง stencil buffer :) ดูเหมือนว่ามันอาจจะเป็นเวอร์ชันที่ใช้ฮาร์ดแวร์มากกว่าในแนวทางแรกของคุณ (สองรอบ, อันแรกใหญ่กว่า)
edA-qa mort-ora-y

วิธี stencil buffer สามารถใช้แบนด์วิดท์ได้มากขึ้นในการอัพเดตและล้างบัฟเฟอร์ stencil และต้องผ่านหลายครั้ง รายการมาร์ตินวิธีการสามารถทำได้ในหนึ่งผ่านในบางกรณี จำกัด สองคนที่มากที่สุดและต้องใช้ค่าใช้จ่ายแบนด์วิดธ์น้อยที่สุด
Sean Middleditch

วิธีนี้ (เพิ่มขนาดตามมาตรฐาน) ไม่ทำงานกับวัตถุอย่างลูกบาศก์ (โดยเฉพาะกับกล้องออร์โธ) ทางออกใดที่จะ?
NPS

4

นอกจากคำตอบของ Martin Sojkas แล้วสำหรับวัตถุคงที่ (หรือสไปรต์) คุณสามารถหลีกหนีจากสิ่งที่ง่ายกว่าได้

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

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

ทั้งคู่จะเพิ่มความทรงจำของคุณ


4

ดังที่ได้กล่าวไว้ในความคิดเห็นต่อคำตอบของ Martin Sojka ผลที่คล้ายกันนี้สามารถทำได้โดยการใช้ stencil หรือ depth buffer ตามรายละเอียดโดย Max McGuire บน FlipCode:

http://www.flipcode.com/archives/Object_Outlining.shtml

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

aproach นี้อาจจะเก่าไปหน่อยโดยใช้ OpenGL ของวันนี้และเพื่อให้วัตถุเค้าร่างแอปเปิ้ลเบลอการเรนเดอร์ไปยังพื้นผิวก็ยังจำเป็น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.