LWJGL倾斜纹理



我试图使用LWJGL的纹理,结果发现RBG png有点歪斜。示例:原始图片/纹理

加载的代码是lwjgl wiki空间入侵者示例的98%。。Texture.java:

public int target, textureID, height, width, texWidth, texHeight;
private float widthRatio, heightRatio;
public Texture(int target, int textureID) {
    this.target = target;
    this.textureID = textureID;
}
public void bind() {
    GL11.glBindTexture(target, textureID);
}
public void setWidth(int width) {
    this.width = width;
    setWidth();
}
public void setHeight(int height) {
    this.height = height;
    setHeight();
}
public int getImageWidth() {
    return width;
}
public int getImageHeight() {
    return height;
}
public float getWidth() {
    return widthRatio;
}
public float getHeight() {
    return heightRatio;
}
public void setTextureWidth(int texWidth) {
    this.texWidth = texWidth;
    setWidth();
}
public void setTextureHeight(int texHeight) {
    this.texHeight = texHeight;
    setHeight();
}
private void setWidth() {
    if (texWidth != 0)
        widthRatio = ((float) width) / texWidth;
}
private void setHeight() {
    if (texHeight != 0)
        heightRatio = ((float) height) / texHeight;
}

TextureLoader.java:

private static HashMap<String, Texture> table = new HashMap<String, Texture>();
    private static ColorModel glAlphaColorModel, glColorModel;
    private static IntBuffer textureIDBuffer = BufferUtils.createIntBuffer(1);
    static {
        glAlphaColorModel = new ComponentColorModel(
                ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] { 8, 8,
                        8, 8 }, true, false, ComponentColorModel.TRANSLUCENT,
                DataBuffer.TYPE_BYTE);
        glColorModel = new ComponentColorModel(
                ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] { 8, 8,
                        8, 0 }, false, false, ComponentColorModel.OPAQUE,
                DataBuffer.TYPE_BYTE);
    }
    private static int createTextureID() {
        GL11.glGenTextures(textureIDBuffer);
        return textureIDBuffer.get(0);
    }
    public static Texture getTexture(String name, BufferedImage image)
            throws IOException {
        Texture tex = table.get(name);
        if (tex != null)
            return tex;
        tex = getTexture(image, GL11.GL_TEXTURE_2D, GL11.GL_RGBA,
                GL11.GL_LINEAR, GL11.GL_LINEAR);
        table.put(name, tex);
        return tex;
    }
    public static Texture getTexture(BufferedImage image, int target,
            int dstPixelFormat, int minFilter, int magFilter)
            throws IOException {
        int srcPixelFormat;
        int textureID = createTextureID();
        Texture texture = new Texture(target, textureID);
        GL11.glBindTexture(target, textureID);
        texture.setWidth(image.getWidth());
        texture.setHeight(image.getHeight());
        if (image.getColorModel().hasAlpha())
            srcPixelFormat = GL11.GL_RGBA;
        else
            srcPixelFormat = GL11.GL_RGB;
        ByteBuffer textureBuffer = convertImageData(image, texture);
        if (target == GL11.GL_TEXTURE_2D) {
            GL11.glTexParameteri(target, GL11.GL_TEXTURE_MIN_FILTER, minFilter);
            GL11.glTexParameteri(target, GL11.GL_TEXTURE_MAG_FILTER, magFilter);
        }
        GL11.glTexImage2D(target, 0, dstPixelFormat, image.getWidth(),
                image.getHeight(), 0, srcPixelFormat,
                GL11.GL_UNSIGNED_BYTE, textureBuffer);
        return texture;
    }
    private static ByteBuffer convertImageData(BufferedImage bufferedImage,
            Texture texture) {
        ByteBuffer imageBuffer;
        WritableRaster raster;
        BufferedImage texImage;
        int texWidth = bufferedImage.getWidth();
        int texHeight = bufferedImage.getHeight();
        texture.setTextureHeight(texHeight);
        texture.setTextureWidth(texWidth);
        if (bufferedImage.getColorModel().hasAlpha()) {
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
                    texWidth, texHeight, 4, null);
            texImage = new BufferedImage(glAlphaColorModel, raster, false,
                    new Hashtable());
        } else {
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
                    texWidth, texHeight, 3, null);
            texImage = new BufferedImage(glColorModel, raster, false,
                    new Hashtable());
        }
        Graphics g = texImage.getGraphics();
        g.setColor(new Color(0f, 0f, 0f, 0f));
        g.fillRect(0, 0, texWidth, texHeight);
        g.drawImage(bufferedImage, 0, 0, null);
        // texImage is NOT skewed at this point
        byte[] data = ((DataBufferByte) texImage.getRaster().getDataBuffer())
                .getData();
        imageBuffer = ByteBuffer.allocateDirect(data.length);
        imageBuffer.order(ByteOrder.nativeOrder());
        imageBuffer.put(data, 0, data.length);
        imageBuffer.flip();
        return imageBuffer;
    }

我知道这是一个老问题,但我刚才自己也遇到过。希望其他人会受益,假设你已经自己解决了这个问题。

纹理扭曲和变色的原因是它没有与UNPACK_ALIGNMENT正确对齐。据我所知,每行中的字节数必须是UNPACK_ALIGNMENT设置为(默认为4(的倍数。

对于4分量格式,这不是问题,因为每个像素由4个字节组成,所以任何维度的图像都是正确对齐的。但对于其他格式,数据会被填充以保持正确对齐,这会导致这样的问题。

您可以更改图像的大小,使其正确对齐((width * formatComponents) % 4 == 0),将格式更改为4组件格式,或者使用将UNPACK_ALIGNMENT更改为不填充图像的格式

glPixelStore(GL_UNPACK_ALIGNMENT, alignment); //Alignment must be 1, 2, 4, or 8

http://www.opengl.org/wiki/Common_Mistakes#Texture_upload_and_pixel_reads

您可能会遇到PNG如何存储在文件中以及Java如何加载的问题。我不确定我以前是否经历过这个问题,但我知道我曾在LWJGL中加载图像时遇到过问题。这是我整理的一个类,它可以确保PNG转换为OpenGL可以理解的格式,而不会出现倾斜或颜色问题。作为警告,这对我的PNG有效,但BufferedImage可能有很多格式,我不相信这段代码涵盖所有情况。希望这能帮到你。它应该是完全独立的,除了另一个类(SimpleTexture(,我也将在这里为您提供它。请注意,BasicTextureLoader类实际上是一个Runnable,因为它最初是为在后台加载纹理而设计的。

import org.lwjgl.opengl.OpenGLException;
import javax.imageio.ImageIO;
import static org.lwjgl.opengl.GL11.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.IOException;
import java.net.URL;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
 * User: FreezerburnVinny
 * Date: 1/1/12
 * Time: 5:59 PM
 */
public class BasicTextureLoader implements Runnable {
    public SimpleTexture texture;
    public BufferedImage image;
    public int width, height;
    protected String mFile;
    protected boolean mShouldRemoveBackground, mKeepBufferedImage;
    public BasicTextureLoader( String file, boolean shouldRemoveBackground ) {
        mFile = file;
        this.texture = null;
        this.width = 0;
        this.height = 0;
        this.mShouldRemoveBackground = shouldRemoveBackground;
        this.mKeepBufferedImage = false;
    }
    public BasicTextureLoader( String file, boolean shouldRemoveBackground, boolean keepBufferedImage ) {
        mFile = file;
        this.texture = null;
        this.width = 0;
        this.height = 0;
        this.mShouldRemoveBackground = shouldRemoveBackground;
        this.mKeepBufferedImage = keepBufferedImage;
    }
     protected ByteBuffer convertBufferedImageToByteBuffer( BufferedImage image ) {
        ByteBuffer buffer = ByteBuffer.allocateDirect( width * height * 4 );
        buffer.order( ByteOrder.nativeOrder() );
        byte[] bytes = ( (DataBufferByte) image.getRaster().getDataBuffer() ).getData();
        switch( image.getType() ) {
            case BufferedImage.TYPE_3BYTE_BGR:
                convertBGRBufferedImageToByteBuffer( buffer, bytes );
                break;
            case BufferedImage.TYPE_4BYTE_ABGR:
                convertABGRBufferedImageToByteBuffer( buffer, bytes );
                break;
            case BufferedImage.TYPE_4BYTE_ABGR_PRE:
                convertBGRBufferedImageToByteBuffer( buffer, bytes );
                break;
            case BufferedImage.TYPE_INT_ARGB:
                convertARGBBufferedImageToByteBuffer( buffer, bytes );
                break;
            case BufferedImage.TYPE_INT_BGR:
                convertBGRBufferedImageToByteBuffer( buffer, bytes );
                break;
            case BufferedImage.TYPE_INT_RGB:
                convertRGBBufferedImageToByteBuffer( buffer, bytes );
                break;
            case 12:
                convertRGBBufferedImageToByteBuffer( buffer, bytes );
                break;
            default:
                throw new OpenGLException( "Unsupported image type: " + image.getType() );
        }
        return buffer;
    }
    protected void convertARGBBufferedImageToByteBuffer( ByteBuffer buffer, byte[] bytes ) {
        byte backgrounda = (byte) 255;
        byte backgroundr = (byte) 255;
        byte backgroundg = (byte) 255;
        byte backgroundb = (byte) 255;
        for( int i = 0; i < bytes.length; i+=4 ) {
            byte alpha = bytes[ i ];
            byte red = bytes[ i + 1 ];
            byte green = bytes[ i + 2 ];
            byte blue = bytes[ i + 3 ];
            if( mShouldRemoveBackground ) {
                if( i == 0 ) {
                    backgrounda = alpha;
                    backgroundr = red;
                    backgroundg = green;
                    backgroundb = blue;
                }
                else if( alpha == backgrounda && red == backgroundr &&
                        green == backgroundg && blue == backgroundb ) {
                    alpha = 0;
                }
            }
            buffer.put( red );
            buffer.put( green );
            buffer.put( blue );
            buffer.put( alpha );
        }
        buffer.rewind();
    }
    protected void convertABGRBufferedImageToByteBuffer( ByteBuffer buffer, byte[] bytes ) {
        byte backgrounda = (byte) 255;
        byte backgroundr = (byte) 255;
        byte backgroundg = (byte) 255;
        byte backgroundb = (byte) 255;
//        System.err.println( buffer.limit() );
        for( int i = 0; i < bytes.length; i+=4 ) {
            byte alpha = bytes[ i ];
            byte blue = bytes[ i + 1 ];
            byte green = bytes[ i + 2 ];
            byte red = bytes[ i + 3 ];
            if( mShouldRemoveBackground ) {
                if( i == 0 ) {
                    backgrounda = alpha;
                    backgroundr = red;
                    backgroundg = green;
                    backgroundb = blue;
                }
                else if( alpha == backgrounda && red == backgroundr &&
                        green == backgroundg && blue == backgroundb ) {
                    alpha = 0;
                }
            }
            buffer.put( red );
            buffer.put( green );
            buffer.put( blue );
            buffer.put( alpha );
        }
        buffer.rewind();
    }
    protected void convertBGRBufferedImageToByteBuffer( ByteBuffer buffer, byte[] bytes ) {
        byte backgrounda = (byte) 255;
        byte backgroundr = (byte) 255;
        byte backgroundg = (byte) 255;
        byte backgroundb = (byte) 255;
        for( int i = 0; i < bytes.length; i+=3 ) {
            byte blue = bytes[ i ];
            byte green = bytes[ i + 1 ];
            byte red = bytes[ i + 2 ];
            byte alpha = (byte) 0xFF;
            buffer.put( red );
            buffer.put( green );
            buffer.put( blue );
            if( mShouldRemoveBackground ) {
                if( i == 0 ) {
                    backgrounda = alpha;
                    backgroundr = red;
                    backgroundg = green;
                    backgroundb = blue;
                }
                else if( alpha == backgrounda && red == backgroundr &&
                        green == backgroundg && blue == backgroundb ) {
                    alpha = 0;
                }
            }
            buffer.put( alpha );
        }
        buffer.rewind();
    }
    protected void convertRGBBufferedImageToByteBuffer( ByteBuffer buffer, byte[] bytes ) {
        byte backgrounda = (byte) 255;
        byte backgroundr = (byte) 255;
        byte backgroundg = (byte) 255;
        byte backgroundb = (byte) 255;
        for( int i = 0; i < bytes.length; i+=3 ) {
            byte red = bytes[ i ];
            byte green = bytes[ i + 1 ];
            byte blue = bytes[ i + 2 ];
            byte alpha = (byte) 0xFF;
            buffer.put( red );
            buffer.put( green );
            buffer.put( blue );
            if( mShouldRemoveBackground ) {
                if( i == 0 ) {
                    backgrounda = alpha;
                    backgroundr = red;
                    backgroundg = green;
                    backgroundb = blue;
                }
                else if( alpha == backgrounda && red == backgroundr &&
                        green == backgroundg && blue == backgroundb ) {
                    alpha = 0;
                }
            }
            buffer.put( alpha );
        }
        buffer.rewind();
    }
    protected int nextPowerOf2( int num ) {
        int ret = 2;
        while( ret < num ) ret *= 2;
        return ret;
    }
    protected int genTextureFromBufferedImage( BufferedImage image ) {
        int tex = -1;
        try {
//            width = nextPowerOf2( image.getWidth() );
//            height = nextPowerOf2( image.getHeight() );
            width = image.getWidth();
            height = image.getHeight();
            ByteBuffer imageBuffer = convertBufferedImageToByteBuffer( image );
            tex = glGenTextures();
            glBindTexture( GL_TEXTURE_2D, tex );
            glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height,
                    0, GL_RGBA, GL_UNSIGNED_BYTE, imageBuffer );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
        }
        catch( IndexOutOfBoundsException e ) {
            e.printStackTrace();
            glDeleteTextures( tex );
            tex = -1;
        }
        catch( OpenGLException e ) {
            e.printStackTrace();
            glDeleteTextures( tex );
            tex = -1;
        }
        return tex;
    }
    protected int genTexture( String file ) {
        try {
            if( System.getProperty( "os.name" ).toLowerCase().contains( "win"  ) ) {
                String fileName = System.getProperty( "user.dir" );
                fileName = fileName.substring( 2 );
                fileName = "file:" + fileName + "\" + file;
                image = ImageIO.read( new URL( fileName ) );
            }
            else {
                String fileName = "file:" + System.getProperty( "user.dir" ) + "/" + file;
//                System.err.println( fileName );
                image = ImageIO.read( new URL( fileName ) );
            }
            return genTextureFromBufferedImage( image );
        }
        catch( IOException e ) {
            e.printStackTrace();
        }
        // If we reach here, an error happened
        return -1;
    }
    @Override
    public void run() {
        texture = new SimpleTexture( GL_TEXTURE_2D, genTexture( mFile ) );
        if( !mKeepBufferedImage ) {
            image.flush();
            image = null;
        }
        texture.setWidth( width );
        texture.setHeight( height );
    }
}

以及SimpleTexture类:

import org.lwjgl.opengl.GL11;
/**
 * Author: FreezerburnVinny
 * Date: 1/5/12
 * Time: $(TIME}
 */
public class SimpleTexture extends Texture {
    private int mTarget, mName;
    private double mWidth, mHeight;
    private double mx1, mx2, my1, my2;
    public SimpleTexture( int target, int name ) {
        this.mTarget = target;
        this.mName = name;
        this.mWidth = 0.0;
        this.mHeight = 0.0;
        this.mx1 = 0.0;
        this.mx2 = 1.0;
        this.my1 = 0.0;
        this.my2 = 1.0;
    }
    public SimpleTexture( int target, int name, double width, double height ) {
        this.mTarget = target;
        this.mName = name;
        this.mWidth = width;
        this.mHeight = height;
    }
    public SimpleTexture( int target, int name, double width, double height,
                          double x1, double x2, double y1, double y2 ) {
        this.mTarget = target;
        this.mName = name;
        this.mWidth = width;
        this.mHeight = height;
        this.mx1 = x1;
        this.mx2 = x2;
        this.my1 = y1;
        this.my2 = y2;
    }
    public double getTexCoordx1() { return mx2; }
    public double getTexCoordy1() { return my1; }
    public double getTexCoordx2() { return mx2; }
    public double getTexCoordy2() { return my2; }
    public double getTexCoordx3() { return mx1; }
    public double getTexCoordy3() { return my2; }
    public double getTexCoordx4() { return mx1; }
    public double getTexCoordy4() { return my1; }
    public double getWidth() { return mWidth; }
    public double getHeight()  { return mHeight; }
    public int getName() { return mName; }
    public int getTarget() { return mTarget; }
    public void setWidth( double width ) { this.mWidth = width; }
    public void setHeight( double height) { this.mHeight = height; }
    public void bind() {
        if( Texture.lastBound != mName ) {
            GL11.glBindTexture( mTarget, mName );
            Texture.lastBound = mName;
        }
    }
    public boolean isValidTexture() {
        if( mName == -1 ) return false;
        return GL11.glIsTexture( mName );
    }
    @Override
    public void restart() {
    }
    @Override
    public void pause() {
    }
    @Override
    public void resume() {
    }
    @Override
    public void stopAt( int frame ) {
    }
    @Override
    public void stopAfterFullCycle() {
    }
    @Override
    public int numFrames() {
        return 1;
    }
}

编辑:哇,差点忘了SimpleTexture依赖于Texture类。给你:

/**
 * Author: FreezerburnVinny
 * Date: 1/10/12
 * Time: $(TIME}
 */
public abstract class Texture {
    protected static int lastBound = -1;
    public abstract double getTexCoordx1();
    public abstract double getTexCoordx2();
    public abstract double getTexCoordx3();
    public abstract double getTexCoordx4();
    public abstract double getTexCoordy1();
    public abstract double getTexCoordy2();
    public abstract double getTexCoordy3();
    public abstract double getTexCoordy4();
    public abstract double getWidth();
    public abstract double getHeight();
    public abstract int getName();
    public abstract int getTarget();
    public abstract void setWidth( double width );
    public abstract void setHeight( double height );
    public abstract void bind();
    public abstract boolean isValidTexture();
    public abstract void restart();
    public abstract void pause();
    public abstract void resume();
    public abstract void stopAt( int frame );
    public abstract void stopAfterFullCycle();
    public abstract int numFrames();
}

相关内容

  • 没有找到相关文章

最新更新