Skip to content

Commit 4cacee8

Browse files
authored
Merge pull request #20 from alt-romes/wip/romes/planets
Finally use textures again for planets demo
2 parents 022c1df + fe107b2 commit 4cacee8

File tree

24 files changed

+409
-640
lines changed

24 files changed

+409
-640
lines changed

examples/full-pipeline/Main.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ main =
9090
runCore (640, 480) Linear.do
9191
(rp1, rp2) <- (Alias.share =<< createSimpleRenderPass )
9292

93-
pipeline :: RenderPipeline π ps <- (makeRenderPipeline rp1 shaderPipeline (StaticBinding (Ur (defaultCamera @"view" @"proj")) :## GHNil) )
93+
pipeline :: RenderPipeline π ps <- (makeRenderPipeline rp1 shaderPipeline (StaticBinding (Ur (cameraLookAt @"view" @"proj" (vec3 0 0 0) (vec3 0 0 1) (640, 480))) :## GHNil) )
9494
(emptyMat, pipeline) <- (material GHNil pipeline )
9595
(mesh :: IcosahedronMesh, pipeline) <- (createMeshWithIxs pipeline GHNil icosahedronVerts icosahedronIndices )
9696

examples/ghengin-games.cabal

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ common common-flags
139139
executable planets-core
140140
import: common-flags
141141
main-is: Main.hs
142-
other-modules: Planet, Shaders
142+
other-modules: Planet, Planet.Noise, Shaders
143143
hs-source-dirs: planets-core
144144

145145
-- library
@@ -229,11 +229,11 @@ executable function-plotting
229229
hs-source-dirs: function-plotting/
230230

231231
-- An XY oscilloscope; TODO: NOT FINISHED
232-
executable oscilloscope
233-
import: common-flags
234-
main-is: Main.hs
235-
other-modules: Shaders
236-
hs-source-dirs: oscilloscope/
232+
-- executable oscilloscope
233+
-- import: common-flags
234+
-- main-is: Main.hs
235+
-- other-modules: Shaders
236+
-- hs-source-dirs: oscilloscope/
237237

238238
-- The Lorenz Attractor
239239
executable lorenz-attractor

examples/planets-core/Main.hs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import Ghengin.Camera
5656
-- planets!
5757
import Shaders -- planet shaders
5858
import Planet
59+
import Planet.Noise
5960

6061
gameLoop :: _
6162
=> UTCTime -> _ -> _ -> Alias RenderPass RenderQueue () Core (RenderQueue ())
@@ -85,19 +86,19 @@ main = do
8586
currTime <- getCurrentTime
8687
withLinearIO $
8788
runCore (1280, 720) Linear.do
88-
-- sampler <- ( createSampler FILTER_NEAREST SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ↑)
89-
-- tex <- ( texture "assets/planet_gradient.png" sampler ↑)
89+
sampler <- ( createSampler FILTER_NEAREST SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE )
90+
tex <- ( texture "examples/planets-core/assets/planet_gradient.png" sampler )
9091

9192
(rp1, rp2) <- (Alias.share =<< createSimpleRenderPass )
92-
pipeline <- (makeRenderPipeline rp1 shaders (StaticBinding (Ur camera) :## GHNil) )
93-
(p1mesh, pipeline) <- newPlanetMesh pipeline defaultPlanet
94-
(emptyMat, pipeline) <- (material GHNil pipeline )
95-
-- (pmat, pipeline) <- newPlanetMaterial minmax tex pipeline
93+
pipeline <- (makeRenderPipeline rp1 shaders (StaticBinding (Ur camera) :## GHNil) )
94+
( (pmesh, pipeline),
95+
Ur minmax ) <- newPlanetMesh pipeline defaultPlanet
96+
(pmat, pipeline) <- newPlanetMaterial minmax tex pipeline
9697

9798
-- remember to provide helper function in ghengin to insert meshes with pipelines and mats, without needing to do this:
9899
(rq, Ur pkey) <- pure (insertPipeline pipeline LMon.mempty)
99-
(rq, Ur mkey) <- pure (insertMaterial pkey emptyMat rq)
100-
(rq, Ur mshkey) <- pure (insertMesh mkey p1mesh rq)
100+
(rq, Ur mkey) <- pure (insertMaterial pkey pmat rq)
101+
(rq, Ur mshkey) <- pure (insertMesh mkey pmesh rq)
101102

102103
rq <- gameLoop currTime mshkey 0 rp2 rq
103104

@@ -112,8 +113,29 @@ defaultPlanet :: Planet
112113
defaultPlanet = Planet
113114
{ resolution = 100
114115
, planetShape = PlanetShape
115-
{ planetRadius = 1
116-
, planetNoise = CoherentNoise (vec3 0 0 0) 1 1
116+
{ planetRadius = 2.50
117+
, planetNoise = AddNoiseMasked
118+
[ StrengthenNoise 0.12 $ MinValueNoise
119+
{ minNoiseVal = 1.1
120+
, baseNoise = LayersCoherentNoise
121+
{ centre = vec3 0 0 0
122+
, baseRoughness = 0.71
123+
, roughness = 1.83
124+
, numLayers = 5
125+
, persistence = 0.54
126+
}
127+
}
128+
, StrengthenNoise 2.5 $ MinValueNoise
129+
{ minNoiseVal = 0
130+
, baseNoise = RidgedNoise
131+
{ seed = 123
132+
, octaves = 5
133+
, scale = 1
134+
, frequency = 2
135+
, lacunarity = 3
136+
}
137+
}
138+
]
117139
}
118140
}
119141

examples/planets-core/Planet.hs

Lines changed: 20 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import Ghengin.Core.Type.Compatible
1616
import Data.List (foldl')
1717
import Ghengin.Core.Log
1818

19-
import GHC.Float
20-
import Numeric.Noise hiding (Noise)
2119
import qualified Data.List.NonEmpty as NE
2220
import qualified Data.Vector as V
2321

@@ -36,6 +34,8 @@ import qualified Math.Linear as FIR
3634

3735
import Ghengin.Core.Shader.Data
3836

37+
import Planet.Noise
38+
3939
--------------------------------------------------------------------------------
4040
-- * Planet
4141
--------------------------------------------------------------------------------
@@ -63,69 +63,48 @@ data PlanetShape = PlanetShape
6363
}
6464

6565
-- | Make the point on a planet for the given point on a unit sphere
66-
pointOnPlanet :: PlanetShape -> Vec3 -> Vec3
66+
--
67+
-- Returns the updated point and the elevation of that point
68+
pointOnPlanet :: PlanetShape -> Vec3 -> (Vec3, Float)
6769
pointOnPlanet PlanetShape{..} pointOnUnitSphere =
6870
let elevation = evalNoise planetNoise pointOnUnitSphere
69-
in pointOnUnitSphere ^* planetRadius ^* (1+elevation)
71+
finalElevation = planetRadius * (1+elevation)
72+
in (pointOnUnitSphere ^* finalElevation, finalElevation)
7073

74+
-- | Construct the planet mesh and return the minimum and maximum elevation points on the planet
7175
newPlanetMesh :: _ -- more constraints
7276
=> CompatibleVertex '[Vec3, Vec3] π
7377
=> CompatibleMesh '[Transform] π
7478
=> RenderPipeline π bs
7579
Planet
76-
-> Core (PlanetMesh, RenderPipeline π bs)
80+
-> Core ((PlanetMesh, RenderPipeline π bs), Ur MinMax)
7781
newPlanetMesh rp Planet{..} = enterD "newPlanetMesh" $ Linear.do
7882

7983
let UnitSphere us is = newUnitSphere resolution
8084

81-
planetVxs = P.map (\(p :&: n) -> pointOnPlanet planetShape p :&: n) us
82-
83-
-- (ps', elevations) = P.unzip $ (`map` vs) \(p :& _) ->
84-
-- case nss of
85-
-- ns NE.:| nss' ->
86-
-- let initialElevation = evalNoise ns p
87-
-- mask = if enableMask then initialElevation else 1
88-
-- noiseElevation = foldl' (\acc ns' -> acc + (evalNoise ns' p)*mask) initialElevation nss'
89-
-- elevation = ra * (1 + noiseElevation)
90-
-- in (p ^* (elevation), elevation)
91-
--
92-
-- ns' = V.toList $ computeNormals (V.fromList (P.map fromIntegral is)) (V.fromList ps')
93-
-- vs'' = P.zipWith3 (\a b c -> a :& b :&: c) ps' ns' (map (\(_ :& _ :&: c) -> c) vs)
85+
(planetPs, elevations)
86+
= P.unzip $ P.map (\(p :&: _) -> pointOnPlanet planetShape p) us
87+
planetNs = V.toList $ computeNormals (V.fromList (P.map fromIntegral is)) (V.fromList planetPs)
88+
planetVs = P.zipWith (:&:) planetPs planetNs
9489

95-
-- minmax = MinMax (P.minimum elevations) (P.maximum elevations)
90+
minmax = MinMax (P.minimum elevations) (P.maximum elevations)
9691

97-
in (createMeshWithIxs rp (DynamicBinding (Ur mempty) :## GHNil) planetVxs is )
92+
in (, Ur minmax) <$> (createMeshWithIxs rp (DynamicBinding (Ur mempty) :## GHNil) planetVs is )
9893

9994
--------------------------------------------------------------------------------
10095
-- * Material
10196
--------------------------------------------------------------------------------
10297

98+
type PlanetMaterial = Material '[MinMax, Texture2D (RGBA8 UNorm)]
99+
103100
newPlanetMaterial :: forall π p
104-
. CompatibleMaterial '[MinMax,Texture2D] π
101+
. CompatibleMaterial '[MinMax, Texture2D (RGBA8 UNorm)] π
105102
=> MinMax
106-
-> Alias Texture2D
103+
-> Alias (Texture2D (RGBA8 UNorm))
107104
RenderPipeline π p
108-
Core (Material '[MinMax,Texture2D], RenderPipeline π p)
105+
Core (PlanetMaterial, RenderPipeline π p)
109106
newPlanetMaterial mm t pl = ( material @_ @π (StaticBinding (Ur mm) :## Texture2DBinding t :## GHNil) pl )
110107

111-
--------------------------------------------------------------------------------
112-
-- * Noise
113-
--------------------------------------------------------------------------------
114-
115-
data Noise = CoherentNoise
116-
{ centre :: !Vec3
117-
, roughness :: !Float
118-
, strength :: !Float
119-
}
120-
121-
evalNoise :: Noise -> Vec3 -> Float
122-
evalNoise CoherentNoise{..} point = double2Float
123-
let seed = 123456
124-
WithVec3 px py pz = point ^* roughness ^+^ centre
125-
noiseValue = coherentNoise seed (float2Double px, float2Double py, float2Double pz)
126-
noiseScaled = (noiseValue + 1) * 0.5 {-from [-1 to 1] to [0 to 1] -}
127-
in noiseScaled * float2Double strength
128-
129108
--------------------------------------------------------------------------------
130109

131110
-- non-compositional instance for "Transform", just for demo
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
module Planet.Noise where
2+
3+
import Prelude
4+
5+
import Geomancy (VectorSpace(..))
6+
import Geomancy.Vec3
7+
8+
import GHC.Float
9+
import Numeric.Noise hiding (Noise)
10+
import Numeric.Noise.Ridged as Ridged
11+
import qualified Data.List.NonEmpty as NonEmpty
12+
13+
--------------------------------------------------------------------------------
14+
-- * Noise
15+
--------------------------------------------------------------------------------
16+
17+
data Noise
18+
-- | Level of detail noise created by repeated application of coherent noise with
19+
-- geometrically increasing roughness and decreasing amplitude.
20+
--
21+
-- You can have simple coherent noise by having numLayers = 1
22+
= LayersCoherentNoise
23+
{ centre :: !Vec3
24+
-- Offset noise point
25+
, baseRoughness :: !Float
26+
-- ^ Roughness for the first layer
27+
, numLayers :: !Int
28+
-- ^ How many layers of detail
29+
, persistence :: !Double
30+
-- ^ Apply multiplier to cummulative strength per layer
31+
, roughness :: !Float
32+
-- ^ Apply multiplier to cummulative roughness per layer
33+
}
34+
-- | Ridged multi-fractal noise
35+
| RidgedNoise
36+
{ seed :: !Int
37+
, octaves :: !Int
38+
, scale :: !Double
39+
, frequency :: !Double
40+
, lacunarity :: !Double
41+
}
42+
-- | A noise value which evaluates the base noise value and makes sure it is
43+
-- at least the given min value
44+
| MinValueNoise
45+
{ minNoiseVal :: !Float
46+
-- ^ Value is increased to at least this much
47+
, baseNoise :: !Noise
48+
-- ^ The base noise value
49+
}
50+
| StrengthenNoise
51+
{ strength :: !Float
52+
-- ^ Multiplies by noise val
53+
, baseNoise :: !Noise
54+
-- ^ To compute the noise val
55+
}
56+
-- | Add noise filters using the first layer to mask all following ones
57+
| AddNoiseMasked
58+
{ noiseLayers :: ![Noise]
59+
}
60+
-- | Add noise filters unconditionally
61+
| AddNoiseLayers
62+
{ noiseLayers :: ![Noise]
63+
}
64+
65+
-- | Evaluate given 'Noise' at a 3D point
66+
evalNoise :: Noise -> Vec3 -> Float
67+
evalNoise LayersCoherentNoise{..} p
68+
= double2Float noiseVal
69+
where
70+
seed = 123456
71+
frequencies = baseRoughness : map (*roughness) frequencies
72+
amplitudes = 1 : map (*persistence) amplitudes
73+
layerNoise frequency amplitude =
74+
let v = coherentNoise seed (vec3Point (p ^* frequency ^+^ centre))
75+
in (v + 1) * 0.5 * amplitude {-from [-1 to 1] to [0 to 1], then * amplitude-}
76+
noiseVal =
77+
sum $ take numLayers $
78+
zipWith layerNoise frequencies amplitudes
79+
evalNoise StrengthenNoise{..} p = evalNoise baseNoise p * strength
80+
evalNoise MinValueNoise{..} p = max 0 (evalNoise baseNoise p - minNoiseVal)
81+
evalNoise RidgedNoise{..} p = double2Float $
82+
Ridged.noiseValue (ridged seed octaves scale frequency lacunarity) (vec3Point p)
83+
evalNoise AddNoiseMasked{..} p =
84+
case NonEmpty.nonEmpty noiseLayers of
85+
Nothing -> 0
86+
Just (firstLayer NonEmpty.:| otherLayers) ->
87+
let firstLayerVal = evalNoise firstLayer p
88+
in firstLayerVal + sum (map ((*firstLayerVal{-mask-}) . (`evalNoise` p)) otherLayers)
89+
evalNoise AddNoiseLayers{..} p = sum (map (`evalNoise` p) noiseLayers)
90+
91+
vec3Point :: Vec3 -> Point
92+
vec3Point (WithVec3 px py pz) = (float2Double px, float2Double py, float2Double pz)

0 commit comments

Comments
 (0)