I always rewriting some old 2D stuffs using old OpenGL glBegin/glEnd for use modern openGL statements.
I’m writing a fillOval
implementation using a fragment shader instead of pushing a lot of vertices for drawing my ellipse.
The idea is to paint a classic rectangle (2 triangles composition) and use a fragment shader that discard all fragment that is not inside the ellipse.
As is, i push on OpenGL in order to draw my ellipse :
- 4 vertices
- 6 indices
- 2 “vec2” uniforms
- the center of the ellipse
- the radius of the ellipse
my fragment shader (responsible to discard fragments) looks like this one:
#version 330
uniform vec2 u_centerOval;
uniform vec2 u_radiusOval;
layout(origin_upper_left) in vec4 gl_FragCoord;
out vec4 outputColor;
void checkFragment() {
/**
* Ellipse equation = (x/a)2 + (y/b)2 = 1
* a = horizontal radius
* b = vertical radius
*/
float e1 = ( gl_FragCoord.x - u_centerOval.x ) / ( u_radiusOval.x );
float e2 = ( gl_FragCoord.y - u_centerOval.y ) / ( u_radiusOval.y );
float d = (e1 * e1) + (e2 * e2);
if( d > 1 ) {
outputColor = vec4(1.0 , 0.0 , 0.0 , 1.0 ); // discard;
}
}
So, it works not so bad. I have an “aliasing” issue, but i will see this later.
But now, if i paint with this statement:
g2d.setColor( Color.YELLOW );
g2d.fillOval( 400 , 50 , 200 , 100 );
But if i apply an affine transformation like this:
g2d.transform( AffineTransform.identity().rotate( 0.2f , 400 + 100 , 50 + 50 ) );
g2d.setColor( Color.YELLOW );
g2d.fillOval( 400 , 50 , 200 , 100 );
g2d.setTransform( null );
That’s quite normal since my fragment shader don’t take in account my affine transform.
It’s only my vertex shader that use it (and it rotate the rectangle as well).
i should inverse my transformation on gl_FragCoord in order to compute the ellipse equation ?
It’s a pain, all matrices are not invertible. I can pass it as an uniform.
Have you a better idea ?
At this point, maybe this technical approach is completely crazy but at first thinking i found it quite fun.
Best regards,
Sébastien.