मैं एक चिकनी 2D प्रकाश प्रभाव कैसे प्राप्त कर सकता हूं?


18

मैं XNA में 2D टाइल आधारित गेम बना रहा हूं।

वर्तमान में मेरी बिजली इस तरह दिखती है ।

मैं इसे इस तरह से कैसे देख सकता हूं ?

प्रत्येक ब्लॉक का अपना टिंट होने के बजाय, यह एक चिकनी ओवरले है।

मैं किसी प्रकार के shader को मान रहा हूं, और आसपास की टाइलों को shader के लिए प्रकाश मान देने के लिए, लेकिन मैं sha शुरुआती के साथ शुरुआत कर रहा हूं इसलिए मुझे यकीन नहीं है।

मेरी वर्तमान प्रकाश व्यवस्था प्रकाश की गणना करती है, और फिर SpriteBatchटिंट पैरामीटर के साथ इसे पास और आरेखित करती है। प्रत्येक टाइल में एक है Colorजो मेरे प्रकाश एल्गोरिथ्म में ड्रा से पहले गणना की जाती है, जिसका उपयोग टिंट के लिए किया जाता है।

यहां एक उदाहरण है कि मैं वर्तमान में प्रकाश की गणना कैसे करता हूं (मैं इसे बाएं, दाएं और नीचे से भी करता हूं, लेकिन मैं इस फ्रेम को फ्रेम करके वास्तव में थक गया हूं ...)

यहाँ छवि विवरण दर्ज करें

तो वास्तव में अब तक प्रकाश प्राप्त करना और आकर्षित करना कोई समस्या नहीं है !

मैंने युद्ध के कोहरे और चिकनी बिजली बनाने के लिए ढाल परिपत्र ओवरले का उपयोग करते हुए अनगिनत ट्यूटोरियल देखे हैं, लेकिन मेरे पास पहले से ही प्रत्येक टाइल को एक बिजली के मूल्य को असाइन करने के लिए एक अच्छा तरीका है, इसे बस उनके बीच सुचारू करने की आवश्यकता है।

तो समीक्षा करने के लिए

  • प्रकाश की गणना (पूर्ण)
  • टाइलें खींचो (मुझे पता है, मुझे इसे छायाकार के लिए संशोधित करने की आवश्यकता होगी)
  • छाया टाइलें (मूल्यों को कैसे पास करें और "ढाल" लागू करें)

जवाबों:


6

इस जैसे किसी और के बारे में क्या राय है?

अपने टाइल स्प्राइट को टिन्ट करके अपनी लाइटिंग न बनाएं। रेंडर टारगेट के लिए अपनी अनलिमिटेड टाइल्स को ड्रा करें , फिर टाइल लाइट को दूसरे रेंडर टारगेट पर ड्रा करें , हर एक को टाइल वाले क्षेत्र को कवर करते हुए ग्रेस्केल आयत के रूप में दर्शाएं। अंतिम दृश्य को प्रस्तुत करने के लिए, दो रेंडर लक्ष्यों को संयोजित करने के लिए एक शेडर का उपयोग करें, दूसरे के मूल्य के अनुसार पहले के प्रत्येक पिक्सेल को गहरा करना।

यह वही पैदा करेगा जो अभी आपके पास है। यह आपकी मदद नहीं करता है, तो चलो इसे थोड़ा बदल दें।

अपने लाइटमैप रेंडर टारगेट के आयामों को बदलें ताकि प्रत्येक टाइल एक आयताकार क्षेत्र के बजाय एकल पिक्सेल द्वारा दर्शाई जाए । अंतिम दृश्य कंपोज़ करते समय, रैखिक फ़िल्टरिंग के साथ एक नमूना स्थिति का उपयोग करें। नहीं तो बाकी सब वही छोड़ दो।

यह मानते हुए कि आपने अपने शेडर को सही ढंग से लिखा है, कंपोजिंग के दौरान लाइटमैप प्रभावी ढंग से "स्केल्ड अप" होना चाहिए। यह आपको ग्राफिक्स डिवाइस की बनावट के नमूने के माध्यम से मुफ्त में एक अच्छा ढाल प्रभाव प्राप्त करेगा।

तुम भी shader बाहर कटौती करने में सक्षम हो सकता है और यह और अधिक बस एक 'darkening' BlendState के साथ, लेकिन इससे पहले कि मैं आपको बारीकियों दे सकता है मैं इसके साथ प्रयोग करना होगा।

अपडेट करें

मेरे पास आज कुछ समय था कि मैं वास्तव में इसका मजाक उड़ाऊं। ऊपर दिया गया उत्तर मेरी हर चीज़ के पहले उत्तर के रूप में शेड्स का उपयोग करने की मेरी आदत को दर्शाता है, लेकिन इस मामले में वे वास्तव में आवश्यक नहीं हैं और उनका उपयोग अनावश्यक रूप से चीजों को जटिल बनाता है।

जैसा कि मैंने सुझाव दिया, आप कस्टम ब्लेंडस्टेट का उपयोग करके ठीक उसी प्रभाव को पूरा कर सकते हैं। विशेष रूप से, यह कस्टम ब्लेंडस्टेट:

BlendState Multiply = new BlendState()
{
    AlphaSourceBlend = Blend.DestinationAlpha,
    AlphaDestinationBlend = Blend.Zero,
    AlphaBlendFunction = BlendFunction.Add,
    ColorSourceBlend = Blend.DestinationColor,
    ColorDestinationBlend = Blend.Zero,
    ColorBlendFunction = BlendFunction.Add
}; 

सम्मिश्रण समीकरण है

result = (source * sourceBlendFactor) blendFunction (dest * destBlendFactor)

तो हमारे कस्टम BlendState के साथ, यह बन जाता है

result = (lightmapColor * destinationColor) + (0)

जिसका अर्थ है कि शुद्ध सफेद (1, 1, 1, 1) का स्रोत रंग गंतव्य रंग को संरक्षित करेगा, शुद्ध काले रंग का स्रोत रंग (0, 0, 0, 1) शुद्ध रंग को काला कर देगा, और कोई भी बीच में भूरे रंग की छाया एक मद्धम राशि से गंतव्य का रंग गहरा कर देगी।

इसे व्यवहार में लाने के लिए, अपना लाइटमैप बनाने के लिए सबसे पहले आपको जो करना है वह करें:

var lightmap = GetLightmapRenderTarget();

फिर अपने बैकलाइट दृश्य को सीधे बैकबफ़र की ओर आकर्षित करें जैसा कि आप सामान्य रूप से करेंगे:

spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
/* draw the world here */
spriteBatch.End();

फिर कस्टम ब्लेंडस्टेट का उपयोग करके लाइटमैप बनाएं:

var offsetX = 0; // you'll need to set these values to whatever offset is necessary
var offsetY = 0; // to align the lightmap with the map tiles currently being drawn
var width = lightmapWidthInTiles * tileWidth;
var height = lightmapHeightInTiles * tileHeight;

spriteBatch.Begin(SpriteSortMode.Immediate, Multiply);
spriteBatch.Draw(lightmap, new Rectangle(offsetX, offsetY, width, height), Color.White);
spriteBatch.End();

यह गंतव्य रंग (टाइलें) को स्रोत रंग (लाइटमैप) से गुणा करेगा, उचित रूप से अनलिमिटेड टाइल्स को गहरा कर देगा, और लाइटमैप बनावट के आवश्यक आकार तक स्केल होने के कारण एक ढाल प्रभाव पैदा करेगा।


यह बहुत आसान लगता है, बीमार देखता है कि मैं बाद में क्या कर सकता हूं। मैंने पहले कुछ अनुकरण करने की कोशिश की (मैंने लाइटमैप को बाकी सब चीज़ों पर प्रस्तुत किया और एक ब्लर शेडर का इस्तेमाल किया, लेकिन मैं रेंडरटार्ग को "पारदर्शी" नहीं बना सका, इसमें बैंगनी ओवरले था, लेकिन मैं चाहता था कि यह
एक्टुवैल

डिवाइस पर अपना रेंडर टारगेट सेट करने के बाद, डिवाइस को कॉल करें। क्लियर (Color.Transparent);
कोल कैंपबेल

हालाँकि, इस मामले में, यह इंगित करने के लायक है कि आपके लाइटमैप को संभवतः या तो सफेद या काले रंग से साफ किया जाना चाहिए, जो क्रमशः पूर्ण प्रकाश और पूर्ण अंधेरा है।
कोल कैंपबेल

मुझे लगता है कि मैंने पहले जो कोशिश की थी, लेकिन यह अभी भी बैंगनी था, अच्छी तरह से यह कल पर देखो जब मेरे पास इस पर काम करने के लिए कुछ समय होगा।
साइरेल

लगभग यह सब काम कर गया, लेकिन यह काले से पारदर्शी के बजाय काले से सफेद हो जाता है। Shader हिस्सा है कि मैं क्या उलझन में हूँ, कैसे एक को लिखने के लिए एक के लिए मूल अयोग्य दृश्य मंद है।
साइरेल

10

ठीक है यहां कुछ सरल और चिकनी 2 डी लाइटनिंग बनाने के लिए एक बहुत ही सरल विधि है, तीन पासों में प्रस्तुत करें:

  • पास 1: बिजली के बिना खेल की दुनिया।
  • दर्रा 2: दुनिया के बिना बिजली
  • 1. और 2. का संयोजन जो स्क्रीन पर प्रदर्शित होता है।

पास 1 में आप सभी स्प्राइट्स और इलाके को आकर्षित करते हैं।

पास 2 में आप स्प्राइट्स का दूसरा समूह बनाते हैं जो प्रकाश स्रोत हैं। उन्हें इस तरह दिखना चाहिए:
यहाँ छवि विवरण दर्ज करें
ब्लैक के साथ रेंडर टारगेट को इनिशियलाइज़ करें और उन स्प्राइट्स को अधिकतम या एडिटिव ब्लेंडिंग के साथ ड्रा करें।

पास 3 में आप दो पूर्व पासों को मिलाते हैं। कई अलग-अलग तरीके हैं कि उन्हें कैसे जोड़ा जा सकता है। लेकिन सबसे सरल और कम से कम कलात्मक विधि उन्हें एक साथ गुणा करना है। यह इस तरह दिखेगा:
यहाँ छवि विवरण दर्ज करें


बात यह है, मेरे पास पहले से ही एक प्रकाश व्यवस्था है, और बिंदु रोशनी यहां काम नहीं करती है क्योंकि कुछ वस्तुओं को प्रकाश से गुजरने की आवश्यकता होती है और कुछ नहीं।
साइरेल

2
वैसे यह ज्यादा मुश्किल है। आपको छाया प्राप्त करने के लिए किरण डालना होगा। Teraria अपने इलाके के लिए बड़े ब्लॉक का उपयोग करता है इसलिए वहाँ कोई समस्या नहीं है। आप रे-कास्टिंग का उपयोग कर सकते हैं, लेकिन यह टेरारिया से बेहतर नहीं होगा और यदि आप ग्राफिक्स को ब्लॉक नहीं करते हैं, तो यह भी कम फिट हो सकता है। उन्नत और अच्छी दिखने वाली तकनीक के लिए यह लेख है: gamedev.net/page/resources/_/technical/…
API-Beast

2

आपके द्वारा पोस्ट किया गया दूसरा लिंक युद्ध के एक कोहरे की तरह लग रहा है, इस पर कुछ अन्य प्रश्न हैं

यह मुझे एक बनावट की तरह दिखता है , जहाँ आप ब्लैक ओवरले के बिट्स को "मिटा" देते हैं (उन पिक्सेल के अल्फ़ा को 0 पर सेट करके) क्योंकि खिलाड़ी आगे बढ़ता है।

मैं कहूंगा कि व्यक्ति ने एक ब्रश प्रकार "मिटा" का उपयोग किया होगा जहां खिलाड़ी ने खोज की है।


1
यह युद्ध का कोहरा नहीं है, यह प्रत्येक फ्रेम बिजली की गणना करता है। मैंने जिस खेल की ओर ध्यान दिलाया वह टेरारिया के समान है।
साइरल

मेरा मतलब है कि यह युद्ध के कोहरे के समान लागू हो सकता है
बॉबोबोबो

2

टाइल्स की जगह लाइट वर्टिकल (टाइल्स के बीच के कोने)। प्रत्येक टाइल पर उसके चार कोने के आधार पर प्रकाश डालें।

प्रत्येक शीर्ष पर दृष्टि परीक्षणों का निर्धारण करें कि यह कैसे जलाया जाता है (आप या तो सभी प्रकाश को रोक सकते हैं या प्रकाश को कम कर सकते हैं, उदाहरण के लिए गणना करें कि प्रत्येक शीर्ष पर कितने चौराहों को दूरी के साथ संयुक्त किया गया है एक प्रकाश मूल्य की गणना करने के बजाय एक का उपयोग करके शुद्ध बाइनरी दिखाई / न दिखने वाला टेस्ट)।

एक टाइल का प्रतिपादन करते समय, प्रत्येक शीर्ष के लिए प्रकाश मान को GPU पर भेजें। आप आसानी से प्रत्येक पिक्सेल को सुचारू रूप से चमकाने के लिए टाइल के स्प्राइट में प्रत्येक टुकड़े में प्रक्षेपित प्रकाश मान लेने के लिए आसानी से एक टुकड़े टुकड़े करने वाले का उपयोग कर सकते हैं। जीएलएसएल को छूने के बाद यह काफी लंबा हो गया है कि मैं वास्तविक को एक कोड नमूना देने में सहज महसूस नहीं करूंगा, लेकिन छद्म कोड में यह उतना ही सरल होगा:

texture t_Sprite
vec2 in_UV
vec4 in_Light // coudl be one float; assuming you might want colored lights though

fragment shader() {
  output = sample2d(t_Sprite, in_UV) * in_Light;
}

वर्टेक्स शेडर को केवल खंड मानों पर इनपुट मानों को पास करना होता है, दूर से जटिल कुछ भी नहीं।

आप और अधिक वर्टीकल के साथ स्मूद लाइटिंग प्राप्त करेंगे (यदि प्रत्येक टाइल को चार उप-टाइलों के रूप में प्रस्तुत किया गया है), लेकिन यह उस गुणवत्ता के आधार पर प्रयास के लायक नहीं हो सकता है, जिसके लिए आप जा रहे हैं। पहले इसे सरल तरीके से आज़माएँ।


1
line-of sight tests to each vertex? वह महंगा होने जा रहा है।
ashes999

आप कुछ चतुराई के साथ अनुकूलन कर सकते हैं। एक 2D गेम के लिए आप एक सख्त ग्रिड के खिलाफ काफी तेज़ी से किरण परीक्षणों की एक आश्चर्यजनक संख्या कर सकते हैं। सीधे एलओएस परीक्षण के बजाय आप "प्रवाह" कर सकते हैं (मैं अपने जीवन के लिए अभी उचित अवधि के बारे में नहीं सोच सकता हूं; बीयर रात) किरण परीक्षण करने के बजाय कोने पर प्रकाश मूल्यों को भी।
सीन मिडिलिचच

दृष्टि परीक्षणों की लाइन के उपयोग से यह अधिक जटिल हो जाता है, मेरे पास पहले से ही प्रकाश व्यवस्था है। अब जब मैं छायाकार को 4 लंबवत भेजता हूं, तो मैं यह कैसे कर सकता हूं? मुझे पता है कि आप वास्तविक को एक कोड नमूना देने में सहज महसूस नहीं करते हैं, लेकिन अगर मुझे थोड़ी और जानकारी मिल सकती है तो अच्छा होगा। मैंने प्रश्न को अधिक जानकारी के साथ संपादित भी किया।
साइरेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.