feat: 3d model and serious bloat incoming
This commit is contained in:
		
							parent
							
								
									b903f3755d
								
							
						
					
					
						commit
						0f4436787c
					
				
					 7 changed files with 57712 additions and 14 deletions
				
			
		
							
								
								
									
										
											BIN
										
									
								
								assets/3d/macg/image0.jpg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/3d/macg/image0.jpg
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 8.5 MiB  | 
							
								
								
									
										23
									
								
								assets/3d/macg/macgregor-house-small.mtl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								assets/3d/macg/macgregor-house-small.mtl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
# File generated by ImageToStl.com - Free Image and 3D model conversion tools
 | 
			
		||||
 | 
			
		||||
newmtl mat0
 | 
			
		||||
Ns 0
 | 
			
		||||
Ka 1.0 1.0 1.0
 | 
			
		||||
Kd 1 1 1
 | 
			
		||||
Ks 0.5 0.5 0.5
 | 
			
		||||
Ke 0.0 0.0 0.0
 | 
			
		||||
Ni 1.0
 | 
			
		||||
d 1
 | 
			
		||||
illum 2
 | 
			
		||||
map_Kd image0.jpg
 | 
			
		||||
 | 
			
		||||
newmtl mat1
 | 
			
		||||
Ns 250
 | 
			
		||||
Ka 1.0 1.0 1.0
 | 
			
		||||
Kd 0.85 0.85 0.85
 | 
			
		||||
Ks 0 0 0
 | 
			
		||||
Ke 0.0 0.0 0.0
 | 
			
		||||
Ni 1.0
 | 
			
		||||
d 1
 | 
			
		||||
illum 1
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										57388
									
								
								assets/3d/macg/macgregor.obj.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										57388
									
								
								assets/3d/macg/macgregor.obj.txt
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								assets/3d/macgregor.zip
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/3d/macgregor.zip
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										25
									
								
								elm.json
									
										
									
									
									
								
							
							
						
						
									
										25
									
								
								elm.json
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -6,16 +6,35 @@
 | 
			
		|||
    "elm-version": "0.19.1",
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "direct": {
 | 
			
		||||
            "andrewMacmurray/elm-simple-animation": "2.3.2",
 | 
			
		||||
            "avh4/elm-color": "1.0.0",
 | 
			
		||||
            "elm/browser": "1.0.2",
 | 
			
		||||
            "elm/core": "1.0.5",
 | 
			
		||||
            "elm/html": "1.0.0",
 | 
			
		||||
            "mdgriffith/elm-ui": "1.1.8"
 | 
			
		||||
            "elm/http": "2.0.0",
 | 
			
		||||
            "elm/time": "1.0.0",
 | 
			
		||||
            "elm-explorations/webgl": "1.1.3",
 | 
			
		||||
            "ianmackenzie/elm-3d-camera": "3.1.0",
 | 
			
		||||
            "ianmackenzie/elm-3d-scene": "1.0.2",
 | 
			
		||||
            "ianmackenzie/elm-geometry": "3.11.0",
 | 
			
		||||
            "ianmackenzie/elm-triangular-mesh": "1.1.0",
 | 
			
		||||
            "ianmackenzie/elm-units": "2.10.0",
 | 
			
		||||
            "mdgriffith/elm-ui": "1.1.8",
 | 
			
		||||
            "w0rm/elm-obj-file": "1.2.1"
 | 
			
		||||
        },
 | 
			
		||||
        "indirect": {
 | 
			
		||||
            "elm/bytes": "1.0.8",
 | 
			
		||||
            "elm/file": "1.0.5",
 | 
			
		||||
            "elm/json": "1.1.3",
 | 
			
		||||
            "elm/time": "1.0.0",
 | 
			
		||||
            "elm/random": "1.0.0",
 | 
			
		||||
            "elm/url": "1.0.0",
 | 
			
		||||
            "elm/virtual-dom": "1.0.3"
 | 
			
		||||
            "elm/virtual-dom": "1.0.3",
 | 
			
		||||
            "elm-explorations/linear-algebra": "1.0.3",
 | 
			
		||||
            "ianmackenzie/elm-1d-parameter": "1.0.1",
 | 
			
		||||
            "ianmackenzie/elm-float-extra": "1.1.0",
 | 
			
		||||
            "ianmackenzie/elm-geometry-linear-algebra-interop": "2.0.2",
 | 
			
		||||
            "ianmackenzie/elm-interval": "3.1.0",
 | 
			
		||||
            "ianmackenzie/elm-units-interval": "3.2.0"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "test-dependencies": {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										282
									
								
								src/Main.elm
									
										
									
									
									
								
							
							
						
						
									
										282
									
								
								src/Main.elm
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,11 +1,69 @@
 | 
			
		|||
module Main exposing (main)
 | 
			
		||||
 | 
			
		||||
import Angle
 | 
			
		||||
import Array
 | 
			
		||||
import Browser
 | 
			
		||||
import Browser.Events as Events
 | 
			
		||||
import Camera3d
 | 
			
		||||
import Color
 | 
			
		||||
import Direction3d
 | 
			
		||||
import Element exposing (..)
 | 
			
		||||
import Element.Background as Background
 | 
			
		||||
import Element.Font as Font
 | 
			
		||||
import Html exposing (Html)
 | 
			
		||||
import Http exposing (Error)
 | 
			
		||||
import Length
 | 
			
		||||
import Obj.Decode
 | 
			
		||||
import Pixels
 | 
			
		||||
import Point3d exposing (Point3d)
 | 
			
		||||
import Scene3d exposing (Entity)
 | 
			
		||||
import Scene3d.Material as Material
 | 
			
		||||
import Scene3d.Mesh as Mesh
 | 
			
		||||
import Simple.Animation as Animation exposing (Animation)
 | 
			
		||||
import Simple.Animation.Animated as Animated
 | 
			
		||||
import Simple.Animation.Property as P
 | 
			
		||||
import Task
 | 
			
		||||
import Time
 | 
			
		||||
import TriangularMesh exposing (TriangularMesh)
 | 
			
		||||
import Viewpoint3d
 | 
			
		||||
import WebGL.Texture
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
getMesh : Cmd Msg
 | 
			
		||||
getMesh =
 | 
			
		||||
    Http.get
 | 
			
		||||
        { url = "../assets/3d/macg/macgregor.obj.txt"
 | 
			
		||||
        , expect = Obj.Decode.expectObj GotMesh Length.meters Obj.Decode.texturedTriangles
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
getTexture : Cmd Msg
 | 
			
		||||
getTexture =
 | 
			
		||||
    Material.loadWith Material.nearestNeighborFiltering "../assets/3d/macg/image0.jpg" |> Task.attempt GotTexture
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
animatedUi :
 | 
			
		||||
    (List (Attribute msg) -> children -> Element msg)
 | 
			
		||||
    -> Animation
 | 
			
		||||
    -> List (Attribute msg)
 | 
			
		||||
    -> children
 | 
			
		||||
    -> Element msg
 | 
			
		||||
animatedUi =
 | 
			
		||||
    Animated.ui
 | 
			
		||||
        { behindContent = Element.behindContent
 | 
			
		||||
        , htmlAttribute = Element.htmlAttribute
 | 
			
		||||
        , html = Element.html
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
animatedEl : Animation -> List (Element.Attribute msg) -> Element msg -> Element msg
 | 
			
		||||
animatedEl =
 | 
			
		||||
    animatedUi Element.el
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
animatedCol : Animation -> List (Element.Attribute msg) -> List (Element msg) -> Element msg
 | 
			
		||||
animatedCol =
 | 
			
		||||
    animatedUi Element.column
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
main : Program Flags Model Msg
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +72,7 @@ main =
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
type alias Model =
 | 
			
		||||
    { w : Int, h : Int }
 | 
			
		||||
    { w : Int, h : Int, mesh : Maybe Object3d, textures : Maybe (Material.Textured Obj.Decode.ObjCoordinates), angle : Float }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
type alias Flags =
 | 
			
		||||
| 
						 | 
				
			
			@ -25,23 +83,76 @@ init : Flags -> ( Model, Cmd Msg )
 | 
			
		|||
init flags =
 | 
			
		||||
    case flags of
 | 
			
		||||
        ( width, height ) ->
 | 
			
		||||
            ( { w = width, h = height }, Cmd.none )
 | 
			
		||||
            ( { w = width, h = height, mesh = Nothing, textures = Nothing, angle = 0 }, Cmd.batch [ getMesh, getTexture ] )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-- type alias Object3d =
 | 
			
		||||
--     TriangularMesh
 | 
			
		||||
--         { position : Point3d Length.Meters Obj.Decode.ObjCoordinates
 | 
			
		||||
--         , normal : Vector3d Quantity.Unitless Obj.Decode.ObjCoordinates
 | 
			
		||||
--         , uv : ( Float, Float )
 | 
			
		||||
--         }
 | 
			
		||||
-- type alias Object3d =
 | 
			
		||||
--     TriangularMesh (Point3d Length.Meters Obj.Decode.ObjCoordinates)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
type alias Object3d =
 | 
			
		||||
    TriangularMesh { position : Point3d Length.Meters Obj.Decode.ObjCoordinates, uv : ( Float, Float ) }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
type Msg
 | 
			
		||||
    = Resize Int Int
 | 
			
		||||
    | GotMesh (Result Http.Error Object3d)
 | 
			
		||||
    | GotTexture (Result WebGL.Texture.Error (Material.Texture Color.Color))
 | 
			
		||||
    | Rotate Time.Posix
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
update : Msg -> Model -> ( Model, Cmd Msg )
 | 
			
		||||
update msg model =
 | 
			
		||||
    let
 | 
			
		||||
        wrap : Model -> ( Model, Cmd Msg )
 | 
			
		||||
        wrap data =
 | 
			
		||||
            ( data, Cmd.none )
 | 
			
		||||
 | 
			
		||||
        pass : ( Model, Cmd Msg )
 | 
			
		||||
        pass =
 | 
			
		||||
            wrap model
 | 
			
		||||
    in
 | 
			
		||||
    case msg of
 | 
			
		||||
        Resize width height ->
 | 
			
		||||
            ( { model | w = width, h = height }, Cmd.none )
 | 
			
		||||
            wrap { model | w = width, h = height }
 | 
			
		||||
 | 
			
		||||
        GotMesh response ->
 | 
			
		||||
            case response of
 | 
			
		||||
                Err _ ->
 | 
			
		||||
                    pass
 | 
			
		||||
 | 
			
		||||
                Ok object ->
 | 
			
		||||
                    wrap { model | mesh = Just object }
 | 
			
		||||
 | 
			
		||||
        GotTexture result ->
 | 
			
		||||
            case result of
 | 
			
		||||
                Err _ ->
 | 
			
		||||
                    pass
 | 
			
		||||
 | 
			
		||||
                Ok texture ->
 | 
			
		||||
                    wrap
 | 
			
		||||
                        { model
 | 
			
		||||
                            | textures =
 | 
			
		||||
                                Just (Material.texturedMatte texture)
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
        Rotate time ->
 | 
			
		||||
            wrap { model | angle = model.angle + 2 * (2 + sin (toFloat (Time.posixToMillis time) / 1000)) }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
subscribe : Model -> Sub Msg
 | 
			
		||||
subscribe _ =
 | 
			
		||||
    Events.onResize Resize
 | 
			
		||||
    Sub.batch
 | 
			
		||||
        [ Events.onResize Resize
 | 
			
		||||
        , Time.every (1000 / 30) Rotate
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
htmlify : List (Element Msg) -> List (Html Msg)
 | 
			
		||||
| 
						 | 
				
			
			@ -64,19 +175,170 @@ view model =
 | 
			
		|||
    { title = "MacGregor House"
 | 
			
		||||
    , body =
 | 
			
		||||
        htmlify
 | 
			
		||||
            [ el
 | 
			
		||||
            [ column
 | 
			
		||||
                [ width fill
 | 
			
		||||
                , height fill
 | 
			
		||||
                , Background.color (rgb255 0 0 0)
 | 
			
		||||
                , spacing (round (vh model -100))
 | 
			
		||||
                ]
 | 
			
		||||
                (el
 | 
			
		||||
                [ el
 | 
			
		||||
                    [ width fill
 | 
			
		||||
                    , height (px (round (vh model 100)))
 | 
			
		||||
                    , Background.color (rgb255 0 0 0)
 | 
			
		||||
                    ]
 | 
			
		||||
                    Element.none
 | 
			
		||||
                , animatedEl crossfadeIn
 | 
			
		||||
                    [ width fill
 | 
			
		||||
                    , height (px (round (vh model 100)))
 | 
			
		||||
                    , Background.gradient { angle = 45, steps = [ rgb255 200 0 100, rgb255 100 0 200 ] }
 | 
			
		||||
                    ]
 | 
			
		||||
                    Element.none
 | 
			
		||||
                , animatedEl crossfadeOut
 | 
			
		||||
                    [ width fill
 | 
			
		||||
                    , height (px (round (vh model 100)))
 | 
			
		||||
                    , Background.gradient { angle = 45, steps = [ rgb255 0 100 200, rgb255 0 200 100 ] }
 | 
			
		||||
                    ]
 | 
			
		||||
                    Element.none
 | 
			
		||||
                , el
 | 
			
		||||
                    [ alignLeft
 | 
			
		||||
                    , alignTop
 | 
			
		||||
                    , moveRight (vw model 10)
 | 
			
		||||
                    , moveDown (vh model 50)
 | 
			
		||||
                    , width (px (round (vw model 50)))
 | 
			
		||||
                    , height (px (round (vh model 100)))
 | 
			
		||||
                    , paddingEach
 | 
			
		||||
                        { top = round (vh model 50) - 96
 | 
			
		||||
                        , bottom = 0
 | 
			
		||||
                        , left = round (vw model 10)
 | 
			
		||||
                        , right = 0
 | 
			
		||||
                        }
 | 
			
		||||
                    , Font.color (rgb255 255 255 255)
 | 
			
		||||
                    , Font.family [ Font.typeface "Imbue" ]
 | 
			
		||||
                    , Font.size 96
 | 
			
		||||
                    ]
 | 
			
		||||
                    (text "MacGregor House")
 | 
			
		||||
                )
 | 
			
		||||
                , el
 | 
			
		||||
                    [ alignRight
 | 
			
		||||
                    , alignTop
 | 
			
		||||
                    , width (px (round (vw model 60)))
 | 
			
		||||
                    , height (px (round (vh model 100)))
 | 
			
		||||
                    , paddingEach
 | 
			
		||||
                        { top = round (vh model 25)
 | 
			
		||||
                        , bottom = round (vh model 25)
 | 
			
		||||
                        , left = 0
 | 
			
		||||
                        , right = 0
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                    (view3D model)
 | 
			
		||||
                ]
 | 
			
		||||
            ]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
pyramidMesh : Mesh.Uniform coordinates
 | 
			
		||||
pyramidMesh =
 | 
			
		||||
    let
 | 
			
		||||
        -- Define the vertices of our pyramid
 | 
			
		||||
        frontLeft =
 | 
			
		||||
            Point3d.centimeters 250 500 0
 | 
			
		||||
 | 
			
		||||
        frontRight =
 | 
			
		||||
            Point3d.centimeters 400 0 -500
 | 
			
		||||
 | 
			
		||||
        backLeft =
 | 
			
		||||
            Point3d.centimeters -250 500 -500
 | 
			
		||||
 | 
			
		||||
        backRight =
 | 
			
		||||
            Point3d.centimeters -250 0 0
 | 
			
		||||
 | 
			
		||||
        tip =
 | 
			
		||||
            Point3d.centimeters 0 0 500
 | 
			
		||||
 | 
			
		||||
        -- Create a TriangularMesh value from an array of vertices and list
 | 
			
		||||
        -- of index triples defining faces (see https://package.elm-lang.org/packages/ianmackenzie/elm-triangular-mesh/latest/TriangularMesh#indexed)
 | 
			
		||||
        triangularMesh =
 | 
			
		||||
            TriangularMesh.indexed
 | 
			
		||||
                (Array.fromList
 | 
			
		||||
                    [ frontLeft -- 0
 | 
			
		||||
                    , frontRight -- 1
 | 
			
		||||
                    , backLeft -- 2
 | 
			
		||||
                    , backRight -- 3
 | 
			
		||||
                    , tip -- 4
 | 
			
		||||
                    ]
 | 
			
		||||
                )
 | 
			
		||||
                [ ( 1, 0, 4 ) -- front
 | 
			
		||||
                , ( 0, 2, 4 ) -- left
 | 
			
		||||
                , ( 2, 3, 4 ) -- back
 | 
			
		||||
                , ( 3, 1, 4 ) -- right
 | 
			
		||||
                , ( 1, 3, 0 ) -- bottom
 | 
			
		||||
                , ( 0, 3, 2 ) -- bottom
 | 
			
		||||
                ]
 | 
			
		||||
    in
 | 
			
		||||
    -- Create a elm-3d-scene Mesh value from the TriangularMesh; we use
 | 
			
		||||
    -- Mesh.indexedFacets so that normal vectors will be generated for each face
 | 
			
		||||
    Mesh.indexedFacets triangularMesh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
view3D : Model -> Element msg
 | 
			
		||||
view3D model =
 | 
			
		||||
    Element.html
 | 
			
		||||
        (let
 | 
			
		||||
            entity : Entity Obj.Decode.ObjCoordinates
 | 
			
		||||
            entity =
 | 
			
		||||
                case model.mesh of
 | 
			
		||||
                    Nothing ->
 | 
			
		||||
                        Scene3d.mesh (Material.matte (Color.rgb255 173 111 101)) pyramidMesh
 | 
			
		||||
 | 
			
		||||
                    Just mesh ->
 | 
			
		||||
                        case model.textures of
 | 
			
		||||
                            Nothing ->
 | 
			
		||||
                                Scene3d.mesh (Material.matte (Color.rgb255 173 111 101)) (Mesh.texturedFacets mesh)
 | 
			
		||||
 | 
			
		||||
                            Just textures ->
 | 
			
		||||
                                Scene3d.mesh textures (Mesh.texturedFacets mesh)
 | 
			
		||||
 | 
			
		||||
            camera : Camera3d.Camera3d Length.Meters coordinates
 | 
			
		||||
            camera =
 | 
			
		||||
                Camera3d.perspective
 | 
			
		||||
                    { viewpoint =
 | 
			
		||||
                        Viewpoint3d.lookAt
 | 
			
		||||
                            { focalPoint = Point3d.origin
 | 
			
		||||
                            , eyePoint =
 | 
			
		||||
                                let
 | 
			
		||||
                                    theta =
 | 
			
		||||
                                        Angle.degrees model.angle
 | 
			
		||||
                                in
 | 
			
		||||
                                Point3d.meters (10 * Angle.cos theta) 2 (10 * Angle.sin theta)
 | 
			
		||||
                            , upDirection = Direction3d.xy (Angle.degrees 90)
 | 
			
		||||
                            }
 | 
			
		||||
                    , verticalFieldOfView = Angle.degrees 100
 | 
			
		||||
                    }
 | 
			
		||||
         in
 | 
			
		||||
         Scene3d.sunny
 | 
			
		||||
            { entities = [ entity ]
 | 
			
		||||
            , camera = camera
 | 
			
		||||
            , upDirection = Direction3d.z
 | 
			
		||||
            , sunlightDirection = Direction3d.yz (Angle.degrees -120)
 | 
			
		||||
            , background = Scene3d.transparentBackground
 | 
			
		||||
            , clipDepth = Length.centimeters 1
 | 
			
		||||
            , shadows = False
 | 
			
		||||
            , dimensions = ( Pixels.int (round (vw model 60)), Pixels.int (round (vh model 100)) )
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
crossfadeIn : Animation
 | 
			
		||||
crossfadeIn =
 | 
			
		||||
    Animation.fromTo
 | 
			
		||||
        { duration = 2017
 | 
			
		||||
        , options = [ Animation.yoyo, Animation.loop ]
 | 
			
		||||
        }
 | 
			
		||||
        [ P.opacity 0 ]
 | 
			
		||||
        [ P.opacity 1 ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
crossfadeOut : Animation
 | 
			
		||||
crossfadeOut =
 | 
			
		||||
    Animation.fromTo
 | 
			
		||||
        { duration = 2027
 | 
			
		||||
        , options = [ Animation.yoyo, Animation.loop ]
 | 
			
		||||
        }
 | 
			
		||||
        [ P.opacity 1 ]
 | 
			
		||||
        [ P.opacity 0 ]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,10 +3,16 @@
 | 
			
		|||
  <head>
 | 
			
		||||
    <meta charset="UTF-8" />
 | 
			
		||||
    <title>MacGregor House</title>
 | 
			
		||||
    <link rel="preconnect" href="https://fonts.googleapis.com" />
 | 
			
		||||
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
 | 
			
		||||
    <link
 | 
			
		||||
      href="https://fonts.googleapis.com/css2?family=Imbue:opsz,wght@10..100,100..900&display=swap"
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
    />
 | 
			
		||||
  </head>
 | 
			
		||||
  <body>
 | 
			
		||||
    <div id="app"></div>
 | 
			
		||||
    <script src="../result/Main.js"></script>
 | 
			
		||||
    <script src="../compiled/Main.js"></script>
 | 
			
		||||
    <script>
 | 
			
		||||
      var app = Elm.Main.init({
 | 
			
		||||
        node: document.getElementById("app"),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue