OpenGL में रेट्रो-शैली पैलेट स्वैपिंग प्रभाव बनाना


37

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

NES पर इस तरह का प्रभाव आम और काफी आसान था क्योंकि प्रोग्रामर की पैलेट तक पहुँच थी और पिक्सल और पैलेट सूचकांकों के बीच तार्किक मैपिंग थी। आधुनिक हार्डवेयर पर, हालांकि, यह थोड़ा अधिक चुनौतीपूर्ण है क्योंकि पैलेट की अवधारणा समान नहीं है।

मेरे सभी बनावट 32-बिट हैं और पैलेट का उपयोग नहीं करते हैं।

मेरे द्वारा चाहा जाने वाले प्रभाव को प्राप्त करने के दो तरीके हैं, लेकिन अगर मुझे इस प्रभाव को आसानी से प्राप्त करने के लिए बेहतर तरीके हैं तो मैं उत्सुक हूं। मेरे द्वारा चुने गए दो विकल्प हैं:

  1. "पैलेट स्वैपिंग" व्यवहार करने के लिए एक shader का उपयोग करें और कुछ GLSL लिखें।
  2. यदि शेड्स उपलब्ध नहीं हैं (कहते हैं, क्योंकि ग्राफिक्स कार्ड उनका समर्थन नहीं करता है) तो "मूल" बनावट को क्लोन करना संभव है और पूर्व-लागू रंग परिवर्तन के साथ विभिन्न संस्करणों को उत्पन्न करना संभव है।

आदर्श रूप से मैं एक शेडर का उपयोग करना चाहूंगा क्योंकि यह सीधा लगता है और डुप्लिकेट-बनावट पद्धति के विपरीत थोड़े अतिरिक्त काम की आवश्यकता होती है। मुझे चिंता है कि उनमें सिर्फ एक रंग बदलने के लिए बनावट की नकल करना वीआरएएम को बर्बाद कर रहा है - क्या मुझे इसके बारे में चिंता नहीं करनी चाहिए?

संपादित करें : मैं स्वीकृत उत्तर की तकनीक का उपयोग करके समाप्त हो गया और यहां संदर्भ के लिए मेरी छायादार है।

uniform sampler2D texture;
uniform sampler2D colorTable;
uniform float paletteIndex;

void main()
{
        vec2 pos = gl_TexCoord[0].xy;
        vec4 color = texture2D(texture, pos);
        vec2 index = vec2(color.r + paletteIndex, 0);
        vec4 indexedColor = texture2D(colorTable, index);
        gl_FragColor = indexedColor;      
}

दोनों बनावट 32-बिट हैं, एक बनावट का उपयोग लुकअप टेबल के रूप में किया जाता है जिसमें कई पट्टियाँ होती हैं जो सभी एक ही आकार की होती हैं (मेरे मामले में 6 रंग)। मैं रंग तालिका में एक इंडेक्स के रूप में स्रोत पिक्सेल के लाल चैनल का उपयोग करता हूं। इसने मेगामैन जैसी पैलेट स्वैपिंग को प्राप्त करने के लिए एक आकर्षण की तरह काम किया!

जवाबों:


41

मैं कुछ चरित्र बनावट के लिए वीआरएएम को बर्बाद करने के बारे में चिंता नहीं करेगा।

अपने विकल्प 2 का उपयोग करने के लिए 2. (अलग-अलग बनावट या अलग यूवी ऑफसेट के साथ यदि वह फिट बैठता है) जाने का रास्ता है: अधिक लचीला, डेटा-चालित, कोड पर कम प्रभाव, कम बग, कम चिंताएं।


यह एक तरफ रख दिया जाता है, यदि आप स्मृति में टन के एनिमेशन के साथ वर्णों के टन को संचित करना शुरू करते हैं, तो शायद आप ओपनगेल द्वारा सुझाए गए का उपयोग करना शुरू कर सकते हैं , यह अपने आप से पैलेट:

पैलेटेड बनावट

प्रमुख GL विक्रेताओं द्वारा EXT_paletted_texture एक्सटेंशन के लिए समर्थन हटा दिया गया है। यदि आपको वास्तव में नए हार्डवेयर पर पैलेट किए गए बनावट की आवश्यकता है, तो आप उस प्रभाव को प्राप्त करने के लिए शेड्स का उपयोग कर सकते हैं।

शेडर उदाहरण:

//Fragment shader
#version 110
uniform sampler2D ColorTable;     //256 x 1 pixels
uniform sampler2D MyIndexTexture;
varying vec2 TexCoord0;

void main()
{
  //What color do we want to index?
  vec4 myindex = texture2D(MyIndexTexture, TexCoord0);
  //Do a dependency texture read
  vec4 texel = texture2D(ColorTable, myindex.xy);
  gl_FragColor = texel;   //Output the color
}

यह केवल ColorTable(आरजीबी MyIndexTexture8 में एक पैलेट), (अनुक्रमित रंगों में 8 बिट्स वर्ग बनावट ) का नमूना ले रहा है । बस रेट्रो-स्टाइल पैलेट के काम करने के तरीके को पुन: पेश करता है।


ऊपर उद्धृत उदाहरण दो का उपयोग करता है sampler2D, जहां यह वास्तव में एक sampler1D+ एक का उपयोग कर सकता है sampler2D। मुझे संदेह है कि यह अनुकूलता के कारणों ( ओपनजीएल ईएस में कोई एक आयामी बनावट नहीं है) ... लेकिन कभी नहीं, डेस्कटॉप ओपन के लिए इसे सरल बनाया जा सकता है:

uniform sampler1D Palette;             // A palette of 256 colors
uniform sampler2D IndexedColorTexture; // A texture using indexed color
varying vec2 TexCoord0;                // UVs

void main()
{
    // Pick up a color index
    vec4 index = texture2D(IndexedColorTexture, TexCoord0);
    // Retrieve the actual color from the palette
    vec4 texel = texture1D(Palette, index.x);
    gl_FragColor = texel;   //Output the color
}

Palette"वास्तविक" रंगों (जैसे GL_RGBA8) IndexedColorTextureकी एक-आयामी बनावट है , और अनुक्रमित रंगों का एक दो-आयामी बनावट है (आमतौर पर GL_R8, जो आपको 256 सूचकांक देता है)। उन बनाने के लिए, वहाँ कई संलेखन उपकरण और छवि फ़ाइल प्रारूप हैं जो तालुका छवियों का समर्थन करते हैं, यह आपकी आवश्यकताओं के अनुरूप होने वाले खोजने के लिए योग्य होना चाहिए।


2
बिल्कुल सही जवाब मैंने दिया, केवल अधिक विस्तृत। अगर मैं कर सकता था +2।
इल्मरी करोनन

मुझे कुछ समस्याएं हो रही हैं जो मेरे लिए काम कर रही हैं, ज्यादातर क्योंकि मुझे समझ में नहीं आता है कि रंग में सूचकांक कैसे निर्धारित किया जाता है - क्या आप संभवतः उस पर थोड़ा और विस्तार कर सकते हैं?
जैक द ह्यूमन

आपको संभवतः अनुक्रमित रंगों पर पढ़ना चाहिए । आपकी बनावट सूचकांकों का 2 डी सरणी बन जाती है, पैलेट में रंगों के अनुरूप सूचकांकों को खो देता है (आमतौर पर एक आयामी बनावट)। मैं OpenGL वेबसाइट द्वारा दिए गए उदाहरण को सरल बनाने के लिए अपना उत्तर संपादित करूँगा।
लॉरेंट कौविदो

मुझे क्षमा करें, मैं अपनी मूल टिप्पणी में स्पष्ट नहीं था। मैं अनुक्रमित रंगों से परिचित हूं और वे कैसे काम करते हैं, लेकिन मैं इस बारे में स्पष्ट नहीं हूं कि वे एक शेडर या 32-बिट बनावट के संदर्भ में कैसे काम करते हैं (क्योंकि वे अनुक्रमित नहीं हैं - सही?)।
ज़ैक द ह्यूमन

खैर, बात यह है कि यहां आपके पास एक 32-बिट पैलेट है जिसमें 256 रंग हैं, और 8-बिट सूचकांकों की एक बनावट (0 से 255 तक जा रही है)। मेरा संपादन देखें;)
लॉरेंट कौविदो

10

मेरे ऐसा करने के 2 तरीके हैं।

रास्ता # 1: GL_MODULATE

आप स्प्राइट को ग्रे, और GL_MODULATEबनावट में बना सकते हैं जब इसे एक ठोस रंग के साथ खींचा जाता है।

उदाहरण के लिए,

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

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

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

रास्ता # 2: ifकथन (प्रदर्शन के लिए खराब)

एक और चीज जो आप कर सकते हैं, वह है अपने टेक्स्ट को R, G और B. SO से युक्त कुछ प्रमुख मानों के साथ रंगना। उदाहरण के लिए, पहला रंग (1,0,0), दूसरा रंग (0,1,0), तीसरा है रंग है (0,0,1)।

आप कुछ समान की घोषणा करते हैं

uniform float4 color1 ;
uniform float4 color2 ;
uniform float4 color3 ;

फिर shader में, अंतिम पिक्सेल रंग कुछ ऐसा होता है

float4 pixelColor = texel.r*color1 + texel.g*color2 + texel.b*color3 ;

color1, color2, color3, वर्दी हैं तो वे शेडर रन से पहले सेट किया जा सकता (क्या "सूट" megaman पर निर्भर करता है में है), तो शेडर बस बाकी है।

ifयदि आपको अधिक रंगों की आवश्यकता होती है, तो आप बयानों का भी उपयोग कर सकते हैं , लेकिन आपको समानता जांच कार्य सही ढंग से करना होगा ( R8G8B8बनावट फ़ाइल में आमतौर पर प्रत्येक के बीच 0 और 255 के बीच होते हैं , लेकिन छाया में, आपके पास आरजीबीए फ्लोट हैं)

रास्ता # 3: बस अलग-अलग रंगीन चित्रों को स्प्राइट मैप में संग्रहीत करें

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

यह सबसे आसान तरीका हो सकता है, यदि आप पागलपन से स्मृति के संरक्षण की कोशिश नहीं कर रहे हैं


2
# 1 साफ-सुथरा हो सकता है, लेकिन # 2 और # 3 सलाह के बुरी तरह से खराब टुकड़े हैं। GPU मानचित्रों (जिनमें से एक पैलेट मूल रूप से है) से अनुक्रमण करने में सक्षम है और उन दोनों सुझावों की तुलना में बेहतर है।
स्काइलर

6

मैं shaders का उपयोग करेंगे। यदि आप उनका उपयोग नहीं करना चाहते हैं (या नहीं कर सकते हैं) तो मैं प्रति रंग एक बनावट (या बनावट का हिस्सा) के साथ जाऊंगा और केवल साफ सफेद का उपयोग करूंगा। यह आपको glColor()रंगों के लिए अतिरिक्त बनावट बनाने के बारे में चिंता किए बिना बनावट (जैसे के माध्यम से ) को टिंट करने की अनुमति देगा । तुम भी अतिरिक्त बनावट काम के बिना रन पर रंग स्वैप कर सकते हैं।


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

हां, आपको स्प्राइट प्रति x पास की भी आवश्यकता होगी, जो काफी जटिलता को जोड़ सकता है। आज के हार्डवेयर को ध्यान में रखते हुए आमतौर पर कम से कम बुनियादी पिक्सेल शेड्स (यहां तक ​​कि नेटबुक जीपीयू) का समर्थन करते हैं, मैं इसके बजाय इनके साथ जाऊंगा। यह साफ-सुथरा हो सकता है यदि आप केवल विशिष्ट चीजों को टेंट देना चाहते हैं, जैसे स्वास्थ्य बार या आइकन।
मारियो

3

"सभी स्प्राइट के रंग नहीं बदलते हैं, केवल कुछ लोग ही करते हैं।"

पुराने खेल पैलेट ट्रिक्स करते थे क्योंकि वह सब उनके पास था। इन दिनों, आप कई बनावटों का उपयोग कर सकते हैं और उन्हें विभिन्न तरीकों से जोड़ सकते हैं।

आप एक अलग ग्रेस्केल मुखौटा बनावट बना सकते हैं जिसका उपयोग आप यह तय करने के लिए करते हैं कि कौन सा पिक्सेल रंग बदल देगा। बनावट में सफेद क्षेत्र पूर्ण रंग संशोधन प्राप्त करते हैं, और काले क्षेत्र अपरिवर्तित रहते हैं।

Shader में अस्पष्ट:

vec3 baseColor = बनावट (BaseSampler, att_TexCoord) .rgb;
फ्लोट राशि = बनावट (MaskSampler, att_TexCoord) .r;
vec3 color = mix (baseColor, baseColor * ModulationColor, amount);

या आप विभिन्न बनावट वाले कॉम्बिनर मोड के साथ फिक्स्ड-फंक्शन मल्टी-टेक्सचरिंग का उपयोग कर सकते हैं।

स्पष्ट रूप से कई अलग-अलग तरीके हैं जिनके बारे में आप जा सकते हैं; आप RGB चैनलों में से प्रत्येक में विभिन्न रंगों के लिए मास्क लगा सकते हैं, या HSV कलरस्पेस में टिंट शिफ्टिंग द्वारा रंगों को संशोधित कर सकते हैं।

एक और, शायद सरल, विकल्प केवल प्रत्येक घटक के लिए एक अलग बनावट का उपयोग करके स्प्राइट को आकर्षित करना है। बालों के लिए एक बनावट, कवच के लिए एक, जूते के लिए एक, आदि प्रत्येक एक रंग अलग से रंगा हुआ है।


2

सबसे पहले इसे आम तौर पर साइकिलिंग (पैलेट साइकिलिंग) के रूप में संदर्भित किया जाता है, ताकि आपके Google-fu को मदद मिल सके।

यह बिल्कुल इस बात पर निर्भर करेगा कि आप क्या प्रभाव पैदा करना चाहते हैं और यदि आप स्थिर 2 डी सामग्री या गतिशील 3 डी सामान के साथ काम कर रहे हैं (यानी क्या आप केवल मसाले / बनावट से निपटना चाहते हैं, या पूरे 3 डी दृश्य को प्रस्तुत करना चाहते हैं तो फूस की अदला-बदली)। इसके अलावा अगर आप खुद को कई रंगों में सीमित कर रहे हैं या पूर्ण रंग का उपयोग कर रहे हैं।

एक अधिक संपूर्ण दृष्टिकोण, शेड्स का उपयोग करना, वास्तव में एक फूस की बनावट के साथ रंगीन अनुक्रमित छवियों का उत्पादन करना होगा। एक बनावट बनाएं लेकिन रंगों के बजाय, एक रंग है जो देखने के लिए एक सूचकांक का प्रतिनिधित्व करता है और फिर रंगों की एक और बनावट है जो प्लेट है। उदाहरण के लिए, लाल रंग का तालमेल नहीं हो सकता है, और हरे रंग का समन्वय हो सकता है। लुकअप करने के लिए shader का उपयोग करें। और उस फूस की बनावट के रंगों को चेतन / संशोधित करें। यह रेट्रो प्रभाव के काफी करीब होगा, लेकिन केवल स्थिर 2D सामग्री जैसे स्प्राइट या बनावट के लिए काम करेगा। यदि आप वास्तविक रेट्रो ग्राफिक्स कर रहे हैं तो आप वास्तविक अनुक्रमित रंग स्प्राइट का उत्पादन करने में सक्षम हो सकते हैं और उन्हें और पैलेटों को आयात करने के लिए कुछ लिख सकते हैं।

यदि आप एक 'वैश्विक' पैलेट का उपयोग करने जा रहे हैं, तो भी आप काम करना चाहेंगे। जैसे पुराना हार्डवेयर कैसे काम करेगा, पैलेट्स के लिए कम मेमोरी, क्योंकि आपको अपनी कलाकृति बनाने के लिए केवल एक की जरूरत है, लेकिन इसके लिए आपको सभी चित्रों में फूस को सिंक्रनाइज़ करना होगा) या प्रत्येक छवि को स्वयं का फूस देना होगा। यह आपको अधिक लचीलापन देगा लेकिन अधिक मेमोरी का उपयोग करेगा। बेशक आप दोनों कर सकते हैं, आप केवल उन चीजों के लिए पैलेट का उपयोग कर सकते हैं जो आप रंग साइकिल हैं। अपने रंगों को सीमित करने के लिए आप किस हद तक काम नहीं करेंगे, पुराने खेल उदाहरण के लिए 256 रंगों का उपयोग करेंगे। यदि आप एक बनावट का उपयोग कर रहे हैं तो आपको पिक्सेल की संख्या मिल जाएगी इसलिए 256 * 256 आपको दे देंगे

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

यदि आपको इसकी आवश्यकता पूर्ण 3 डी में है तो आप उड़ने पर अनुक्रमित छवि बनाने की कोशिश कर सकते हैं लेकिन यह धीमा होगा क्योंकि आपको फूस को देखना होगा, आप संभवतः रंगों की सीमा में भी सीमित होंगे।

अन्यथा आप इसे सिर्फ छायादार में नकली कर सकते हैं, यदि रंग == रंग स्वैपिंग, इसे स्वैप करें। यह धीमा होगा और केवल सीमित संख्या में स्वैपिंग रंगों के साथ काम करेगा, लेकिन आज के किसी भी हार्डवेयर पर जोर नहीं देना चाहिए, खासकर यदि आप सिर्फ 2 डी ग्राफिक्स के साथ काम कर रहे हैं और आप हमेशा यह चिह्नित कर सकते हैं कि कौन से स्प्राइट में रंग की अदला-बदली होती है और एक अलग शेडर का उपयोग होता है।

अन्यथा वास्तव में उन्हें नकली, प्रत्येक राज्य के लिए एनिमेटेड बनावट का एक गुच्छा बनाएं।

एचटीएमएल 5 में किए गए पैलेट साइकिलिंग का एक शानदार डेमो यहां दिया गया है


0

मेरा मानना ​​है कि अगर रंग अंतरिक्ष के लिए पर्याप्त तेज हैं [0 ... 1] को दो में विभाजित किया जा सकता है:

if (color.r > 0.5) {
   color.r = (color.r-0.5) * uniform_r + uniform_base_r;
} else {
  color.r *=2.0;
} // this could be vectorised for all colors

इस तरह 0 और 0.5 के बीच के रंग मान सामान्य रंग मूल्यों के लिए आरक्षित होते हैं; और 0.5 - 1.0 "मॉड्यूलेटेड" मूल्यों के लिए आरक्षित हैं, जहां उपयोगकर्ता द्वारा चयनित किसी भी सीमा के लिए 0.5..1.0 नक्शे हैं।

केवल रंग रिज़ॉल्यूशन को 256 मान प्रति पिक्सेल से 128 मान तक छोटा किया जाता है।

शायद पूरी तरह से ifs को हटाने के लिए अधिकतम (रंग 0.5f, 0.0f) जैसे अंतर्निहित कार्यों का उपयोग कर सकते हैं (उन्हें शून्य या एक से गुणा करने के लिए व्यापार कर सकते हैं ...)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.