7

I have drawn the Barth sextic with Haskell OpenGL and there's a problem. I have also drawn it in R (with packages rgl and misc3d) and there's no problem. The two algorithms (in Haskell and R) are very similar. The Barth sextic is an implicit surface, and in Haskell I compute a triangulation of this surface with a marching cubes algorithm that I got by translating the one of misc3d to Haskell and C. I use the vertex normals, each defined by the gradient of the implicit equation.

Here is the problem:

enter image description here

I don't want these black shadows. When I look at the back of the sextic, by a 180° rotation, there's no such shadow:

enter image description here

The full code is available in this Github repo. Here are the parts of the code relevant to the colors:

fuchsia :: Color4 GLfloat
fuchsia = Color4 1.00 0.00 1.00 1
discord :: Color4 GLfloat
discord = Color4 0.21 0.22 0.25 1

  renderPrimitive Triangles $ mapM_ drawTriangle triangles
  swapBuffers
  where
    drawTriangle ((v1,v2,v3), (n1,n2,n3)) = do
      materialDiffuse FrontAndBack $= fuchsia
      normal n1
      vertex v1
      normal n2
      vertex v2
      normal n3
      vertex v3

  clearColor $= discord
  materialAmbient FrontAndBack $= black
  materialDiffuse FrontAndBack $= white
  materialEmission FrontAndBack $= black
  lighting $= Enabled
  lightModelTwoSide $= Enabled
  light (Light 0) $= Enabled
  position (Light 0) $= Vertex4 0 0 (-1000) 1
  ambient (Light 0) $= white
  diffuse (Light 0) $= white
  specular (Light 0) $= white

I have tried to change the colors in this last piece of code, but no way to get rid of these shadows. Am I doing something bad with the colors? I am sure the normals are correct because this works in R. However the shadows appear where the surface is not smooth, so I'm wondering whether the issue is caused by the normals.

The R rendering:

gfycat

Edit

I have managed to get rid of these shadows:

enter image description here

I don't really know how, I've done so many attempts... But anyway, now the problem is that the back of the sextic is too lighty:

enter image description here

Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
  • 1
    Color-debug the normals – Nadir Nov 16 '18 at 10:30
  • @Nadir What do you mean? – Stéphane Laurent Nov 16 '18 at 10:37
  • 1
    Instead of drawing the shaded color of your implicit surface, set the color output as if the normal vector would be a color. – Nadir Nov 16 '18 at 11:08
  • 1
    The thing is that the real normals of the surface are changing too quickly and the coarse triangulation cannot reproduce them. Therefore, one thing you can try is to increase the Marching Cubes resolution. Cusps like these are always problematic for per-vertex normals since you cannot reasonably interpolate them. A second option would be to leave them as corners and duplicate the vertices using separate normals (which you evaluate a bit off the vertex inside the face). – Nico Schertler Nov 16 '18 at 13:46
  • @NicoSchertler Yes indeed, this is better when I increase the resolution. But I'm wondering why this issue does not occur with `rgl` in R (I've just edited my post to add the `rgl` rendering). I use the same resolution and the same normals, and the marching cubes algorithm is the same as well. The `rgl` package is also based on `OpenGL` (I think, I should check), so I'm wondering whether there's a default option set in `rgl` and that I don't set in Haskell. – Stéphane Laurent Nov 16 '18 at 14:00
  • Might rgl use flat shading? It is hard to see from the screenshot. – Nico Schertler Nov 16 '18 at 14:20
  • @NicoSchertler No, it uses smooth shading. I've tried the flat shading and the result is ugly. – Stéphane Laurent Nov 16 '18 at 14:42
  • 1
    That's really weird. I observe a similar behavior when there's only one light, at (0,0,0), which is the center of the object. – Stéphane Laurent Nov 16 '18 at 17:05
  • I don't know if this is what is causing it, but it might be: You should set the position of the light to be a bit off-center; put it where the sun might be. Try e.g. `Vertex4 500 500 (-1000)` and see how it looks. – luqui Nov 16 '18 at 20:08
  • @NicoSchertler Please take a look at my edit. Now the front view is nice, but the back view is too bright. Do you have an idea that would help to decrease this brightness ? I really don't understand why there is this difference. The front view and the back view (i.e. the 180° rotated front view) are exposed to the light in the same way. – Stéphane Laurent Nov 17 '18 at 10:21

1 Answers1

2

Now the rendering is nice :-)

enter image description here

I don't know what caused the problem because I have done numerous changes... Here are the relevant parts of the code:

resize :: Double -> Size -> IO ()
resize zoom s@(Size w h) = do
  viewport $= (Position 0 0, s)
  matrixMode $= Projection
  loadIdentity
  perspective 45.0 (w'/h') 1.0 100.0
  lookAt (Vertex3 0 0 (-6+zoom)) (Vertex3 0 0 0) (Vector3 0 1 0)
  matrixMode $= Modelview 0
  where
    w' = realToFrac w
    h' = realToFrac h

main :: IO ()
main = do
  _ <- getArgsAndInitialize
  _ <- createWindow "Barth Sextic"
  windowSize $= Size 500 500
  initialDisplayMode $= [RGBMode, DoubleBuffered, WithDepthBuffer]
  clearColor $= discord
  clientState ColorArray $= Disabled -- this is a default option, I think
  materialAmbient Front $= black
  materialDiffuse Front $= white
  materialEmission Front $= Color4 0 0 0 0
  materialSpecular Front $= white
  materialShininess Front $= 50
  lighting $= Enabled
  light (Light 0) $= Enabled
  position (Light 0) $= Vertex4 500 500 (-1000) 1
  diffuse (Light 0) $= white
  specular (Light 0) $= white
  lightModelAmbient $= Color4 0.35 0.35 0.35 1
  depthMask $= Enabled -- this is default option
  depthFunc $= Just Lequal
  shadeModel $= Smooth
  fog $= Disabled -- this is default option, I think
  polygonMode $= (Fill, Fill) -- this is default option
  polygonSmooth $= Enabled
  cullFace $= Just Front
  rescaleNormal $= Enabled
  ......

I have also changed the order of the vertices of each triangle:

drawTriangle ((v1,v2,v3), (n1,n2,n3)) = do
  materialDiffuse Front $= fuchsia
  normal n1
  vertex v1
  normal n3
  vertex v3
  normal n2
  vertex v2

This answer is a bit premature. I will investigate more later, and I'll edit to write my findings.

EDIT

Well, I have done further investigations and sadly, my conclusion is that I have no explanation: I have reverted all my changes, and no way to reproduce the issue !!

Now I use this shorter code:

display :: ...... -> displayCallback
  ......
  renderPrimitive Triangles $
    mapM_ drawTriangle triangles
  swapBuffers
  where
    drawTriangle ((v1,v2,v3), (n1,n2,n3)) = do
      materialDiffuse Front $= fuchsia
      normal n1
      vertex v1
      normal n2
      vertex v2
      normal n3
      vertex v3

resize :: Double -> Size -> IO ()
resize zoom s@(Size w h) = do
  viewport $= (Position 0 0, s)
  matrixMode $= Projection
  loadIdentity
  perspective 45.0 (w'/h') 1.0 100.0
  lookAt (Vertex3 0 0 (-6+zoom)) (Vertex3 0 0 0) (Vector3 0 1 0)
  matrixMode $= Modelview 0
  where
    w' = realToFrac w
    h' = realToFrac h

The two MatrixMode are important.

main :: IO ()
main = do
  _ <- getArgsAndInitialize
  _ <- createWindow "Barth Sextic"
  windowSize $= Size 500 500
  initialDisplayMode $= [RGBMode, DoubleBuffered, WithDepthBuffer]
  clearColor $= discord
  materialAmbient Front $= black
  materialDiffuse Front $= white
  materialEmission Front $= black
  lighting $= Enabled
  light (Light 0) $= Enabled
  position (Light 0) $= Vertex4 500 500 (-1000) 1
  ambient (Light 0) $= white
  diffuse (Light 0) $= white
  specular (Light 0) $= white
  depthFunc $= Just Less
  shadeModel $= Smooth
  cullFace $= Just Back
  ......

polygonSmooth and rescaleNormal were useless. I have also changed the position of the light but this is not the point which caused the issue. The cullFace is not necessary but it is good because there's no visible back face.

Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
  • There are two things that stand out to me here: - `rescaleNormal $= Enabled`, which may be correctly "fixing" your normals. - The location of your light is in a much different position. My hunch is that the likely cause of your original problem was due to incorrect normals. – Mokosha Nov 18 '18 at 08:53
  • Thanks @Mokosha. I will try later to unset each option one by one, in order to find the smoking gun. I have also changed the order of the vertices of each triangle, I would not be surprised if this was the source of the problem. – Stéphane Laurent Nov 18 '18 at 09:00
  • @Mokosha Nope. The `rescaleNormal` has no effect, and the issue was not due to the position of the light (see my edit). I'm lost. I am sure I have reproduced the code which caused the issue, but now it causes no issue... Surely I forget a subtle point, or this was a bug. – Stéphane Laurent Nov 19 '18 at 15:29