Merge pull request #2 from w0rm/css3d

Css3d
This commit is contained in:
Andrey Kuzmin
2017-01-21 21:16:02 +01:00
committed by GitHub
5 changed files with 335 additions and 0 deletions

BIN
CSS3D.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 KiB

296
CSS3d.elm Normal file
View File

@@ -0,0 +1,296 @@
module Main exposing (main)
import Html exposing (Html, div, text)
import Html.Attributes exposing (height, style, width)
import Math.Matrix4 as Mat4 exposing (Mat4, translate3)
import Math.Vector3 as Vec3 exposing (Vec3, vec3)
import Math.Vector4 as Vec4 exposing (Vec4, vec4)
import Mouse
import Native.Mat4
import Task exposing (Task)
import WebGL exposing (Entity, Mesh, Shader)
import WebGL.Settings as Settings
import WebGL.Settings.DepthTest as DepthTest
import Window
type alias Model =
{ size : Window.Size
, position : Mouse.Position
}
type Action
= Resize Window.Size
| MouseMove Mouse.Position
main : Program Never Model Action
main =
Html.program
{ init = init
, view = view
, subscriptions = subscriptions
, update = update
}
init : ( Model, Cmd Action )
init =
( { size = Window.Size 0 0
, position = Mouse.Position 0 0
}
, Task.perform Resize Window.size
)
subscriptions : Model -> Sub Action
subscriptions _ =
Sub.batch
[ Window.resizes Resize
, Mouse.moves MouseMove
]
update : Action -> Model -> ( Model, Cmd Action )
update action model =
case action of
Resize size ->
( { model | size = size }, Cmd.none )
MouseMove position ->
( { model | position = position }, Cmd.none )
-- Meshes
type alias Vertex =
{ position : Vec3
, color : Vec4
}
faceMesh : Mesh Vertex
faceMesh =
WebGL.triangles (square 100 (vec4 0 0 0 0))
sidesMesh : Mesh Vertex
sidesMesh =
[ ( 90, 0 ), ( 180, 0 ), ( 270, 0 ), ( 0, 90 ), ( 0, 270 ) ]
|> List.concatMap (rotatedSquare (vec4 0 0 1 1))
|> WebGL.triangles
rotatedSquare : Vec4 -> ( Float, Float ) -> List ( Vertex, Vertex, Vertex )
rotatedSquare color ( angleXZ, angleYZ ) =
let
transformMat =
Mat4.mul
(Mat4.makeRotate (degrees angleXZ) Vec3.j)
(Mat4.makeRotate (degrees angleYZ) Vec3.i)
transform vertex =
{ vertex
| position =
Mat4.transform transformMat vertex.position
}
transformTriangle ( a, b, c ) =
( transform a, transform b, transform c )
in
List.map transformTriangle (square 100 color)
square : Float -> Vec4 -> List ( Vertex, Vertex, Vertex )
square scale color =
let
topLeft =
Vertex (vec3 -scale scale scale) color
topRight =
Vertex (vec3 scale scale scale) color
bottomLeft =
Vertex (vec3 -scale -scale scale) color
bottomRight =
Vertex (vec3 scale -scale scale) color
in
[ ( topLeft, topRight, bottomLeft )
, ( bottomLeft, topRight, bottomRight )
]
type Tuple16
= Tuple16 Float Float Float Float Float Float Float Float Float Float Float Float Float Float Float Float
mat4toTuple : Mat4 -> Tuple16
mat4toTuple =
Native.Mat4.toTuple
-- VIEW
view : Model -> Html Action
view { size, position } =
let
eye =
vec3 (1 - 2 * toFloat position.x / toFloat size.width) -(1 - 2 * toFloat position.y / toFloat size.height) 1
|> Vec3.normalize
|> Vec3.scale 600
lookAt =
Mat4.makeLookAt eye (vec3 0 0 0) Vec3.j
perspective =
Mat4.makePerspective 45 (toFloat size.width / toFloat size.height) 1 10000
webglMat =
Mat4.mul perspective lookAt
css3dMat =
lookAt
fov =
toFloat size.height / 2 / (tan (degrees (45 * 0.5)))
in
div
[ style
[ ( "position", "absolute" )
, ( "transform-style", "preserve-3d" )
, ( "perspective", toString fov ++ "px" )
, ( "overflow", "hidden" )
, ( "width", toString size.width ++ "px" )
, ( "height", toString size.height ++ "px" )
]
]
[ camera
fov
size
css3dMat
[ box 200 200 (Mat4.makeTranslate3 0 0 100) ]
, WebGL.toHtml
[ width size.width
, height size.height
, style
[ ( "position", "absolute" )
]
]
[ WebGL.entityWith [ DepthTest.default, Settings.colorMask False False False False ] vertexShader fragmentShader faceMesh { perspective = webglMat }
, WebGL.entity vertexShader fragmentShader sidesMesh { perspective = webglMat }
]
]
cameraMatrix3d : Mat4 -> String
cameraMatrix3d matrix =
let
(Tuple16 a1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4 d1 d2 d3 d4) =
mat4toTuple matrix
in
[ a1, -a2, a3, a4, b1, -b2, b3, b4, c1, -c2, c3, c4, d1, -d2, d3, d4 ]
|> List.map toString
|> List.intersperse ","
|> List.foldr (++) ""
|> (\s -> "matrix3d(" ++ s ++ ")")
objectMatrix3d : Mat4 -> String
objectMatrix3d matrix =
let
(Tuple16 a1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4 d1 d2 d3 d4) =
mat4toTuple matrix
in
[ a1, a2, a3, a4, -b1, -b2, -b3, -b4, c1, c2, c3, c4, d1, d2, d3, d4 ]
|> List.map toString
|> List.intersperse ","
|> List.foldr (++) ""
|> (\s -> "matrix3d(" ++ s ++ ")")
box : Float -> Float -> Mat4 -> Html Action
box width height matrix =
div
[ style
[ ( "position", "absolute" )
, ( "background-color", "red" )
, ( "transform-style", "preserve-3d" )
, ( "width", toString width ++ "px" )
, ( "height", toString height ++ "px" )
, ( "transform"
, "translate3d(-50%, -50%, 0) " ++ objectMatrix3d matrix
)
]
]
[ text "OH WOW, I'm a DIV in the WebGL space!" ]
camera : Float -> Window.Size -> Mat4 -> List (Html Action) -> Html Action
camera fov { width, height } matrix =
div
[ style
[ ( "position", "absolute" )
, ( "transform-style", "preserve-3d" )
, ( "width", toString width ++ "px" )
, ( "height", toString height ++ "px" )
, ( "transform"
, ""
++ "translate3d(0,0,"
++ toString fov
++ "px)"
++ cameraMatrix3d matrix
++ "translate3d("
++ toString (toFloat width / 2)
++ "px,"
++ toString (toFloat height / 2)
++ "px,"
++ "0)"
)
]
]
-- SHADERS
type alias Uniforms =
{ perspective : Mat4
}
vertexShader : Shader Vertex Uniforms { vcolor : Vec4 }
vertexShader =
[glsl|
attribute vec3 position;
attribute vec4 color;
varying vec4 vcolor;
uniform mat4 perspective;
void main () {
gl_Position = perspective * vec4(position, 1.0);
vcolor = color;
}
|]
fragmentShader : Shader {} Uniforms { vcolor : Vec4 }
fragmentShader =
[glsl|
precision mediump float;
varying vec4 vcolor;
void main () {
gl_FragColor = vcolor;
}
|]

27
Native/Mat4.js Normal file
View File

@@ -0,0 +1,27 @@
var _w0rm$elm_webgl_playground$Native_Mat4 = function () {
return {
toTuple: function (mat) {
return {
ctor: 'Tuple16',
_0: mat[0],
_1: mat[1],
_2: mat[2],
_3: mat[3],
_4: mat[4],
_5: mat[5],
_6: mat[6],
_7: mat[7],
_8: mat[8],
_9: mat[9],
_10: mat[10],
_11: mat[11],
_12: mat[12],
_13: mat[13],
_14: mat[14],
_15: mat[15]
}
}
}
}();

View File

@@ -1,5 +1,16 @@
# elm-webgl-playground
## CSS3d.elm
Mixes WebGL and DOM layers in one common 3D space.
![Demo](CSS3D.gif)
The front face of the cube is rendered with a transparent color. This makes
a part of the canvas transparent so the DOM element can be seen through it.
Native module had to be used in order to extract the values from `Mat4`.
## Tangram.elm
Elm tangram pieces in 3D, composing different logos of Elm-related projects.

View File

@@ -7,6 +7,7 @@
"."
],
"exposed-modules": [],
"native-modules": true,
"dependencies": {
"elm-community/linear-algebra": "1.0.0 <= v < 2.0.0",
"elm-community/webgl": "2.0.0 <= v < 3.0.0",