দ্বীপ মানচিত্র মাস্ক তৈরির একটি সহজ পদ্ধতি


21


আমি সি # সহ একটি দ্বীপের মানচিত্রে একটি মাস্ক উত্পন্ন করার জন্য একটি দুর্দান্ত এবং সহজ উপায় অনুসন্ধান করছি।


মূলত আমি পার্লিন শব্দের সাথে উত্পন্ন এলোমেলো উচ্চতা ম্যাপটি ব্যবহার করছি, যেখানে ভূখণ্ডটি জলের চারপাশে নয়।

এখানে চিত্র বর্ণনা লিখুন

পরবর্তী পদক্ষেপটি হবে একটি মুখোশ তৈরি করা, কোণ এবং সীমানা কেবল জল কিনা তা নিশ্চিত করা।

এখানে চিত্র বর্ণনা লিখুন

তারপরে আমি একটি দ্বীপ পেতে পার্লিন শব্দ শব্দটি থেকে কেবল মুখোশটি বিয়োগ করতে পারি।

এখানে চিত্র বর্ণনা লিখুন

এবং বিপরীতে খেলা প্রায় ...

এখানে চিত্র বর্ণনা লিখুন

এবং গ্রেডিয়েন্ট বক্ররেখা, আমি যেমন চাই ঠিক তেমন একটি দ্বীপের উচ্চতা ম্যাপটি পেতে পারি ..

এখানে চিত্র বর্ণনা লিখুন

(এগুলি অবশ্যই উদাহরণস্বরূপ)

আপনি যেমন দেখতে পাচ্ছেন, দ্বীপের "প্রান্তগুলি" সবেমাত্র কেটে গেছে, রঙের মান খুব বেশি সাদা না হলে এটি কোনও বড় সমস্যা নয়, কারণ আমি গ্রেস্কেলকে কেবল 4 টি স্তরগুলিতে ভাগ করব (জল, বালু, ঘাস এবং শিলা)।

আমার প্রশ্ন হ'ল আমি কীভাবে দ্বিতীয় চিত্রের মতো একটি ভাল চেহারাওয়ালা মুখোশ তৈরি করতে পারি?


হালনাগাদ

আমি এই কৌশলটি পেয়েছি, এটি আমার কাছে একটি দুর্দান্ত সূচনার পয়েন্ট বলে মনে হচ্ছে, তবে আমি নিশ্চিত না যে আমি কীভাবে সুনির্দিষ্টভাবে এটি বাস্তবায়িত করতে পছন্দসই আউটপুট পেতে পারি। http://mrl.nyu.edu/~perlin/experiments/puff/


আপডেট 2

এটি আমার চূড়ান্ত সমাধান।

আমি 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;
        }
    }

কোনও সুযোগ আপনি আপনার সম্পূর্ণ উত্স লিঙ্ক করতে পারেন?
স্টু

উত্তর:


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 এর মধ্যে কোনও মান শক্ত (আপনার কাটা বন্ধ যাই হোক না কেন)। এটি খুব সাধারণ ফাংশন, এটি দেখতে এটির মতো দেখাচ্ছে:

#Solid (ভাসমান মান) ফেরতের মান <solidCutOffValue

solidCutOffValueকঠিন বা না-এর মধ্যে সিদ্ধান্ত নিতে আপনি যে মানটি ব্যবহার করছেন তা কোথায় । এটি .5এমনকি বিভক্তের জন্য, বা .75আরও শক্ত বা .25কম শক্তের জন্যও হতে পারে ।

অবশেষে, এই সামান্য বিট (1 - (d/maxDVal)) * noiseAt(x,y)। প্রথমত, আমরা এর সাথে 0 এবং 1 এর মধ্যে একটি ফ্যাক্টর পাই:

(1 - (d/maxDVal))

এখানে চিত্র বর্ণনা লিখুন

কোথায় 0বাহিরে কিনারায় এবং 1ভিতরে প্রান্ত চালু আছে। এর অর্থ আমাদের শব্দের অভ্যন্তরে দৃ solid় এবং বাইরের স্থিতিশীল নয় more আমরা যে শব্দটি পাই তার থেকে আমরা এটি প্রয়োগ করি noiseAt(x,y)

নামগুলি আসল মানগুলির জন্য বিভ্রান্তিকর হতে পারে বলে মানগুলি কী কী তার এটির আরও ভিজ্যুয়াল উপস্থাপনা:

এখানে চিত্র বর্ণনা লিখুন


এই দ্রুত উত্তরের জন্য THX, আমি এই কৌশলটি বাস্তবায়নের চেষ্টা করব। এটি দিয়ে কাঙ্ক্ষিত আউটপুট পাওয়ার আশা করি।
Ace

আপনি যেভাবে চাইছেন শোরগোলের প্রান্তগুলি পেতে সম্ভবত কিছু টুইট করার দরকার হবে। তবে এটি আপনার পক্ষে একটি শক্ত ভিত্তি হওয়া উচিত। শুভকামনা!
MichaelHouse

এখনও অবধি কাজটি করার জন্য বেস বাস্তবায়ন পেয়েছি, আপনি কি কেবল আমাকে ইসসোলিড ফাংশনের উদাহরণ দিতে পারেন? আমি জানি না কীভাবে আমি প্রান্ত থেকে ন্যূনতম এবং সর্বাধিক দূরত্বের ভিত্তিতে 0 এবং 1 এর মধ্যে একটি মান পেতে পারি। এখনও পর্যন্ত আমার কোডের জন্য আমার আপডেট দেখুন।
এসি

আমি সেখানে কিছু মিশ্রিত যুক্তি ছিল। আমি আরও বোঝার জন্য এটি স্থির করেছি। এবং isSolid
মাইকেলহাউস

0 এবং 1 এর মধ্যে একটি মান পেতে, আপনি সর্বাধিক মান কী হতে পারে তা সন্ধান করুন এবং এটির দ্বারা আপনার বর্তমান মানটি ভাগ করুন। তারপরে আমি এটিকে একটি থেকে বিয়োগ করেছি, কারণ আমি চেয়েছিলাম যে শূন্যটি বাইরের প্রান্তে এবং 1 টি অভ্যন্তরের প্রান্তে থাকতে হবে।
MichaelHouse

14

আপনি যদি এর জন্য কিছু গণনামূলক শক্তি ছাড়তে ইচ্ছুক হন তবে আপনি এই ব্লগের লেখক যা করেছিলেন তার অনুরূপ কৌশল ব্যবহার করতে পারেন । ( এনবি: আপনি যদি সরাসরি তার কোডটি অনুলিপি করতে চান তবে এটি অ্যাকশনস্ক্রিপ্টে রয়েছে)। মূলত, তিনি আধা-এলোমেলো পয়েন্টগুলি তৈরি করেন (অর্থাত্ তুলনামূলকভাবে অভিন্ন দেখায়) এবং তারপরে ভোরোনাই বহুভুজ তৈরি করতে এগুলি ব্যবহার করেন ।

ভোরোনাই বহুভুজ

এরপর তিনি বহুভুজ বাকি পানি এবং iterates বাইরে বহুভুজ সেট করে, তাদের পানি উপার্জন যদি সংলগ্ন বহুভুজের একটি নির্দিষ্ট শতাংশ জল । তারপরে আপনি একটি বহুভুজ মুখোশটি প্রায় একটি দ্বীপের প্রতিনিধিত্ব করে রেখে আসবেন।

বহুভুজ মানচিত্র

এ থেকে আপনি প্রান্তগুলিতে শব্দটি প্রয়োগ করতে পারেন, এর সদৃশ কিছু হওয়ার ফলে (রঙগুলি অন্যরকম, সম্পর্কিত নয় এমন পদক্ষেপ):

গোলমাল প্রান্ত সহ বহুভুজ মানচিত্র

তারপরে আপনার কাছে একটি (বেশ) বাস্তববাদী-দৃষ্টিনন্দন দ্বীপ-আকারের মুখোশ রয়েছে যা আপনার উদ্দেশ্যগুলি পরিবেশন করবে। আপনি নিজের পার্লিন শব্দটির জন্য এটি একটি মুখোশ হিসাবে ব্যবহার করতে বেছে নিতে পারেন, বা আপনি সমুদ্রের দূরত্বের ভিত্তিতে উচ্চতার মান তৈরি করতে পারেন এবং গোলমাল যোগ করতে পারেন (যদিও এটি অপ্রয়োজনীয় বলে মনে হয়)।


আপনার জবাবের জন্য thx, তবে এটি ওয়েবটি অনুসন্ধান করা থেকে পাওয়া প্রথম (বেশ কয়েকটি কেবলমাত্র) সমাধান পেয়েছি। এই সমাধানটি খুব সুন্দর বলে মনে হচ্ছে তবে আমি "সহজ" উপায়টি দেখতে চাই।
Ace

@ একসাথে যথেষ্ট, আপনি যা যা করতে যাচ্ছেন এটি সম্ভবত কিছুটা ওভারকিল: পি তবুও, আপনার যদি কখনও প্রয়োজন হয় তবে এটি মনে রাখা উচিত
পোলার

এর সাথে লিঙ্কিত কাউকে খুশি - সেই পৃষ্ঠাটি সর্বদা আমার তালিকায় থাকে "কেউ কীভাবে কিছু বাস্তবায়িত করেছিল সে সম্পর্কে সত্যিই দুর্দান্ত পোস্টগুলি" "
টিম হল্ট

+1 টি। এই এত শান্ত. এর জন্য আপনাকে ধন্যবাদ, এটি অবশ্যই আমার পক্ষে সহায়ক হবে!
আন্দ্রে

1

একটি খুব সহজ পদ্ধতি হ'ল প্রস্থ / 2 এবং উচ্চতা / 2 এ কেন্দ্রের সাথে ইনভার্স রেডিয়াল বা গোলাকৃতির গ্রেডিয়েন্ট তৈরি করা। মাস্কিংয়ের জন্য আপনি শব্দটি থেকে গুনটির পরিবর্তে গুনফলকে বিয়োগ করতে চান । এটি আপনাকে ত্রুটিযুক্ত দ্বীপপুঞ্জগুলি অগত্যা সংযুক্ত নয় বলে আরও বাস্তবসম্মত চেহারা দেওয়ার তীরে দেয়।

আপনি এখানে গ্রেডিয়েন্টের সাথে গোলমালকে বিয়োগ করে এবং গুণনের মধ্যে পার্থক্য দেখতে পাবেন: http://www.vfxpedia.com/index.php?title=Tips_and_T কৌশল / প্রাকৃতিক_প্রেমিকা / স্মোক

আপনি কীভাবে র‌্যাডিয়াল গ্রেডিয়েন্ট তৈরি করবেন তা নিশ্চিত না হলে আপনি এটি সূচনা পয়েন্ট হিসাবে ব্যবহার করতে পারেন:

    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 এর মধ্যে বিস্তৃত আকারযুক্ত, এই ফাংশনটি মানচিত্রের কেন্দ্রে ( x = y = 0.5 তে) 0 মান নিয়ে যায় এবং প্রান্তে অনন্ত হয়ে থাকে। সুতরাং, আপনার উচ্চতার মানচিত্র থেকে এটিকে (একটি উপযুক্ত ধ্রুবক ফ্যাক্টর দ্বারা মাপা) বিয়োগ করা নিশ্চিত করে যে উচ্চতার মানগুলি মানচিত্রের প্রান্তগুলির কাছাকাছি বিয়োগ অনন্তের দিকে ঝুঁকবে। কেবল আপনি যে কোনও স্বেচ্ছাসেবী উচ্চতা চান তা চয়ন করুন এবং এটিকে সমুদ্র স্তর বলুন।

অলিপেক্কা নোট হিসাবে, এই পদ্ধতির গ্যারান্টি দিবে না যে দ্বীপটি সুসংগত হবে। তবে, মোটামুটি ছোট স্কেল ফ্যাক্টর দ্বারা পক্ষপাতিত্ব ফাংশনটি স্কেলিংয়ের ফলে এটি মানচিত্রের মাঝের অঞ্চলে বেশিরভাগ ক্ষেত্রে সমতল হওয়া উচিত (এইভাবে আপনার অঞ্চলটিকে খুব বেশি প্রভাবিত করবে না), কেবলমাত্র কিনারাগুলির নিকটে একটি উল্লেখযোগ্য পক্ষপাত উপস্থিত হবে। সুতরাং, এটি করার ফলে আপনাকে একটি স্কোয়ারিশ দেওয়া উচিত, বেশিরভাগ সংলগ্ন দ্বীপ, সর্বাধিক, সম্ভবত কয়েকটি ছোট ছোট উপ-দ্বীপগুলি প্রান্তের কাছে দেওয়া উচিত।

অবশ্যই, যদি আপনি সংযোগ বিচ্ছিন্ন ভূখণ্ডের সম্ভাবনাটিকে আপত্তি না করেন তবে কিছুটা বড় স্কেলিং ফ্যাক্টর আপনাকে আরও জল এবং আরও প্রাকৃতিক চেহারার দ্বীপ আকার দিতে হবে। সমুদ্রের স্তর এবং / অথবা আপনার মূল উচ্চতা ম্যাপকে সামঞ্জস্য করে ফলাফল দ্বীপ (গুলি) এর আকার এবং আকার পৃথক করতে ব্যবহার করা যেতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.