summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-06-16 23:47:34 -0400
committerJoe Crayne <joe@jerkface.net>2019-06-17 02:34:36 -0400
commitf9a26d4785260fef8fcb2a19bc8edcfccab94dbf (patch)
tree89abb5aa9a8808198134238fc89ee111d3fb1ac0
parent93616e1bd801d9a4bf78e2da3cb076af91534580 (diff)
Scale loaded mesh to fit viewport.
-rw-r--r--LoadMesh.hs82
-rw-r--r--MeshSketch.hs3
2 files changed, 78 insertions, 7 deletions
diff --git a/LoadMesh.hs b/LoadMesh.hs
index affadba..9eaa047 100644
--- a/LoadMesh.hs
+++ b/LoadMesh.hs
@@ -1,5 +1,6 @@
1{-# LANGUAGE LambdaCase #-} 1{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE RecordWildCards #-} 2{-# LANGUAGE RecordWildCards #-}
3{-# LANGUAGE FlexibleContexts #-}
3module LoadMesh where 4module LoadMesh where
4 5
5import LambdaCube.GL as LambdaCubeGL -- renderer 6import LambdaCube.GL as LambdaCubeGL -- renderer
@@ -15,13 +16,16 @@ import qualified Data.ByteString as SB
15import qualified Data.ByteString.Lazy.Char8 as L 16import qualified Data.ByteString.Lazy.Char8 as L
16import Data.Text (unpack,Text) 17import Data.Text (unpack,Text)
17import Data.List (groupBy,nub) 18import Data.List (groupBy,nub)
19import Numeric.LinearAlgebra hiding ((<>))
18 20
19import Codec.Picture as Juicy 21import Codec.Picture as Juicy
20import Wavefront 22import Wavefront
21import Wavefront.Types 23import Wavefront.Types
22import Data.Aeson 24import Data.Aeson
23 25
24type MeshData = ([(Mesh,Maybe Text)],MtlLib) 26type MeshData = ( [(Mesh,Maybe Text)] -- List of uniform-material meshes (and the name of the material).
27 , MtlLib -- Material definitions.
28 )
25 29
26loadOBJ :: String -> IO (Either String MeshData) 30loadOBJ :: String -> IO (Either String MeshData)
27loadOBJ fname = L.readFile fname >>= \bs -> do 31loadOBJ fname = L.readFile fname >>= \bs -> do
@@ -31,10 +35,76 @@ loadOBJ fname = L.readFile fname >>= \bs -> do
31 return $ Right (objToMesh obj,mtlLib) 35 return $ Right (objToMesh obj,mtlLib)
32 36
33 37
34uploadOBJToGPU :: MeshData -> IO ([(GPUMesh, Maybe Text)], MtlLib) 38data BoundingBox = BoundingBox
35uploadOBJToGPU (subModels,mtlLib) = do 39 { minX :: Float
36 gpuSubModels <- forM subModels $ \(mesh,mat) -> LambdaCubeGL.uploadMeshToGPU mesh >>= \a -> return (a,mat) 40 , maxX :: Float
37 return (gpuSubModels,mtlLib) 41 , minY :: Float
42 , maxY :: Float
43 , minZ :: Float
44 , maxZ :: Float
45 }
46 deriving (Eq,Ord,Show)
47
48instance Semigroup BoundingBox where
49 a <> b = BoundingBox
50 { minX = if minX b < minX a then minX b else minX a
51 , maxX = if maxX b > maxX a then maxX b else maxX a
52 , minY = if minY b < minY a then minY b else minY a
53 , maxY = if maxY b > maxY a then maxY b else maxY a
54 , minZ = if minZ b < minZ a then minZ b else minZ a
55 , maxZ = if maxZ b > maxZ a then maxZ b else maxZ a
56 }
57instance Monoid BoundingBox where mempty = BoundingBox 0 0 0 0 0 0
58
59attribBoundingBox :: Map String MeshAttribute -> BoundingBox
60attribBoundingBox attrib = case Map.lookup "position" attrib of
61 Just (A_V3F vs) -> V.foldr (\(V3 x y z ) bb -> bb <> BoundingBox x x y y z z) mempty vs
62 Just (A_V4F vs) -> V.foldr (\(V4 x y z _) bb -> bb <> BoundingBox x x y y z z) mempty vs
63 _ -> mempty
64
65bbnorm :: BoundingBox -> Float
66bbnorm (BoundingBox x0 x y0 y z0 z) = sqrt $ (x-x0)^2 + (y-y0)^2 + (z-z0)^2
67
68scaleWithin :: BoundingBox -> BoundingBox -> Matrix Float
69scaleWithin meshbb scalebb =
70 if meshbb <> scalebb /= scalebb
71 || (let {m=bbnorm meshbb; s=bbnorm scalebb} in m < 0.1*s)
72 then let tr0 = (4><4) [ 1,0,0, negate $ (minX meshbb + maxX meshbb)/2
73 , 0,1,0, negate $ (minY meshbb + maxY meshbb)/2
74 , 0,0,1, negate $ (minZ meshbb + maxZ meshbb)/2
75 , 0,0,0, 1 ]
76 sc = (4><4) [s,0,0,0
77 ,0,s,0,0
78 ,0,0,s,0
79 ,0,0,0,1]
80 s = minimum [sx,sy,sz]
81 sx = (maxX scalebb - minX scalebb) / (maxX meshbb - minX meshbb)
82 sy = (maxY scalebb - minY scalebb) / (maxY meshbb - minY meshbb)
83 sz = (maxZ scalebb - minZ scalebb) / (maxZ meshbb - minZ meshbb)
84 tr1 = (4><4) [ 1,0,0, (minX scalebb + maxX scalebb)/2
85 , 0,1,0, (minY scalebb + maxY scalebb)/2
86 , 0,0,1, (minZ scalebb + maxZ scalebb)/2
87 , 0,0,0, 1 ]
88 in tr1 <> sc <> tr0
89 else ident 4
90
91transV3 t (V3 x y z) = let v = t #> fromList [x,y,z,1] in V3 (v!0/v!3) (v!1/v!3) (v!2/v!3)
92transV4 t (V4 x y z w) = let v = t #> fromList [x,y,z,w] in V4 (v!0) (v!1) (v!2) (v!3)
93
94tranformAttribute t (A_V3F v) = A_V3F $ transV3 t <$> v
95tranformAttribute t (A_V4F v) = A_V4F $ transV4 t <$> v
96
97transformMesh :: Matrix Float -> Mesh -> Mesh
98transformMesh t m = m
99 { mAttributes = Map.adjust (tranformAttribute t) "position" (mAttributes m)
100 }
101
102uploadOBJToGPU :: Maybe BoundingBox -> MeshData -> IO (([(GPUMesh, Maybe Text)], MtlLib),Matrix Float)
103uploadOBJToGPU scalebb (subModels,mtlLib) = do
104 let meshbb = foldMap (attribBoundingBox . mAttributes . fst) subModels :: BoundingBox
105 m = maybe (ident 4) (scaleWithin meshbb) scalebb
106 gpuSubModels <- forM subModels $ \(mesh,mat) -> LambdaCubeGL.uploadMeshToGPU (transformMesh m mesh) >>= \a -> return (a,mat)
107 return ((gpuSubModels,mtlLib),m)
38 108
39uploadMtlLib :: MtlLib -> IO (Map Text (ObjMaterial,TextureData)) 109uploadMtlLib :: MtlLib -> IO (Map Text (ObjMaterial,TextureData))
40uploadMtlLib mtlLib = do 110uploadMtlLib mtlLib = do
@@ -45,7 +115,7 @@ uploadMtlLib mtlLib = do
45 checkerTex <- LambdaCubeGL.uploadTexture2DToGPU checkerImage 115 checkerTex <- LambdaCubeGL.uploadTexture2DToGPU checkerImage
46 -- load images and upload to gpu 116 -- load images and upload to gpu
47 textureLib <- forM (Map.fromList $ zip usedTextures usedTextures) $ \fname -> Juicy.readImage fname >>= \case 117 textureLib <- forM (Map.fromList $ zip usedTextures usedTextures) $ \fname -> Juicy.readImage fname >>= \case
48 Left err -> putStrLn err >> return checkerTex 118 Left err -> putStrLn (fname ++": "++err) >> return checkerTex
49 Right img -> LambdaCubeGL.uploadTexture2DToGPU img 119 Right img -> LambdaCubeGL.uploadTexture2DToGPU img
50 whiteTex <- LambdaCubeGL.uploadTexture2DToGPU whiteImage 120 whiteTex <- LambdaCubeGL.uploadTexture2DToGPU whiteImage
51 -- pair textures and materials 121 -- pair textures and materials
diff --git a/MeshSketch.hs b/MeshSketch.hs
index f1ee612..a153f5e 100644
--- a/MeshSketch.hs
+++ b/MeshSketch.hs
@@ -163,7 +163,8 @@ xzPlaneVector = fromList [ 0,1,0 -- unit normal
163uploadState :: IsWidget glarea => MeshData -> glarea -> GLStorage -> IO State 163uploadState :: IsWidget glarea => MeshData -> glarea -> GLStorage -> IO State
164uploadState obj glarea storage = do 164uploadState obj glarea storage = do
165 -- load OBJ geometry and material descriptions 165 -- load OBJ geometry and material descriptions
166 (objMesh,mtlLib) <- uploadOBJToGPU obj 166 let workarea = BoundingBox (-1.5) (1.5) (-1.5) 1.5 (-1.5) (1.5)
167 ((objMesh,mtlLib),objscale) <- uploadOBJToGPU (Just workarea) obj
167 -- load materials textures 168 -- load materials textures
168 gpuMtlLib <- uploadMtlLib mtlLib 169 gpuMtlLib <- uploadMtlLib mtlLib
169 -- add OBJ to pipeline input 170 -- add OBJ to pipeline input