使用Haskell Opengl实现光泽度

使用Haskell Opengl实现光泽度,haskell,opengl,Haskell,Opengl,我用Haskell OpenGL做了很多图形。它们在我这里的回购协议中:(画廊并非详尽无遗)。然而,我有一个问题:当我使用材料时,透明度什么都没有发生。有什么东西可以让你拥有光泽吗 下面是我的一个程序示例。它还不完整,但我希望它足以确定问题所在 module CompoundFiveTetrahedra2 where import CompoundFiveTetrahedra.Data import Control.Monad

我用Haskell OpenGL做了很多图形。它们在我这里的回购协议中:(画廊并非详尽无遗)。然而,我有一个问题:当我使用
材料时,透明度
什么都没有发生。有什么东西可以让你拥有光泽吗

下面是我的一个程序示例。它还不完整,但我希望它足以确定问题所在

module CompoundFiveTetrahedra2
  where
import           CompoundFiveTetrahedra.Data
import           Control.Monad                     (when)
import qualified Data.ByteString                   as B
import           Data.IORef
import           Graphics.Rendering.OpenGL.Capture (capturePPM)
import           Graphics.Rendering.OpenGL.GL
import           Graphics.UI.GLUT
import           Text.Printf
import           Utils.ConvertPPM
import           Utils.OpenGL                      (negateNormal)
import           Utils.Prism

blue,red,green,yellow,purple,white,black :: Color4 GLfloat
blue   = Color4 0   0   1   1
red    = Color4 1   0   0   1
green  = Color4 0   1   0   1
yellow = Color4 1   1   0   1
white  = Color4 1   1   1   1
black  = Color4 0   0   0   1
purple = Color4 0.5 0   0.5 1

display :: IORef GLfloat -> IORef GLfloat -> IORef GLfloat -> IORef GLdouble
        -> IORef GLint -> IORef GLfloat -> DisplayCallback
display rot1 rot2 rot3 zoom capture angle = do
  clear [ColorBuffer, DepthBuffer]
  r1 <- get rot1
  r2 <- get rot2
  r3 <- get rot3
  z <- get zoom
  a <- get angle
  i <- get capture
  loadIdentity
  (_, size) <- get viewport
  resize z size
  rotate a $ Vector3 1 1 1
  rotate r1 $ Vector3 1 0 0
  rotate r2 $ Vector3 0 1 0
  rotate r3 $ Vector3 0 0 1
  mapM_ (drawEdge blue)   (edges!!0)
  mapM_ (drawEdge red)    (edges!!1)
  mapM_ (drawEdge green)  (edges!!2)
  mapM_ (drawEdge yellow) (edges!!3)
  mapM_ (drawEdge purple) (edges!!4)
  mapM_ (drawVertex blue)   vertices1
  mapM_ (drawVertex red)    vertices2
  mapM_ (drawVertex green)  vertices3
  mapM_ (drawVertex yellow) vertices4
  mapM_ (drawVertex purple) vertices5
  when (i > 0) $ do
    let ppm = printf "tetrahedra%04d.ppm" i
        png = printf "tetrahedra%04d.png" i
    (>>=) capturePPM (B.writeFile ppm)
    convert ppm png True
    capture $~! (+1)
  swapBuffers

drawVertex :: Color4 GLfloat -> Vertex3 GLfloat -> IO ()
drawVertex col v =
  preservingMatrix $ do
    translate $ toVector v
    materialDiffuse Front $= col
    renderObject Solid $ Sphere' 0.03 30 30
  where
    toVector (Vertex3 x y z) = Vector3 x y z

drawEdge :: Color4 GLfloat -> (Vertex3 GLfloat, Vertex3 GLfloat) -> IO ()
drawEdge col (v1,v2) = do
  let cylinder = prism v1 v2 30 0.03
  renderPrimitive Quads $ do
    materialDiffuse Front $= col
    mapM_ drawQuad cylinder
  where
    drawQuad ((w1,w2,w3,w4),n) = do
      normal $ negateNormal n
      vertex w1
      vertex w2
      vertex w3
      vertex w4

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 (-3 + zoom)) (Vertex3 0 0 0) (Vector3 0 1 0)
  matrixMode $= Modelview 0
  where
    w' = realToFrac w
    h' = realToFrac h

keyboard :: IORef GLfloat -> IORef GLfloat -> IORef GLfloat -> IORef GLint
         -> KeyboardCallback
keyboard rot1 rot2 rot3 capture c _ =
  case c of
    'r' -> rot1 $~! subtract 1
    't' -> rot1 $~! (+1)
    'f' -> rot2 $~! subtract 1
    'g' -> rot2 $~! (+1)
    'v' -> rot3 $~! subtract 1
    'b' -> rot3 $~! (+1)
    'c' -> capture $~! (+1)
    'q' -> leaveMainLoop
    _   -> return ()

mouse :: IORef GLdouble -> MouseCallback
mouse zoom button keyState _ =
  case (button, keyState) of
    (LeftButton, Down)  -> zoom $~! (+0.1)
    (RightButton, Down) -> zoom $~! subtract 0.1
    _                   -> return ()

idle :: IORef GLfloat -> IdleCallback
idle angle = do
  angle $~! (+ 2)
  postRedisplay Nothing

main :: IO ()
main = do
  _ <- getArgsAndInitialize
  _ <- createWindow "Five tetrahedra"
  initialDisplayMode $= [RGBAMode, DoubleBuffered, WithDepthBuffer]
  clearColor $= black
  materialAmbient Front $= black
  materialShininess Front $= 80 -- THIS DOES NOT WORK
  lighting $= Enabled
  light (Light 0) $= Enabled
  position (Light 0) $= Vertex4 0 0 (-100) 1
  ambient (Light 0) $= white
  diffuse (Light 0) $= white
  specular (Light 0) $= white
  depthFunc $= Just Lequal
  depthMask $= Enabled
  shadeModel $= Smooth
  rot1 <- newIORef 0.0
  rot2 <- newIORef 0.0
  rot3 <- newIORef 0.0
  zoom <- newIORef 0.0
  capture <- newIORef 0
  angle <- newIORef 0.0
  displayCallback $= display rot1 rot2 rot3 zoom capture angle
  reshapeCallback $= Just (resize 0)
  keyboardCallback $= Just (keyboard rot1 rot2 rot3 capture)
  mouseCallback $= Just (mouse zoom)
  idleCallback $= Just (idle angle)
  mainLoop
模块组件五层四面体A2
哪里
导入CompoundFiveTetrahedra.Data
导入控制.Monad(何时)
将限定数据.ByteString作为B导入
导入数据.IORef
导入Graphics.Rendering.OpenGL.Capture(capturePPM)
导入Graphics.Rendering.OpenGL.GL
导入Graphics.UI.GLUT
导入文本.Printf
导入Utils.convertpm
导入Utils.OpenGL(默认值)
导入Utils.Prism
蓝色、红色、绿色、黄色、紫色、白色、黑色::彩色4 GLfloat
蓝色=彩色4 0 1 1 1
红色=颜色41 0 0 1
绿色=彩色4 0 1 0 1
黄色=颜色4 1 0 1
白色=彩色4 1
黑色=彩色4 0 0 1
紫色=颜色40.50 0.51
显示::IORef GLfloat->IORef GLfloat->IORef GLfloat->IORef GLdouble
->IORef闪烁->IORef GLfloat->显示回调
显示rot1 rot2 rot3缩放捕捉角度=do
清除[颜色缓冲区,深度缓冲区]

r1更新:尝试1.0的反光度,以在低分辨率下更清楚地看到差异

“光泽度”参数会影响镜面反射照明的锐度,因此需要为材质启用这种类型的照明,方法是为材质指定镜面反射颜色。(默认情况下,镜面反射颜色为黑色,因此“光泽度”参数的效果将不可见。)您还需要减小此场景的“光泽度”值,因为该值太高,无法非常可见

尝试:

您将开始看到白色高光,尤其是沿着形状的弯曲边缘。平面也会反射一些白光,但只有当它们几乎垂直于观察者和光源之间夹角的直线时——这有点复杂

请注意,大多数材质的镜面反射颜色都是白色的“倍数”(即,对于完全暗淡的材质,黑色与对于场景中最亮的材质,白色之间的某个位置)。唯一具有有色镜面反射颜色的材料是有色金属,如金或青铜

一些补充说明:

  • 您使用的是旧式OpenGL 2.1着色,而不是“现代OpenGL”,因此您不必太担心@user2297560所说的“着色器”。OpenGL 2.1自带了内置的着色器来进行基本着色;使用现代OpenGL,您必须从头开始构建所有内容
  • 正如@luqui所提到的,如果你在寻找能够真实反映场景其他部分的材质,这种反光对你没有帮助
这就是区别。您的原始代码在左侧,上面的设置在右侧,在您的“compoundfivetetrahedra”示例中。如果你加大窗户的尺寸,看起来会更好

请注意,它在曲面上效果更好。以下是圆柱体示例,使用:

materialShininess Front $= 5
materialSpecular Front $= white
你可以在更近的球体上看到光亮


非常酷的例子。我不是OpenGL专家,但我以前玩过它。iirc,您需要创建一个着色器,该着色器需要用一种特殊的着色器语言编译一些代码。请参见Graphics.Rendering.OpenGL.GL.Shaders.Thank you@user2297560。我也不是专家,但我不知道着色器是什么。它可能会起作用,但不会达到您的预期,并且可能不会在您创建的示例场景中产生任何效果。光泽度只是照明中镜面反射点的大小,它不会产生反射或任何东西。谢谢@luqui。不幸的是,我不容易理解这样的讨论。顺便说一句,我也在使用R包rgl,它也是OpenGL的包装,我想知道作者是如何处理反光的。不幸的是,代码很难。回到你的评论,我应该说我对所有与照明有关的东西都有点迷茫。我经常随机尝试,直到我达到我想要的。@Stéphanelant我不认为这一定是一个坏方法——你可以阅读有关照明的数学知识,但我不确定它是否给出了实践中的直觉。虽然了解不同的术语的含义会有所帮助。也许值得读一本专门关于照明的教程(我并没有读过,只是略读了一下),以获得不同组件的结构化感觉。谢谢。我试得很快,但没有发现任何区别。稍后我将在球体上进行尝试。我不知道“模型OpenGL”。很抱歉,我没有获得白度。我编辑了我的文章,加入了一个例子来说明我的意思。我从你的代码中添加了几个例子来展示效果。非常感谢!我稍后再试。太好了。嗯,对不起,我还没来得及。我试过马鞍,它很弯。你到底把代码放在哪里了?把它放在主功能中可以吗?或者我应该把它放在我做的
renderPrimitive
的地方吗?
materialShininess Front $= 5
materialSpecular Front $= white