在 LibGDX 中模糊屏幕

问题描述 投票:0回答:2

我正在尝试为我的暂停菜单创建背景效果像这样。我当前的想法是在暂停时截取屏幕截图,保存它,打开它,对其进行高斯模糊,然后将其渲染到屏幕上并将菜单渲染在顶部。唯一的问题是我不知道如何有效地保存屏幕截图。

我尝试使用

batch.setColor(0,0,0,0.7f);
在背景上渲染褪色的图像,但它没有给我带来我正在寻找的模糊效果,而只是像我想象的那样提供色调。

非常感谢示例/文档。

编辑:找到此代码

package com.me.mygdxgame;

import java.awt.Point;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import com.badlogic.gdx.Application.ApplicationType;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.ScreenUtils;

public class ScreenShot {

    private static final int[] RGBA_OFFSETS = { 0, 1, 2, 3 };
    private static final int[] RGB_OFFSETS = { 0, 1, 2 };

    public static void saveScreenshot(String baseName) throws IOException {
        File createTempFile = File.createTempFile(baseName, ".png");
        saveScreenshot(createTempFile);
    }

    public static void saveScreenshot(File file) throws IOException {
        saveScreenshot(file, false);
    }

    public static void saveScreenshot(File file, boolean hasAlpha) throws IOException {
        if (Gdx.app.getType() == ApplicationType.Android)
            return;

        byte[] screenshotPixels = ScreenUtils.getFrameBufferPixels(true);

        int width = Gdx.graphics.getWidth();
        int height = Gdx.graphics.getHeight();

        saveScreenshot(file, screenshotPixels, width, height, hasAlpha);
    }

    public static void saveScreenshot(File file, byte[] pixels, int width, int height, boolean hasAlpha) throws IOException {
        DataBufferByte dataBuffer = new DataBufferByte(pixels, pixels.length);

        PixelInterleavedSampleModel sampleModel = new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, width, height, 4, 4 * width, getOffsets(hasAlpha));

        WritableRaster raster = Raster.createWritableRaster(sampleModel, dataBuffer, new Point(0, 0));

        BufferedImage img = new BufferedImage(getColorModel(hasAlpha), raster, false, null);

        ImageIO.write(img, "png", file);
    }

    private static ColorModel getColorModel(boolean alpha) {
        if (alpha)
            return new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] { 8, 8, 8, 8 }, true, false, ComponentColorModel.TRANSLUCENT, DataBuffer.TYPE_BYTE);
        return new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] { 8, 8, 8 }, false, false, ComponentColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
    }

    private static int[] getOffsets(boolean alpha) {
        if (alpha)
            return RGBA_OFFSETS;
        return RGB_OFFSETS;
    }

}

但是当我尝试

saveScreenshot("output");
时它给了我这个错误(运行桌面版本,如果这有影响的话。还没有在android上测试过)

Exception in thread "LWJGL Application" com.badlogic.gdx.utils.GdxRuntimeException: java.awt.image.RasterFormatException: Incorrect scanline stride: 3200
    at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:111)
Caused by: java.awt.image.RasterFormatException: Incorrect scanline stride: 3200

错误行:

ImageIO.write(img, "png", file);

java android libgdx blur
2个回答
14
投票

我参加聚会迟到了,但这正是您要找的:

https://github.com/mattdesl/lwjgl-basics/wiki/ShaderLesson5

使用着色器渲染到场缓冲区对象以创建模糊,然后将其从帧缓冲区绘制到屏幕上。


0
投票

我为 libgdx 创建了自己的高斯模糊实现。也许这对某人有用。只需将以下类添加到您的项目中即可:

package com.mygdx.game;

import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Color;
import java.lang.Math;

class Blur {
    private static double matrix [];
    private static int radius;

    public static void setMatrix(int radius, double sigma) {
        Blur.matrix = new double[radius+1];
        Blur.radius = radius;
        for(int i=0; i<=radius; i++)
            matrix[i] = gauss((double)i, sigma);
        double sum = 0;
        for(int i=-radius; i<=radius; i++)
            sum += matrix[Math.abs(i)];
        for(int i=0; i<=radius; i++)
            matrix[i]/=sum;
    }

    private static double gauss(double x, double sigma) {
        return 1/(sigma*Math.sqrt(2*Math.PI))*Math.exp(-(x*x)/(2*sigma*sigma));
    }

    public static Pixmap blur(Pixmap pixmap, boolean vertical) {
        int width = pixmap.getWidth();
        int height = pixmap.getHeight();
        Pixmap result = new Pixmap(width,height,Format.RGBA8888);

        for(int y=0; y<height; y++)
            for(int x=0; x<width; x++){
                float r=0,g=0,b=0,a=0;
                for(int i=-radius; i<=radius; i++) {
                    int px=x, py=y;
                    if(vertical)
                        py=mirrorTheEdge(py+i,height);
                    else 
                        px=mirrorTheEdge(px+i,width);
                    Color color = new Color(pixmap.getPixel(px,py));
                    float weight = (float)matrix[Math.abs(i)];
                    r+=color.r*weight;
                    g+=color.g*weight;
                    b+=color.b*weight;
                    a+=color.a*weight;
                }
                result.setColor(new Color(r,g,b,a));
                result.drawPixel(x,y);
            }

        return result;
    }

    private static int mirrorTheEdge(int p, int limit) {
        if(p<0) 
            p=p*-1-1;
        if(p>=limit) 
            p=limit*2-p+1;
        return p;
    }
}

这是一个使用示例:

package com.mygdx.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.ScreenUtils;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.files.FileHandle;

public class MyGdxGame extends ApplicationAdapter {
    SpriteBatch batch;
    Texture img;
    
    @Override
    public void create () {
        batch = new SpriteBatch();

        Pixmap pixmap = new Pixmap(new FileHandle("badlogic.jpg")); // Creating pixmap from file
        Blur.setMatrix(15,7.5); // Setting the blur strength
        pixmap = Blur.blur(pixmap,false); // Blurring the pixmap horizontally
        pixmap = Blur.blur(pixmap,true); // Blurring the pixmap vertically
        //pixmap = Blur.blur(Blur.blur(pixmap,false),true); // same in one line

        img = new Texture(pixmap);
    }

    @Override
    public void render () {
        ScreenUtils.clear(1, 0, 0, 1);
        batch.begin();
        batch.draw(img, 0, 0);
        batch.end();
    }
    
    @Override
    public void dispose () {
        batch.dispose();
        img.dispose();
    }
}

基本上,任何可以转换为像素图的东西都可以被模糊。要设置模糊强度,请使用 Blur.setMatrix(radius,sigma)。我不太明白,但这两个值越高,图像越模糊。如果您想对此进行优化,请记住半径越小越好。仅此而已。

© www.soinside.com 2019 - 2024. All rights reserved.