<!-- p5.js WebGL मोड सोर्स कोड पर काम कैसे शुरू करें। -->

# वेबजीएल योगदान गाइड

नमस्ते, यदि आप इस पृष्ठ को पढ़ रहे हैं, तो आप शायद वेबजीएल मोड पर काम करने में मदद करने के इच्छुक हैं। आपकी मदद के लिए धन्यवाद, हम आपकी सहायता के लिए आभारी हैं! इस पृष्ठ का उद्देश्य वेबजीएल योगदानों को संरचित करने का तरीका समझाना और परिवर्तन करते समय कुछ सुझाव प्रदान करना है।

## संसाधन

- हमारे [p5.js वेबजीएल मोड की संरचना अवलोकन](https://github.com/processing/p5.js/blob/main/contributor_docs/webgl_mode_architecture.md) पढ़ें ताकि समझा जा सके कि 2डी मोड से वेबजीएल मोड कैसे भिन्न है। इससे शेडर, स्ट्रोक और अन्य के लिए कुछ कार्यान्वयन विशेषताओं को समझने में मदद मिलेगी।
- हमारे [योगदानकर्ता दिशानिर्देश](https://p5js.org/contributor-docs/#/./contributor_guidelines) पढ़ें जिससे यह पता चलेगा कि समस्या को कैसे बनाया जाए, कोडबेस को कैसे सेट किया जाए और परिवर्तनों को कैसे परीक्षित किया जाए।
- यह जानना भी उपयोगी हो सकता है कि ब्राउज़र के वेबजीएल एपीआई के बारे में थोड़ा जानना, जिस पर p5.js का वेबजीएल मोड बनाया गया है:
    - [वेबजीएल मूलभूत बातें](https://webglfundamentals.org/) कई कोर रेंडरिंग अवधारणाओं पर जाती है
    - [शेडर की किताब](https://thebookofshaders.com/) वेबजीएल शेडर में उपयोग की जाने वाली कई तकनीकों को समझाती है

## योजना बनाना

हम खुली समस्यों को [एक गिटहब प्रोजेक्ट में](https://github.com/orgs/processing/projects/5) व्यवस्थित करते हैं, जहां हम उन्हें कुछ प्रकारों में विभाजित करते हैं:

- **प्रणाली-स्तरीय परिवर्तन** लंबी अवधि के लक्ष्य हैं जिनके कोड में व्यापक निहितार्थ हैं। इन्हें कार्यान्वयन में कूटनीति और योजनाबद्धता की सबसे अधिक चर्चा और योजना की आवश्यकता होती है।।
- **कोई समाधान नहीं वाले बग** ऐसे बग रिपोर्ट हैं जिनमें कारण को संकीर्ण करने के लिए डीबगिंग की आवश्यकता होती है। ये अभी तक ठीक करने के लिए तैयार नहीं हैं: एकबार कारण मिल जाता है, तो हम इसे कैसे ठीक करना है, इस पर चर्चा कर सकते हैं।
- **समाधान वाले बग लेकिन कोई पीआर नहीं वाले बग** वे हैं जहां हमने इसे कैसे ठीक करना है तय कर लिया है और किसी को भी कोड लिखने के लिए स्वतंत्र हैं।
- **छोटे विस्तार** वे समस्या हैं जिनमें नई सुविधाएं हैं जिनके लिए वर्तमान संरचना के भीतर एक स्पष्ट स्थान है और इसे फिट करने की तरीके पर चर्चा करने की आवश्यकता नहीं है। एक बार यह तय हो जाता है कि इन्हें करना लायक है, तो आप कोड लिखने के लिए स्वतंत्र हैं।
- **2डी सुविधाएं** वे हैं जो पहले से ही p5.js में मौजूद हैं लेकिन वेबजीएल मोड में नहीं। इस सुविधा को लागू करने के बाद, उम्मीद है कि इसका व्यवहार 2डी मोड से मेल खाएगा। हमें शायद इसके सर्वोत्तम कार्यान्वयन पर चर्चा करनी पड़ सकती है, लेकिन इनके लिए उपयोगकर्ता आवश्यकताएं स्पष्ट हैं।
- **सभी संदर्भों में काम नहीं करने वाली सुविधाएं** वे हैं जो वेबजीएल मोड में मौजूद हैं लेकिन वेबजीएल मोड का उपयोग करने के सभी तरीकों में काम नहीं करती हैं। उदाहरण के लिए, कुछ p5.js विधियां 2डी निर्देशांकों और 3डी निर्देशांकों दोनों के साथ काम करती हैं, लेकिन अन्य 3डी निर्देशांकों का उपयोग करने पर टूट जाती हैं। आमतौर पर इन पर काम शुरू करने के लिए स्वतंत्र हैं।
- **विशेषता अनुरोध** सभी अन्य कोड परिवर्तन अनुरोध हैं। इन पर यह सुनिश्चित करने के लिए थोड़ी चर्चा करने की आवश्यकता होती है कि वे वेबजीएल मोड की रोडमैप में फिट बैठते हैं या नहीं।  
- **दस्तावेजीकरण समस्या** वे हैं जिनके लिए कोड परिवर्तन की आवश्यकता नहीं होती है, बल्कि इसके बजाय p5.js के व्यवहार की बेहतर दस्तावेजीकरण की आवश्यकता होती है।

## कोड कहाँ रखना है

यहां वेबजीएल से संबंधित सभी चीजें src/webgl सबडायरेक्टरी में हैं। इस डायरेक्टरी के भीतर, शीर्ष-स्तरीय p5.js फ़ंक्शन विषय क्षेत्र के आधार पर फाइलों में विभाजित हैं: प्रकाश सेट करने के आदेश lighting.js में जाते हैं; सामग्रियां सेट करने के आदेश materials.js में जाते हैं।

जब उपयोगकर्ता-अभिमुख वर्गों को लागू किया जाता है, तो हम आमतौर पर एक फ़ाइल प्रति वर्ग रखने की कोशिश करते हैं। इन फ़ाइलों में कभी-कभी कुछ अन्य आंतरिक उपयोगिता वर्ग हो सकते हैं। उदाहरण के लिए, `p5.Framebuffer.js` में `p5.Framebuffer` वर्ग शामिल है, और इसमें अन्य मुख्य वर्गों की कुछ फ्रेमबफर-विशिष्ट उपवर्ग भी शामिल हैं। अन्य फ्रेमबफर-विशिष्ट उपवर्ग भी इस फ़ाइल में जा सकते हैं।

`p5.RendererGL` एक बड़ा वर्ग है जो बहुत सारे व्यवहार को संभालता है। इस कारण से, एक बड़ी वर्ग फ़ाइल होने के बजाय, इसकी कार्यक्षमता कई फ़ाइलों में विभाजित है, जो इस बात पर निर्भर करती है कि यह किस विषय क्षेत्र से संबंधित है। यहां एक विवरण है कि हम `p5.RendererGL` को किन फाइलों में विभाजित करते हैं, और प्रत्येक में क्या डालना है:

#### `p5.RendererGL.js`

आरंभीकरण और मूल कार्यक्षमता।

#### `p5.RendererGL.Immediate.js`

**तत्काल मोड** आरेखण से संबंधित कार्यक्षमता (आकृतियां जो संग्रहीत और पुन: उपयोग नहीं की जाएंगी, जैसे `beginShape()` और `endShape()`)

#### `p5.RendererGL.Retained.js`

**रिटेन्ड मोड** आरेखण से संबंधित कार्यक्षमता (आकृतियां जो पुन: उपयोग के लिए संग्रहीत की गई हैं, जैसे `sphere()`)

#### `material.js`

मिश्रण मोड का प्रबंधन

#### `3d_primitives.js`

उपयोगकर्ता-अभिमुख फ़ंक्शन जो आकृतियां आरेखित करते हैं, जैसे `triangle()`। ये आकृतियों की ज्यामिति परिभाषित करते हैं। उन आकृतियों का रेंडरिंग फिर `p5.RendererGL.Retained.js` या `p5.RendererGL.Immediate.js` में होता है, ज्यामिति इनपुट को एक सामान्य आकृति के रूप में मानते हुए।

#### `Text.js`

लेखन रेंडरिंग के लिए कार्यक्षमता और उपयोगिता वर्ग।

## वेबजीएल परिवर्तनों का परीक्षण करना

### सुसंगतता का परीक्षण

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

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

```js
test('coplanar strokes match 2D', function() {
  const getColors = function(mode) {
    myp5.createCanvas(20, 20, mode);
    myp5.pixelDensity(1);
    myp5.background(255);
    myp5.strokeCap(myp5.SQUARE);
    myp5.strokeJoin(myp5.MITER);
    if (mode === myp5.WEBGL) {
      myp5.translate(-myp5.width/2, -myp5.height/2);
    }
    myp5.stroke('black');
    myp5.strokeWeight(4);
    myp5.fill('red');
    myp5.rect(10, 10, 15, 15);
    myp5.fill('blue');
    myp5.rect(0, 0, 15, 15);
    myp5.loadPixels();
    return [...myp5.pixels];
  };
  assert.deepEqual(getColors(myp5.P2D), getColors(myp5.WEBGL));
});
```

यह हमेशा काम नहीं करता क्योंकि आप 2डी मोड में एंटीएलियासिंग को बंद नहीं कर सकते, और वेबजीएल मोड में एंटीएलियासिंग अक्सर थोड़ा अलग होगा। हालांकि, ये x और y अक्षों में सीधी रेखाओं के लिए काम कर सकता है!

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

```js
test('color interpolation', function() {
  const renderer = myp5.createCanvas(256, 256, myp5.WEBGL);
  // upper color: (200, 0, 0, 255);
  // lower color: (0, 0, 200, 255);
  // expected center color: (100, 0, 100, 255);
  myp5.beginShape();
  myp5.fill(200, 0, 0);
  myp5.vertex(-128, -128);
  myp5.fill(200, 0, 0);
  myp5.vertex(128, -128);
  myp5.fill(0, 0, 200);
  myp5.vertex(128, 128);
  myp5.fill(0, 0, 200);
  myp5.vertex(-128, 128);
  myp5.endShape(myp5.CLOSE);
  assert.equal(renderer._useVertexColor, true);
  assert.deepEqual(myp5.get(128, 128), [100, 0, 100, 255]);
});
```

### परफॉर्मेंस परीक्षण

जबकि यह p5.js का # 1 समस्या नहीं है, हम सुनिश्चित करने की कोशिश करते हैं कि परिवर्तन परफॉर्मेंस पर बहुत अधिक प्रभाव नहीं डालते हैं। आमतौर पर, यह दो परीक्षण स्केच बनाकर किया जाता है: एक आपके बदलाव के साथ और एक बिना बदलाव के। फिर हम दोनों के फ्रेम रेट की तुलना करते हैं।

परफॉर्मेंस को मापने के बारे में कुछ सलाह:

- अपने स्केच के शीर्ष पर `p5.disableFriendlyErrors = true` के साथ अनुकूल त्रुटियों को अक्षम करें (या बस `p5.min.js` का परीक्षण करें, जिसमें अनुकूल त्रुटि प्रणाली शामिल नहीं है)
- स्थिर स्टेट फ्रेम दर का स्पष्ट अनुभव प्राप्त करने के लिए औसत फ्रेम दर प्रदर्शित करें:

```js
let frameRateP;
let avgFrameRates = [];
let frameRateSum = 0;
const numSamples = 30;
function setup() {
  // ...
  frameRateP = createP();
  frameRateP.position(0, 0);
}
function draw() {
  // ...
  const rate = frameRate() / numSamples;
  avgFrameRates.push(rate);
  frameRateSum += rate;
  if (avgFrameRates.length > numSamples) {
    frameRateSum -= avgFrameRates.shift();
  }
 
  frameRateP.html(round(frameRateSum) + ' avg fps');
}
```

हम निम्नलिखित मामलों का परीक्षण करने की कोशिश करते हैं क्योंकि वे रेंडरिंग पाइपलाइन के विभिन्न हिस्सों पर दबाव डालते हैं:

- कुछ बहुत ही जटिल आकृतियां (उदाहरण के लिए, एक बड़ा 3डी मॉडल या एक लंबी वक्र रेखा)
- कई सरल आकृतियां (उदाहरण के लिए, एक फॉर लूप में कई बार `line()` फ़ंक्शन का उपयोग)
