আমি কীভাবে 3 ডি মডেলের চারপাশে রূপরেখা আঁকতে পারি? আমি সাম্প্রতিক পোকেমন গেমের এমন প্রভাবগুলির মতো কিছু উল্লেখ করছি, যার চারপাশে একটি একক পিক্সেল রূপরেখা উপস্থিত রয়েছে:
আমি কীভাবে 3 ডি মডেলের চারপাশে রূপরেখা আঁকতে পারি? আমি সাম্প্রতিক পোকেমন গেমের এমন প্রভাবগুলির মতো কিছু উল্লেখ করছি, যার চারপাশে একটি একক পিক্সেল রূপরেখা উপস্থিত রয়েছে:
উত্তর:
আমি মনে করি না যে এখানে অন্য উত্তরগুলির মধ্যে কোনও পোকমন এক্স / ওয়াইয়ের প্রভাব অর্জন করবে। এটি ঠিক কীভাবে হয়েছে তা আমি জানতে পারি না তবে আমি এমন একটি উপায় খুঁজে পেয়েছি যা দেখে মনে হয় তারা খেলায় কী করে।
পোকেমন এক্স / ওয়াইতে, সিলুয়েটের প্রান্ত এবং অন্যান্য নন-সিলুয়েট প্রান্তের উভয়রেখা (যেমন রাইচুর কান নীচের স্ক্রিনশটে তাঁর মাথার সাথে মিলিত হয়েছে) উভয়ই আঁকা হয়েছে।
ব্লেন্ডারে রাইচুর জাল দেখে আপনি দেখতে পাচ্ছেন কান (উপরে কমলাতে হাইলাইট করা) কেবল একটি পৃথক, সংযোগ বিচ্ছিন্ন বস্তু যা মাথাকে ছেদ করে এবং পৃষ্ঠের নরমালগুলিতে আকস্মিক পরিবর্তন তৈরি করে।
তার ভিত্তিতে, আমি নরমালগুলির উপর ভিত্তি করে বাহ্যরেখা তৈরি করার চেষ্টা করেছি, যার জন্য দুটি পাসে রেন্ডারিং প্রয়োজন:
প্রথম পাস : রূপরেখা ছাড়াই মডেলটি (টেক্সচার্ড এবং সেল শেডেড) রেন্ডার করুন এবং ক্যামেরা-স্পেস নরমালটিকে দ্বিতীয় রেন্ডার টার্গেটে রেন্ডার করুন।
দ্বিতীয় পাস : প্রথম পাস থেকে স্বাভাবিকের উপরে একটি পূর্ণ-স্ক্রিন প্রান্ত সনাক্তকরণ ফিল্টার করুন।
নীচের প্রথম দুটি চিত্র প্রথম পাসের ফলাফলগুলি দেখায়। তৃতীয়টি নিজেই রূপরেখা এবং শেষটি চূড়ান্ত সম্মিলিত ফলাফল।
দ্বিতীয় পাসের প্রান্ত সনাক্তকরণের জন্য আমি ওপেনজিএল ফ্রেগমেন্ট শেডারটি ব্যবহার করেছি। আমি সবচেয়ে ভালভাবে আসতে পেরেছি, তবে এর থেকে আরও ভাল উপায় থাকতে পারে। এটি সম্ভবত খুব ভাল অনুকূলিত হয় না।
// first render target from the first pass
uniform sampler2D uTexColor;
// second render target from the first pass
uniform sampler2D uTexNormals;
uniform vec2 uResolution;
in vec2 fsInUV;
out vec4 fsOut0;
void main(void)
{
float dx = 1.0 / uResolution.x;
float dy = 1.0 / uResolution.y;
vec3 center = sampleNrm( uTexNormals, vec2(0.0, 0.0) );
// sampling just these 3 neighboring fragments keeps the outline thin.
vec3 top = sampleNrm( uTexNormals, vec2(0.0, dy) );
vec3 topRight = sampleNrm( uTexNormals, vec2(dx, dy) );
vec3 right = sampleNrm( uTexNormals, vec2(dx, 0.0) );
// the rest is pretty arbitrary, but seemed to give me the
// best-looking results for whatever reason.
vec3 t = center - top;
vec3 r = center - right;
vec3 tr = center - topRight;
t = abs( t );
r = abs( r );
tr = abs( tr );
float n;
n = max( n, t.x );
n = max( n, t.y );
n = max( n, t.z );
n = max( n, r.x );
n = max( n, r.y );
n = max( n, r.z );
n = max( n, tr.x );
n = max( n, tr.y );
n = max( n, tr.z );
// threshold and scale.
n = 1.0 - clamp( clamp((n * 2.0) - 0.8, 0.0, 1.0) * 1.5, 0.0, 1.0 );
fsOut0.rgb = texture(uTexColor, fsInUV).rgb * (0.1 + 0.9*n);
}
এবং প্রথম পাসের রেন্ডারিংয়ের আগে আমি ক্যামেরা থেকে দূরে থাকা কোনও ভেক্টরকে নরমালসের রেন্ডার টার্গেটটি সাফ করে দিই:
glDrawBuffer( GL_COLOR_ATTACHMENT1 );
Vec3f clearVec( 0.0, 0.0, -1.0f );
// from normalized vector to rgb color; from [-1,1] to [0,1]
clearVec = (clearVec + Vec3f(1.0f, 1.0f, 1.0f)) * 0.5f;
glClearColor( clearVec.x, clearVec.y, clearVec.z, 0.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
আমি কোথাও পড়েছি (আমি মন্তব্যে একটি লিঙ্ক রেখে দেব) যে নিন্টেন্ডো 3 ডি এস শেডারগুলির পরিবর্তে একটি ফিক্সড ফাংশন পাইপলাইন ব্যবহার করে, তাই আমি অনুমান করি যে এটি খেলায় ঠিক এটি করা হয়নি, তবে আপাতত আমি ' আমি নিশ্চিত আমার পদ্ধতিটি যথেষ্ট কাছে।
এই প্রভাবটি গেমগুলিতে বিশেষত প্রচলিত যা সেল শেডিং প্রভাব ব্যবহার করে তবে বাস্তবে এমন কিছু যা সেল শ্যাডিং শৈলীতে স্বাধীনভাবে প্রয়োগ করা যেতে পারে।
আপনি যা বর্ণনা করছেন তাকে "বৈশিষ্ট্য প্রান্তে উপস্থাপনা" বলা হয় এবং এটি একটি মডেলের বিভিন্ন রূপ এবং রূপরেখা হাইলাইট করার সাধারণ প্রক্রিয়াতে থাকে। বিষয়টিতে অনেক কৌশল এবং অনেকগুলি কাগজপত্র উপলব্ধ।
একটি সহজ কৌশলটি কেবল সিলুয়েটের প্রান্তটি রেন্ডার করা, একেবারে বাহ্যরেখা out এটি স্টেনসিল লিখনের সাথে মূল মডেলটিকে রেন্ডারিং হিসাবে এবং তারপর এটি ঘন ওয়্যারফ্রেম মোডে পুনরায় রেন্ডারিংয়ের মতো করা যেতে পারে, কেবল যেখানে স্টেনসিলের মান ছিল না। উদাহরণ বাস্তবায়নের জন্য এখানে দেখুন ।
এটি অভ্যন্তরের কনট্যুর এবং ক্রিজ প্রান্তগুলি হাইলাইট করবে না, যদিও (আপনার ছবিতে দেখানো হয়েছে)। সাধারণত, কার্যকরভাবে এটি করার জন্য, আপনাকে জালের প্রান্তগুলি (প্রান্তের উভয় পাশের মুখের স্বাভাবিকতাগুলির উপর ভিত্তি করে, এবং প্রতিটি প্রান্তকে উপস্থাপন করে একটি ডেটা স্ট্রাকচার তৈরি করতে হবে) সম্পর্কিত তথ্য বের করতে হবে।
তারপরে আপনি ছাঁটা ছাঁটা করতে বা অন্যথায় সেই প্রান্তগুলিকে নিয়মিত জ্যামিতি হিসাবে আপনার বেস মডেলটিকে (বা এটির সাথে একত্রে) রেন্ডার করতে পারেন। একটি প্রান্তের অবস্থান এবং ভিউ ভেক্টরের সাথে সম্পর্কিত সংলগ্ন মুখগুলির নরমালগুলি নির্দিষ্ট প্রান্তটি আঁকতে পারে কিনা তা নির্ধারণ করতে ব্যবহৃত হয়।
ইন্টারনেটে বিভিন্ন উদাহরণ সহ আপনি আরও আলোচনা, বিশদ এবং কাগজপত্রগুলি পেতে পারেন। উদাহরণ স্বরূপ:
dz/dx
dz/dy
এটি করার সহজ উপায়, পিক্সেল / টুকরো টুকরো ছায়ার আগে পুরানো হার্ডওয়্যারগুলিতে সাধারণ, এবং এখনও মোবাইলে ব্যবহৃত হয়, এটি মডেলটিকে নকল করা, ভার্টেক্স ওয়াইন্ডিং ক্রমের বিপরীত হওয়া যাতে মডেলটি ভিতরে বাইরে প্রদর্শিত হয় (বা আপনি যদি চান, আপনি করতে পারেন) আপনার 3D সম্পদ তৈরির সরঞ্জামটিতে এটি করুন, ব্লেন্ডারটি বলুন, পৃষ্ঠের নরমালগুলি উল্টিয়ে - একই জিনিস), তারপরে পুরো ডুপ্লিকেটটি এর কেন্দ্রের চারপাশে কিছুটা প্রসারিত করুন এবং অবশেষে রঙ / টেক্সচারটি এই নকলটিকে পুরোপুরি কালো করে দিন। যদি এটি কোনও কিউবের মতো সাধারণ মডেল হয় তবে আপনার আসল মডেলটির চারদিকে রূপরেখার ফলস্বরূপ । অবতল ফর্মগুলি সহ আরও জটিল মডেলের জন্য (যেমন নীচের চিত্রটিতে) মিনকভস্কির যোগফলের মতো ডুপ্লিকেট মডেলটিকে মূল আসল অংশের চেয়ে কিছুটা "মোটা" হওয়ার জন্য ম্যানুয়ালি মুছে ফেলা প্রয়োজন is3D তে ব্লেন্ডারের সঙ্কুচিত / ফ্যাটেন রূপান্তর যেমন হয় তেমন রূপরেখা জাল গঠনের জন্য আপনি প্রতিটি ভার্টেক্সকে তার স্বাভাবিক বরাবর কিছুটা ধাক্কা দিয়ে শুরু করতে পারেন।
স্ক্রিন স্পেস / পিক্সেল শেডার পন্থাগুলি ভালভাবে প্রয়োগ করতে ধীর এবং শক্ত হতে থাকে তবে ওটিওএইচ আপনার বিশ্বে সংখ্যাটির দ্বিগুণ হয় না। সুতরাং আপনি যদি উচ্চ পলির কাজ করে থাকেন তবে সেই পদ্ধতির জন্য সেরাটি বেছে নিন। জ্যামিতি প্রক্রিয়াকরণের জন্য আধুনিক কনসোল এবং ডেস্কটপ ধারণক্ষমতা দেওয়া, আমি 2 একটি গুণক সম্পর্কে চিন্তা করবেন চাই সব সময়ে । কার্টুন-স্টাইল = নিশ্চিতভাবে কম পলি, সুতরাং জ্যামিতির সদৃশ করা সবচেয়ে সহজ।
আপনি নিজের জন্য উদাহরণটি পরীক্ষা করতে পারেন যেমন কোনও কোড স্পর্শ না করে ব্লেন্ডার। আউটলাইনগুলি নীচের চিত্রটির মতো হওয়া উচিত, কিছু আভ্যন্তরীণ যেমন, আর্মের নিচে note আরও বিশদ এখানে ।
।
জন্য মসৃণ মডেল (খুব গুরুত্বপূর্ণ), এই মর্মে মোটামুটি সহজ। আপনার টুকরা / পিক্সেল শেডারটিতে আপনাকে এই খণ্ডটির ছায়াছবিয় হওয়ার স্বাভাবিক প্রয়োজন হবে। যদি এটি লম্বের খুব কাছাকাছি থাকে ( dot(surface_normal,view_vector) <= .01
- আপনার সেই প্রান্তিকের সাথে খেলার প্রয়োজন হতে পারে) তবে খণ্ডটিকে তার স্বাভাবিক রঙের পরিবর্তে কালো রঙ করুন।
এই পদ্ধতির রূপরেখাটি করতে মডেলটির কিছুটা "গ্রাস" করে। এটি আপনি যা চান তা হতে পারে বা নাও পারে। পোকেমন ছবি থেকে এটি জানা খুব কঠিন যে যদি এটি করা হচ্ছে তবে। আপনি যদি চরিত্রের কোনও সিলুয়েটে রূপরেখা অন্তর্ভুক্ত করার আশা করেন বা আপনার পরিবর্তে সিলুয়েটটি আবদ্ধ থাকে (যার জন্য আলাদা কৌশল প্রয়োজন) তবে এটি নির্ভর করে on
হাইলাইটটি পৃষ্ঠের যে কোনও অংশে হবে যেখানে এটি সামনের দিক থেকে পিছন দিকে "অভ্যন্তরীণ প্রান্তগুলি" সহ (যেমন সবুজ পোকেমন বা তার মাথাতে পা রয়েছে) - অন্য কিছু কৌশলগুলি এতে কোনও রূপরেখা যুক্ত করবে না )।
যে বিষয়গুলিতে শক্ত, নন-মসৃণ প্রান্ত রয়েছে (ঘনকের মতো) এই পদ্ধতির সাথে পছন্দসই অবস্থানগুলিতে হাইলাইটটি পাবেন না। এর অর্থ কিছু ক্ষেত্রে এই পদ্ধতির কোনও বিকল্প নয়; পোকেমন মডেলগুলি সমস্ত মসৃণ কিনা তা আমার কোনও ধারণা নেই।
এটি করা সবচেয়ে সাধারণ উপায়টি হ'ল আপনার মডেলের দ্বিতীয় রেন্ডার পাসের মাধ্যমে। মূলত, এটির সদৃশ করুন এবং নরমালগুলি ফ্লিপ করুন এবং এটি একটি ভার্টেক্স শ্যাডারে নিক্ষেপ করুন। শেডারে প্রতিটি ভার্টেক্সকে এর স্বাভাবিক বরাবর স্কেল করুন। পিক্সেল / টুকরা শেডারে, কালো আঁকুন। এটি আপনাকে বাহ্যিক এবং অভ্যন্তরীণ উভয় রূপরেখা দেবে, যেমন ঠোঁট, চোখ ইত্যাদির আশেপাশে This গিলিটি গিয়ার এক্সার্ড এই পদ্ধতিটি ব্যবহার করে কারণ ভার্টেক্সের রঙের মাধ্যমে লাইনের বেধ নিয়ন্ত্রণ করা সহজ।
অভ্যন্তরীণ লাইনগুলি করার দ্বিতীয় উপায়টি আমি একই খেলা থেকে শিখেছি। আপনার ইউভি মানচিত্রে, আপনার টেক্সচারটি ইউ বা ভি অক্ষের সাথে প্রান্তিককরণ করুন, বিশেষত যেখানে আপনি অভ্যন্তরীণ রেখা চান সেখানে। অক্ষটি বরাবর একটি কালো রেখা আঁকুন, এবং অভ্যন্তরীণ লাইনটি তৈরি করতে আপনার ইউভি স্থানাঙ্কগুলি সেই লাইনটির ভিতরে বা বাইরে সরান।
আরও ভাল ব্যাখ্যার জন্য জিডিসি থেকে ভিডিওটি দেখুন: https://www.youtube.com/watch?v=yhGjCzxJV3E
একটি রূপরেখা তৈরির অন্যতম উপায় হ'ল আমাদের মডেলগুলি সাধারণ ভেক্টরগুলি ব্যবহার করা। সাধারণ ভেক্টরগুলি হ'ল ভেক্টর যা তাদের পৃষ্ঠের লম্ব হয় (পৃষ্ঠ থেকে দূরে ইশারা করে)। কৌশলটি এখানে আপনার চরিত্রের মডেলটিকে দুটি ভাগে ভাগ করা। ক্যামেরার মুখোমুখি যে শিখরগুলি এবং ক্যামেরা থেকে দূরে মুখোমুখি যে শীর্ষে রয়েছে আমরা তাদের যথাক্রমে এফআরন্ট এবং ব্যাক বলব।
রূপরেখার জন্য আমরা আমাদের BACK শীর্ষকে নিয়ে যাই এবং তাদের স্বাভাবিক ভেক্টরগুলির দিকে কিছুটা সরাই। আমাদের চরিত্রের যে অংশটি ক্যামেরা থেকে দূরে রয়েছে তার অংশটি তৈরি করার মতো এটি ভাবুন। এটি সম্পন্ন করার পরে, আমরা তাদের আমাদের পছন্দের রঙ নির্ধারণ করি এবং আমাদের একটি সুন্দর রূপরেখা আছে।
Shader "Custom/OutlineShader" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_Outline("Outline Thickness", Range(0.0, 0.3)) = 0.002
_OutlineColor("Outline Color", Color) = (0,0,0,1)
}
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
half4 _MainTex_ST;
half _Outline;
half4 _OutlineColor;
struct appdata {
half4 vertex : POSITION;
half4 uv : TEXCOORD0;
half3 normal : NORMAL;
fixed4 color : COLOR;
};
struct v2f {
half4 pos : POSITION;
half2 uv : TEXCOORD0;
fixed4 color : COLOR;
};
ENDCG
SubShader
{
Tags {
"RenderType"="Opaque"
"Queue" = "Transparent"
}
Pass{
Name "OUTLINE"
Cull Front
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
v2f vert(appdata v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
half3 norm = mul((half3x3)UNITY_MATRIX_IT_MV, v.normal);
half2 offset = TransformViewToProjection(norm.xy);
o.pos.xy += offset * o.pos.z * _Outline;
o.color = _OutlineColor;
return o;
}
fixed4 frag(v2f i) : COLOR
{
fixed4 o;
o = i.color;
return o;
}
ENDCG
}
Pass
{
Name "TEXTURE"
Cull Back
ZWrite On
ZTest LEqual
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
v2f vert(appdata v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.color = v.color;
return o;
}
fixed4 frag(v2f i) : COLOR
{
fixed4 o;
o = tex2D(_MainTex, i.uv.xy);
return o;
}
ENDCG
}
}
}
41 লাইন: "কুল ফ্রন্ট" সেটিংটি শেডারকে সামনের মুখোমুখি কোণে একটি কুলিং সম্পাদন করতে বলে। এর অর্থ হ'ল আমরা এই পাসে সামনের সমস্ত সামনের মুখোমুখি উপেক্ষা করব। আমরা কিছুটা সামাল দিতে চাই এমন পিছনের দিকটি রেখে দেওয়া হয়েছে।
৫১-৫৩ লাইন: তাদের স্বাভাবিক ভেক্টরগুলির সাথে বরাবর উল্লম্বের গণিত।
54 লাইন: শেডারের বৈশিষ্ট্যগুলিতে সংজ্ঞায়িত আমাদের পছন্দের রঙটিতে ভার্টেক্স রঙ নির্ধারণ করা।
দরকারী লিঙ্ক: http://wiki.unity3d.com/index.php/Silhouette- আউটলাইন_ডিফিউজ
আরেকটি উদাহরণ
Shader "Custom/CustomOutline" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_Outline ("Outline Color", Color) = (0,0,0,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Size ("Outline Thickness", Float) = 1.5
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
// render outline
Pass {
Stencil {
Ref 1
Comp NotEqual
}
Cull Off
ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
half _Size;
fixed4 _Outline;
struct v2f {
float4 pos : SV_POSITION;
};
v2f vert (appdata_base v) {
v2f o;
v.vertex.xyz += v.normal * _Size;
o.pos = UnityObjectToClipPos (v.vertex);
return o;
}
half4 frag (v2f i) : SV_Target
{
return _Outline;
}
ENDCG
}
Tags { "RenderType"="Opaque" }
LOD 200
// render model
Stencil {
Ref 1
Comp always
Pass replace
}
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
fixed4 _Color;
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
এটি করার দুর্দান্ত উপায়গুলির মধ্যে একটি হ'ল ফ্রেমবফার টেক্সচারটিতে আপনার দৃশ্যের রেন্ডার করা , তারপরে প্রতি পিক্সলে সোবেল ফিল্টারিং করার সময় সেই টেক্সচারটি রেন্ডার করা, এটি প্রান্ত সনাক্তকরণের জন্য একটি সহজ কৌশল। এইভাবে আপনি কেবল দৃশ্যটিকে পিক্সেলিটেড করতে পারবেন না (ফ্রেমবফার টেক্সচারটিতে একটি কম রেজোলিউশন সেট করে), তবে সোবেলকে কাজ করতে প্রতিটি পিক্সেল মানগুলিতে অ্যাক্সেসও রয়েছে।