如何在创建小于窗口的PGraphics对象时避免“抗锯齿效果”,然后将其缩放到窗口大小?

时间:2017-04-01 01:40:33

标签: java processing antialiasing

运行时,程序会在PGraphics对象'g'中显示在P3D环境中渲染的3D球体,通过获取渲染的PGraphics对象并通过主图形上下文中的image()方法显示它。碰巧是P2D。

该程序的目的是显示窗口大小与渲染大小的关系并不总是如此。如果您全屏播放旧的Widows98游戏,游戏最有可能以480p呈现,无论如何,所以将其全屏显示只会降低每英寸的像素,并使图像看起来模糊。这很好,因为480p的全屏优先于窗口模式(特别是如果你使用的是4K X_X)

鼠标在窗口中的y位置会更改3d摄像机的视野,x位置会更改用于显示球体的P3D上下文的渲染分辨率。此外,P3D上下文通过image()方法在主(P2D)上下文中绘制,并且是“强制”的。以窗口大小显示。因此,如果P3D渲染分辨率小于窗口,则它将开始看起来模糊且更像素化,并且如果渲染分辨率更大,则会产生奇怪的锐化效果。

现在,我的程序工作正常,但是。该程序的另一个目的是被这个问题所掩盖,这就是随着渲染分辨率的降低,球体的“清晰度”逐渐消失。你可能会说它清楚地显示出来了,但我正在寻找的是一个没有“消除别名”效果的图像。我希望图像在分辨率变小时保留像素,因此您可以看到球体的实际形状,例如50 x 50像素。

noSmooth()方法似乎不起作用,在你告诉我做

之前
g.loadPixels();

然后执行双循环以将原始像素绘制到2d上下文。不,这很草率。我知道必须有一些理由说明为什么会出现这种模糊现象。我希望它是image()方法,我应该使用不同的方法,或者我应该在它之前添加另一个方法来删除图像模糊。

PGraphics g;

void setup(){
  size(1000,1000,P2D);
  frameRate(1000);
  noSmooth();
}

void draw(){
  background(200);
  float res = map(mouseX,0,width,0.75,128);
  if (res==0) {
    res=1;
  }

  g = createGraphics((int)(width/res),(int)(height/res),P3D);
  g.noSmooth(); // is this thing working?????
  float cameraZ = ((height/2.0) / tan(PI*60.0/360.0));

  g.beginDraw();
    g.perspective(radians(map(mouseY,0,height,0.1,160)), width/height, cameraZ/10.0, cameraZ*10.0);
    g.camera(g.width/2.0, g.height/2.0, (height/2.0) / tan(PI*30.0 / 180.0), g.width/2.0, g.height/2.0, 0, 0, 1, 0);

    g.background(200);
    g.translate(g.width/2 ,g.height/2);
    g.sphere(100);
  g.endDraw();

  image(g, 0, 0, width, height); // this is where it all comes together
  text("rendering resolution: "+g.width+" x "+g.height,0,14);
  text("fps: "+frameRate,0,14*2);
}

2 个答案:

答案 0 :(得分:2)

g.noSmooth()替换为((PGraphicsOpenGL)g).textureSampling(2);

积分转到Vallentin因为奇怪的是我对P3D渲染器有同样的问题

答案 1 :(得分:1)

编辑:此解决方案修复了默认渲染器中的问题,但OP正在使用P2D渲染器。解决方案应该类似,所以如果有人知道如何更改图像插值模式opengl,这就是答案。)

这实际上并不是由抗锯齿引起的。它是由image scaling引起的。

此外,如果您提供MCVE,则可以更轻松地提供帮助,如下所示:

PGraphics buffer;

void setup() {

  size(1000, 1000);

  buffer = createGraphics(100, 100);
  buffer.noSmooth();
  buffer.beginDraw();
  buffer.background(255);
  buffer.line(0, 0, width, height);
  buffer.endDraw();
}

void draw() {    
  background(0);
  image(buffer, 0, 0, mouseX, mouseY);
}

此代码表现出同样的问题,但理解和使用起来要容易得多。

blurry image

无论如何,通过Processing's code进行追踪,我们可以看到image()函数最终调用imageImpl()here中的PGraphics函数。

然后,此函数使用以下代码绘制图像:

beginShape(QUADS);
texture(img);
vertex(x1, y1, u1, v1);
vertex(x1, y2, u1, v2);
vertex(x2, y2, u2, v2);
vertex(x2, y1, u2, v1);
endShape();

然后在渲染器中实现endShape()函数,特别是PGraphicsJava2D类,它调用drawShape()函数here

protected void drawShape(Shape s) {
    if (fillGradient) {
      g2.setPaint(fillGradientObject);
      g2.fill(s);
    } else if (fill) {
      g2.setColor(fillColorObject);
      g2.fill(s);
    }
    if (strokeGradient) {
      g2.setPaint(strokeGradientObject);
      g2.draw(s);
    } else if (stroke) {
      g2.setColor(strokeColorObject);
      g2.draw(s);
    }
}

最后,这告诉我们正在调用Graphics2D.fill()函数,这实际上是在绘制函数。

“问题”是Graphics2D.fill()正在使用导致某些模糊的算法缩放图像。我们可以咨询the Java API和Google以了解如何解决这个问题。

具体来说,this tutorial向您展示了如何设置各种渲染提示以更改缩放算法。我们可以在Processing中使用它:

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import processing.awt.PGraphicsJava2D;

PGraphics buffer;

void setup() {

  size(1000, 1000);

  buffer = createGraphics(100, 100);
  buffer.noSmooth();
  buffer.beginDraw();
  buffer.background(255);
  buffer.line(0, 0, width, height);
  buffer.endDraw();
}

void draw() {

  if (mousePressed) {
    Graphics2D g2d = ((PGraphicsJava2D)g).g2;

    g2d.setRenderingHint(
      RenderingHints.KEY_INTERPOLATION, 
      RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
  }

  background(0);
  image(buffer, 0, 0, mouseX, mouseY);
}

首先,我们导入我们需要的类。然后我们到达渲染器中的Graphics2D实例,最后调用它的setRenderingHint()函数。我把它包裹在if(mousePressed)中,这样你就可以很容易地看到差异。单击鼠标时,插值设置为最近邻居,您不再看到模糊。

clear image

另请注意,我的代码使用的是继承自g超类的PApplet变量,因此您必须更改g变量,以便它不再隐藏它。