jzy3d-api icon indicating copy to clipboard operation
jzy3d-api copied to clipboard

Polygon not explicitely splitted as triangle may be badly rendered when alpha and small number of polygons

Open jzy3d opened this issue 3 years ago • 2 comments

In the below picture, the polygons are made of 4 points. OpenGL split the polygon in two triangle by itself but the two triangle do not have particular instruction for rendering order - which is annoying when depth buffer is intentionally disabled to perform alpha blending.

image

In this situation, the barycenter ordering strategy usually applied consider quads and not triangle (dots with number indicate the barycenter position and its distance to camera)

image

One fix would be to provide a jzy3d Polygon implementation that do not order quads but rather is a set of two triangle that would be independently ordered and rendered hence avoiding the glitch. There is an impact on performance as 100 polygons would lead to 200 triangles. Processing the ordering of triangles w.r.t. to camera position will be longer.

jzy3d avatar Apr 02 '21 14:04 jzy3d

Not sure this is related but the problem can be seen between polygons that seam to be far enough from each other and flat enough by themselves so that the disordered triangle hypothesis may not hold

Problem appears both on EmulGL and Native charts.

image

image

Drawing the distance of the barycenter shows that the red polygon is indeed considered more far from camera than the blue one (respectively 8.724e+05 and 8.629e+05)

image

For orthogonal projections, one improvement of the camera-barycenter distance processing could be to consider the distance between the barycenter and a plane representing the camera instead of the point of the camera. This may avoid adding extra distance to barycenter of long polygons.

jzy3d avatar Apr 02 '21 14:04 jzy3d

Code to reproduce the issue

import org.jzy3d.analysis.AWTAbstractAnalysis;
import org.jzy3d.analysis.AnalysisLauncher;
import org.jzy3d.analysis.IAnalysis;
import org.jzy3d.chart.factories.AWTChartFactory;
import org.jzy3d.chart.factories.ChartFactory;
import org.jzy3d.colors.Color;
import org.jzy3d.colors.ColorMapper;
import org.jzy3d.colors.DefaultColorMapperUpdatePolicy;
import org.jzy3d.colors.OrderingStrategyScoreColorMapper;
import org.jzy3d.colors.colormaps.ColorMapRainbow;
import org.jzy3d.colors.colormaps.ColorMapRainbowNoBorder;
import org.jzy3d.colors.colormaps.IColorMap;
import org.jzy3d.maths.Dimension;
import org.jzy3d.maths.Range;
import org.jzy3d.maths.Rectangle;
import org.jzy3d.plot3d.builder.Mapper;
import org.jzy3d.plot3d.builder.SurfaceBuilder;
import org.jzy3d.plot3d.builder.concrete.OrthonormalGrid;
import org.jzy3d.plot3d.primitives.Shape;
import org.jzy3d.plot3d.primitives.axis.layout.IAxisLayout;
import org.jzy3d.plot3d.rendering.canvas.Quality;
import org.jzy3d.plot3d.rendering.legends.AWTLegend;
import org.jzy3d.plot3d.rendering.legends.colorbars.AWTColorbarLegend;
import org.jzy3d.plot3d.rendering.scene.Graph;
import org.jzy3d.plot3d.rendering.view.annotation.CameraDistanceAnnotation;

public class FaceOrderingEmulGL2 extends AWTAbstractAnalysis {
  public static void main(String[] args) throws Exception {
    IAnalysis demo = new FaceOrderingEmulGL2();
    AnalysisLauncher.open(demo, new Rectangle(200, 200, 800, 600));
  }

  @Override
  public void init() {
    ChartFactory factory = new AWTChartFactory();
    //ChartFactory factory = new EmulGLChartFactory();
    init(factory);
  }

  protected void init(ChartFactory factory) {
    Quality q = Quality.Advanced();
    q.setDepthActivated(false); // WHEN ON : POOR, WHEN OFF = REQUIRES LOW ALPHA TO HIDE POLYGON ORDERING GLITCH
    //q.setDisableDepthBufferWhenAlpha(false); // PIRE QUE TOUT
    q.setPreserveViewportSize(false);
    
    float surfAlpha= 0.75f;

    
    
    final Shape surface = surface(surfAlpha);

    // Create a chart and add surface
    
    chart = factory.newChart(q);
    chart.getScene().getGraph().add(surface);

    
    //distanceColorMap(surface, chart.getAxisLayout(), chart.getScene().getGraph());

    //EmulGLPainter emulGL = (EmulGLPainter)chart.getPainter();
    //emulGL
    //chart.getView().getCamera().setViewportMode(ViewportMode.SQUARE);
    
    // grids
    //chart.getView().getCamera().setScreenGridDisplayed(true);
    //colorbar.setScreenGridDisplayed(true);
    colorbar.setMinimumSize(new Dimension(100,300));
    colorbar.setMinimumDimension(new Dimension(100,300));
    
    chart.addMouseCameraController();
    chart.setAnimated(true);
    
    chart.getView().getAnnotations().add(new CameraDistanceAnnotation(chart.getView(), Color.RED));
    //chart.getView().getAnnotations().add(BarycenterAnnotation.annotate(surface));
    //((AWTView) chart.getView()).addRenderer2d(new CameraEyeOverlayAnnotation(chart.getView()));

  }

  private Shape surface(float surfAlpha) {
    // Define a function to plot
    Mapper mapper = new Mapper() {
      @Override
      public double f(double x, double y) {
        return 10 * Math.sin(x / 10) * Math.cos(y / 20) * x;
      }
    };

    // Define range and precision for the function to plot
    Range range = new Range(-0, 100);
    int steps = 10;

    // Create the object to represent the function over the given range.
    final Shape surface =
        new SurfaceBuilder().orthonormal(new OrthonormalGrid(range, steps, range, steps), mapper);
    surface.setColorMapper(new ColorMapper(new ColorMapRainbow(), surface.getBounds().getZmin(),
        surface.getBounds().getZmax(), new Color(1, 1, 1, surfAlpha)));
    surface.setFaceDisplayed(true);
    surface.setWireframeDisplayed(true);
    Color w = Color.WHITE;
    w.alphaSelf(surfAlpha);
    surface.setWireframeColor(w);
    return surface;
  }
  
  public void distanceColorMap(Shape surface, IAxisLayout layout, Graph graph) {
    Color factor = new Color(1, 1, 1, 0.75f);
    // Color factor = new Color(1, 1, 1, 1f);

    IColorMap colormap = new ColorMapRainbowNoBorder();
    colormap.setDirection(false);

    ColorMapper colormapper = new OrderingStrategyScoreColorMapper(colormap,
        new DefaultColorMapperUpdatePolicy(), graph, factor);
    surface.setColorMapper(colormapper);
    surface.setWireframeDisplayed(false);

    AWTLegend colorbar = new AWTColorbarLegend(surface, layout);
    surface.setLegend(colorbar);
  }

}

jzy3d avatar Aug 11 '21 15:08 jzy3d