द्वीप मानचित्र मुखौटा बनाने के लिए एक सरल विधि


21


मैं सी # के साथ एक द्वीप के नक्शे के लिए एक मुखौटा बनाने के लिए एक अच्छा और आसान तरीका खोज रहा हूं।


मूल रूप से मैं एक यादृच्छिक ऊंचाई के साथ उपयोग कर रहा हूँ जो कि पेरेलिन के शोर से उत्पन्न होती है, जहाँ इलाके पानी से नहीं घिरे होते हैं।

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

अगला कदम एक मुखौटा उत्पन्न करना होगा, यह सुनिश्चित करने के लिए कि कोनों और सीमाएं सिर्फ पानी हैं।

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

तब मैं सिर्फ एक द्वीप पाने के लिए पर्किन शोर छवि से मुखौटा घटा सकता हूं।

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

और इसके विपरीत के साथ खेल रहा है ..

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

और ढाल वक्र, मैं एक द्वीप ऊंचाई प्राप्त कर सकता हूं जैसे मैं चाहता हूं।

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

(ये सिर्फ उदाहरण हैं)

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

मेरा सवाल यह है कि मैं दूसरी छवि में एक अच्छा दिखने वाला मुखौटा कैसे बना सकता हूं?


अद्यतन करें

मैंने इस तकनीक को पाया है, यह मेरे लिए एक अच्छा शुरुआती बिंदु प्रतीत होता है, लेकिन मुझे यकीन नहीं है कि वांछित आउटपुट प्राप्त करने के लिए मैं इसे कैसे लागू कर सकता हूं। http://mrl.nyu.edu/~perlin/experiments/puff/


अद्यतन २

यह मेरा अंतिम समाधान है।

मैंने makeMask()अपने सामान्यीकरण लूप के अंदर फ़ंक्शन को इस तरह लागू किया है :

        //normalisation
        for( int i = 0; i < width; i++ ) {
            for( int j = 0; j < height; j++ ) {
                perlinNoise[ i ][ j ] /= totalAmplitude;
                perlinNoise[ i ][ j ] = makeMask( width, height, i, j, perlinNoise[ i ][ j ] );
            }
        }

और यह अंतिम कार्य है:

    public static float makeMask( int width, int height, int posX, int posY, float oldValue ) {
        int minVal = ( ( ( height + width ) / 2 ) / 100 * 2 );
        int maxVal = ( ( ( height + width ) / 2 ) / 100 * 10 );
        if( getDistanceToEdge( posX, posY, width, height ) <= minVal ) {
            return 0;
        } else if( getDistanceToEdge( posX, posY, width, height ) >= maxVal ) {
            return oldValue;
        } else {
            float factor = getFactor( getDistanceToEdge( posX, posY, width, height ), minVal, maxVal );
            return oldValue * factor;
        }
    }

    private static float getFactor( int val, int min, int max ) {
        int full = max - min;
        int part = val - min;
        float factor = (float)part / (float)full;
        return factor;
    }

    public static int getDistanceToEdge( int x, int y, int width, int height ) {
        int[] distances = new int[]{ y, x, ( width - x ), ( height - y ) };
        int min = distances[ 0 ];
        foreach( var val in distances ) {
            if( val < min ) {
                min = val;
            }
        }
        return min;
    }

यह इमेज # 3 में आउटपुट देगा।

कोड में थोड़े बदलाव के साथ, आप छवि # 2 -> में मूल रूप से वांछित आउटपुट प्राप्त कर सकते हैं

    public static float makeMask( int width, int height, int posX, int posY, float oldValue ) {
        int minVal = ( ( ( height + width ) / 2 ) / 100 * 2 );
        int maxVal = ( ( ( height + width ) / 2 ) / 100 * 20 );
        if( getDistanceToEdge( posX, posY, width, height ) <= minVal ) {
            return 0;
        } else if( getDistanceToEdge( posX, posY, width, height ) >= maxVal ) {
            return 1;
        } else {
            float factor = getFactor( getDistanceToEdge( posX, posY, width, height ), minVal, maxVal );
            return ( oldValue + oldValue ) * factor;
        }
    }

किसी भी मौका आप youur पूर्ण स्रोत से लिंक कर सकते हैं?
उदासीन

जवाबों:


12

केंद्र के प्रति उच्च मूल्यों के लिए पूर्वाग्रह के साथ नियमित शोर उत्पन्न करें। यदि आप अपने उदाहरण में वर्ग-ईश द्वीप आकार चाहते हैं, तो मैं आपके कारक के रूप में निकटतम किनारे की दूरी का उपयोग करूंगा।

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

उस कारक के साथ, आप मास्क शोर उत्पन्न करते समय कुछ का उपयोग कर सकते हैं:

maxDVal = (minIslandSolid - maxIslandSolid)

getMaskValueAt(x, y)
    d = distanceToNearestEdge(x,y)
    if(d < maxIslandSolid)
        return isSolid(NonSolidValue) //always non-solid for outside edges
    else if(d < minIslandSolid)
        //noisy edges
        return isSolid((1 - (d/maxDVal)) * noiseAt(x,y))
    else
        return isSolid(SolidValue) //always return solid for center of island

जहाँ distanceToNearestEdgeउस स्थिति से नक्शे के निकटतम किनारे की दूरी वापस आती है। और isSolidतय करता है कि 0 और 1 के बीच का कोई मूल्य ठोस है (जो भी आपका कट ऑफ है)। यह एक बहुत ही सरल कार्य है, यह इस तरह दिख सकता है:

isSolid (फ्लोट वैल्यू) रिटर्न वैल्यू <solidCutOffValue

जहां solidCutOffValueआप ठोस या नहीं के बीच तय करने के लिए उपयोग कर रहे हैं जो कुछ भी मूल्य है। यह .5विभाजन के लिए भी हो सकता है , या .75अधिक ठोस के लिए या .25कम ठोस के लिए।

अंत में, यह थोड़ा सा (1 - (d/maxDVal)) * noiseAt(x,y)। सबसे पहले, हमें इसके साथ 0 और 1 के बीच एक कारक मिलता है:

(1 - (d/maxDVal))

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

जहां 0बाहरी किनारे 1पर है और अंदर के किनारे पर है। इसका मतलब है कि हमारा शोर अंदर से ठोस और बाहर से गैर-ठोस होने की अधिक संभावना है। यह वह कारक है जिसे हम उस शोर पर लागू करते हैं जो हम प्राप्त करते हैं noiseAt(x,y)

यहां मूल्यों का क्या है, इसका अधिक दृश्य प्रतिनिधित्व है, क्योंकि नाम वास्तविक मूल्यों के लिए भ्रामक हो सकते हैं:

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


उस त्वरित उत्तर के लिए thx, मैं इस तकनीक को लागू करने की कोशिश करूंगा। इस के साथ वांछित उत्पादन प्राप्त करने की उम्मीद है।
ऐस

यह संभावना है कि शोर किनारों को प्राप्त करने के लिए कुछ ट्विकिंग लेंगे जिस तरह से आप उन्हें चाहते हैं। लेकिन यह आपके लिए एक ठोस आधार होना चाहिए। सौभाग्य!
MichaelHouse

अब तक मुझे काम करने के लिए आधार कार्यान्वयन मिल गया, क्या आप मुझे IsSolid फ़ंक्शन का उदाहरण दे सकते हैं? मुझे नहीं पता कि मैं कैसे 0 और 1 के बीच का मान प्राप्त कर सकता हूं जो किनारे से न्यूनतम और अधिकतम दूरी के आधार पर हो सकता है। मेरे कोड के लिए मेरा अपडेट अब तक देखें।
ऐस

मेरे पास वहां कुछ मिश्रित तर्क थे। मैंने इसे और अधिक समझ बनाने के लिए तय किया है। और का एक उदाहरण प्रदान कीisSolid
MichaelHouse

0 और 1 के बीच का मान प्राप्त करने के लिए, आपको केवल यह पता लगाना है कि अधिकतम मूल्य क्या हो सकता है और उसके द्वारा अपने वर्तमान मूल्य को विभाजित कर सकते हैं। फिर मैंने उसे एक से घटा दिया, क्योंकि मैं चाहता था कि शून्य बाहरी छोर पर हो और 1 अंदर के किनारे पर हो।
MichaelHouse

14

यदि आप इसके लिए कुछ कम्प्यूटेशनल पावर को छोड़ना चाहते हैं, तो आप इस तकनीक का उपयोग इस ब्लॉग के लेखक के लिए कर सकते हैं । ( NB: यदि आप सीधे उसके कोड की प्रतिलिपि बनाना चाहते हैं, तो यह ActionScript में है)। मूल रूप से, वह अर्ध-यादृच्छिक अंक उत्पन्न करता है (अर्थात अपेक्षाकृत समान दिखता है) और फिर वोरोनोई पॉलीगॉन बनाने के लिए इनका उपयोग करता है ।

वोरोनोई पॉलीगॉन

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

बहुभुज मानचित्र

इससे आप किनारों पर शोर लागू कर सकते हैं, जिसके परिणामस्वरूप यह जैसा दिखता है (रंग दूसरे से हैं, असंबंधित चरण):

शोर किनारों के साथ बहुभुज मानचित्र

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


आपके उत्तर के लिए thx, लेकिन यह वेब पर खोज करने से मुझे मिला पहला (केवल एक बहुत ही) समाधान है। यह समाधान दुश्मन को बहुत अच्छा लगता है, लेकिन मैं "सरल" तरीके से कोशिश करना चाहूंगा।
ऐस

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

खुशी किसी से जुड़ी हुई है - वह पेज हमेशा मेरी सूची में है "वास्तव में शानदार पोस्ट के बारे में कि किसी ने कुछ कैसे लागू किया।"
टिम होल्ट

+1। यह बहुत अच्छा है। इसके लिए धन्यवाद, यह निश्चित रूप से मेरे लिए उपयोगी होगा!
आंद्रे

1

एक बहुत ही सरल विधि है चौड़ाई / 2 और ऊंचाई / 2 पर केंद्र के साथ उलटा रेडियल या गोलाकार ढाल बनाना। मास्किंग के लिए आप शोर को ग्रेडिएंट को गुणा करने के बजाय घटाना चाहते हैं । यह आपको इस तरह की कमियों के साथ अधिक यथार्थवादी दिखने वाले किनारे प्रदान करता है कि द्वीप आवश्यक रूप से जुड़े नहीं हैं।

आप यहां ग्रेडिएंट के साथ शोर को घटाने और गुणा करने के बीच अंतर देख सकते हैं: http://www.vfxpedia.com/index.php?title=Tips_and_Techniques/Natural_Phenomena/Smoke

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

    public static float[] CreateInverseRadialGradient(int size, float heightScale = 1)
    {
        float radius = size / 2;

        float[] heightMap = new float[size * size];

        for (int iy = 0; iy < size; iy++)
        {
            int stride = iy * size;
            for (int ix = 0; ix < size; ix++)
            {
                float centerToX = ix - radius;
                float centerToY = iy - radius;

                float distanceToCenter = (float)Math.Sqrt(centerToX * centerToX + centerToY * centerToY);
                heightMap[iy * size + ix] = distanceToCenter / radius * heightScale;
            }
        }

        return heightMap;
    }

अपनी ऊँचाई को अपनी ऊंचाई के नक्शे में ढालने के लिए अपने ढाल को भूलना न भूलें और आपको अभी भी किसी तरह अपनी पानी की रेखा में कारक बनाना होगा।

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


उत्तर के लिए thx। मुझे यकीन नहीं है कि अगर मैं आपको सही समझ रहा हूं, लेकिन क्या आपने देखा कि नकाब मूल ऊंचाई डेटा को बिल्कुल प्रभावित नहीं करता है, यह सिर्फ नकारात्मक में प्रभावित होता है, इसलिए यह केवल उन पिक्स को परिभाषित करता है जो प्रदर्शित होते हैं (% में) या नहीं । लेकिन मैं भी यह सरल ग्रेडिएंट के साथ करने की कोशिश की है, और मैं परिणाम से खुश नहीं था।
ऐस

1

मैं दूसरा ओलिपेकका सुझाव देता हूं: आप जो करना चाहते हैं, वह आपके ऊंचाई से एक उपयुक्त पूर्वाग्रह फ़ंक्शन को घटाना है, ताकि किनारों को पानी के नीचे होने की गारंटी दी जाए।

बहुत सारे उपयुक्त पूर्वाग्रह कार्य हैं, लेकिन एक काफी सरल है:

f(x, y) = 1 / (x * (1-x) * y * (1-y)) - 16

जहां x और y समन्वित मूल्य हैं, 0 और 1. के बीच झूठ बोलने के लिए स्केल किया गया है। यह फ़ंक्शन 0 के मान को मानचित्र के केंद्र ( x = y = 0.5) पर ले जाता है और किनारों पर अनंतता को जाता है। इस प्रकार, इसे अपने ऊंचाई के नक्शे से घटाकर (एक उपयुक्त स्थिर कारक द्वारा स्केल किया गया) यह सुनिश्चित करता है कि ऊंचाई के मान भी मानचित्र किनारों के पास माइनस इनफिनिटी के लिए जाएंगे। बस आप चाहते हैं किसी भी मनमाना ऊंचाई उठाओ और इसे समुद्र तल कहते हैं।

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

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

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