Pygame में एक SNES मोड 7 (affine ट्रांसफॉर्म) प्रभाव करना


19

वहाँ एक मोड 7 / mario kart प्रकार pygame में प्रभाव करने के लिए कैसे पर एक छोटे से जवाब के रूप में ऐसी बात है?

मैंने बड़े पैमाने पर गुगली की है, मैं जितने भी डॉक्स के साथ आ सकता हूं, अन्य भाषाओं के दर्जनों पृष्ठ (asm, c) में बहुत सारे अजीब-अजीब समीकरण हैं और ऐसे हैं।

आदर्श रूप में, मैं गणितीय शब्दों की तुलना में अंग्रेजी में कुछ समझाया जाना चाहूंगा।

मैं छवि / बनावट में हेरफेर करने के लिए PIL या pygame का उपयोग कर सकता हूं, या जो भी आवश्यक हो।

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

यदि मैं इसका पता लगा सकता हूं, तो मैं एक निश्चित लिखूंगा कि न्यूबॉक् स पेज के लिए मोड 7 कैसे करें।

संपादित करें: मोड 7 डॉक्टर: http://www.coranac.com/tonc/text/mode7.htm


5
यहाँ समीकरण प्रतीत होते हैं: en.wikipedia.org/wiki/Mode_7 हालांकि, इन दिनों हमारे पास 3 डी त्वरण है, मोड 7 जैसी चीजें, या अजीब तरीके से काम किया कयामत एक समाधान की तुलना में अधिक जिज्ञासा है।
साल्मोनेमोसे

3
@ 2D_Guy यह पृष्ठ मेरे लिए एल्गोरिथ्म को बहुत अच्छी तरह से समझाता है। आप यह जानना चाहते हैं कि यह कैसे करना है, या आप चाहते हैं कि यह आपके लिए पहले से ही लागू हो?
गुस्तावो मैकील

1
SNES सिस्टम पर @stephelton, एकमात्र परत जिसे विकृत किया जा सकता है, घुमाया जा सकता है .. (मैट्रिस के साथ अनुप्रयुक्त रूपांतरण) सातवीं परत है। पृष्ठभूमि परत। अन्य सभी परतों का उपयोग साधारण स्प्राइट्स के लिए किया गया था, इसलिए यदि आप एक 3 डी प्रभाव चाहते हैं, तो आपको इस परत का उपयोग करना होगा, यह वह जगह है जहां से नाम आया :)
गुस्तावो मैकिएल

3
@GustavoMaciel: यह थोड़ा गलत है। एसएनईएस में 8 अलग-अलग मोड (4-7) थे, जिसमें 4 पृष्ठभूमि परतों तक अलग-अलग कार्यक्षमता थी, लेकिन केवल एक मोड (मोड 7, इसलिए नाम) ने रोटेशन और स्केलिंग का समर्थन किया (और आपको एक भी परत तक सीमित कर दिया)। आप वास्तव में मोड को जोड़ नहीं सकते।
माइकल मैडसेन

1
@ मिचेल: मैं भी जोड़ूंगा: एसएनईएस 90 के दशक (खेल एफ-जीरो के साथ) में इस प्रभाव का उपयोग करने वाला पहला लोकप्रिय कंसोल था, और इसीलिए इसके बाद लोग दूसरे में देखे गए सभी 2D क्षैतिज बनावट-मैपेड विमान प्रभावों का उल्लेख करना शुरू करते हैं। "मोड 7" के रूप में खेल। वास्तव में, इस तरह का प्रभाव नया नहीं था और बहुत समय पहले आर्केड, सीएफ में मौजूद था। स्पेस हैरियर / हैंग-ऑन (1985)।
टिगोर

जवाबों:


45

मोड 7 एक बहुत ही सरल प्रभाव है। यह किसी मंजिल / छत पर 2D x / y बनावट (या टाइलें) का निर्माण करता है। पुराने एसएनईएस ऐसा करने के लिए हार्डवेयर का उपयोग करते हैं, लेकिन आधुनिक कंप्यूटर इतने शक्तिशाली हैं कि आप इस रियलटाइम (और एएसएम की आवश्यकता नहीं है जैसा कि आप उल्लेख कर सकते हैं)।

एक 3 डी बिंदु (x, y, z) को 2 डी बिंदु (x, y) प्रोजेक्ट करने के लिए मूल 3 डी गणित सूत्र है:

x' = x / z;
y' = y / z; 

जब आप इसके बारे में सोचते हैं, तो यह समझ में आता है। दूर की वस्तुएं आपके आस-पास की वस्तुओं से छोटी होती हैं। कहीं जाने वाली रेल की पटरियों के बारे में सोचें:

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

यदि हम सूत्र इनपुट मानों पर वापस नज़र डालते हैं: xऔर yवर्तमान पिक्सेल हम प्रसंस्करण कर रहे हैं, और zबिंदु कितनी दूर है, इसके बारे में दूरी की जानकारी होगी। यह समझने के लिए कि क्या zहोना चाहिए, उस चित्र को देखें, यह zऊपर की छवि के लिए मान दिखाता है:

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

बैंगनी = निकट दूरी, लाल = दूर

इसलिए इस उदाहरण में, zमान y - horizon( (x:0, y:0)स्क्रीन के केंद्र में है)

यदि हम सब कुछ एक साथ करते हैं, तो यह बन जाता है: (स्यूडोकोड)

for (y = -yres/2 ; y < yres/2 ; y++)
  for (x = -xres/2 ; x < xres/2 ; x++)
  {
     horizon = 20; //adjust if needed
     fov = 200; 

     px = x;
     py = fov; 
     pz = y + horizon;      

     //projection 
     sx = px / pz;
     sy = py / pz; 

     scaling = 100; //adjust if needed, depends of texture size
     color = get2DTexture(sx * scaling, sy * scaling);  

     //put (color) at (x, y) on screen
     ...
  }

एक आखिरी बात: यदि आप एक मारियो कार्ट गेम बनाना चाहते हैं, तो मुझे लगता है कि आप नक्शे को घुमाना भी चाहते हैं। वैसे इसका भी बहुत आसान है: बनावट मूल्य प्राप्त करने से पहले बारी बारी से sxऔर sy। यहाँ सूत्र है:

  x' = x * cos(angle) - y * sin(angle);
  y' = x * sin(angle) + y * cos(angle);

और यदि आप नक्शे को गर्त में ले जाना चाहते हैं, तो बनावट मूल्य प्राप्त करने से पहले कुछ ऑफसेट जोड़ें:

  get2DTexture(sx * scaling + xOffset, sy * scaling + yOffset);

नोट: मैंने एल्गोरिथ्म (लगभग कॉपी-पेस्ट) का परीक्षण किया और यह काम करता है। यहाँ उदाहरण है: http://glslsandbox.com/e#26532.3 (हाल के ब्राउज़र और WebGL सक्षम होना चाहिए)

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

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

अधिक जानकारी के लिए, मैं पढ़ने का सुझाव देता हूं: http://en.wikipedia.org/wiki/3D_projection#Perspective_projection


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

1

यहाँ इसे बनाने के लिए कोड है। मैं अपने ब्लॉग पर बनाए गए ट्यूटोरियल का समान कोड हूं । मोड 7 विधि और RayCasting जानने के लिए वहाँ की जाँच करें।

मूल रूप से, छद्म कोड यह है:

//This is the pseudo-code to generate the basic mode7

for each y in the view do
    y' <- y / z
    for each x in the view do
        x' <- x / z
        put x',y' texture pixel value in x,y view pixel
    end for
    z <- z + 1
end for

यहाँ वह कोड है जो मैंने अपने ट्यूटोरियल के बाद JAVA में बनाया था।

package mode7;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;

/**
 * Mode 7 - Basic Implementation
 * This code will map a texture to create a pseudo-3d perspective.
 * This is an infinite render mode. The texture will be repeated without bounds.
 * @author VINICIUS
 */
public class BasicModeSeven {

    //Sizes
    public static final int WIDTH = 800;
    public static final int WIDTH_CENTER = WIDTH/2;
    public static final int HEIGHT = 600;
    public static final int HEIGHT_CENTER = HEIGHT/2;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException {

        //Create Frame
        JFrame frame = new JFrame("Mode 7");
        frame.setSize(WIDTH, HEIGHT);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        //Create Buffered Images:
        //image - This is the image that will be printed in the render view
        //texture - This is the image that will be mapped to the render view
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        BufferedImage texture = ImageIO.read(new File("src/mode7/texture.png"));

        //The new coords that will be used to get the pixel on the texture
        double _x, _y;

        //z - the incrementable variable that beggins at -300 and go to 300, because 
        //the depth will be in the center of the HEIGHT
        double z =  HEIGHT_CENTER * -1;

        //Scales just to control de scale of the printed pixel. It is not necessary
        double scaleX = 16.0;
        double scaleY = 16.0; 

        //Mode 7 - loop (Left Top to Down)
        for(int y = 0; y < HEIGHT; y++){

            _y = y / z; //The new _y coord generated
            if(_y < 0)_y *= -1; //Control the _y because the z starting with a negative number
            _y *= scaleY; //Increase the size using scale
            _y %= texture.getHeight(); //Repeat the pixel avoiding get texture out of bounds 

            for(int x = 0; x < WIDTH; x++){

                _x = (WIDTH_CENTER - x) / z; //The new _x coord generated
                if(_x < 0)_x *= -1; //Control the _x to dont be negative
                _x *= scaleX; //Increase the size using scale
                _x %= texture.getWidth(); //Repeat the pixel avoiding get texture out of bounds 

                //Set x,y of the view image with the _x,_y pixel in the texture
                image.setRGB(x, y, texture.getRGB((int)_x, (int)_y));
            }

            //Increment depth
            z++;
        }

        //Loop to render the generated image
        while(true){
            frame.getGraphics().drawImage(image, 0, 0, null);
        }
    }
}

परिणाम है:

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


स्पष्टीकरण यहाँ programandocoisas.blogspot.com.br है । आप इस प्रभाव को बनाने के लिए स्टेप बाय स्टेप ट्यूटोरियल पा सकते हैं। लेकिन मैं अपनी पोस्ट को अपडेट करूंगा ताकि टिप्पणियों को बेहतर बनाया जा सके;)।
विनीसस बियावत्ती
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.