OpenGL Skalowanie tekstur

0

Witam, od wczoraj zacząłem moją zabawę z opengl i mam pewien problem. Otóż napisałem metodę która ułatwia rysowanie obrazów podczas ustawiania wielkości zwykłego obrazu nie ma żadnego problemu, lecz przy próbie rysowania obrazu z kanałem alpha obraz jest mniejszy niż powinien.
Dla rozjaśnienia sytuacji podam dwa zdjęcia
<image>9d8dec49ac.png</image>
Rycerz po lewej teoretycznie jest takiej samej wielkości jak zielony kwadrat.
<image>e4c9206c38.png</image>
Na drugim zdjęciu widać to dokładnie. Nie wiem w czym leży problem, zwykłym obrazom można ustawić wielkość bez problemu lecz tym z kanałem alpha już nie.
Będę wdzięczny za pomoc.

 

public static void DrawImage(Texture texture,int x,int y, int width, int height){
		if(texture != null){
			texture.bind();
			glEnable(GL_BLEND);
			glBlendFunc(GL_ONE, GL_ZERO);
			glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	
			//set transparency
			glColor4f(1, 1, 1,1);
			//
			glTranslatef(x, y, 0);
			glBegin(GL_QUADS);
			glTexCoord2f(0, 0);
			glVertex2i(0, 0);
			glTexCoord2f(1, 0);
			glVertex2i(width, 0);
			glTexCoord2f(1, 1);
			glVertex2i(width, height);
			glTexCoord2f(0, 1);
			glVertex2i(0, height);
			glEnd();
			glLoadIdentity(); 
			
			
		}
	} 
 
        Texture tex = LoadTexture("res/1.png", "PNG");
        Texture t2 = LoadTexture("res/image.png", "PNG");
     
        while (!Display.isCloseRequested()) {
            int delta = getDelta();
        	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    		
            update(delta);
            renderGL();

        	 DrawImage(tex, 0, 0, 100 , 120);
        	 DrawImage(t2, 100, 0, 100, 120);
             
            Display.update();
            Display.sync(60); // cap fps to 60fps
        } 
0

Ja zawsze wywoływałem TexParameter podczas ładowania tekstury:

void Texture::Load(string filename,bool fixEdge)
{
	//load and decode
	std::vector<unsigned char> buffer, image;
	loadFile(buffer, filename);
	unsigned long w, h;
	int error = decodePNG(image, w, h, buffer.empty() ? 0 : &buffer[0], (unsigned long)buffer.size());

	if (!error) {
		glEnable(GL_TEXTURE_2D);
		width=w;
		height=h;
		glPixelStorei(GL_UNPACK_ALIGNMENT,4);
		glGenTextures(1,&texID);
		glBindTexture(GL_TEXTURE_2D,texID);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		if (fixEdge) {
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE  );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE  );
		} else {
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT  );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT  );
		}

		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, &image[0]);
	} else {
		cout << "Error: " << filename << endl;
	}
}

CLAMP_TO_EDGE to ważny parametr dla sprite, bo przy nakładaniu tekstury na quada eliminujesz niedoskonałość liczb zmiennoprzecinkowych i nie będą dodawać się śmieci po bokach obrazka ;)

glBlendFunc poprawnie wykorzystujący kanał alpha robiłem zawsze w taki sposób:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Nie wiem, czemu dwa razy wywołujesz blend func, z różnymi parametrami.

BTW. przywitaj się z OpenGL 4, albo chociaż 3 ;)

0

Odpowiadaj w wątku, a nie w komentarzach.

decodePNG to funkcja, której używałem w C++ (z "modułu" picopng - http://lodev.org/lodepng/picopng.cpp). To mało istotne w naszych rozważaniach ;)

Na Twoje szczęście lwjgl też używałem ze starym OpenGL. Żeby mieć CLAMP_TO_EDGE prawdopodobnie musisz zaimportować odpowiednie moduły, ja mam taką formułkę w pliku z loaderem tekstur:

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.PixelFormat.*;
import static org.lwjgl.util.glu.GLU.*;

Do ładowania PNG używałem takich modułów:

import de.matthiasmann.twl.utils.PNGDecoder;
import de.matthiasmann.twl.utils.PNGDecoder.Format;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Paths;

Tak wygląda moja metoda ładująca PNG w Javie:

	public void load(String fileName,boolean fixEdge) throws IOException
	{
		InputStream in = null;
		try {
			in = new FileInputStream(Paths.get(fileName).toString());
			PNGDecoder decoder = new PNGDecoder(in);
 
			width=decoder.getWidth();
			height=decoder.getHeight();
			ByteBuffer buf = ByteBuffer.allocateDirect(4*width*height);
			decoder.decode(buf, width*4, Format.RGBA);
			buf.flip();
			texID=glGenTextures();
			glBindTexture(GL_TEXTURE_2D, texID);
 
			// All RGB bytes are aligned to each other and each component is 1 byte
			glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
 
			if (fixEdge) {
				glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE  );
				glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE  );
			} else {
				glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT  );
				glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT  );
			}
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
 
			in.close(); // przy 250 uruchomieniach w jednej instancji, krzyczalo, ze za duzo otwartych plikow
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
0

@Spine Dodałem ale to nadal nie rozwiązuje problemu, podam kod całej klasy.

 @SuppressWarnings("unused")
public class Start {
	
	
	
	
	  float x = 400, y = 300;
    float rotation = 0;
  
    /** time at last frame */
    long lastFrame;
  
    /** frames per second */
    int fps;
    /** last fps time */
    long lastFPS;
     
    /** is VSync Enabled */
    boolean vsync;
  
    public void start() {
        try {
            Display.setDisplayMode(new DisplayMode(1280, 720));
            Display.create();
        } catch (LWJGLException e) {
            e.printStackTrace();
            System.exit(0);
        }
  
    	glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(0, 1280, 720, 0, 1, -1);
		glMatrixMode(GL_MODELVIEW);
		glEnable(GL_TEXTURE_2D);
		
        getDelta(); // call once before loop to initialise lastFrame
        lastFPS = getTime(); // call before loop to initialise fps timer
        Texture tex = LoadTexture("res/1.png", "PNG");
        Texture t2 = LoadTexture("res/image.png", "PNG");
        Texture t3 = LoadTexture("res/atack1/1.png", "PNG");
        
        while (!Display.isCloseRequested()) {
            int delta = getDelta();
        	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    		
            update(delta);
          
            	DrawImage(t2, 0, 0, 600, 420);
             	DrawImage(t3, 0, 0, 307, 160);
                
             Display.update();
            Display.sync(60); // cap fps to 60fps
        }
  
        Display.destroy();
        System.exit(0);
    }
  
    public void update(int delta) {
        // rotate quad
        rotation += 0.15f * delta;
  
        if (Keyboard.isKeyDown(Keyboard.KEY_LEFT)) x -= 0.35f * delta;
        if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) x += 0.35f * delta;
  
        if (Keyboard.isKeyDown(Keyboard.KEY_UP)) y -= 0.35f * delta;
        if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) y += 0.35f * delta;
  
        while (Keyboard.next()) {
            if (Keyboard.getEventKeyState()) {
                if (Keyboard.getEventKey() == Keyboard.KEY_F) {
                    setDisplayMode(1280, 720, !Display.isFullscreen());
                }
                else if (Keyboard.getEventKey() == Keyboard.KEY_V) {
                    vsync = !vsync;
                    Display.setVSyncEnabled(vsync);
                }
            }
        }
         
        // keep quad on the screen
        if (x < 0) x = 0;
        if (x > 800) x = 800;
        if (y < 0) y = 0;
        if (y > 600) y = 600;
  
        updateFPS(); // update FPS Counter
    }
  
    /**
     * Set the display mode to be used 
     * 
     * @param width The width of the display required
     * @param height The height of the display required
     * @param fullscreen True if we want fullscreen mode
     */
    public void setDisplayMode(int width, int height, boolean fullscreen) {
 
        // return if requested DisplayMode is already set
                if ((Display.getDisplayMode().getWidth() == width) && 
            (Display.getDisplayMode().getHeight() == height) && 
            (Display.isFullscreen() == fullscreen)) {
            return;
        }
         
        try {
            DisplayMode targetDisplayMode = null;
             
            if (fullscreen) {
                DisplayMode[] modes = Display.getAvailableDisplayModes();
                int freq = 0;
                 
                for (int i=0;i<modes.length;i++) {
                    DisplayMode current = modes[i];
                     
                    if ((current.getWidth() == width) && (current.getHeight() == height)) {
                        if ((targetDisplayMode == null) || (current.getFrequency() >= freq)) {
                            if ((targetDisplayMode == null) || (current.getBitsPerPixel() > targetDisplayMode.getBitsPerPixel())) {
                                targetDisplayMode = current;
                                freq = targetDisplayMode.getFrequency();
                            }
                        }
 
                        // if we've found a match for bpp and frequence against the 
                        // original display mode then it's probably best to go for this one
                        // since it's most likely compatible with the monitor
                        if ((current.getBitsPerPixel() == Display.getDesktopDisplayMode().getBitsPerPixel()) &&
                            (current.getFrequency() == Display.getDesktopDisplayMode().getFrequency())) {
                            targetDisplayMode = current;
                            break;
                        }
                    }
                }
            } else {
                targetDisplayMode = new DisplayMode(width,height);
            }
             
            if (targetDisplayMode == null) {
                System.out.println("Failed to find value mode: "+width+"x"+height+" fs="+fullscreen);
                return;
            }
 
            Display.setDisplayMode(targetDisplayMode);
            Display.setFullscreen(fullscreen);
             
        } catch (LWJGLException e) {
            System.out.println("Unable to setup mode "+width+"x"+height+" fullscreen="+fullscreen + e);
        }
    }
     
    /** 
     * Calculate how many milliseconds have passed 
     * since last frame.
     * 
     * @return milliseconds passed since last frame 
     */
    public int getDelta() {
        long time = getTime();
        int delta = (int) (time - lastFrame);
        lastFrame = time;
  
        return delta;
    }
  
    /**
     * Get the accurate system time
     * 
     * @return The system time in milliseconds
     */
    public long getTime() {
        return (Sys.getTime() * 1000) / Sys.getTimerResolution();
    }
  
    /**
     * Calculate the FPS and set it in the title bar
     */
    public void updateFPS() {
        if (getTime() - lastFPS > 1000) {
            Display.setTitle("FPS: " + fps);
            fps = 0;
            lastFPS += 1000;
        }
        fps++;
    }
  
    public void initGL() {
        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glLoadIdentity();
        GL11.glOrtho(0, 800, 0, 600, 1, -1);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
    }
	 
    
    public static void main(String[] argv) {
        Start fullscreenExample = new Start();
        fullscreenExample.start();
        
    }
	
     public static void DrawImage(Texture texture,float x,float y, float width, float height){
		if(texture != null){
			texture.bind();
			
			glEnable(GL_BLEND);
			
			glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT  );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT  );
	
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE  );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE  );
   
         
	
			//set transparency
			glColor4f(1, 1, 1,1);
			//
			glTranslatef(x, y, 0);
			glBegin(GL_QUADS);
			glTexCoord2f(0, 0);
			glVertex2f(0, 0);
			glTexCoord2f(1, 0);
			glVertex2f(width, 0);
			glTexCoord2f(1, 1);
			glVertex2f(width, height);
			glTexCoord2f(0, 1);
			glVertex2f(0, height);
			glEnd();
			glLoadIdentity(); 
			
			
		}
	}
	
	
     public static Texture LoadTexture(String path,String fileType){
 		Texture tex = null;
 		InputStream in = ResourceLoader.getResourceAsStream(path);
 		try {
 			tex = TextureLoader.getTexture(fileType, in);
 		} catch (IOException e) {
 			// TODO Auto-generated catch block
 			e.printStackTrace();
 		}
 		return tex;
 		
 	}
	
	
	
	
	
	
	
	
	
}
0

Powinno być:

GL12.GL_CLAMP_TO_EDGE

Ale import to załatwia, żeby nie trzeba było pisać nazwy modułu:

import static org.lwjgl.opengl.GL12.*;

Poza tym jak podajesz kod "całej klasy", to nie obcinaj importów ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1