Нежелательные тени с Haskell OpenGL

Я нарисовал секстику Барта с помощью Haskell OpenGL, и возникла проблема. Я также нарисовал его в R (с пакетами rgl и misc3d), и проблем нет. Два алгоритма (в Haskell и R) очень похожи. Секстик Барта — это неявная поверхность, и в Haskell я вычисляю триангуляцию этой поверхности с помощью алгоритма марширующих кубов, который я получил, переведя один из misc3d в Haskell и C. Я использую нормали вершин, каждая из которых определяется градиентом неявное уравнение.

Вот проблема:

введите здесь описание изображения

Я не хочу этих черных теней. Когда я смотрю на секстик сзади, повернув его на 180°, такой тени нет:

введите здесь описание изображения

Полный код доступен в этом репозитории Github. Вот части кода, относящиеся к цветам:

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

Я пытался изменить цвета в этом последнем фрагменте кода, но никак не мог избавиться от этих теней. Я что-то не так делаю с цветами? Я уверен, что нормали правильные, потому что это работает в R. Однако тени появляются там, где поверхность не гладкая, поэтому мне интересно, вызвана ли проблема нормалями.

Рендеринг R:

gfycat

Редактировать

Мне удалось избавиться от этих теней:

введите здесь описание изображения

Сам не знаю как, столько попыток делал... Но все равно теперь проблема в том, что спинка секстика слишком легкая:

введите здесь описание изображения


person Stéphane Laurent    schedule 16.11.2018    source источник
comment
Цветовая отладка нормалей   -  person Nadir    schedule 16.11.2018
comment
@Надир Что ты имеешь в виду?   -  person Stéphane Laurent    schedule 16.11.2018
comment
Вместо того, чтобы рисовать затененный цвет вашей неявной поверхности, установите вывод цвета, как если бы вектор нормали был цветом.   -  person Nadir    schedule 16.11.2018
comment
Дело в том, что реальные нормали поверхности меняются слишком быстро и грубая триангуляция не может их воспроизвести. Поэтому вы можете попробовать увеличить разрешение Marching Cubes. Подобные каспы всегда проблематичны для нормалей каждой вершины, поскольку вы не можете разумно интерполировать их. Вторым вариантом было бы оставить их как углы и дублировать вершины, используя отдельные нормали (которые вы оцениваете немного вне вершины внутри грани).   -  person Nico Schertler    schedule 16.11.2018
comment
@NicoSchertler Да, действительно, становится лучше, когда я увеличиваю разрешение. Но мне интересно, почему эта проблема не возникает с rgl в R (я только что отредактировал свой пост, чтобы добавить рендеринг rgl). Я использую то же разрешение и те же нормали, и алгоритм марширующих кубов такой же. Пакет rgl также основан на OpenGL (думаю, мне следует проверить), поэтому мне интересно, есть ли параметр по умолчанию, установленный в rgl, и который я не устанавливаю в Haskell.   -  person Stéphane Laurent    schedule 16.11.2018
comment
Может ли rgl использовать плоское затенение? На скриншоте плохо видно.   -  person Nico Schertler    schedule 16.11.2018
comment
@NicoSchertler Нет, он использует плавное затенение. Я попробовал плоское затенение, и результат уродлив.   -  person Stéphane Laurent    schedule 16.11.2018
comment
Это действительно странно. Я наблюдаю подобное поведение, когда есть только один источник света в точке (0,0,0), которая является центром объекта.   -  person Stéphane Laurent    schedule 16.11.2018
comment
Я не знаю, является ли это причиной, но это может быть: Вы должны установить положение источника света немного не по центру; поставить его там, где может быть солнце. Попробуйте, например. Vertex4 500 500 (-1000) и посмотрите, как это выглядит.   -  person luqui    schedule 16.11.2018
comment
@NicoSchertler Пожалуйста, взгляните на мою правку. Теперь вид спереди хорош, но вид сзади слишком яркий. У вас есть идея, которая поможет уменьшить эту яркость? Я вообще не понимаю, почему такая разница. Вид спереди и вид сзади (т. е. вид спереди с поворотом на 180°) подвергаются воздействию света одинаково.   -  person Stéphane Laurent    schedule 17.11.2018


Ответы (1)


Теперь рендеринг хороший :-)

введите здесь описание изображения

Я не знаю, что вызвало проблему, потому что я сделал множество изменений... Вот соответствующие части кода:

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
  ......

Я также изменил порядок вершин каждого треугольника:

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

Этот ответ несколько преждевременный. Я буду исследовать больше позже, и я отредактирую, чтобы написать мои выводы.

РЕДАКТИРОВАТЬ

Что ж, я провел дальнейшее расследование и, к сожалению, пришел к выводу, что у меня нет объяснений: я отменил все свои изменения и не могу воспроизвести проблему !!

Теперь я использую этот более короткий код:

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

Два MatrixMode важны.

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 и rescaleNormal были бесполезны. Я также изменил положение источника света, но проблема не в этом. cullFace не обязательно, но это хорошо, потому что задняя сторона не видна.

person Stéphane Laurent    schedule 17.11.2018
comment
Есть две вещи, которые выделяются здесь для меня: - rescaleNormal $= Enabled, который может корректно исправлять ваши нормали. - Расположение вашего света находится в совершенно другом положении. Я предполагаю, что вероятная причина вашей первоначальной проблемы была связана с неправильными нормалями. - person Mokosha; 18.11.2018
comment
Спасибо @Мокоша. Я постараюсь позже отключить каждую опцию один за другим, чтобы найти дымящийся пистолет. Я также изменил порядок вершин каждого треугольника, я не удивлюсь, если это было источником проблемы. - person Stéphane Laurent; 18.11.2018
comment
@Мокоша Нет. rescaleNormal не имеет никакого эффекта, и проблема не в положении источника света (см. мое редактирование). Я потерялся. Я уверен, что воспроизвел код, вызвавший проблему, но теперь он не вызывает проблем... Конечно, я забыл один тонкий момент, или это была ошибка. - person Stéphane Laurent; 19.11.2018