Reputation: 721
When ran, the program displays a 3D sphere rendered in a P3D environment in the PGraphics object 'g', which is shown by taking the rendered PGraphics object and displaying it through the image() method in the main graphics context, which happens to be P2D.
The purpose of the program is to show how window size doesn't always correlate with render size. If you play an old Widows98 game in full screen, the game most likely will be rendered at 480p no matter what, so taking it into full screen just decreases the pixels per inch, plus making the image appear blurry. Which is fine, since fullscreen at 480p is preferred over windowed mode ( esp. if you're on 4K X_X )
the mouse's y position in the window changes the 3d camera's field of view, and the x position changes the rendering resolution of the P3D context used to display the sphere. Additionally, the P3D context is drawn in the main (P2D) context through the image() method, and is 'forcefully'. displayed at the size of the window. So if the P3D render resolution is smaller than the window, then it will start to look blurry and more pixelated, and if the render resolution is larger, you get a strange sharpening effect.
Now, my program works fine as it is, but. Another purpose of the program is shadowed by this issue, it's how the 'crispness' of the sphere fades as the render resolution decreases. You might say that it's clearly shown, but what I'm looking for is an image where there is no "anti-alias" effect going on. I want the image to preserve the pixels as the resolution gets smaller, so you can see the actual shape of the sphere at say, 50 x 50 pixels.
The noSmooth() method doesn't seem to work, and before you tell me to just do
g.loadPixels();
and then do a double for loop to draw the raw pixels to the 2d context. No, it's sloppy. I know that there must be some reason why this blurring is going on. I'm hoping that it's the image() method and that I should be using a different method or I should add another method before it to remove image blurring.
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);
}
Upvotes: 0
Views: 556
Reputation: 51837
Replace g.noSmooth()
with ((PGraphicsOpenGL)g).textureSampling(2);
Credits go to Vallentin as I oddly enough had the same question with the P3D renderer
Upvotes: 2
Reputation: 42176
(Edit: This solution fixes the problem in the default renderer, but the OP is using the P2D renderer. The solution should be similar, so if somebody knows how to change the image interpolation mode in opengl, that's the answer.)
This is not really caused by anti-aliasing. It's caused by image scaling.
Also, it's much easier to help if you provide a MCVE, like this one:
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);
}
This code exhibits the same problem, but it's much easier to understand and work with.
Anyway, tracing through Processing's code, we can see that the image()
function eventually calls the imageImpl()
function in the PGraphics
class here.
This function then draws your image using this code:
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();
The endShape()
function is then implemented in the renderer, specifically the PGraphicsJava2D
class, which calls the drawShape()
function 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);
}
}
Finally, that shows us that the Graphics2D.fill()
function is being called, which is what actually draws your function.
The "problem" is that Graphics2D.fill()
is scaling your image using an algorithm that causes some blurriness. We can consult the Java API and Google to figure out how to fix that though.
Specifically, this tutorial shows you how to set various rendering hints to change the scaling algorithm. We can use that in Processing like this:
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);
}
First, we import the classes we're going to need. Then we get to the Graphics2D
instance in the renderer, and finally we call its setRenderingHint()
function. I wrapped it in an if(mousePressed)
so you could easily see the difference. When you click the mouse, interpolation is set to nearest neighbor, and you no longer see the blurriness.
Also notice that my code uses the g
variable that's inherited from the PApplet
superclass, so you would have to change your g
variable so it's no longer hiding it.
Upvotes: 1