Skip to content

Instantly share code, notes, and snippets.

@eitoball
Created December 27, 2019 14:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eitoball/475811ae303d670cacf22c62eb04f8f1 to your computer and use it in GitHub Desktop.
Save eitoball/475811ae303d670cacf22c62eb04f8f1 to your computer and use it in GitHub Desktop.
マンデルブロ集合
module Main exposing (main)
import Browser
import Browser.Dom exposing ( Viewport, getViewport )
import Browser.Events exposing ( onMouseMove, onResize )
import Html exposing ( Html )
import Html.Attributes exposing ( height, style, width )
import Json.Decode as Decode exposing ( Decoder )
import Math.Vector2 exposing ( Vec2, vec2 )
import Math.Vector3 exposing ( Vec3, vec3 )
import Task
import Time
import WebGL exposing ( Mesh, Shader )
type alias Model =
{ size :
{ width : Float
, height : Float
}
, location :
{ x : Float
, y : Float
}
, load_time : Float
}
main : Program () Model Msg
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
init : () -> ( Model, Cmd Msg )
init _ =
(
{ load_time = 0.0
, size = { width = 0.0, height = 0.0 }
, location = { x = 0.0, y = 0.0 }
}
, Cmd.batch
[ Task.perform GetViewport getViewport
]
)
view : Model -> Html Msg
view model =
let
location = model.location
size = model.size
_ = Debug.log "location" location
in
WebGL.toHtml
[ width (size.width |> round)
, height (size.height |> round)
]
[ WebGL.entity
vertexShader
fragmentShader
mesh
{ mouse = vec2 location.x location.y
, resolution = vec2 size.width size.height
, time = model.load_time
}
]
type Msg
= GetViewport Viewport
| MouseMove Float Float
| Resize Int Int
| Tick Time.Posix
mouseMoveDecoder : Decode.Decoder Msg
mouseMoveDecoder =
Decode.map2 MouseMove
(Decode.field "pageX" Decode.float)
(Decode.field "pageY" Decode.float)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GetViewport { viewport } ->
( { model
| size =
{ width = viewport.width
, height = viewport.height
}
}
, Cmd.none
)
MouseMove left top ->
let
location = { x = left / 1000.0, y = top / 1000.0 }
in
( { model | location = location }, Cmd.none )
Resize width height ->
( { model
| size =
{ width = width |> toFloat
, height = height |> toFloat
}
}
, Cmd.none
)
Tick time ->
( { model | load_time = model.load_time + 1.0 }, Cmd.none )
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.batch
[ onMouseMove mouseMoveDecoder
, onResize Resize
, Time.every 1000 Tick
]
mesh : Mesh { position : Vec3 }
mesh =
WebGL.triangles
[
( { position = vec3 -1.0 1.0 0.0 }
, { position = vec3 1.0 1.0 0.0 }
, { position = vec3 1.0 -1.0 0.0 }
)
, ( { position = vec3 1.0 -1.0 0.0 }
, { position = vec3 -1.0 -1.0 0.0 }
, { position = vec3 -1.0 1.0 0.0 }
)
]
type alias Uniforms =
{ mouse : Vec2
, resolution : Vec2
, time : Float
}
vertexShader : Shader { position : Vec3 } Uniforms {}
vertexShader =
[glsl|
attribute vec3 position;
void main() {
gl_Position = vec4(position, 1.0);
}
|]
fragmentShader : Shader {} Uniforms {}
fragmentShader =
[glsl|
precision mediump float;
uniform vec2 mouse;
uniform vec2 resolution;
uniform float time;
vec3 hsv(float h, float s, float v) {
vec4 t = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(vec3(h) + t.xyz) * 6.0 - vec3(t.w));
return v * mix(vec3(t.x), clamp(p - vec3(t.x), 0.0, 1.0), s);
}
void main() {
vec2 m = vec2(mouse.x * 2.0 - 1.0, -mouse.y * 2.0 + 1.0);
vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
int j = 0;
vec2 x = p + vec2(-0.5, 0.0);
float y = 1.5 - m.x * 0.5;
vec2 z = vec2(0.0, 0.0);
for (int i = 0; i < 360; ++i) {
j++;
if (length(z) > 2.0) {
break;
}
z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + x * y;
}
float h = mod(time * 20.0, 360.0) / 360.0;
vec3 rgb = hsv(h, 1.0, 1.0);
float t = float(j) / 360.0;
gl_FragColor = vec4(rgb * t, 1.0);
}
|]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment