phác thảo hiệu ứng đối tượng


26

Làm cách nào tôi có thể đạt được hiệu ứng phác thảo tương tự như hiệu ứng được tìm thấy trong Liên minh huyền thoại hoặc Diablo III?

Phác thảo Liên Minh Huyền Thoại Phác thảo Liên Minh Huyền Thoại Phác thảo Diablo III

Được thực hiện bằng cách sử dụng một shader? Làm sao?
Tôi thích các câu trả lời không bị ràng buộc với bất kỳ động cơ cụ thể nào nhưng một câu trả lời mà tôi có thể thích nghi với bất kỳ động cơ nào tôi đang làm việc.

Câu trả lời:


19

Bạn sẽ phải kết xuất đối tượng hai lần tại một số điểm. Bạn có thể thoát khỏi việc chỉ hiển thị các mặt đối diện với máy ảnh một lần và các mặt quay ra khỏi máy ảnh một lần, nhưng nó có sự đánh đổi.

Giải pháp phổ biến đơn giản nhất được thực hiện bằng cách hiển thị đối tượng hai lần trong cùng một lượt:

  • Bạn sử dụng một shader đỉnh để đảo ngược các quy tắc của đối tượng và "thổi nó lên" theo kích thước của phác thảo và một shader mảnh để hiển thị nó trong màu phác thảo
  • Qua bản phác thảo đó, bạn kết xuất đối tượng bình thường. Thứ tự z thường tự động đúng, ít nhiều, vì đường viền được tạo bởi các mặt nằm ở "mặt sau" của đối tượng trong khi hình vẽ được tạo thành từ các mặt đối diện với máy ảnh.

Điều này đủ đơn giản để xây dựng và thực hiện và tránh mọi thủ thuật kết xuất đồ họa, nhưng có một vài nhược điểm đáng chú ý:

  • Kích thước phác thảo, nếu bạn không chia tỷ lệ theo khoảng cách từ máy ảnh, sẽ thay đổi. Các đối tượng ở xa hơn sẽ có một phác thảo nhỏ hơn so với những đối tượng gần đó. Tất nhiên, đây có thể là những gì bạn thực sự muốn .
  • Trình tạo bóng đỉnh "nổ tung" không hoạt động tốt cho các đối tượng phức tạp như bộ xương trong ví dụ của bạn, dễ dàng đưa các vật phẩm chiến đấu z vào kết xuất. Việc sửa nó đòi hỏi bạn phải hiển thị đối tượng trong hai lần, nhưng giúp bạn không bị đảo ngược quy tắc.
  • Phác thảo và đối tượng có thể không hoạt động tốt khi các đối tượng khác chiếm cùng một không gian và nói chung là một nỗi đau để có được ngay khi kết hợp với các bóng đổ phản xạ và khúc xạ.

Ý tưởng cơ bản cho một shader như thế này (Cg, đối với Unity - mã là một shader toon được sửa đổi một chút mà tôi tìm thấy ở đâu đó và không lưu ý đến nguồn, vì vậy nó là một khái niệm bằng văn bản tồi tệ hơn là sẵn sàng sử dụng 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"
}

Phương pháp phổ biến khác cũng làm cho đối tượng hai lần, nhưng tránh hoàn toàn shader đỉnh. Mặt khác, nó không thể được thực hiện dễ dàng trong một lần duy nhất và cần kết xuất đồ họa: Kết xuất đối tượng một lần với trình tạo bóng mảnh màu phác thảo "phẳng" và sử dụng hiệu ứng làm mờ (có trọng số) trên kết xuất này trong không gian màn hình , sau đó kết xuất đối tượng như bình thường trên đầu nó.

Ngoài ra còn có một phương pháp thứ ba và có thể dễ thực hiện nhất, mặc dù nó đánh thuế GPU nhiều hơn một chút và sẽ khiến các nghệ sĩ của bạn muốn giết bạn trong giấc ngủ trừ khi bạn tạo ra chúng dễ dàng: Để các đối tượng có đường viền riêng biệt chia lưới mọi lúc, hoàn toàn trong suốt hoặc di chuyển đến nơi không nhìn thấy (như sâu dưới lòng đất) cho đến khi bạn cần nó


Là bộ đệm stpson không phải là một cách tiếp cận thường được sử dụng ở đây?
edA-qa mort-ora-y

1
@ edA-qamort-ora-y: Điều này cũng có thể hoạt động, nhưng tôi chưa bao giờ thử phương pháp đó, vì vậy không thể nhận xét về nó. :) Nếu bạn có một thuật toán làm việc trong đầu, hãy thêm phương thức này làm câu trả lời khác.
Martin Sojka

Bản thân tôi không biết nhiều về nó, chỉ có những phác thảo thường được đề cập liên quan đến bộ đệm stpson. :) Có vẻ như nó có thể chỉ là một phiên bản dựa trên phần cứng nhiều hơn của cách tiếp cận đầu tiên của bạn (hai vượt qua, đầu tiên lớn hơn).
edA-qa mort-ora-y

Cách tiếp cận bộ đệm stpson có thể sử dụng nhiều băng thông hơn trong việc cập nhật và xóa bộ đệm stpson và yêu cầu nhiều lượt đi. Cách tiếp cận danh sách Martin có thể được thực hiện trong một lần trong một số trường hợp giới hạn, nhiều nhất là hai và yêu cầu chi phí băng thông tối thiểu.
Sean Middleditch

Cách tiếp cận này (làm tăng kích thước dọc theo quy tắc) không hoạt động với các đối tượng như hình khối (đặc biệt là với máy ảnh ortho). Bất kỳ giải pháp cho điều đó?
NPS

4

Ngoài câu trả lời của Martin Sojkas, đối với các đối tượng tĩnh (hoặc các họa tiết), bạn có thể thoát khỏi một cái gì đó đơn giản hơn.

Bạn có thể lưu cùng một sprite nhưng với phác thảo vào tập bản đồ kết cấu của bạn hoặc kết cấu khác hoàn toàn, điều này làm cho việc chuyển đổi dễ dàng. Điều này cũng sẽ cho phép bạn thực hiện các phác thảo tùy chỉnh hấp dẫn hơn hoặc trông khác biệt.

Phương pháp khác là lưu sprite dưới dạng một màu lớn hơn một chút và hiển thị ngay trước khi sprite được hiển thị. Điều này sẽ cung cấp cho bạn khả năng dễ dàng thay đổi màu của lựa chọn và bạn có thể không cần nhiều hình dạng màu khác nhau như bạn cần các họa tiết phác thảo với phương pháp # 1.

Cả hai sẽ tăng dấu chân bộ nhớ của bạn mặc dù.


4

Như đã chỉ ra trong các bình luận cho câu trả lời của Martin Sojka, một hiệu ứng tương tự cũng có thể đạt được bằng cách sử dụng bộ đệm st sâu hoặc bộ đệm sâu, như chi tiết của Max McGuire trên FlipCode:

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

Về cơ bản, nó vẽ một phiên bản khung dây của mô hình mà bạn muốn phác thảo với chiều rộng đường tăng (hoặc trong trường hợp không thể thực hiện được, như trong D3D, sử dụng camera đối diện với các đường thẳng) trong khi đặt bộ đệm stpson thành giá trị không đổi.

Aproach này có thể là một ngày ít sử dụng OpenGL ngày nay và để làm mờ phác thảo đối tượng, kết xuất thành kết cấu sẽ vẫn cần thiết.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.