9

I draw patterns which have detailed pixels and they often face with Moire effect. I am not good at shading and I am not sure if this problem will be solved by shaders. I have not found any basic, understandable and complete example of shaders. Most of the tutorial websites start a program from the middle omitting the header file includes!

This is a MWE of my code. Is it possible to mitigate or remove the Moire effect from it?

#include <cmath>
#include <vector>

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

const int w=640,h=480;
float cam_angle=0.0f;

void init()
{
    GLfloat LightAmbient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
    GLfloat LightDiffuse[] = { 0.5f, 0.5f, 0.5f, 1.0f };
    GLfloat LightPosition[] = { 5.0f, 5.0f, -10.0f, 1.0f };

    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_DEPTH_TEST);
    glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
    glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
    glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
    glEnable(GL_LIGHT1);
}

void onDisplay()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (90, float(w)/float(h), 0.01, 10000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    const double pi=3.1415926;
    double cam_x=2.0*cos(pi/4.0)*cos(cam_angle);;
    double cam_y=2.0*sin(pi/4.0)*cos(cam_angle);;
    double cam_z=2.0*sin(cam_angle);
    gluLookAt(cam_x, cam_y, cam_z,  0, 0, 0, 0, 0, 1);

    struct Point3D
    {
        double x, y, z;
        unsigned char r, g, b, a=255;
    };

    for(double r=0.5;r<=1.0;r+=0.03)
    {
        std::vector<Point3D> points;
        for(int i=0;i<1000;i++)
        {
            double theta=double(i)/1000.0*pi*2.0;
            Point3D p;
            p.x=r*sin(theta);
            p.y=r*cos(theta);
            p.z=r;
            p.r=128;
            p.g=200;
            p.b=50;
            points.push_back(p);
        }
    // draw
        glPushMatrix();
        glColor3ub(255,255,255);
        glEnableClientState( GL_VERTEX_ARRAY );
        glEnableClientState( GL_COLOR_ARRAY );
        glVertexPointer(3, GL_DOUBLE, sizeof(Point3D), &points[0].x );
        glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(Point3D), &points[0].r );
        // glPointSize( 3.0 );
        glLineWidth(2.0);
        glDrawArrays( GL_LINE_STRIP, 0, int(points.size()) );
        glDisableClientState( GL_VERTEX_ARRAY );
        glDisableClientState( GL_COLOR_ARRAY );
        glPopMatrix();
    }

    glFlush();
    glutSwapBuffers();
}

void Timer(int /*value*/)
{
    cam_angle+=0.01f;
    glutPostRedisplay();
    // 100 milliseconds
    glutTimerFunc(100, Timer, 0);
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitWindowSize (w, h);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
    glutInitWindowPosition (100, 100);
    glutCreateWindow ("my window");
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    init();
    glutDisplayFunc(onDisplay);
    Timer(0);
    glutMainLoop();

    return 0;
}

Moire effect

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
ar2015
  • 5,558
  • 8
  • 53
  • 110
  • 1
    This loop `for(double r=0.5;r<=1.0;r+=0.03)` is not guaranteed to run the same number of times, depending on compiler, compiler settings, etc. Floating point is not exact, thus adding 0.03 to 0.5 will yield an inexact number and the error accumulates on each iteration. Use integer as loop counters, not floating point. – PaulMcKenzie Sep 24 '17 at 05:21
  • 1
    @PaulMcKenzie. It does not matter. All of the scenarios eventually lead to the Moire effect. – ar2015 Sep 24 '17 at 06:14
  • 1
    If you display detailed pixel patterns, with a resolution and location-period near the display resolution, then only fine tuned content (e.g. NOT having lines cross, NOT having pixel-wise "stepping" slopes....) will be free of Moire. You cannot solve the problem as long as you stick with pixel-precision and a few colors. The solution (though possibly not satisfying to you) is to either change the content or to start anti-aliasing and live with the sometimes "washed out" or "blurred" effect, both in comparison to the "sharp" and "precise" impression of single colored pixels. – Yunnosch Sep 24 '17 at 06:43
  • @Yunnosch, thanks a lot. Could you please explain them in more detail? – ar2015 Sep 24 '17 at 07:19
  • if you are not bound to lines you can use solid mesh instead with normals and lighting that would look much better and overcome your moire effect. With lines I would try change the color based on distance to camera or angle to light vector (either in shader or during mesh generation but the latter would need to recompute at any camera change) – Spektre Sep 24 '17 at 07:24
  • You seem to have missed the point, whatever you mean by "them". Let me try in a different way. Open your favoriute drawing software. Draw a few ellipses like those shown in your screen shot. That should demonstrate that the Moire effect is not an OpenGL problem, it is between pixels, your eyes and your brain processing the optical input. – Yunnosch Sep 24 '17 at 08:11
  • Another approach is to research "anti aliasing". I am not sure what you already read, but since you attempt OpenGL and probably have played some pretty-graphic games, I expect you basically know what it is. Just do the reading to learn doing it yourself. Hint: It is not easy. – Yunnosch Sep 24 '17 at 08:12
  • @ar2015 -- The reason for my comment is just that, a comment. You should avoid writing loops that are not determinate in terms of how many times the loop will iterate. The `for` loop could have been written `for (int r = 50; r <= 100; r+=3)` and divide `r` by 100 within the loop when doing the calculations. – PaulMcKenzie Sep 24 '17 at 15:48
  • @PaulMcKenzie, Thanks a lot Paul. – ar2015 Sep 24 '17 at 22:31

1 Answers1

5

If you use Multisampling, then the result will be significantly improved:

glutSetOption(GLUT_MULTISAMPLE, 8);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE | GLUT_MULTISAMPLE);

without GLUT_MULTISAMPLE:
enter image description here

with GLUT_MULTISAMPLE:
enter image description here


See also the answer to GLUT + OpenGL multisampling anti aliasing (MSAA)

Rabbid76
  • 202,892
  • 27
  • 131
  • 174