雑記帳
Haskell + OpenGL で 3DCG 描画を行ってみた - SSAO
LEARN OpenGL の SSAO 解説ページを読みながら、「スクリーンスペース・アンビエント・オクルージョン (SSAO: Screen-Space Ambient Occlusion)」を Haskell の OpenGL パッケージを使って実際に行ってみた。
SSAO の詳しい解説はリンク先の記事で行われているためここではしないが、もしかすると「Haskell で OpenGL を使用すること」への興味がある物好きがいるかもしれないし、そういった方々の参考用になればうれしいなということでそのソースコードは載せておく。
例えば、「Haskell + OpenGL」という環境において
- DEPTH_TEST (Zテスト / 深度テスト) の設定
- CULL_FACE の設定
は、以下のソースコードを確認すればわかるように
GL.depthFunc $= Just GL.Less
GL.cullFace $= Just GL.Back
というスタイルで設定される。
※ GitHub にもソースコードと実行結果となる画像を載せてはあるのだけど、こちらの個人サイトの方の更新がメインになり GitHub は完全放置状態になってしまったので、こちらにも持ってきておこうかなということで記事にしてみた。
コードの実行結果
ソースコード
シェーダプログラムのソースは上のリンク先 (或いは GitHub) を参照。
ここでは Haskell プログラム本体のソースコードのみを載せておく。
import System.Random
import Codec.Picture
import Codec.Picture.Metadata as JP
import Graphics.Rendering.OpenGL as GL
import Graphics.UI.GLFW as GLFW
import Linear.Epsilon
import Linear.Vector
import Linear.Matrix
import Linear.Metric
import Linear.V3
import Linear.V4
import Linear.Quaternion
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import Foreign.Ptr
import Foreign.Storable
import Control.Lens
import Control.Monad.Fix
import Data.StateVar
import qualified Data.ByteString as B
main :: IO ()
main = do
GLFW.init
GLFW.windowHint $ GLFW.WindowHint'ContextVersionMajor 3
GLFW.windowHint $ GLFW.WindowHint'ContextVersionMinor 3
GLFW.windowHint $ GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core
winMaybe <- GLFW.createWindow 1024 768 "LearnOpenGL" Nothing Nothing
case winMaybe of
Nothing -> do
putStrLn "Failed to create GLFW window"
GLFW.terminate
Just window -> do
GLFW.makeContextCurrent (Just window)
GLFW.swapInterval 1
GLFW.setFramebufferSizeCallback window (Just framebufferSizeCallback)
GL.depthFunc $= Just GL.Less
GL.cullFace $= Just GL.Back
geopassShader <- buildShaderProgram window ["./g_buffer.vs", "./g_buffer.fs"]
lightingShader <- buildShaderProgram window ["./quad.vs", "./lighting.fs"]
ssaoShader <- buildShaderProgram window ["./quad.vs", "./ssao.fs"]
ssaoBlurShader <- buildShaderProgram window ["./quad.vs", "./ssao_blur.fs"]
skyboxShader <- buildShaderProgram window ["./skybox.vs", "./skybox.fs"]
simpleDepthShader <- buildShaderProgram window ["./depth.vs", "./depth.fs"]
-- ## Attriblocations (fixed)
aLoc_aPos <- return $ GL.AttribLocation 0
aLoc_aNormal <- return $ GL.AttribLocation 1
aLoc_aTexCoords <- return $ GL.AttribLocation 2
GL.currentProgram $= Just lightingShader
-- ## uniformLocations
uLoc_A_light_ambient <- get $ GL.uniformLocation lightingShader "light.ambient"
uLoc_A_light_diffuse <- get $ GL.uniformLocation lightingShader "light.diffuse"
uLoc_A_light_specular <- get $ GL.uniformLocation lightingShader "light.specular"
uLoc_A_light_position <- get $ GL.uniformLocation lightingShader "light.position"
uLoc_A_gPosition <- get $ GL.uniformLocation lightingShader "gPosition"
uLoc_A_gNormal <- get $ GL.uniformLocation lightingShader "gNormal"
uLoc_A_gAlbedo <- get $ GL.uniformLocation lightingShader "gAlbedo"
uLoc_A_ssao <- get $ GL.uniformLocation lightingShader "ssao"
GL.currentProgram $= Just skyboxShader
-- ## uniformLocations
uLoc_B_view <- get $ GL.uniformLocation skyboxShader "view"
uLoc_B_projection <- get $ GL.uniformLocation skyboxShader "projection"
uLoc_B_skybox <- get $ GL.uniformLocation skyboxShader "skybox"
GL.currentProgram $= Just simpleDepthShader
-- ## uniformLocations
uLoc_C_lightSpaceMatrix <- get $ GL.uniformLocation simpleDepthShader "lightSpaceMatrix"
uLoc_C_model <- get $ GL.uniformLocation simpleDepthShader "model"
GL.currentProgram $= Just geopassShader
-- ## uniformLocations
uLoc_D_material_diffuse <- get $ GL.uniformLocation geopassShader "material.diffuse"
uLoc_D_material_specular <- get $ GL.uniformLocation geopassShader "material.specular"
uLoc_D_material_shininess <- get $ GL.uniformLocation geopassShader "material.shininess"
uLoc_D_model <- get $ GL.uniformLocation geopassShader "model"
uLoc_D_view <- get $ GL.uniformLocation geopassShader "view"
uLoc_D_projection <- get $ GL.uniformLocation geopassShader "projection"
uLoc_D_lightSpaceMatrix <- get $ GL.uniformLocation geopassShader "lightSpaceMatrix"
uLoc_D_shadowMap <- get $ GL.uniformLocation geopassShader "shadowMap"
GL.currentProgram $= Just ssaoShader
-- ## uniformLocations
uLoc_E_gPosition <- get $ GL.uniformLocation ssaoShader "gPosition"
uLoc_E_gNormal <- get $ GL.uniformLocation ssaoShader "gNormal"
uLoc_E_texNoise <- get $ GL.uniformLocation ssaoShader "texNoise"
uLoc_E_projection <- get $ GL.uniformLocation ssaoShader "projection"
uLoc_E_samples <- foldr (\a b -> do{x<-a;xs<-b;return$x:xs}) (return []) $ do
i <- [0..(64-1)]
return $ get $ GL.uniformLocation ssaoShader ("samples[" ++ show i ++ "]")
GL.currentProgram $= Just ssaoBlurShader
-- ## uniformLocations
uLoc_F_ssaoInput <- get $ GL.uniformLocation ssaoBlurShader "ssaoInput"
GL.currentProgram $= Nothing
let
cubeVertices = model_cube
sizeOfElm = sizeOf (undefined::GLfloat)
bufferWidth = 1024
bufferHeight = 768
gBuffer <- genObjectName
GL.bindFramebuffer GL.Framebuffer $= gBuffer
gPosition <- genObjectName
GL.textureBinding GL.Texture2D $= Just gPosition
GL.texImage2D GL.Texture2D GL.NoProxy 0 GL.RGBA16F
(TextureSize2D bufferWidth bufferHeight) 0
(GL.PixelData GL.RGBA GL.Float nullPtr)
GL.textureFilter GL.Texture2D
$= ((GL.Nearest, Nothing), GL.Nearest)
GL.textureWrapMode GL.Texture2D GL.S
$= (GL.Repeated, GL.ClampToEdge)
GL.textureWrapMode GL.Texture2D GL.T
$= (GL.Repeated, GL.ClampToEdge)
GL.framebufferTexture2D GL.Framebuffer (GL.ColorAttachment 0)
GL.Texture2D gPosition 0
gNormal <- genObjectName
GL.textureBinding GL.Texture2D $= Just gNormal
GL.texImage2D GL.Texture2D GL.NoProxy 0 GL.RGBA16F
(TextureSize2D bufferWidth bufferHeight) 0
(GL.PixelData GL.RGBA GL.Float nullPtr)
GL.textureFilter GL.Texture2D
$= ((GL.Nearest, Nothing), GL.Nearest)
GL.framebufferTexture2D GL.Framebuffer (GL.ColorAttachment 1)
GL.Texture2D gNormal 0
gAlbedo <- genObjectName
GL.textureBinding GL.Texture2D $= Just gAlbedo
GL.texImage2D GL.Texture2D GL.NoProxy 0 GL.RGBA'
(TextureSize2D bufferWidth bufferHeight) 0
(GL.PixelData GL.RGBA GL.Float nullPtr)
GL.textureFilter GL.Texture2D
$= ((GL.Nearest, Nothing), GL.Nearest)
GL.framebufferTexture2D GL.Framebuffer (GL.ColorAttachment 2)
GL.Texture2D gAlbedo 0
GL.drawBuffers $= [GL.FBOColorAttachment 0, GL.FBOColorAttachment 1, GL.FBOColorAttachment 2]
rboDepth <- genObjectName
GL.bindRenderbuffer GL.Renderbuffer $= rboDepth
GL.renderbufferStorage GL.Renderbuffer GL.DepthComponent' (GL.RenderbufferSize bufferWidth bufferHeight)
GL.framebufferRenderbuffer GL.Framebuffer GL.DepthAttachment GL.Renderbuffer rboDepth
GL.bindFramebuffer GL.Framebuffer $= GL.defaultFramebufferObject
ssaoFBO <- genObjectName
ssaoBlurFBO <- genObjectName
GL.bindFramebuffer GL.Framebuffer $= ssaoFBO
ssaoColorBuffer <- genObjectName
GL.textureBinding GL.Texture2D $= Just ssaoColorBuffer
GL.texImage2D GL.Texture2D GL.NoProxy 0 GL.R16
(TextureSize2D bufferWidth bufferHeight) 0
(GL.PixelData GL.Red GL.Float nullPtr)
GL.textureFilter GL.Texture2D
$= ((GL.Nearest, Nothing), GL.Nearest)
GL.framebufferTexture2D GL.Framebuffer (GL.ColorAttachment 0)
GL.Texture2D ssaoColorBuffer 0
GL.bindFramebuffer GL.Framebuffer $= ssaoBlurFBO
ssaoColorBufferBlur <- genObjectName
GL.textureBinding GL.Texture2D $= Just ssaoColorBufferBlur
GL.texImage2D GL.Texture2D GL.NoProxy 0 GL.R16
(TextureSize2D bufferWidth bufferHeight) 0
(GL.PixelData GL.Red GL.Float nullPtr)
GL.textureFilter GL.Texture2D
$= ((GL.Linear', Nothing), GL.Linear')
GL.framebufferTexture2D GL.Framebuffer (GL.ColorAttachment 0)
GL.Texture2D ssaoColorBufferBlur 0
GL.bindFramebuffer GL.Framebuffer $= GL.defaultFramebufferObject
let
kernelSize = 64
rnds = take (kernelSize*4) $ (randomRs (0,1) (mkStdGen 90) :: [GLfloat])
ssaoKernel <- return $ do
i <- [0..(kernelSize-1)]
let
scale = fromIntegral i / fromIntegral kernelSize
x1 = rnds!!(4*i+0)*2-1
x2 = rnds!!(4*i+1)*2-1
x3 = rnds!!(4*i+2)
k = rnds!!(4*i+3)
return $ (lerp' 0.1 1 (scale*scale) * k) *^ (Linear.Metric.normalize $ V3 x1 x2 x3)
-- print ssaoKernel
let
sizeOfNoiseTex = 4*4
rnds2 = take (sizeOfNoiseTex*2) $ (randomRs (0,1) (mkStdGen 91) :: [GLfloat])
ssaoNoise <- return $ do
i <- [0..(sizeOfNoiseTex-1)]
[rnds2!!(2*i+0)*2-1, rnds2!!(2*i+1)*2-1, 0]
-- print ssaoNoise
noiseTexture <- genObjectName
GL.textureBinding GL.Texture2D $= Just noiseTexture
withArray ssaoNoise $ \ptr -> do
GL.texImage2D GL.Texture2D GL.NoProxy 0 GL.RGBA32F
(TextureSize2D 4 4) 0
(GL.PixelData GL.RGB GL.UnsignedByte ptr)
GL.textureFilter GL.Texture2D
$= ((GL.Nearest, Nothing), GL.Nearest)
GL.textureWrapMode GL.Texture2D GL.S
$= (GL.Repeated, GL.Repeat)
GL.textureWrapMode GL.Texture2D GL.T
$= (GL.Repeated, GL.Repeat)
cubeVBO <- genObjectName
GL.bindBuffer GL.ArrayBuffer $= Just cubeVBO
bufferListData GL.ArrayBuffer cubeVertices GL.StaticDraw
cubeVAO <- genObjectName
GL.bindVertexArrayObject $= Just cubeVAO
initAttribVars sizeOfElm [(3, Just aLoc_aPos), (3, Just aLoc_aNormal), (2, Just aLoc_aTexCoords)]
planeVBO <- genObjectName
GL.bindBuffer GL.ArrayBuffer $= Just planeVBO
bufferListData GL.ArrayBuffer planeVertices GL.StaticDraw
planeVAO <- genObjectName
GL.bindVertexArrayObject $= Just planeVAO
initAttribVars sizeOfElm [(3, Just aLoc_aPos), (3, Just aLoc_aNormal), (2, Just aLoc_aTexCoords)]
quadVBO <- genObjectName
GL.bindBuffer GL.ArrayBuffer $= Just quadVBO
bufferListData GL.ArrayBuffer quadVertices GL.StaticDraw
quadVAO <- genObjectName
GL.bindVertexArrayObject $= Just quadVAO
initAttribVars sizeOfElm [(3, Just aLoc_aPos), (2, Just aLoc_aTexCoords)]
skyboxVBO <- genObjectName
GL.bindBuffer GL.ArrayBuffer $= Just skyboxVBO
bufferListData GL.ArrayBuffer skyboxVertices GL.StaticDraw
skyboxVAO <- genObjectName
GL.bindVertexArrayObject $= Just skyboxVAO
initAttribVars sizeOfElm [(3, Just aLoc_aPos)]
diffuseMap <- loadTexture2D $ "./container2.jpg"
specularMap <- loadTexture2D $ "./container2_specular.jpg"
floorTexture <- loadTexture2D $ "./grass.jpg"
(Just cubemapTexture) <- loadCubemap (fmap (++".bmp") $ ["right","left","top","bottom","front","back"])
let
shadowWidth = 1024
shadowHeight = 1024
depthMapFBO <- genObjectName
depthMap <- genObjectName
GL.textureBinding GL.Texture2D $= Just depthMap
GL.texImage2D GL.Texture2D GL.NoProxy 0 GL.DepthComponent'
(TextureSize2D shadowWidth shadowHeight) 0
(GL.PixelData GL.DepthComponent GL.Float nullPtr)
GL.textureFilter GL.Texture2D
$= ((GL.Nearest, Nothing), GL.Nearest)
GL.textureWrapMode GL.Texture2D GL.S
$= (GL.Repeated, GL.ClampToBorder)
GL.textureWrapMode GL.Texture2D GL.T
$= (GL.Repeated, GL.ClampToBorder)
GL.textureBorderColor GL.Texture2D $= Color4 1 1 1 1
GL.bindFramebuffer GL.Framebuffer $= depthMapFBO
GL.framebufferTexture2D GL.Framebuffer GL.DepthAttachment
GL.Texture2D depthMap 0
GL.drawBuffer $= GL.NoBuffers
GL.readBuffer $= GL.NoBuffers
GL.bindFramebuffer GL.Framebuffer $= GL.defaultFramebufferObject
GL.currentProgram $= Just lightingShader
GL.uniform uLoc_A_gPosition $= (0::GLint)
GL.uniform uLoc_A_gNormal $= (1::GLint)
GL.uniform uLoc_A_gAlbedo $= (2::GLint)
GL.uniform uLoc_A_ssao $= (3::GLint)
GL.currentProgram $= Just skyboxShader
GL.uniform uLoc_B_skybox $= (0::GLint)
GL.currentProgram $= Just geopassShader
GL.uniform uLoc_D_material_diffuse $= (0::GLint)
GL.uniform uLoc_D_material_specular $= (1::GLint)
GL.uniform uLoc_D_shadowMap $= (2::GLint)
GL.currentProgram $= Just ssaoShader
GL.uniform uLoc_E_gPosition $= (0::GLint)
GL.uniform uLoc_E_gNormal $= (1::GLint)
GL.uniform uLoc_E_texNoise $= (2::GLint)
foldr (>>) (return ()) $ do
i <- [0..(64-1)]
return $ GL.uniform (uLoc_E_samples !! i) $= v3ToVector3 (ssaoKernel !! i)
GL.currentProgram $= Just ssaoBlurShader
GL.uniform uLoc_F_ssaoInput $= (0::GLint)
GL.currentProgram $= Nothing
GL.bindBuffer GL.ArrayBuffer $= Nothing
GL.bindVertexArrayObject $= Nothing
let
material_B = MyMaterial2 (Just diffuseMap) (Just specularMap) 64
modelData = (ModelData (makeListOfVAOs planeVAO cubeVAO) []) `addObject`
(Obj_Plane, MyMaterial2 (Just floorTexture) Nothing 64, identity) `addObject`
(Obj_Cube, material_B, identity) `addObject`
(Obj_Cube, material_B, mat4_translate (V3 10.5 0 3)) `addObject`
(Obj_Cube, material_B, mat4_translate (V3 2 0 (-4))) `addObject`
(Obj_Cube, material_B, mat4_translate (V3 (-3) 0 (-3))) `addObject`
(Obj_Cube, material_B, mat4_translate (V3 1 0 4.5)) `addObject`
(Obj_Cube, material_B, mat4_translate (V3 7.2 0 (-1.4))) `addObject`
(Obj_Cube, material_B, mat4_translate (V3 (-9) 0 (-1))) `addObject`
(Obj_Cube, material_B, mat4_translate (V3 (-0.2) 0 (-1.19))) `addObject`
(Obj_Cube, material_B, mat4_translate (V3 (-0.59) 0 1)) `addObject`
(Obj_Cube, material_B, mat4_translate (V3 (-1.89) 0 0)) `addObject`
(Obj_Cube, material_B, mat4_translate (V3 (-0.1) 1 (-0.5))) `addObject`
(Obj_Cube, material_B, (mat4_translate (V3 (-3+0.59) ((1+sqrt 3)/4-0.5) (-3.5-((1+sqrt 3)/4)))) !*! mat4_rotate (V3 1 0 0) (radians (-60))) `addObject`
(Obj_Cube, material_B, mat4_translate (V3 (-5) 0 2))
myState <- initMyStateVars
let
deltaTime = getMyStateVar_f myState DeltaTime
lastFrame = getMyStateVar_f myState LastFrame
yaw = getMyStateVar_f myState Yaw
pitch = getMyStateVar_f myState Pitch
cameraPos = getMyStateVar_3f myState CameraPos
cameraDir = getMyStateVar_3f myState CameraDir
cameraUp = getMyStateVar_3f myState CameraUp
lightPos = getMyStateVar_3f myState LightPos
deltaTime $= 0
lastFrame $= 0
yaw $= 0
pitch $= 0
cameraPos $= V3 0 0 7
cameraDir $= calcDirectionVector 0 0
cameraUp $= V3 0 1 0
lightPos $= (21 *^ V3 (-0.41925156) 0.49880368 (-0.75856644))
fix $ \rec -> do
b <- GLFW.windowShouldClose window
if b then
return ()
else do
(_, (Size scrWidth scrHeight)) <- get $ GL.viewport
-- GL.clearColor $= GL.Color4 (0.5*0.19) (0.8*0.19) (0.9*0.19) 1
GL.clearColor $= GL.Color4 0 0 0 1
t_maybe <- getTime
case t_maybe of
Just t -> do
currentCameraPos <- get cameraPos
currentCameraDir <- get cameraDir
currentCameraUp <- get cameraUp
currentLightPos <- get lightPos
currentYaw <- get yaw
processInput window myState (realToFrac t)
lightSpaceMatrix <- mat4ToGLmatrix $
(mat4_ortho 20 20 1 27.5) !*!
(mat4_lookAt ((8/21)*^currentLightPos) (V3 0 0 0) (V3 0 1 0))
view_ <- return $ mat4_lookAt currentCameraPos (currentCameraPos + currentCameraDir) currentCameraUp
view <- mat4ToGLmatrix $ view_
view2 <- mat4ToGLmatrix $
removeTranslation $ view_
projection <- mat4ToGLmatrix $
mat4_perspective (radians 45)
((fromIntegral scrWidth)/(fromIntegral scrHeight)) 0.1 100
model2 <- mat4ToGLmatrix $
mat4_translate currentLightPos !*!
mat4_rotate (V3 0.3 0.2 0.1) (realToFrac t * radians (-55)) !*!
mat4_scale 0.2 0.2 0.2
-- compute the depth data for shadow mapping
GL.cullFace $= Just GL.Front
GL.currentProgram $= Just simpleDepthShader
GL.uniform uLoc_C_lightSpaceMatrix $= lightSpaceMatrix
GL.viewport $= (GL.Position 0 0, GL.Size shadowWidth shadowHeight)
GL.bindFramebuffer GL.Framebuffer $= depthMapFBO
GL.clear [GL.DepthBuffer]
renderScene modelData (uLoc_C_model, Nothing, Nothing, Nothing)
GL.bindFramebuffer GL.Framebuffer $= GL.defaultFramebufferObject
GL.cullFace $= Just GL.Back
GL.viewport $= (GL.Position 0 0, GL.Size bufferWidth bufferHeight)
GL.clear [GL.ColorBuffer, GL.DepthBuffer]
-- create gBuffers
GL.bindFramebuffer GL.Framebuffer $= gBuffer
GL.clear [GL.ColorBuffer, GL.DepthBuffer]
GL.currentProgram $= Just geopassShader
GL.uniform uLoc_D_view $= view
GL.uniform uLoc_D_projection $= projection
GL.uniform uLoc_D_lightSpaceMatrix $= lightSpaceMatrix
GL.activeTexture $= GL.TextureUnit 2
GL.textureBinding GL.Texture2D $= Just depthMap
renderScene modelData (uLoc_D_model, Nothing, Nothing, Just uLoc_D_material_shininess)
-- drawing skybox
GL.depthFunc $= Just GL.Lequal
GL.currentProgram $= Just skyboxShader
GL.uniform uLoc_B_view $= view2
GL.uniform uLoc_B_projection $= projection
GL.bindVertexArrayObject $= Just skyboxVAO
GL.activeTexture $= GL.TextureUnit 0
GL.textureBinding GL.TextureCubeMap $= Just cubemapTexture
GL.drawArrays GL.Triangles 0 36
GL.bindVertexArrayObject $= Nothing
GL.depthFunc $= Just GL.Less
GL.bindFramebuffer GL.Framebuffer $= GL.defaultFramebufferObject
-- SSAO
GL.bindFramebuffer GL.Framebuffer $= ssaoFBO
GL.clear [GL.ColorBuffer]
GL.currentProgram $= Just ssaoShader
GL.uniform uLoc_E_projection $= projection
GL.activeTexture $= GL.TextureUnit 0
GL.textureBinding GL.Texture2D $= Just gPosition
GL.activeTexture $= GL.TextureUnit 1
GL.textureBinding GL.Texture2D $= Just gNormal
GL.activeTexture $= GL.TextureUnit 2
GL.textureBinding GL.Texture2D $= Just noiseTexture
GL.bindVertexArrayObject $= Just quadVAO
GL.drawArrays GL.TriangleStrip 0 4
GL.bindFramebuffer GL.Framebuffer $= GL.defaultFramebufferObject
-- SSAO Blur
GL.bindFramebuffer GL.Framebuffer $= ssaoBlurFBO
GL.clear [GL.ColorBuffer]
GL.currentProgram $= Just ssaoBlurShader
GL.activeTexture $= GL.TextureUnit 0
GL.textureBinding GL.Texture2D $= Just ssaoColorBuffer
GL.bindVertexArrayObject $= Just quadVAO
GL.drawArrays GL.TriangleStrip 0 4
GL.bindFramebuffer GL.Framebuffer $= GL.defaultFramebufferObject
-- lighting
GL.viewport $= (GL.Position 0 0, GL.Size scrWidth scrHeight)
GL.currentProgram $= Just lightingShader
GL.uniform uLoc_A_light_position $= (v3ToVector3 $ (view_ !* point currentLightPos) ^._xyz)
GL.uniform uLoc_A_light_ambient $= (Vector3 0.2 0.2 0.2 :: Vector3 GLfloat)
GL.uniform uLoc_A_light_diffuse $= (Vector3 0.5 0.5 0.5 :: Vector3 GLfloat)
GL.uniform uLoc_A_light_specular $= (Vector3 1 1 1 :: Vector3 GLfloat)
GL.activeTexture $= GL.TextureUnit 0
GL.textureBinding GL.Texture2D $= Just gPosition
GL.activeTexture $= GL.TextureUnit 1
GL.textureBinding GL.Texture2D $= Just gNormal
GL.activeTexture $= GL.TextureUnit 2
GL.textureBinding GL.Texture2D $= Just gAlbedo
GL.activeTexture $= GL.TextureUnit 3
GL.textureBinding GL.Texture2D $= Just ssaoColorBufferBlur
GL.bindVertexArrayObject $= Just quadVAO
GL.drawArrays GL.TriangleStrip 0 4
Nothing -> return ()
GLFW.swapBuffers window
GLFW.pollEvents
rec
freeMyStateVars myState
deleteObjectName cubeVAO
deleteObjectName cubeVBO
deleteObjectName planeVAO
deleteObjectName planeVBO
deleteObjectName quadVAO
deleteObjectName quadVBO
deleteObjectName skyboxVAO
deleteObjectName skyboxVBO
deleteObjectName lightingShader
deleteObjectName skyboxShader
GLFW.terminate
data ObjType = Obj_Plane | Obj_Cube deriving Enum
makeListOfVAOs :: VertexArrayObject -> VertexArrayObject -> [VertexArrayObject]
makeListOfVAOs plane cube = do
i <- [0..1]
if i == fromEnum Obj_Plane then
return plane
else if i == fromEnum Obj_Cube then
return cube
else
[]
data MaterialType = Default | MyMaterial1 (V3 GLfloat) (V3 GLfloat) GLfloat | MyMaterial2 (Maybe TextureObject) (Maybe TextureObject) GLfloat
type UniformLocs = (UniformLocation, Maybe UniformLocation, Maybe UniformLocation, Maybe UniformLocation)
data ModelData = ModelData [VertexArrayObject] [((ObjType, MaterialType), M44 GLfloat)]
emptyData :: ModelData
emptyData = (ModelData [] [])
addObject :: ModelData -> (ObjType, MaterialType, M44 GLfloat) -> ModelData
addObject (ModelData objInfo objData) (a, b, c) = (ModelData objInfo (((a,b),c):objData))
renderScene :: ModelData -> UniformLocs -> IO ()
renderScene (ModelData objInfo objData) (modelLoc, difLoc', specLoc', shLoc') = do
let
uniforms' = do
(x,i) <- zip [difLoc', specLoc', shLoc'] [0..2]
case x of
Just x' -> return (x',i)
Nothing -> []
ignoreMaterial = null uniforms'
foldr (>>) (return ()) $ do
i <- enumFromTo 0 (length objData - 1)
let
objType = fst.fst $ objData !! i
materialType = snd.fst $ objData !! i
modelMat = snd $ objData !! i
return $ do
mat4ToGLmatrix modelMat >>= \model ->
GL.uniform modelLoc $= model
case objType of
Obj_Plane -> do
GL.bindVertexArrayObject $= Just (objInfo !! fromEnum Obj_Plane)
if ignoreMaterial then
return ()
else
case materialType of
MyMaterial2 diffuseTex specularTex shininess -> do
if snd (uniforms' !! 0) == 2 then do
GL.uniform (fst $ uniforms' !! 0) $= shininess
GL.activeTexture $= GL.TextureUnit 0
GL.textureBinding GL.Texture2D $= diffuseTex
GL.activeTexture $= GL.TextureUnit 1
GL.textureBinding GL.Texture2D $= specularTex
else
return ()
_ -> return ()
GL.drawArrays GL.Triangles 0 6
GL.bindVertexArrayObject $= Nothing
Obj_Cube -> do
GL.bindVertexArrayObject $= Just (objInfo !! fromEnum Obj_Cube)
if ignoreMaterial then
return ()
else
case materialType of
MyMaterial2 diffuseTex specularTex shininess -> do
if snd (uniforms' !! 0) == 2 then do
GL.uniform (fst $ uniforms' !! 0) $= shininess
GL.activeTexture $= GL.TextureUnit 0
GL.textureBinding GL.Texture2D $= diffuseTex
GL.activeTexture $= GL.TextureUnit 1
GL.textureBinding GL.Texture2D $= specularTex
else
return ()
_ -> return ()
GL.drawArrays GL.Triangles 0 36
GL.bindVertexArrayObject $= Nothing
data MyState =
MyState (Ptr GLfloat) (Ptr (V3 GLfloat))
(StateVar GLfloat) (StateVar GLfloat)
(StateVar GLfloat) (StateVar GLfloat)
(StateVar (V3 GLfloat)) (StateVar (V3 GLfloat)) (StateVar (V3 GLfloat))
(StateVar (V3 GLfloat))
data MyStateName =
DeltaTime | LastFrame | Yaw | Pitch | CameraPos | CameraDir | CameraUp | LightPos
initMyStateVars :: IO MyState
initMyStateVars = do
p1 <- mallocArray 4 :: IO (Ptr GLfloat)
p2 <- mallocArray 4 :: IO (Ptr (V3 GLfloat))
let
deltaTime =
makeStateVarFromPtr $ p1 `plusPtr` (0*sizeOf(undefined::GLfloat))
lastFrame =
makeStateVarFromPtr $ p1 `plusPtr` (1*sizeOf(undefined::GLfloat))
yaw =
makeStateVarFromPtr $ p1 `plusPtr` (2*sizeOf(undefined::GLfloat))
pitch =
makeStateVarFromPtr $ p1 `plusPtr` (3*sizeOf(undefined::GLfloat))
cameraPos =
makeStateVarFromPtr $ p2 `plusPtr` (0*sizeOf(undefined::(V3 GLfloat)))
cameraDir =
makeStateVarFromPtr $ p2 `plusPtr` (1*sizeOf(undefined::(V3 GLfloat)))
cameraUp =
makeStateVarFromPtr $ p2 `plusPtr` (2*sizeOf(undefined::(V3 GLfloat)))
lightPos =
makeStateVarFromPtr $ p2 `plusPtr` (3*sizeOf(undefined::(V3 GLfloat)))
return (MyState p1 p2 deltaTime lastFrame yaw pitch cameraPos cameraDir cameraUp lightPos)
getMyStateVar_f :: MyState -> MyStateName -> StateVar GLfloat
getMyStateVar_f (MyState _ _ v1 v2 v3 v4 v5 v6 v7 v8) varName = do
case varName of
DeltaTime -> v1
LastFrame -> v2
Yaw -> v3
Pitch -> v4
_ -> makeStateVarFromPtr nullPtr
getMyStateVar_3f :: MyState -> MyStateName -> StateVar (V3 GLfloat)
getMyStateVar_3f (MyState _ _ v1 v2 v3 v4 v5 v6 v7 v8) varName = do
case varName of
CameraPos -> v5
CameraDir -> v6
CameraUp -> v7
LightPos -> v8
_ -> makeStateVarFromPtr nullPtr
freeMyStateVars :: MyState -> IO ()
freeMyStateVars (MyState p1 p2 _ _ _ _ _ _ _ _) = do
free p1
free p2
processInput :: Window -> MyState -> GLfloat -> IO ()
processInput window myState t = do
let
sensitivity = 7
deltaTime = getMyStateVar_f myState DeltaTime
lastFrame = getMyStateVar_f myState LastFrame
yaw = getMyStateVar_f myState Yaw
pitch = getMyStateVar_f myState Pitch
cameraPos = getMyStateVar_3f myState CameraPos
cameraDir = getMyStateVar_3f myState CameraDir
cameraUp = getMyStateVar_3f myState CameraUp
lightPos = getMyStateVar_3f myState LightPos
lastFrame_val <- get lastFrame
let
deltaTime = t
cameraSpeed = 2.5 * (t - lastFrame_val)
lastFrame $= t
currentCameraDir <- get cameraDir
currentCameraUp <- get cameraUp
GLFW.getKey window GLFW.Key'Escape >>= \s ->
if (s == GLFW.KeyState'Pressed) then
GLFW.setWindowShouldClose window True
else return ()
GLFW.getKey window GLFW.Key'Right >>= \s ->
if (s == GLFW.KeyState'Pressed) then
cameraPos $~ (+ (cameraSpeed *^ Linear.Metric.normalize(currentCameraDir `cross` currentCameraUp)))
else return ()
GLFW.getKey window GLFW.Key'Left >>= \s ->
if (s == GLFW.KeyState'Pressed) then
cameraPos $~ (+ ((-1)*cameraSpeed *^ Linear.Metric.normalize(currentCameraDir `cross` currentCameraUp)))
else return ()
GLFW.getKey window GLFW.Key'Down >>= \s ->
if (s == GLFW.KeyState'Pressed) then
cameraPos $~ (+ ((-1)*cameraSpeed *^ currentCameraDir))
else return ()
GLFW.getKey window GLFW.Key'Up >>= \s ->
if (s == GLFW.KeyState'Pressed) then
cameraPos $~ (+ (cameraSpeed *^ currentCameraDir))
else return ()
yaw_val <- get yaw
pitch_val <- get pitch
GLFW.getKey window GLFW.Key'W >>= \s ->
if (s == GLFW.KeyState'Pressed) then
pitch $~ (+ (cameraSpeed * sensitivity))
else return ()
GLFW.getKey window GLFW.Key'S >>= \s ->
if (s == GLFW.KeyState'Pressed) then
pitch $~ (+ ((-1)*cameraSpeed * sensitivity))
else return ()
GLFW.getKey window GLFW.Key'A >>= \s ->
if (s == GLFW.KeyState'Pressed) then
yaw $~ (+ ((-1)*cameraSpeed * sensitivity))
else return ()
GLFW.getKey window GLFW.Key'D >>= \s ->
if (s == GLFW.KeyState'Pressed) then
yaw $~ (+ (cameraSpeed * sensitivity))
else return ()
yaw_val <- get yaw
pitch_val <- get pitch
if abs yaw_val > 360 then
yaw $~ (\x -> (signum x) * (abs x - (fromIntegral.floor) (abs x/360) * 360))
else
return ()
if abs pitch_val > 89 then
pitch $= (signum pitch_val) * 89
else
return ()
yaw_val' <- get yaw
pitch_val' <- get pitch
cameraDir $= calcDirectionVector yaw_val' pitch_val'
framebufferSizeCallback :: GLFW.FramebufferSizeCallback
framebufferSizeCallback window width height =
GL.viewport $= (GL.Position 0 0, GL.Size (fromIntegral width) (fromIntegral height))
v3ToVector3 :: V3 GLfloat -> Vector3 GLfloat
v3ToVector3 (V3 x y z) = Vector3 x y z
mat4ToGLmatrix :: M44 GLfloat -> IO (GLmatrix GLfloat)
mat4ToGLmatrix d = (GL.newMatrix GL.ColumnMajor $ mat4ToList $ d)
mat4ToList :: M44 a -> [a]
mat4ToList (V4 (V4 a11 a12 a13 a14) (V4 a21 a22 a23 a24) (V4 a31 a32 a33 a34) (V4 a41 a42 a43 a44)) =
[a11,a21,a31,a41,a12,a22,a32,a42,a13,a23,a33,a43,a14,a24,a34,a44]
radians :: (Floating a) => a -> a
radians x = x * pi/180
mat4_translate :: (Num a) => V3 a -> M44 a
mat4_translate (V3 r1 r2 r3) =
(V4 (V4 1 0 0 r1) (V4 0 1 0 r2) (V4 0 0 1 r3) (V4 0 0 0 1))
mat4_scale :: (Num a) => a -> a -> a -> M44 a
mat4_scale x y z =
(V4 (V4 x 0 0 0) (V4 0 y 0 0) (V4 0 0 z 0) (V4 0 0 0 1))
mat4_rotate :: (Epsilon a, Floating a) => V3 a -> a -> M44 a
mat4_rotate axis angle =
(mkTransformation (axisAngle axis angle) $ V3 0 0 0)
mat4_perspective :: (Floating a) => a -> a -> a -> a -> M44 a
mat4_perspective fovX aspect near far =
(V4 (V4 (near/npWith_2) 0 0 0) (V4 0 (near/npHeight_2) 0 0)
(V4 0 0 (-(far+near)/d) (-2*far*near/d)) (V4 0 0 (-1) 0))
where
d = far - near
npWith_2 = near * tan (fovX/2)
npHeight_2 = npWith_2 / aspect
mat4_ortho :: (Floating a) => a -> a -> a -> a -> M44 a
mat4_ortho npWidth npHeight near far =
(V4 (V4 (1/npWith_2) 0 0 0) (V4 0 (1/npHeight_2) 0 0)
(V4 0 0 (-2/d) (-1*(far+near)/d)) (V4 0 0 0 1))
where
d = far - near
npWith_2 = npWidth/2
npHeight_2 = npHeight/2
mat4_lookAt :: (Epsilon a, Floating a) => V3 a -> V3 a -> V3 a -> M44 a
mat4_lookAt pos target up =
pTrans !*! mat4_translate (-pos)
where
cDir = Linear.Metric.normalize $ target - pos
cRight = Linear.Metric.normalize $ cDir `cross` up
cUp = cRight `cross` cDir
pTrans = mkTransformationMat (V3 cRight cUp (-cDir)) (V3 0 0 0)
removeTranslation :: (Num a) => M44 a -> M44 a
removeTranslation (V4 (V4 a11 a12 a13 _) (V4 a21 a22 a23 _) (V4 a31 a32 a33 _) _) =
(V4 (V4 a11 a12 a13 0) (V4 a21 a22 a23 0) (V4 a31 a32 a33 0) (V4 0 0 0 1))
skyboxVertices :: [GLfloat]
skyboxVertices =
[(-1), 1, (-1)
,(-1), (-1), (-1)
,1, (-1), (-1)
,1, (-1), (-1)
,1, 1, (-1)
,(-1), 1, (-1)
,(-1), (-1), 1
,(-1), (-1), (-1)
,(-1), 1, (-1)
,(-1), 1, (-1)
,(-1), 1, 1
,(-1), (-1), 1
,1, (-1), (-1)
,1, (-1), 1
,1, 1, 1
,1, 1, 1
,1, 1, (-1)
,1, (-1), (-1)
,(-1), (-1), 1
,(-1), 1, 1
,1, 1, 1
,1, 1, 1
,1, (-1), 1
,(-1), (-1), 1
,(-1), 1, (-1)
,1, 1, (-1)
,1, 1, 1
,1, 1, 1
,(-1), 1, 1
,(-1), 1, (-1)
,(-1), (-1), (-1)
,(-1), (-1), 1
,1, (-1), (-1)
,1, (-1), (-1)
,(-1), (-1), 1
,1, (-1), 1]
model_cube :: [GLfloat]
model_cube =
[(-0.5), (-0.5), (-0.5), 0, 0, (-1), 0, 0
,(-0.5), 0.5, (-0.5), 0, 0, (-1), 0, 1
,0.5, 0.5, (-0.5), 0, 0, (-1), 1, 1
,0.5, 0.5, (-0.5), 0, 0, (-1), 1, 1
,0.5, (-0.5), (-0.5), 0, 0, (-1), 1, 0
,(-0.5), (-0.5), (-0.5), 0, 0, (-1), 0, 0
,(-0.5), (-0.5), 0.5, 0, 0, 1, 0, 0
,0.5, (-0.5), 0.5, 0, 0, 1, 1, 0
,0.5, 0.5, 0.5, 0, 0, 1, 1, 1
,0.5, 0.5, 0.5, 0, 0, 1, 1, 1
,(-0.5), 0.5, 0.5, 0, 0, 1, 0, 1
,(-0.5), (-0.5), 0.5, 0, 0, 1, 0, 0
,(-0.5), 0.5, 0.5, (-1), 0, 0, 1, 0
,(-0.5), 0.5, (-0.5), (-1), 0, 0, 1, 1
,(-0.5), (-0.5), (-0.5), (-1), 0, 0, 0, 1
,(-0.5), (-0.5), (-0.5), (-1), 0, 0, 0, 1
,(-0.5), (-0.5), 0.5, (-1), 0, 0, 0, 0
,(-0.5), 0.5, 0.5, (-1), 0, 0, 1, 0
,0.5, 0.5, 0.5, 1, 0, 0, 1, 0
,0.5, (-0.5), 0.5, 1, 0, 0, 0, 0
,0.5, (-0.5), (-0.5), 1, 0, 0, 0, 1
,0.5, (-0.5), (-0.5), 1, 0, 0, 0, 1
,0.5, 0.5, (-0.5), 1, 0, 0, 1, 1
,0.5, 0.5, 0.5, 1, 0, 0, 1, 0
,(-0.5), (-0.5), (-0.5), 0, (-1), 0, 0, 1
,0.5, (-0.5), (-0.5), 0, (-1), 0, 1, 1
,0.5, (-0.5), 0.5, 0, (-1), 0, 1, 0
,0.5, (-0.5), 0.5, 0, (-1), 0, 1, 0
,(-0.5), (-0.5), 0.5, 0, (-1), 0, 0, 0
,(-0.5), (-0.5), (-0.5), 0, (-1), 0, 0, 1
,(-0.5), 0.5, (-0.5), 0, 1, 0, 0, 1
,(-0.5), 0.5, 0.5, 0, 1, 0, 0, 0
,0.5, 0.5, 0.5, 0, 1, 0, 1, 0
,0.5, 0.5, 0.5, 0, 1, 0, 1, 0
,0.5, 0.5, (-0.5), 0, 1, 0, 1, 1
,(-0.5), 0.5, (-0.5), 0, 1, 0, 0, 1]
planeVertices :: [GLfloat]
planeVertices =
[(-210), (-0.5), (-210), 0, 1, 0, 0, 210
,(-210), (-0.5), 210, 0, 1, 0, 0, 0
,210, (-0.5), 210, 0, 1, 0, 210, 0
,210, (-0.5), (-210), 0, 1, 0, 210, 210
,(-210), (-0.5), (-210), 0, 1, 0, 0, 210
,210, (-0.5), 210, 0, 1, 0, 210, 0]
quadVertices :: [GLfloat]
quadVertices =
[(-1), 1, 0, 0, 1
,(-1), (-1), 0, 0, 0
,1, 1, 0, 1, 1
,1, (-1), 0, 1, 0]
makeStateVarFromPtr :: Storable a => Ptr a -> StateVar a
makeStateVarFromPtr p = makeStateVar (peek p) (poke p)
calcDirectionVector :: GLfloat -> GLfloat -> V3 GLfloat
calcDirectionVector yaw_deg pitch_deg =
Linear.Metric.normalize $ V3 x y z
where
yaw = radians (yaw_deg - 90)
pitch = radians pitch_deg
x = cos yaw * cos pitch
y = sin pitch
z = sin yaw * cos pitch
withImg :: Bool -> String -> (Ptr GLubyte -> GLsizei -> GLsizei -> IO ()) -> IO Bool
withImg upsidedown imgSrc action = do
img' <- readImageWithMetadata imgSrc
case img' of
Left s -> (putStrLn $ "Error: " ++ s) >> return False
Right (img, metaData) -> do
t <- return $ do
w <- (JP.lookup Width metaData)
h <- (JP.lookup Height metaData)
return (w,h)
case t of
Nothing -> (putStrLn "Failed to read meta-data") >> return False
Just (imgWidth, imgHeight) -> do
(width, height) <- return (fromIntegral imgWidth, fromIntegral imgHeight)
imgRGB <- return $ convertRGB8 img
ptr <- mallocArray (width*height*3)
if upsidedown then
($(0,0)) . fix $ \rec (i,j) ->
if i < height then do
let
(PixelRGB8 r g b) = pixelAt imgRGB j i
rbg_GLubyte = (fmap fromIntegral $ [r,g,b])::[GLubyte]
pokeElemOff ptr (3*(width*(height-1-i)+j) + 0) (rbg_GLubyte!!0)
pokeElemOff ptr (3*(width*(height-1-i)+j) + 1) (rbg_GLubyte!!1)
pokeElemOff ptr (3*(width*(height-1-i)+j) + 2) (rbg_GLubyte!!2)
(return $ if (succ j) >= width then (succ i, 0) else (i, succ j))
>>= rec
else
return ()
else
($(0,0)) . fix $ \rec (i,j) ->
if i < height then do
let
(PixelRGB8 r g b) = pixelAt imgRGB j i
rbg_GLubyte = (fmap fromIntegral $ [r,g,b])::[GLubyte]
pokeElemOff ptr (3*(width*i+j) + 0) (rbg_GLubyte!!0)
pokeElemOff ptr (3*(width*i+j) + 1) (rbg_GLubyte!!1)
pokeElemOff ptr (3*(width*i+j) + 2) (rbg_GLubyte!!2)
(return $ if (succ j) >= width then (succ i, 0) else (i, succ j))
>>= rec
else
return ()
action ptr (fromIntegral imgWidth) (fromIntegral imgHeight)
free ptr
return True
buildShaderProgram :: Window -> [String] -> IO Program
buildShaderProgram window shaders = do
vertexShaderSource <- B.readFile $ selectShaderSrc Shader_Vert shaders
fragmentShaderSource <- B.readFile $ selectShaderSrc Shader_Frag shaders
GLFW.makeContextCurrent (Just window)
vertexShader <- compileShaderSrc vertexShaderSource GL.VertexShader
checkIfSuccess $ Left vertexShader
fragmentShader <- compileShaderSrc fragmentShaderSource GL.FragmentShader
checkIfSuccess $ Left fragmentShader
shaderProgram <- GL.createProgram
GL.attachShader shaderProgram vertexShader
GL.attachShader shaderProgram fragmentShader
GL.linkProgram shaderProgram
checkIfSuccess $ Right shaderProgram
deleteObjectName vertexShader
deleteObjectName fragmentShader
return shaderProgram
data ShaderType = Shader_Vert | Shader_Frag | Shader_Unknown deriving Eq
selectShaderSrc t xs = do
let xs' = zip (fmap getShaderType $ xs) xs
(shaderType, fileName) <- xs'
if shaderType == t then
fileName
else
[]
getShaderType fileName =
if ext == ".vs" then
Shader_Vert
else if ext == ".fs" then
Shader_Frag
else
Shader_Unknown
where ext = '.' : (reverse $ takeWhile (/='.') $ reverse fileName)
checkIfSuccess obj = case obj of
Left shaderObj -> do
success <- get $ GL.compileStatus shaderObj
if success then
return ()
else do
infoLog <- get $ GL.shaderInfoLog shaderObj
putStrLn $ "ERROR::COMPILATION_FAILED\n" ++ infoLog
Right shaderProgramObj -> do
success <- get $ GL.linkStatus shaderProgramObj
if success then
return ()
else do
infoLog <- get $ GL.programInfoLog shaderProgramObj
putStrLn $ "ERROR::LINKING_FAILED\n" ++ infoLog
compileShaderSrc src t = do
shaderObj <- GL.createShader t
GL.shaderSourceBS shaderObj $= src
GL.compileShader shaderObj
return shaderObj
bufferListData t l u =
withArray l $ \ptr2Data -> do
let sizeOfData = fromIntegral $ (length l) * (sizeOf $ l !! 0)
GL.bufferData t $= (sizeOfData, ptr2Data, u)
loadTexture2D :: String -> IO TextureObject
loadTexture2D src = do
texture <- genObjectName
GL.textureBinding GL.Texture2D $= Just texture
GL.textureFilter GL.Texture2D
$= ((GL.Linear', Just GL.Linear'), GL.Linear')
GL.textureWrapMode GL.Texture2D GL.S
$= (GL.Repeated, GL.Repeat)
GL.textureWrapMode GL.Texture2D GL.T
$= (GL.Repeated, GL.Repeat)
withImg True src $ \ptr imgWidth imgHeight -> do
GL.texImage2D GL.Texture2D GL.NoProxy 0 GL.RGB'
(TextureSize2D imgWidth imgHeight) 0
(GL.PixelData GL.RGB GL.UnsignedByte ptr)
GL.generateMipmap' GL.Texture2D
return texture
initAttribVars :: Int -> [(GLint, Maybe AttribLocation)] -> IO ()
initAttribVars sizeOfElm v_layout = foldr (>>) (return ()) $ do
i <- enumFromTo 0 (pred . length $ v_layout)
return $ do
let
size = v_layout1 !! i
attribLoc' = v_layout2 !! i
offset = v_layout3 !! i
stride = last v_layout3
case attribLoc' of
Just attribLoc -> do
GL.vertexAttribPointer attribLoc
$= (GL.ToFloat, GL.VertexArrayDescriptor size GL.Float stride (plusPtr nullPtr . fromIntegral $ offset))
GL.vertexAttribArray attribLoc $= GL.Enabled
Nothing -> return ()
where
v_layout1 = fmap fst $ v_layout
v_layout2 = fmap snd $ v_layout
v_layout3 = do
d <- return v_layout1
x <- (0:) . foldr (\a b -> zipWith (+) (repeat a) (0:b)) [] $ d
return $ x * (fromIntegral sizeOfElm)
loadCubemap :: [String] -> IO (Maybe TextureObject)
loadCubemap faces = do
let
labels =
[ GL.TextureCubeMapPositiveX
, GL.TextureCubeMapNegativeX
, GL.TextureCubeMapPositiveY
, GL.TextureCubeMapNegativeY
, GL.TextureCubeMapPositiveZ
, GL.TextureCubeMapNegativeZ ]
if length faces == 6 then do
texture <- genObjectName
GL.textureBinding GL.TextureCubeMap $= Just texture
($0) . fix $ \rec i -> do
if i < 6 then do
success <- withImg False (faces !! i) $ \ptr imgWidth imgHeight -> do
GL.texImage2D (labels !! i) GL.NoProxy 0 GL.RGB'
(TextureSize2D imgWidth imgHeight) 0
(GL.PixelData GL.RGB GL.UnsignedByte ptr)
if success then do
-- print $ (faces !! i, labels !! i)
rec $ succ i
else do
-- putStrLn "Failed to load images."
return Nothing
else do
GL.textureFilter GL.TextureCubeMap
$= ((GL.Linear', Nothing), GL.Linear')
GL.textureWrapMode GL.TextureCubeMap GL.S
$= (GL.Repeated, GL.ClampToEdge)
GL.textureWrapMode GL.TextureCubeMap GL.T
$= (GL.Repeated, GL.ClampToEdge)
GL.textureWrapMode GL.TextureCubeMap GL.R
$= (GL.Repeated, GL.ClampToEdge)
return $ Just texture
else do
-- putStrLn "The number of pictures is inadequate."
return Nothing
lerp' :: (Num a) => a -> a -> a -> a
lerp' a b t = a + t*(b-a)
タグ一覧: