मैं एक स्वर इंजन में प्रकाश व्यवस्था कैसे लागू कर सकता हूं?


15

मैं MC को इलाके के इंजन की तरह बना रहा हूं, और मैंने सोचा है कि प्रकाश व्यवस्था से यह पूरी तरह से अच्छा लगेगा। समस्या यह है कि ब्लॉक को ठीक से जलाया नहीं जा रहा है जब प्रकाश को उत्सर्जित करने वाले ब्लॉक को रखा गया है (नीचे स्क्रीनशॉट देखें) पेज पर।

अब तक मैं माइनक्राफ्ट की "ब्लॉकी" लाइटिंग को लागू करना चाहता हूं। इसलिए मैंने एक वर्टेफ़ॉर्मरेट बनाया:

 struct VertexPositionTextureLight
    {
        Vector3 position;
        Vector2 textureCoordinates;
        float light;

        public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
        (
            new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
            new VertexElement(sizeof(float) * 3, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
            new VertexElement(sizeof(float) * 5, VertexElementFormat.Single, VertexElementUsage.TextureCoordinate, 1)
        );

        public VertexPositionTextureLight(Vector3 position, Vector3 normal, Vector2 textureCoordinate, float light)
        {
            // I don't know why I included normal data :)
            this.position = position;
            this.textureCoordinates = textureCoordinate;
            this.light = light;
        }
    }

मुझे लगता है कि अगर मैं प्रकाश व्यवस्था को लागू करना चाहता हूं तो मुझे प्रत्येक शीर्ष के लिए एक प्रकाश निर्दिष्ट करना होगा ... और अब मेरी प्रभाव फ़ाइल में मैं उस मूल्य को लेने में सक्षम होना चाहता हूं और तदनुसार शीर्ष को हल्का कर सकता हूं:

float4x4 World;
float4x4 Projection;
float4x4 View;

Texture Texture;

sampler2D textureSampler = sampler_state  {
    Texture = <Texture>;
    MipFilter = Point;
    MagFilter = Point;
    MinFilter = Point;
    AddressU = Wrap;
    AddressV = Wrap;
};

struct VertexToPixel  {
    float4 Position     : POSITION;
    float4 TexCoords    : TEXCOORD0;
    float4 Light        : TEXCOORD01;
};

struct PixelToFrame  {
    float4 Color        : COLOR0;
};

VertexToPixel VertexShaderFunction(float4 inPosition : POSITION, float4 inTexCoords : TEXCOORD0, float4 light : TEXCOORD01)  {
    VertexToPixel Output = (VertexToPixel)0;

    float4 worldPos = mul(inPosition, World);
    float4 viewPos = mul(worldPos, View);

    Output.Position = mul(viewPos, Projection);
    Output.TexCoords = inTexCoords;
    Output.Light = light;

    return Output;
}

PixelToFrame PixelShaderFunction(VertexToPixel PSIn)  {
    PixelToFrame Output = (PixelToFrame)0;

    float4 baseColor = 0.086f;
    float4 textureColor = tex2D(textureSampler, PSIn.TexCoords);
    float4 colorValue = pow(PSIn.Light / 16.0f, 1.4f) + baseColor;

    Output.Color = textureColor;

    Output.Color.r *= colorValue;
    Output.Color.g *= colorValue;
    Output.Color.b *= colorValue;
    Output.Color.a = 1;

    return Output;
}

technique Block  {
    pass Pass0  {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

VertexToPixel VertexShaderBasic(float4 inPosition : POSITION, float4 inTexCoords : TEXCOORD0)  {
    VertexToPixel Output = (VertexToPixel)0;

    float4 worldPos = mul(inPosition, World);
    float4 viewPos = mul(worldPos, View);

    Output.Position = mul(viewPos, Projection);
    Output.TexCoords = inTexCoords;

    return Output;
}

PixelToFrame PixelShaderBasic(VertexToPixel PSIn)  {
    PixelToFrame Output = (PixelToFrame)0;

    Output.Color = tex2D(textureSampler, PSIn.TexCoords);

    return Output;
}


technique Basic  {
    pass Pass0  {
        VertexShader = compile vs_2_0 VertexShaderBasic();
        PixelShader = compile ps_2_0 PixelShaderBasic();
    }
}

और यह एक उदाहरण है कि मैं प्रकाश कैसे लागू करता हूं:

            case BlockFaceDirection.ZDecreasing:
                light = world.GetLight((int)(backNormal.X + pos.X), (int)(backNormal.Y + pos.Y), (int)(backNormal.Z + pos.Z));

                SolidVertices.Add(new VertexPositionTextureLight(bottomRightBack, backNormal, bottomLeft, light));
                SolidVertices.Add(new VertexPositionTextureLight(bottomLeftBack, backNormal, bottomRight, light));
                SolidVertices.Add(new VertexPositionTextureLight(topRightBack, backNormal, topLeft, light));
                SolidVertices.Add(new VertexPositionTextureLight(topLeftBack, backNormal, topRight, light));
                AddIndices(0, 2, 3, 3, 1, 0);
                break;

और यहाँ सब से आखिरी अल्गोरिथिम है जो इसकी गणना करता है:

    public void AddCubes(Vector3 location, float light)
    {
        AddAdjacentCubes(location, light);
        Blocks = new List<Vector3>();
    }

    public void Update(World world)
    {
        this.world = world;
    }

    public void AddAdjacentCubes(Vector3 location, float light)
    {
        if (light > 0 && !CubeAdded(location))
        {
            world.SetLight((int)location.X, (int)location.Y, (int)location.Z, (int)light);
            Blocks.Add(location);

            // Check ajacent cubes
            for (int x = -1; x <= 1; x++)
            {
                for (int y = -1; y <= 1; y++)
                {
                    for (int z = -1; z <= 1; z++)
                    {
                        // Make sure the cube checked it not the centre one
                        if (!(x == 0 && y == 0 && z == 0))
                        {
                            Vector3 abs_location = new Vector3((int)location.X + x, (int)location.Y + y, (int)location.Z + z);

                            // Light travels on transparent block ie not solid
                            if (!world.GetBlock((int)location.X + x, (int)location.Y + y, (int)location.Z + z).IsSolid)
                            {
                                AddAdjacentCubes(abs_location, light - 1);
                            }
                        }
                    }
                }
            }

        }
    }

    public bool CubeAdded(Vector3 location)
    {
        for (int i = 0; i < Blocks.Count; i++)
        {
            if (location.X == Blocks[i].X &&
                location.Y == Blocks[i].Y &&
                location.Z == Blocks[i].Z)
            {
                return true;
            }
        }

        return false;
    }

किसी भी सुझाव और मदद की बहुत सराहना की जाएगी

SCREENSHOTS इलाके में शीर्ष पर स्थित कलाकृतियों को नोटिस करें और केवल बाएं भाग को आंशिक रूप से कैसे जलाया जाए ... प्रकाश करने का प्रयास १ किसी कारणवश घन के केवल कुछ पक्षों को जलाया जा रहा है और यह जमीन को प्रकाश नहीं देता है प्रकाश 2 पर प्रयास

पिछले का एक और उदाहरण

मेरी समस्या का पता लगाया! मैं जाँच नहीं कर रहा था कि क्या उस ब्लॉक को पहले से ही जलाया गया था और यदि ऐसा है तो किस हद तक (यदि यह कम रोशनी है तो अधिक है)

    public void DoLight(int x, int y, int z, float light)
    {
        Vector3 xDecreasing = new Vector3(x - 1, y, z);
        Vector3 xIncreasing = new Vector3(x + 1, y, z);
        Vector3 yDecreasing = new Vector3(x, y - 1, z);
        Vector3 yIncreasing = new Vector3(x, y + 1, z);
        Vector3 zDecreasing = new Vector3(x, y, z - 1);
        Vector3 zIncreasing = new Vector3(x, y, z + 1);

        if (light > 0)
        {
            light--;

            world.SetLight(x, y, z, (int)light);
            Blocks.Add(new Vector3(x, y, z));

            if (world.GetLight((int)yDecreasing.X, (int)yDecreasing.Y, (int)yDecreasing.Z) < light &&
                world.GetBlock((int)yDecreasing.X, (int)yDecreasing.Y, (int)yDecreasing.Z).BlockType == BlockType.none)
                DoLight(x, y - 1, z, light);
            if (world.GetLight((int)yIncreasing.X, (int)yIncreasing.Y, (int)yIncreasing.Z) < light &&
                world.GetBlock((int)yIncreasing.X, (int)yIncreasing.Y, (int)yIncreasing.Z).BlockType == BlockType.none)
                DoLight(x, y + 1, z, light);
            if (world.GetLight((int)xDecreasing.X, (int)xDecreasing.Y, (int)xDecreasing.Z) < light &&
                world.GetBlock((int)xDecreasing.X, (int)xDecreasing.Y, (int)xDecreasing.Z).BlockType == BlockType.none)
                DoLight(x - 1, y, z, light);
            if (world.GetLight((int)xIncreasing.X, (int)xIncreasing.Y, (int)xIncreasing.Z) < light &&
                world.GetBlock((int)xIncreasing.X, (int)xIncreasing.Y, (int)xIncreasing.Z).BlockType == BlockType.none)
                DoLight(x + 1, y, z, light);
            if (world.GetLight((int)zDecreasing.X, (int)zDecreasing.Y, (int)zDecreasing.Z) < light &&
                world.GetBlock((int)zDecreasing.X, (int)zDecreasing.Y, (int)zDecreasing.Z).BlockType == BlockType.none)
                DoLight(x, y, z - 1, light);
            if (world.GetLight((int)zIncreasing.X, (int)zIncreasing.Y, (int)zIncreasing.Z) < light &&
                world.GetBlock((int)zIncreasing.X, (int)zIncreasing.Y, (int)zIncreasing.Z).BlockType == BlockType.none)
                DoLight(x, y, z + 1, light);
        }
    }

उपरोक्त काम करता है, क्या किसी को पता होगा कि मैं इसे और अधिक प्रभावी कैसे बनाऊंगा?



एक अच्छा सवाल है, लेकिन यह कई मौजूदा सवालों का एक डुप्लिकेट है ... gamedev.stackexchange.com/questions/6507/… gamedev.stackexchange.com/questions/19207/…
टिम होल्ट

जवाबों:


17

मैंने इसके समान कुछ लागू किया है। मैंने अपने ब्लॉग पर इसके बारे में एक पोस्ट लिखी: byte56.com/2011/06/a-light-post । लेकिन मैं यहां थोड़ा और विस्तार में जाऊंगा।

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

मुझे लगता है कि आप एमसी में जल प्रवाह से परिचित हैं। एमसी में प्रकाश व्यवस्था अनिवार्य रूप से एक ही बात है। मैं आपको एक साधारण उदाहरण के माध्यम से चलता हूँ।

यहां कुछ बातों का ध्यान रखना चाहिए।

  • हम ऐसे क्यूब्स की एक सूची रखने जा रहे हैं जिन्हें उनके प्रकाश मूल्यों की जाँच करने की आवश्यकता है
  • केवल पारदर्शी क्यूब्स और प्रकाश उत्सर्जक क्यूब्स में प्रकाश मूल्य हैं

पहला घन जो हम जोड़ते हैं वह प्रकाश स्रोत है। एक स्रोत एक विशेष मामला है। यह प्रकाश स्रोत प्रकार के अनुसार प्रकाश मूल्य निर्धारित किया जाता है (उदाहरण के लिए मशालों को लावा की तुलना में उज्जवल मूल्य मिलता है)। यदि किसी घन का प्रकाश मान 0 से ऊपर है, तो हम उस घन से सटे सभी पारदर्शी घन को सूची में जोड़ते हैं। सूची में प्रत्येक क्यूब के लिए, हम इसके सबसे चमकीले पड़ोसी ऋण के लिए इसका हल्का मूल्य निर्धारित करते हैं। इसका मतलब यह है कि प्रकाश स्रोत के बगल में सभी पारदर्शी क्यूब्स (इसमें "वायु" शामिल है) को 15. का हल्का मूल्य मिलता है। हम प्रकाश स्रोत के चारों ओर क्यूब्स को चलना जारी रखते हैं, क्यूब्स को जोड़ते हैं जिन्हें चेक करने की आवश्यकता होती है और सूची से बंद क्यूब्स ले रहे हैं। , उपयोग हम अब जोड़ने के लिए कोई भी नहीं है। इसका मतलब है कि सेट किए गए सभी नवीनतम मान 0 पर सेट किए गए हैं, जिसका अर्थ है कि हम अपने प्रकाश के अंत तक पहुंच गए हैं।

यह प्रकाश की एक काफी सरल व्याख्या है। मैंने कुछ अधिक उन्नत किया है, लेकिन मैंने उसी मूल सिद्धांत के साथ शुरुआत की है। यह एक उदाहरण है कि यह क्या पैदा करता है:

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

अब जब आपके पास अपना सभी लाइट डेटा सेट है। जब आप अपने कोने के लिए रंग मानों का निर्माण कर रहे हैं, तो आप इस चमक डेटा को संदर्भित कर सकते हैं। आप ऐसा कुछ कर सकते हैं (जहां प्रकाश 0 और 15 के बीच एक अंतर मूल्य है):

float baseColor = .086f;
float colorValue = (float) (Math.pow(light / 16f, 1.4f) + baseColor );
return new Color(colorValue, colorValue, colorValue, 1);

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

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

संपादित करें

एक चेहरे के लिए प्रकाश पाने के लिए, आप चेहरे के सामान्य की दिशा में घन को देखते हैं। उदाहरण के लिए, क्यूब के शीर्ष चेहरे को ऊपर क्यूब से प्रकाश डेटा मिलता है।

EDIT 2

मैं आपके कुछ सवालों का समाधान करने का प्रयास करूंगा।

तो मैं क्या करूँगा इस मामले में पुनरावृत्ति जैसा कुछ है?

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

इसके अलावा एल्गोरिथ्म "नीचे की ओर प्रकाश" कैसे होगा?

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

मैं केवल एक चेहरे के लिए प्रकाश कैसे निर्दिष्ट करूंगा?

आप केवल एक चेहरे के लिए प्रकाश निर्दिष्ट नहीं करते हैं। प्रत्येक पारदर्शी घन सभी ठोस घन के लिए प्रकाश को निर्दिष्ट करता है जो इसके साथ एक चेहरा साझा करता है। यदि आप एक चेहरे के लिए प्रकाश प्राप्त करना चाहते हैं, तो बस इसे छूने वाले पारदर्शी घन के लिए प्रकाश मूल्य की जांच करें। यदि यह एक पारदर्शी घन को नहीं छू रहा है, तो आप इसे वैसे भी प्रदान नहीं करेंगे।

कोड नमूने?

नहीं।


@ Byte56 यह जानना पसंद करेगा कि "कलन" में काम करने के लिए इस एल्गोरिथ्म का अनुवाद कैसे किया जाए।
गोपगोप

मैंने पड़ोसी के अनुसार सिर्फ चंक के प्रत्येक पक्ष को अपडेट करने के बारे में सोचा और फिर सभी बदले हुए ब्लॉकों को बदलने के लिए ब्लॉकों की सूची में जोड़ दिया लेकिन यह काम नहीं करता है
gopgop

@gopgop टिप्पणियाँ चर्चा के लिए जगह नहीं हैं। आप मुझे कुछ समय चैट में पा सकते हैं। या वहां के अन्य लोगों के साथ इस पर चर्चा करें।
MichaelHouse

4

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

http://codeflow.org/entries/2010/dec/09/minecraft-like-rendering-experiments-in-opengl-4/

लेकिन आपके प्रश्न का मूल उत्तर देने की कोशिश कर रहा है:

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

    या ...

    रंग जोड़ने के बाद, परिणाम को क्लैंप करने के बजाय (यानी 0 और 1 के बीच रंग के प्रत्येक घटक को क्लैम्प करना) के बजाय परिणाम को स्केल करें - यह पता लगाएं कि कौन से तीन घटक (RGB) सबसे बड़े हैं और उन सभी को उस मान से विभाजित करते हैं। यह विधि रंग के मूल गुणों को थोड़ा बेहतर बनाए रखती है।

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