2017-12-29 93 views
8

मैं एक कपड़ा सिमुलेशन के लिए जीपीयू के साथ कुछ काम करने की कोशिश कर रहा हूं और मुझे विभिन्न हार्डवेयर के साथ कुछ समस्याएं आ रही हैं। मैं ढांचे के रूप में तीनjs का उपयोग कर रहा हूं, लेकिन मेरा मानना ​​है कि मेरे पास होने वाली समस्या के लिए प्रासंगिक नहीं है।जीएलएसएल मैट्रिक्स/उलटा गुणा सटीक

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

सही: img

गलत: img

कुछ डिबगिंग मेरे पास करने के बाद इसे दो समस्याओं तक सीमित कर दिया। उनमें से दोनों दशमलव परिशुद्धता से संबंधित हैं। मैट्रिक्स गुणा और उलटा उपयोग करते समय बाधाओं (और बाधाओं के दौरान परिशुद्धता की समस्या) और परिशुद्धता खोने के कारण शिखरों का ढहना।

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

जबकि परिवर्तन और उलटा अक्षम है तो यह सामान्य दिखता है।

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

' vec2 cellSize = 1.0/res;', 
    ' vec4 pos = texture2D(vertexPositions, vuv.xy);', 


    ' vec2 newUV;', 
    ' if(type == 0.0){', 
     ' float px = floor(vuv.x * res.x);', 
     ' float spacingx = px- (2.0 * floor(px/2.0));', 
     ' float py = floor(vuv.y * res.y);', 
     ' float spacingy = py- (2.0 * floor(py/2.0));', 
     ' float total = spacingx + spacingy;', 
     ' total = total- (2.0 * floor(total/2.0));', 

     ' if(total == 0.0){', 
     '  newUV = vuv + (direction * cellSize);', 
     ' }', 
     ' else{', 
     '  newUV = vuv - (direction * cellSize);', 
     ' }', 
    ' }', 
    ' if(type == 1.0){', 
     ' float px = floor(vuv.x * res.x);', 
     ' float spacingx = px- (2.0 * floor(px/2.0));', 

     ' float total = spacingx;', 


     ' if(total == 0.0){', 
     '  newUV = vuv + (direction * cellSize);', 
     ' }', 
     ' else{', 
     '  newUV = vuv - (direction * cellSize);', 
     ' }', 
    ' }', 






    ' vec4 totalDisplacement = vec4(0.0);', 

    '   if(newUV.x > 0.0 && newUV.x < 1.0 && newUV.y > 0.0 && newUV.y < 1.0){ ', 
    '    vec4 posOld = texture2D(vertexPositionsStart, vuv);' , 
    '    vec4 posOld2 = texture2D(vertexPositionsStart, newUV);' , 

    '    float targetDistance = length(posOld - posOld2);', 
    '    vec4 newPos = texture2D(vertexPositions, newUV);', 
    '    float dx = pos.x - newPos.x;', 
    '    float dy = pos.y - newPos.y;', 
    '    float dz = pos.z - newPos.z;', 
    '    float distance = sqrt(dx * dx + dy * dy + dz * dz);', 
    '    float difference = targetDistance- distance;', 
    '    float percent = difference/distance/2.0;', 
    '    float offsetX = dx * percent * rigid;', 
    '    float offsetY = dy * percent * rigid;', 
    '    float offsetZ = dz * percent * rigid;', 
    '    totalDisplacement.x += offsetX;', 
    '    totalDisplacement.y += offsetY;', 
    '    totalDisplacement.z += offsetZ;', 
    '   }', 
    '  }', 
    ' }', 

    ' pos += totalDisplacement;', 
    ' if( vuv.x > 1.0 - cellSize.x && topConstrain == 1){', 
    '  pos =transformation * texture2D(vertexPositionsStart, vuv.xy);', 
    ' }', 

    ' if( vuv.x < cellSize.x && bottomConstrain == 1){', 
    '  pos =transformation * texture2D(vertexPositionsStart, vuv.xy);', 
    ' }', 

    ' if( vuv.y < cellSize.y && leftConstrain == 1){', 
    '  pos =transformation * texture2D(vertexPositionsStart, vuv.xy);', 
    ' }', 


    ' if( vuv.y > 1.0 - cellSize.y && rightConstrain == 1){', 
    '  pos =transformation * texture2D(vertexPositionsStart, vuv.xy);', 
    ' }', 




    ' gl_FragColor = vec4(pos.xyz , 1.0);', 
+1

जीएलएस के लिए सटीक आवश्यकताओं डेस्कटॉप जीएल (विशेष रूप से जब आप GLES2 के साथ काम करते हैं) के मुकाबले बहुत कम हैं। यह आपकी मदद नहीं करता है अगर आप पूर्ण fp32 बनावट का उपयोग करते हैं जब आपके शेडर एएलयू अभी भी बहुत कम परिशुद्धता का उपयोग करते हैं। – derhass

+0

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

+1

** सापेक्ष समन्वय प्रणाली ** का उपयोग करने का प्रयास करें, इसलिए परिवर्तित किए गए कशेरुक आपके [matrices origins] से बहुत दूर नहीं हैं (https://stackoverflow.com/questions/28075743/how-do- i-रचना-ए-रोटेशन-मैट्रिक्स-साथ-मानव पठनीय-कोण-से-खरोंच/28084380 एस = 1 |? 64.0697 # 28084380)।गणना के बाद मूल समन्वय प्रणाली में वापस अनुवाद करें। इस तरह आप matrices के साथ उच्च आवर्धन वैक्टर गुणा का उपयोग करने से बचेंगे जो सटीकता की समस्या पैदा करता है। अधिक जानकारी के लिए देखें [रे और एलिप्सिड चौराहे सटीकता सुधार] (https://stackoverflow.com/q/25470493/2521214) – Spektre

उत्तर

1

सुनिश्चित करने के लिए कि आपके शेडर चल बिन्दु गणना के लिए उच्च परिशुद्धता चर बनाता है, निम्नलिखित अपने शिखर शेडर की शुरुआत करने के लिए जोड़ा जाना चाहिए::

शेडर के लिए कोड की तरह लग रहा है निम्नलिखित

precision highp float; 
precision highp int; 

और टुकड़ा शेडर में, चल बिन्दु चर घोषणाओं इस प्रकार घोषित किया जाना चाहिए:

precision highp float; 

फ़्लोटिंग पॉइंट त्रुटियों को बढ़ाया जाता है यदि आप अपनी गणना में मानों का उपयोग करते हैं जो फ़्लोट के रूप में संग्रहीत पिछली गणनाओं का परिणाम हैं। अन्यथा मध्यवर्ती मूल्य के रूप में जाना जाता है।

इन त्रुटियों को कम करने के लिए, आपको शेडर में किए गए मध्यवर्ती गणनाओं की संख्या सीमित करनी चाहिए।उदाहरण के लिए, आप पूरी तरह से newUV के लिए गणना का विस्तार कर सकते हैं:

newUV = vuv + (direction * (1.0/res)); 

तुम भी पूरी तरह से तो जैसे totalDisplacement के लिए गणना, कदम से कदम, पहला विकल्प offsetX का विस्तार कर सकते हैं:

totalDisplacement.x += (dx * percent * rigid) 

अब प्रत्येक चर स्थानापन्न dx, और percent ऊपर में:

totalDisplacement.x += ((pos.x - newPos.x) * (difference/distance/2.0) * rigid) 

Y इस बिंदु पर

totalDisplacement.x += ((pos.x - newPos.x) * ((targetDistance- distance)/(distance * 2.0)) * rigid); 

आप को सरल बनाने और (distance द्वारा प्रभाग) कुछ चर को रद्द करने के कुछ बीजगणित कर सकते हैं: कहां अब तो जैसे difference में, देख सकते हैं कि समीकरण भी आगे विस्तार किया जा सकता स्थानापन्न। अन्य निर्देशांक के लिए

totalDisplacement.x += ((pos.x - newPos.x) * ((length(posOld - posOld2)/(distance * 2.0) - 0.5) * rigid); 

और क्रमश:

totalDisplacement.x += ((pos.x - newPos.x) * ((targetDistance/(distance * 2.0) - 0.5) * rigid); 

अंत में हम सूत्र targetDistance के लिए बहुत तरह स्थानापन्न कर सकते हैं:

totalDisplacement.y += ((pos.y - newPos.y) * ((length(posOld - posOld2)/(distance * 2.0) - 0.5) * rigid); 
totalDisplacement.z += ((pos.z - newPos.z) * ((length(posOld - posOld2)/(distance * 2.0) - 0.5) * rigid); 
उपरोक्त समीकरण को सरल बनाकर अब हम निम्नलिखित मिल

और स्पष्ट रूप से आप posOld, posOld2 और newPos के मान में प्रतिस्थापित करके जा सकते हैं।

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

आप उत्सुक हैं, तो आप भी एक दिया शेडर संकलक के लिए परिशुद्धता के स्तर glGetShaderPrecisionFormat फोन करके निरीक्षण कर सकते हैं:

int range[2], precision; 
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, &precision); 

आप अपने आवेदन की desktop और mobile संस्करण के लिए इसी का परिणाम का निरीक्षण किया, तो आप दो संस्करणों के लिए परिशुद्धता में अंतर की तुलना करने में सक्षम होंगे।