Compare commits

...

8 Commits

9 changed files with 119 additions and 54 deletions

View File

@ -1,39 +1,49 @@
### FPS Scene
#+OPTIONS: toc:nil
You can walk around the scene with simple FPS controls.
Open `scene.html` with an http server, you can use the following;
* PQ Torus Knot
```python3 -m http.server 8000```
** About
Unfortunately, elm-reactor has issues with loading obj files so that's why the
python server is needed.
[[https://ferano.io/pqtk/][Live Link]]
![alt text](screenshots/elm-fps.png "FPS Scene")
This is an implementation of the [[https://en.wikipedia.org/wiki/Torus_knot][PQ Torus Knot]] in the Elm programming language
using WebGL.
** Showcase
##### Controls
[[file:./media/red-p2q5.gif]]
[[file:./media/blue-p3q5.gif]]
[[file:./media/green-p2q9.gif]]
[[file:./media/yellow-p8q9.gif]]
Mouse - Look Rotation
** Keybindings
WASD - Player movement
You can increment P or Q with the keyboard by pressing ~p~ or ~q~ and decrement with
the neighboring letter ~o~ and ~w~ respectively.
◀ ▼ ▲ ▶ - Move the Robot
- Incr/Decr P: ~p/o~
- Incr/Decr Q: ~q/w~
N and M - Rotate robot left and right
** Building with Elm 0.18.0
To install the binaries manually, follow this short guide; - [[https://sirfitz.medium.com/install-elm-0-18-0-in-2021-3f64ce298801][Install Binaries]]
Y and H - Rotate robot arm up and down
If you want to use =npm= instead; - =npm install -g elm@elm0.18.0=
U and J - Rotate robot hand up and down
If you use =npm=, note that you will likely need an older version of Node.js, so
it is recommended to use [[https://github.com/nvm-sh/nvm][nvm]] for that. I have not attempted this method
personally, fyi.
Once you have the Elm compiler, go ahead and run
### PQTorusknot
=elm make Torus.elm=
Either open up `torus.html`, or use the command `elm-reactor`, if you want to be able to modify the source file and compile;
And that should first pull in all the dependencies then generate an =index.html=
file.
https://guide.elm-lang.org/install.html
Alternatively, you can use ~elm-reactor~, run the command and open up your browser
to ~https://localhost:8000~ and then click on ~Torus.elm~ in the nice project
webview provided.
Alternatively, here's the Ellie link
https://ellie-app.com/vVTgpBj77ra1
![alt text](screenshots/elm-knot.png "PQ Torus Knot")
** License
This project is licensed under the terms of the MIT license. For more
information, see the included LICENSE file.

106
Torus.elm
View File

@ -3,6 +3,7 @@ module Torus exposing (..)
import Html exposing (Html)
import Html.Attributes exposing (width, height, style)
import AnimationFrame
import Keyboard exposing (..)
import Time exposing (Time)
import Math.Matrix4 as Mat4 exposing (Mat4)
import Math.Vector2 as Vec2 exposing (vec2, Vec2)
@ -25,19 +26,26 @@ type alias Attributes = { position : Vec3 , normal : Vec3 }
type Msg
= Animate Time
| KeyChange Bool Keyboard.KeyCode
| WindowResized Window.Size
type alias Model =
{ p : Float
, q : Float
-- , mesh : Mesh Attributes
, torus : Mesh Attributes
, time : Float
, winSize : Window.Size }
totalLinePoints = 250
ringRadius = 0.1
ringVerts = 40
knotScale = 0.2
init: ( Model , Cmd Msg )
init =
-- ( { p = 1 , q = 0 , time = 0.0 , winSize = (Window.Size 1 1)
( { p = 12 , q = 29 , time = 0.0 , winSize = (Window.Size 1 1)
( { p = 2 , q = 9 , time = 0.0 , winSize = (Window.Size 1 1)
, torus = constructTorus 2 9
-- ( { p = 8 , q = 9 , time = 0.0 , winSize = (Window.Size 1 1)
-- , mesh = (torusPoints 2 15 |> torusShell)
}
, Cmd.batch [ Task.perform WindowResized Window.size ] )
@ -47,14 +55,25 @@ subscriptions: Model -> Sub Msg
subscriptions _ =
Sub.batch
[ AnimationFrame.diffs Animate
, Keyboard.downs (KeyChange True)
, Window.resizes WindowResized ]
update: Msg -> Model -> (Model , Cmd Msg)
update msg model =
let m = case msg of
KeyChange b k ->
let (p,q) = case (b, k) of
-- pq / wo
(True, 80) -> (model.p+1, model.q )
(True, 81) -> (model.p , model.q+1)
(True, 79) -> (model.p-1, model.q )
(True, 87) -> (model.p , model.q-1)
_ -> (model.p, model.q)
_ = Debug.log "P Q: " (p, q)
in { model | torus = constructTorus p q , p = p , q = q }
Animate dt ->
-- { model | time = model.time + dt * 0.001 }
{ model | time = model.time + dt * 0.001 , p = model.p + 0.008 , q = model.q + 0.004}
{ model | time = model.time + dt * 0.001 }
-- { model | time = model.time + dt * 0.001 , p = model.p + 0.008 , q = model.q + 0.004}
-- Animate dt -> model
WindowResized size -> { model | winSize = size }
@ -62,16 +81,33 @@ update msg model =
view: Model -> Html Msg
view model =
WebGL.toHtml
Html.div []
[ Html.div [ style [ ("position", "absolute")
, ("top", "10px")
, ("left", "10px")
, ("background-color", "rgba(128, 128, 128, 1)")
, ("padding", "5px")
]
]
[ Html.text ("P: " ++ toString model.p) ]
, Html.div [ style [ ("position", "absolute")
, ("top", "10px")
, ("left", "40px")
, ("background-color", "rgba(128, 128, 128, 1)")
, ("padding", "5px")
]
]
[ Html.text ("Q: " ++ toString model.q) ]
, WebGL.toHtml
[ width model.winSize.width
, height model.winSize.height
, style [ ( "display" , "block") , ( "background" , "black" ) ] ]
, style [ ( "display" , "block") , ( "background" , "#151515" ) ] ]
([ WebGL.entity
diffuseVS
diffuseFS
-- model.mesh
-- (constructTorus model)
(constructTorus2 model)
-- (constructTorusMesh model)
model.torus
(DiffuseColor
(Mat4.makePerspective
50
@ -79,37 +115,35 @@ view model =
0.01
1000)
(Mat4.makeLookAt (vec3 0 0 5) (vec3 0 0 0) (vec3 0 1 0))
(Mat4.makeRotate (model.time * 0.5) (vec3 1 1 1 ) )
(Mat4.makeRotate (model.time * 0.9) (vec3 1 1 1 ) )
-- (Mat4.makeRotate (pi) (vec3 0.3 0.5 1 ) )
-- Mat4.identity
(colorToVec3 Color.red)
-- (colorToVec3 Color.darkGrey)
-- (colorToVec3 Color.white)
-- (colorToVec3 Color.red)
(colorToVec3 Color.green)
-- (colorToVec3 Color.blue)
-- (colorToVec3 Color.yellow)
(vec3 1 1 1)
(vec3 1 1 1)
(vec3 1 1 1)
1.0) ] )
1.0)
])]
totalLinePoints = 100
ringRadius = 0.15
ringVerts = 18
constructTorus: Model -> Mesh Attributes
constructTorus model =
constructTorusMesh: Model -> Mesh Attributes
constructTorusMesh model =
let points = torusPoints model.p model.q |> makePairs
rings = torusRings points |> List.concatMap makePairs
in points ++ rings |> toLines
-- in points |> toLines
constructTorus2: Model -> Mesh Attributes
constructTorus2 model =
torusPoints model.p model.q
constructTorus: Float -> Float -> Mesh Attributes
constructTorus p q =
torusPoints p q
|> makePairs
|> torusRings
|> torusTris
|> withTris
-- |> wireframe |> List.map (\ x -> toAttributes x Vec3.i) |> WebGL.lineStrip
-- |> wireframe |> List.map (\ x -> toAttributes x Vec3.i) |> WebGL.lineStrip
withTris: List (Vec3 , Vec3 , Vec3) -> Mesh Attributes
withTris tris =
@ -124,10 +158,10 @@ torusPoints p q =
interpolatedCircle totalLinePoints
|> List.map
(\ t ->
let r = 0.5 * (2 + sin (q * t))
let r = 2 + sin (q * t)
in vec3
(cos (t * p) * r)
(cos (t * q) * r * 0.5)
(cos (t * q) * r * 0.25)
(sin (t * p) * r) )
@ -136,9 +170,11 @@ torusRings verts =
verts
|> List.map
(\ (p1, p2)->
(List.map circlePoint <| interpolatedCircle ringVerts)
ringVerts
|> interpolatedCircle
|> List.map circlePoint
|> List.map (\ p ->
let (mid , dir) = (Vec3.add p1 p2 |> Vec3.scale 0.5 , Vec3.sub p2 p1 |> Vec3.normalize)
let (mid , dir) = (Vec3.add p1 p2 |> Vec3.scale knotScale , Vec3.sub p2 p1 |> Vec3.normalize)
p_ = Vec3.toRecord p
dir_ = Vec3.toRecord dir
u = Vec3.cross dir Vec3.j |> Vec3.normalize
@ -168,7 +204,12 @@ circlePoint: Float -> Vec3
circlePoint x = vec3 (cos x) (sin x) 0
makePairs: List a -> List (a ,a)
makePairs ps = List.map2 (,) ps (List.drop 1 ps)
makePairs ps1 =
case ps1 of
[] -> []
h::tail ->
let ps2 = tail ++ [h]
in List.map2 (,) ps1 ps2
closedPairs: List a -> List (a ,a)
closedPairs xs =
@ -197,6 +238,10 @@ colorToVec3 color =
c = Color.toRgb color
in vec3 (to01 c.red) (to01 c.green) (to01 c.blue)
-------------
-- Shaders
-------------
type alias DiffuseColor =
{ projection : Mat4
, view : Mat4
@ -248,6 +293,3 @@ diffuseFS =
gl_FragColor = vec4(color * vlightWeight, 1.0);
}
|]

8
build.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
elm make Torus.elm
sed -i 's/<title>Torus<\/title>/<title>PQ Torus Knot<\/title>/g' index.html
mkdir -p ./public
mv index.html ./public/
cd public
zip -r ../pqtk.zip .

4
deploy.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
scp pqtk.zip joe-vps:~
ssh joe-vps 'unzip -o pqtk.zip -d ~/websites/pqtk/ && rm pqtk.zip'

View File

@ -13,6 +13,7 @@
"elm-lang/animation-frame": "1.0.1 <= v < 2.0.0",
"elm-lang/core": "5.1.1 <= v < 6.0.0",
"elm-lang/window": "1.0.1 <= v < 2.0.0",
"elm-lang/keyboard": "1.0.1 <= v < 2.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"

BIN
media/blue-p3q5.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 KiB

BIN
media/green-p2q9.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 KiB

BIN
media/red-p2q5.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 KiB

BIN
media/yellow-p8q9.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 850 KiB