OpenGL ES में टेक्स्ट ड्रा करें


131

मैं वर्तमान में एंड्रॉइड प्लेटफ़ॉर्म के लिए एक छोटा सा ओपनगैल गेम विकसित कर रहा हूं और मुझे आश्चर्य है कि यदि रेंडर किए गए फ्रेम के शीर्ष पर पाठ को प्रस्तुत करने का एक आसान तरीका है (जैसे खिलाड़ी के स्कोर के साथ एक एचयूडी)। पाठ को एक कस्टम फ़ॉन्ट का भी उपयोग करने की आवश्यकता होगी।

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

कोई विचार?


इस परियोजना पर एक नज़र डालें: code.google.com/p/rokon
whunmr

इस तरह से देखें कि libgdx बिटमैप फ़ॉन्ट्स के माध्यम से ऐसा करता है।
रॉबर्ट मैसाइली

जवाबों:


103

Android SDK OpenGL के विचारों पर पाठ आकर्षित करने के लिए किसी भी आसान तरीके के साथ नहीं आता है। निम्नलिखित विकल्पों के साथ आपको छोड़कर।

  1. अपने SurfaceView पर एक TextView रखें। यह धीमा और खराब है, लेकिन सबसे प्रत्यक्ष दृष्टिकोण है।
  2. बनावट के लिए सामान्य तार रेंडर करें, और बस उन बनावटों को आकर्षित करें। यह अब तक का सबसे सरल और सबसे तेज़, लेकिन सबसे कम लचीला है।
  3. एक प्रेत के आधार पर अपना-अपना पाठ रेंडरिंग कोड। यदि दूसरा विकल्प नहीं है तो संभवतः दूसरा सबसे अच्छा विकल्प है। अपने पैरों को गीला करने का एक अच्छा तरीका है, लेकिन ध्यान दें कि जब यह सरल लगता है (और बुनियादी विशेषताएं हैं), तो यह अधिक कठिन और अधिक चुनौतीपूर्ण हो जाता है क्योंकि आप अधिक सुविधाएँ (बनावट-संरेखण, लाइन-विराम से निपटने, चर-चौड़ाई के फोंट आदि) जोड़ते हैं। ) - यदि आप इस मार्ग को लेते हैं, तो इसे उतना ही सरल बना दें जितना आप दूर कर सकते हैं!
  4. एक ऑफ-द-शेल्फ / ओपन-सोर्स लाइब्रेरी का उपयोग करें। यदि आप Google पर शिकार करते हैं तो कुछ आस-पास हैं, मुश्किल बिट उन्हें एकीकृत और चल रहा है। लेकिन कम से कम, एक बार जब आप ऐसा करते हैं, तो आपके पास सभी लचीलेपन और परिपक्वता होगी जो वे प्रदान करते हैं।

3
मैंने अपने GLView पर एक दृश्य जोड़ने का फैसला किया है, यह करने के लिए सबसे कुशल तरीका नहीं हो सकता है, लेकिन दृश्य बहुत बार अपडेट नहीं किया जाता है, साथ ही यह मुझे जो भी फ़ॉन्ट मुझे पसंद है उसे जोड़ने की सुविधा देता है। सभी उत्तरों के लिए धन्यवाद!
शेकजेड

1
मैं बनावट के लिए सामान्य तार कैसे प्रस्तुत कर सकता हूं, और बस उन बनावटों को आकर्षित कर सकता हूं? धन्यवाद।
वंसफैनलाइन

1
VansFannel: बस अपने सभी तार एक छवि में रखने के लिए एक पेंट प्रोग्राम का उपयोग करें, फिर अपने ऐप में ऑफ़सेट का उपयोग केवल उस छवि के हिस्से को रेंडर करने के लिए करें जिसमें वह स्ट्रिंग है जिसे आप चाहते हैं।
डेव

2
या इसे प्राप्त करने के लिए अधिक प्रोग्रामेटिक तरीके के लिए जेविटेला का जवाब नीचे देखें।
डेव

4
JVitela का जवाब बेहतर है। यही मैं वर्तमान में उपयोग कर रहा हूं। कारण है कि आप मानक Android vier + कैनवास से opengl पर स्विच करते हैं (दूसरों के बीच) गति के लिए। अपने opengl तरह के नेगेट पर एक टेक्स्ट बॉक्स जोड़ना।
शिवन ड्रैगन

166

पाठ को बनावट में रेंडर करना उस पाठ की तुलना में सरल है जो स्प्राइट टेक्स्ट डेमो बनाता है, जैसा दिखता है, मूल विचार एक बिटमैप को रेंडर करने के लिए कैनवस क्लास का उपयोग करना है और फिर बिटमैप को ओपनग्ल बनावट में पास करना है:

// Create an empty, mutable bitmap
Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_4444);
// get a canvas to paint over the bitmap
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);

// get a background image from resources
// note the image format must match the bitmap format
Drawable background = context.getResources().getDrawable(R.drawable.background);
background.setBounds(0, 0, 256, 256);
background.draw(canvas); // draw the background to our bitmap

// Draw the text
Paint textPaint = new Paint();
textPaint.setTextSize(32);
textPaint.setAntiAlias(true);
textPaint.setARGB(0xff, 0x00, 0x00, 0x00);
// draw the text centered
canvas.drawText("Hello World", 16,112, textPaint);

//Generate one texture pointer...
gl.glGenTextures(1, textures, 0);
//...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

//Create Nearest Filtered Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

//Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);

//Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

//Clean up
bitmap.recycle();

5
इससे मुझे डिबगिंग के लिए मेरे ऐप पर थोड़ा एफपीएस काउंटर पर प्रदर्शित करने में मदद मिली, धन्यवाद!
स्टील्थोप्टर

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

9
यह बहुत धीमा है, यह पाठ के लिए एक गेम पर एफपीएस को मार देगा जो हमेशा बदल रहा है (स्कोर, आदि), हालांकि यह अर्ध-स्थिर सामान (खिलाड़ी का नाम, स्तर नाम, आदि) के लिए अच्छी तरह से काम करता है।
led42

3
मैं यह नोट करना चाहूंगा कि इस उत्तर में कोड शायद केवल एक डेमो है और जिसे कभी-कभी अनुकूलित नहीं किया गया है! कृपया अपने तरीके से अनुकूलन / कैश करें।
शरीफ इल्हातिब

1
क्या आप इसे OpenGL ES 2.0 के लिए प्रदान कर सकते हैं?
असीमित

36

मैंने एक ट्यूटोरियल लिखा है जो JVitela द्वारा पोस्ट किए गए उत्तर पर फैलता है । मूल रूप से, यह एक ही विचार का उपयोग करता है, लेकिन प्रत्येक स्ट्रिंग को एक बनावट में प्रस्तुत करने के बजाय, यह एक फ़ॉन्ट फ़ाइल से एक बनावट तक सभी वर्णों को प्रदान करता है और इसका उपयोग करता है कि पूर्ण डायनामिक पाठ रेंडरिंग को आगे नहीं मंदी के साथ अनुमति देने के लिए (एक बार प्रारंभिक पूरा हो जाने के बाद) ।

विभिन्न फॉन्ट एटलस जेनरेटरों की तुलना में मेरी पद्धति का मुख्य लाभ यह है कि आप हर फॉन्ट वेरिएशन और साइज के लिए बड़े बिटमैप्स को शिप करने के बजाय अपने प्रोजेक्ट के साथ छोटे फॉन्ट फाइल्स (.ttf .otf) को शिप कर सकते हैं। यह किसी भी रिज़ॉल्यूशन में केवल एक फॉन्ट फाइल का उपयोग करके उत्तम गुणवत्ता के फोंट उत्पन्न कर सकता है :)

ट्यूटोरियल पूरा कोड है कि किसी भी परियोजना में इस्तेमाल किया जा सकता है :)


मैं वर्तमान में इस समाधान को देख रहा हूं, और मुझे यकीन है कि मुझे समय में उत्तर मिल जाएगा, लेकिन क्या आपका कार्यान्वयन किसी भी रन टाइम आवंटन का उपयोग करता है?
निक हार्टुंग

@Nick - सभी आवंटन (बनावट, शीर्ष बफ़र्स, आदि) एक फ़ॉन्ट उदाहरण बनाते समय किए जाते हैं, फ़ॉन्ट आवृत्ति का उपयोग करते हुए तार को रेंडर करने के लिए आगे आवंटन की आवश्यकता नहीं होती है। तो आप रन समय में कोई और आवंटन के साथ "लोड समय" पर फ़ॉन्ट बना सकते हैं।
free3dom

वाह, महान काम! यह वास्तव में उन मामलों में विशेष रूप से सहायक है जहां आपका पाठ अक्सर बदलता है।
मदिर

यह सबसे अच्छा जवाब है, प्रदर्शन-वार, उन अनुप्रयोगों के लिए जिन्हें रनटाइम में अक्सर पाठ को बदलना पड़ता है। Android के लिए इसके अलावा और कुछ भी अच्छा नहीं देखा। यह OpenGL ES के लिए एक पोर्ट का उपयोग कर सकता है, हालांकि।
greeble31

1
यदि आप टेक्स्ट अलाइनमेंट, लाइन ब्रेक आदि से निपटना नहीं चाहते हैं - तो आप टेक्स्ट व्यू का उपयोग कर सकते हैं। एक TextView आसानी से एक कैनवास में प्रदान किया जा सकता है। प्रदर्शन वार दिए गए दृष्टिकोण से भारी नहीं होना चाहिए, आपको केवल उन सभी पाठों को प्रस्तुत करने के लिए एक TextView उदाहरण की आवश्यकता है। इस तरह से आपको सरल HTML फॉर्मेटिंग भी मुफ्त में मिलती है।
Gena Batsyan

8

इस लिंक के अनुसार:

http://code.neenbedankt.com/how-to-render-an-android-view-to-a-bitmap

आप किसी भी व्यू को बिटमैप पर रेंडर कर सकते हैं । यह शायद यह मान लेने के लायक है कि आप किसी दृश्य को लेआउट कर सकते हैं, जिसकी आपको आवश्यकता होती है (पाठ, चित्र आदि सहित) और फिर उसे एक बिटमैप पर प्रस्तुत करें।

आपके ऊपर JVitela के कोड का उपयोग करके आप उस Bitmap को OpenGL बनावट के रूप में उपयोग करने में सक्षम होना चाहिए।


हाँ, मैंने इसे एक गेम में मैपव्यू के साथ किया था और इसे एक शानदार बनावट के लिए बाध्य किया था ताकि मैप्स और ओपेंग्ल को मिलाएं। तो हाँ, सभी विचारों में onDraw (कैनवस c) है और आप किसी भी कैनवास को किसी भी बिटमैप में बाँध सकते हैं और बाँध सकते हैं।
HaMMeReD

7

CBFG और लोडिंग / रेंडरिंग कोड के एंड्रॉइड पोर्ट पर एक नज़र डालें। आपको अपनी परियोजना में कोड को छोड़ने और इसे सीधे उपयोग करने में सक्षम होना चाहिए।

CBFG - http://www.codehead.co.uk/cbfg

Android लोडर - http://www.codehead.co.uk/cbfg/TexFont.java


6

मैंने स्प्राइट टेक्स्ट उदाहरण को देखा और यह इस तरह के कार्य के लिए भयानक रूप से जटिल लग रहा है, मैंने एक बनावट को भी प्रतिपादन किया, लेकिन मैं उस प्रदर्शन हिट के बारे में चिंतित हूं जो कारण हो सकता है। मुझे इसके बजाय बस एक दृश्य के साथ जाना पड़ सकता है और उस पुल को पार करने का समय आने पर पोर्टिंग की चिंता करनी होगी :)



4

IMHO एक खेल में OpenGL ES का उपयोग करने के तीन कारण हैं:

  1. एक खुले मानक का उपयोग करके मोबाइल प्लेटफार्मों के बीच अंतर से बचें;
  2. रेंडर प्रक्रिया का अधिक नियंत्रण रखना;
  3. GPU समानांतर प्रसंस्करण से लाभ उठाने के लिए;

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

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

ड्रॉ समय में आलसी मेमोरी ट्रांसफर ऑपरेशंस से बचने के लिए कोड में जल्दी और टेक्सचर के लिए रिमोट बफर (वर्टेक्स बफर ऑब्जेक्ट्स - वीबीओ) आवंटित करना सबसे अच्छा तरीका है।

ध्यान रखें कि खेल खिलाड़ी पाठ को पढ़ना पसंद नहीं करते हैं, इसलिए आप एक लंबे गतिशील रूप से उत्पन्न पाठ नहीं लिखेंगे। लेबल के लिए, आप स्थिर पाठ का उपयोग कर सकते हैं, समय और स्कोर के लिए गतिशील पाठ छोड़ सकते हैं, और दोनों कुछ वर्णों के साथ संख्यात्मक हैं।

तो, मेरा समाधान सरल है:

  1. सामान्य लेबल और चेतावनी के लिए बनावट बनाएं;
  2. 0-9, ":", "+", और "-" संख्या के लिए बनावट बनाएं। प्रत्येक चरित्र के लिए एक बनावट;
  3. स्क्रीन में सभी पदों के लिए दूरस्थ VBOs उत्पन्न करें। मैं उस स्थिति में स्थिर या गतिशील पाठ प्रस्तुत कर सकता हूं, लेकिन वीबीओ स्थिर हैं;
  4. केवल एक बनावट VBO उत्पन्न करें, क्योंकि पाठ को हमेशा एक ही तरीके से प्रस्तुत किया जाता है;
  5. ड्रा समय में, मैं स्थिर पाठ को प्रस्तुत करता हूं;
  6. डायनेमिक टेक्स्ट के लिए, मैं VBO की स्थिति को देख सकता हूं, चरित्र बनावट प्राप्त कर सकता हूं और इसे आकर्षित कर सकता हूं, एक बार में एक चरित्र।

यदि आप दूरस्थ स्थैतिक बफ़र्स का उपयोग करते हैं, तो ड्रॉ ऑपरेशन तेज़ हैं।

मैं स्क्रीन पदों (स्क्रीन के विकर्ण प्रतिशत के आधार पर) और बनावट (स्थिर और वर्ण) के साथ एक XML फ़ाइल बनाता हूं, और फिर मैं प्रतिपादन से पहले इस XML को लोड करता हूं।

एक उच्च एफपीएस दर प्राप्त करने के लिए, आपको ड्रॉ समय पर वीबीओ उत्पन्न करने से बचना चाहिए।


"VOB" से, क्या आपका मतलब "VBO" (वर्टेक्स बफर ऑब्जेक्ट) है?
दान हुलमे

3

यदि आप GL का उपयोग करने पर जोर देते हैं, तो आप टेक्स्ट को टेक्स्ट पर रेंडर कर सकते हैं। यह मानते हुए कि अधिकांश HUD अपेक्षाकृत स्थिर है, आपको बनावट को अक्सर मेमोरी में लोड नहीं करना चाहिए।


3

पर एक नजर डालें CBFGऔर लदान / प्रतिपादन कोड का एंड्रॉयड बंदरगाह। आपको अपनी परियोजना में कोड को छोड़ने और इसे सीधे उपयोग करने में सक्षम होना चाहिए।

  1. CBFG

  2. Android लोडर

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


2

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

स्रोत फ़ोल्डर के नीचे देखें

ApiDemos/src/com/example/android/apis/graphics/spritetext

और आपको अपनी जरूरत की हर चीज मिल जाएगी।


1

के लिए स्थिर पाठ :

  • अपने पीसी पर उपयोग किए जाने वाले सभी शब्दों के साथ एक छवि बनाएं (उदाहरण के लिए जीआईएमपी के साथ)।
  • इसे एक बनावट के रूप में लोड करें और इसे एक विमान के लिए सामग्री के रूप में उपयोग करें।

के लिए लंबे समय तक पाठ कि जरूरतों को एक समय में एक बार अपडेट करना:

  • एक बिटमैप कैनवास (JVitela के समाधान) पर Android आकर्षित करें।
  • इसे एक विमान के लिए सामग्री के रूप में लोड करें।
  • प्रत्येक शब्द के लिए अलग-अलग बनावट के निर्देशांक का उपयोग करें।

के लिए एक नंबर (00.0 प्रारूपित):

  • सभी नंबरों और एक डॉट के साथ एक छवि बनाएं।
  • इसे एक विमान के लिए सामग्री के रूप में लोड करें।
  • नीचे shader का उपयोग करें।
  • अपने onDraw इवेंट में केवल shader को भेजे गए वैल्यू वेरिएबल को अपडेट करें।

    precision highp float;
    precision highp sampler2D;
    
    uniform float uTime;
    uniform float uValue;
    uniform vec3 iResolution;
    
    varying vec4 v_Color;
    varying vec2 vTextureCoord;
    uniform sampler2D s_texture;
    
    void main() {
    
    vec4 fragColor = vec4(1.0, 0.5, 0.2, 0.5);
    vec2 uv = vTextureCoord;
    
    float devisor = 10.75;
    float digit;
    float i;
    float uCol;
    float uRow;
    
    if (uv.y < 0.45) {
        if (uv.x > 0.75) {
            digit = floor(uValue*10.0);
            digit = digit - floor(digit/10.0)*10.0;
            i = 48.0 - 32.0 + digit;
            uRow = floor(i / 10.0);
            uCol = i - 10.0 * uRow;
            fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-1.5) / devisor, uRow / devisor) );
        } else if (uv.x > 0.5) {
            uCol = 4.0;
            uRow = 1.0;
            fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-1.0) / devisor, uRow / devisor) );
        } else if (uv.x > 0.25) {
            digit = floor(uValue);
            digit = digit - floor(digit/10.0)*10.0;
            i = 48.0 - 32.0 + digit;
            uRow = floor(i / 10.0);
            uCol = i - 10.0 * uRow;
            fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-0.5) / devisor, uRow / devisor) );
        } else if (uValue >= 10.0) {
            digit = floor(uValue/10.0);
            digit = digit - floor(digit/10.0)*10.0;
            i = 48.0 - 32.0 + digit;
            uRow = floor(i / 10.0);
            uCol = i - 10.0 * uRow;
            fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-0.0) / devisor, uRow / devisor) );
        } else {
            fragColor = vec4(0.0, 0.0, 0.0, 0.0);
        }
    } else {
        fragColor = vec4(0.0, 0.0, 0.0, 0.0);
    }
    gl_FragColor = fragColor;
    
    }

ऊपर कोड एक बनावट एटलस के लिए काम करता है जहां संख्याएं फ़ॉन्ट एटलस (बनावट) की दूसरी पंक्ति के 7 वें कॉलम पर 0 से शुरू होती हैं।

प्रदर्शन के लिए https://www.shadertoy.com/view/Xl23Dw देखें (हालांकि गलत बनावट के साथ)


0

OpenGL ES 2.0 / 3.0 में आप OGL व्यू और एंड्रॉइड के UI-एलिमेंट्स को भी मिला सकते हैं:

public class GameActivity extends AppCompatActivity {
    private SurfaceView surfaceView;
    @Override
    protected void onCreate(Bundle state) { 
        setContentView(R.layout.activity_gl);
        surfaceView = findViewById(R.id.oglView);
        surfaceView.init(this.getApplicationContext());
        ...
    } 
}

public class SurfaceView extends GLSurfaceView {
    private SceneRenderer renderer;
    public SurfaceView(Context context) {
        super(context);
    }

    public SurfaceView(Context context, AttributeSet attributes) {
        super(context, attributes);
    }

    public void init(Context context) {
        renderer = new SceneRenderer(context);
        setRenderer(renderer);
        ...
    }
}

लेआउट activity_gl.xml बनाएं:

<?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        tools:context=".activities.GameActivity">
    <com.app.SurfaceView
        android:id="@+id/oglView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    <TextView ... />
    <TextView ... />
    <TextView ... />
</androidx.constraintlayout.widget.ConstraintLayout>

रेंडर थ्रेड से तत्वों को अपडेट करने के लिए, हैंडलर / लूपर का उपयोग कर सकते हैं।

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