WebGL Geometry Terrain

A 3D world right in the browser

This demo is a Fable port of the WebGL Geometry Terrain three.js demo. It uses the three.js library to randomly generate a 3D terrain which can be navigated in a first-person view. The code was originally written by John Quigley for FunScript, you can find Fable's version on GitHub.

On the technical side, the demo shows some of the more interesting aspects of calling JavaScript libraries from Fable. You'll learn how to define mapping for global objects and other useful functions.






Generating world...
If this message doesn't disappear after a few seconds, you may want to verify that WebGL is enabled in your web browser
three.js - webgl terrain demo
(left click: forward, right click: backward; or WASD to move)

JavaScript helpers and imports

Fable comes with an F# mapping for three.js, which defines all the types and functions for three.js that we'll need in this example. In addition this demo uses custom scripts for ImprovedNoise and FirstPersonControls. We'll write the mappings for those two inline.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
open System
open Fable.Core
open Fable.Core.JsInterop
open Fable.Import

/// Represents the API exposed by ImprovedNoise script
type IPerlin =
    abstract noise: x:float * y:float * z:float -> float

/// Represents the API exposed by FirstPersonControls script
type IFirstPersonControls =
    abstract movementSpeed: float with get, set
    abstract lookSpeed: float with get, set
    abstract handleResize: unit -> unit
    abstract update: float -> unit

The Global attribute on ImprovedNoise specifies that the function is globally available.

FirstPersonControls is a bit more complicated because we need to use the new keyword. Fable won't do this automatically so we make sure the proper JS is emitted with Emit attribute. The dots after the placeholder $0... indicate any additional argument must also be applied in JS. This is very useful when we have a method with ParamArray args.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
// Globally imported JS libs (loaded with <script> tag)    
[<Global>]
let ImprovedNoise(): IPerlin = failwith "JS only"

[<Emit("new THREE.FirstPersonControls($0...)")>]
let FirstPersonControls(camera: Three.Camera,
                        domElement: Browser.HTMLElement):
                        IFirstPersonControls = failwith "JS only"

Initial settings and helper functions

Note: this sample is intended to be a direct port of the original and doesn't attempt to refactor the original to be more "functional".

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
let worldWidth = 256
let worldDepth = 256
let worldHalfWidth = worldWidth / 2
let worldHalfDepth = worldDepth / 2

let clock = Three.Clock()

// We can also use `System.Random`, but the native JS `Math.random`
// will be a bit more performant here.
let inline rand() = JS.Math.random()

Using the perlin library (ImprovedNoise script) define the peaks of the mountains in our random terrain.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
let generateHeight width height =
    let size = width * height
    let data:float[] = Array.zeroCreate size
    let perlin = ImprovedNoise()
    let mutable quality = 1.0
    let z = rand() * 100.0

    for j in 0..3 do
        for i in 0..(size-1) do
            let x = i % width
            let y = i / width
            let noise =
                perlin.noise(float x / quality, float y / quality, z)
                    * quality * 1.75
            data.[i] <- data.[i] + (JS.Math.abs ( noise ))
        quality <- quality * 5.0
    data

To generate the textures for the terrain, we'll be using a canvas element to draw the image and later pass it directly to THREE.Texture class.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
63: 
64: 
65: 
66: 
67: 
68: 
69: 
70: 
let generateTexture (data:float[]) (width:int) (height:int) = 
    let vector3 = Three.Vector3(0.0, 0.0, 0.0)
    let sun = (Three.Vector3(1.0, 1.0, 1.0) :> Three.Vector).normalize()

    let canvas = Browser.document.createElement_canvas()
    canvas.width <- float width
    canvas.height <- float height

    let context = canvas.getContext_2d()
    context.fillStyle <- U3.Case1 "#000"
    context.fillRect(0.0, 0.0, float width, float height)

    let image = context.getImageData(
                    0.0, 0.0, canvas.width, canvas.height)
    let imageData = image.data

    let mutable i = 0
    let mutable j = 0
    let mutable l = int imageData.length

    while i < l do
        // Note: data elements -2 and -1 are accessed here at the start
        // of the loop. It's a bug in the original (producing NaN after
        // normalize()), but JS just keeps on truckin'. There is a similar
        // issue with z.  The result is that imageData is set to zero (black)
        // in these cases
        vector3.x <- data.[ j - 2 ] - data.[ j + 2 ]
        vector3.y <- 2.0
        vector3.z <- data.[ j - width * 2 ] - data.[ j + width * 2 ]
        (vector3 :> Three.Vector).normalize() |> ignore

        let shade = vector3.dot(sun :?> Three.Vector3)

        imageData.[ i ] <-
            (96.0 + shade * 128.0) * (0.5 + data.[ j ] * 0.007)
        imageData.[ i + 1 ] <-
            (32.0 + shade * 96.0) * (0.5 + data.[ j ] * 0.007)
        imageData.[ i + 2 ] <-
            (shade * 96.0) * (0.5 + data.[ j ] * 0.007)

        i <- i + 4
        j <- j + 1

    context.putImageData( image, 0.0, 0.0 );

    let canvasScaled = Browser.document.createElement_canvas()
    canvasScaled.width <- float(width * 4)
    canvasScaled.height <- float(height * 4)

    let context = canvasScaled.getContext_2d()
    context.scale(4.0,4.0)
    context.drawImage(U3.Case2 canvas, 0.0, 0.0)

    let image = context.getImageData(
                    0.0, 0.0, canvasScaled.width, canvasScaled.height)
    let imageData = image.data

    let mutable i = 0
    let mutable l = int imageData.length
    while i < l do
        // I presume double-not is used here for this reason:
        // http://james.padolsey.com/javascript/double-bitwise-not/
        let v = ~~~ (~~~ (rand() * 5.0 |> int)) |> float
        imageData.[ i ] <- imageData.[ i ] + v
        imageData.[ i + 1 ] <- imageData.[ i + 1 ] + v
        imageData.[ i + 2 ] <- imageData.[ i + 2 ] + v
        i <- i + 4

    context.putImageData(image, 0.0, 0.0)
    canvasScaled

Initialize elements

Here we initialize the elements necessary to draw the scene: the renderer, the scene itself, a camera and controls to move it.

Note the use of a compiler directive: normally we take the whole window space, but if we are in the tutorial we should leave space for the explanations.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
63: 
64: 
65: 
66: 
67: 
68: 
69: 
70: 
71: 
72: 
73: 
74: 
75: 
76: 
77: 
78: 
let init() =
    #if TUTORIAL
    let getWidth() = 800.
    let getHeight() = 450.
    #else
    let getWidth() = Browser.window.innerWidth
    let getHeight() = Browser.window.innerHeight
    #endif

    let container = Browser.document.getElementById("container")
    let camera = Three.PerspectiveCamera(
                    60.0, getWidth() / getHeight(), 1.0, 20000.0)
    let scene = Three.Scene()
    
    let renderer = Three.WebGLRenderer()
    renderer.setClearColor("#bfd1e5")
    (renderer :> Three.Renderer).setSize(getWidth(), getHeight())
    let domElement = (renderer :> Three.Renderer).domElement
    container.innerHTML <- ""
    container.appendChild(domElement) |> ignore

    let controls = FirstPersonControls(camera :> Three.Camera, domElement)
    controls.movementSpeed <- 1000.0
    controls.lookSpeed <- 0.1

    let data = generateHeight worldWidth worldDepth

    camera.position.y <-
        data.[worldHalfWidth + worldHalfDepth * worldWidth] * 10. + 500.

    let geometry = Three.PlaneBufferGeometry(
                        7500.0, 7500.0,
                        float (worldWidth - 1), float (worldDepth - 1))
    geometry.applyMatrix(Three.Matrix4()
            .makeRotationX(-JS.Math.PI / 2.0))
            |> ignore

    let vertices = geometry.getAttribute("position")
                    |> unbox<Three.BufferAttribute>
    let vertices = vertices.array
    let l = int vertices.length
    let mutable i = 0
    let mutable j = 0
    while i < l do
        vertices.[j + 1] <- data.[i] * 10.0
        i <- i + 1
        j <- j + 3

    let texCanvas = generateTexture data worldWidth worldDepth
    let texture = Three.Texture(
                    U3.Case2 texCanvas, Three.UVMapping,
                    Three.ClampToEdgeWrapping,
                    Three.ClampToEdgeWrapping)
    texture.needsUpdate <- true

    // We use createEmpty here to create an empty object used to set
    // configuration parameters. The type qualifier indicates what fields
    // we will be able to set on the resulting object. For those fields that
    // are enum types, the possible values are usually found in three globals.
    let matProps = createEmpty<Three.MeshBasicMaterialParameters>
    matProps.map <- Some texture

    let mesh = Three.Mesh(geometry, Three.MeshBasicMaterial(matProps))
    scene.add mesh

    let onWindowResize(e:Browser.UIEvent):obj =
        camera.aspect <- getWidth() / getHeight()
        camera.updateProjectionMatrix()
        (renderer :> Three.Renderer).setSize(getWidth(), getHeight())
        controls.handleResize() 
        null

    Browser.window.addEventListener_resize(
        Func<_,_> onWindowResize, false)

    renderer, scene, camera, controls

let renderer,scene,camera,controls = init()

Start animation

Now the only thing left is to start the animation. Note we use the window.requestAnimationFrame function here, this will make sure animate is executed at a proper frame rate.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
let render() =
    controls.update(clock.getDelta())
    renderer.render(scene, camera)

let rec animate (dt:float) =
    Browser.window.requestAnimationFrame(Func<_,_> animate)
    |> ignore
    render()

// kick it off
animate(0.0)
namespace System
namespace Fable
namespace Fable.Core
module JsInterop

from Fable.Core
namespace Fable.Import
type IPerlin =
  interface
    abstract member noise : x:float * y:float * z:float -> float
  end

Full name: WebGLTerrain.IPerlin


 Represents the API exposed by ImprovedNoise script
abstract member IPerlin.noise : x:float * y:float * z:float -> float

Full name: WebGLTerrain.IPerlin.noise
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
type IFirstPersonControls =
  interface
    abstract member lookSpeed : float
    abstract member movementSpeed : float
    abstract member handleResize : unit -> unit
    abstract member lookSpeed : float with set
    abstract member movementSpeed : float with set
    abstract member update : float -> unit
  end

Full name: WebGLTerrain.IFirstPersonControls


 Represents the API exposed by FirstPersonControls script
abstract member IFirstPersonControls.movementSpeed : float with set

Full name: WebGLTerrain.IFirstPersonControls.movementSpeed
val set : elements:seq<'T> -> Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.set
abstract member IFirstPersonControls.lookSpeed : float with set

Full name: WebGLTerrain.IFirstPersonControls.lookSpeed
abstract member IFirstPersonControls.handleResize : unit -> unit

Full name: WebGLTerrain.IFirstPersonControls.handleResize
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
abstract member IFirstPersonControls.update : float -> unit

Full name: WebGLTerrain.IFirstPersonControls.update
Multiple items
type GlobalAttribute =
  inherit Attribute
  new : unit -> GlobalAttribute

Full name: Fable.Core.GlobalAttribute

--------------------
new : unit -> GlobalAttribute
val ImprovedNoise : unit -> IPerlin

Full name: WebGLTerrain.ImprovedNoise
val failwith : message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.failwith
Multiple items
type EmitAttribute =
  inherit Attribute
  private new : unit -> EmitAttribute
  new : macro:string -> EmitAttribute
  new : emitterType:Type * methodName:string -> EmitAttribute

Full name: Fable.Core.EmitAttribute

--------------------
new : macro:string -> EmitAttribute
new : emitterType:Type * methodName:string -> EmitAttribute
val FirstPersonControls : camera:Three.Camera * domElement:Browser.HTMLElement -> IFirstPersonControls

Full name: WebGLTerrain.FirstPersonControls
val camera : Three.Camera
module Three

from Fable.Import
Multiple items
type Camera =
  inherit Object3D
  new : unit -> Camera
  member clone : unit -> Camera
  member copy : ?camera:Camera -> Camera
  member getWorldDirection : ?optionalTarget:Vector3 -> Vector3
  member matrixWorldInverse : Matrix4
  member projectionMatrix : Matrix4
  member lookAt : vector:Vector3 -> unit
  member matrixWorldInverse : Matrix4 with set
  member projectionMatrix : Matrix4 with set

Full name: Fable.Import.Three.Camera

--------------------
new : unit -> Three.Camera
val domElement : Browser.HTMLElement
module Browser

from Fable.Import
Multiple items
val HTMLElement : Browser.HTMLElementType

Full name: Fable.Import.Browser.HTMLElement

--------------------
type HTMLElement =
  interface
    inherit Element
    abstract member addEventListener : type:string * listener:EventListenerOrEventListenerObject * ?useCapture:bool -> unit
    abstract member addEventListener_MSContentZoom : listener:Func<UIEvent,obj> * ?useCapture:bool -> unit
    abstract member addEventListener_MSGestureChange : listener:Func<MSGestureEvent,obj> * ?useCapture:bool -> unit
    abstract member addEventListener_MSGestureDoubleTap : listener:Func<MSGestureEvent,obj> * ?useCapture:bool -> unit
    abstract member addEventListener_MSGestureEnd : listener:Func<MSGestureEvent,obj> * ?useCapture:bool -> unit
    abstract member addEventListener_MSGestureHold : listener:Func<MSGestureEvent,obj> * ?useCapture:bool -> unit
    abstract member addEventListener_MSGestureStart : listener:Func<MSGestureEvent,obj> * ?useCapture:bool -> unit
    abstract member addEventListener_MSGestureTap : listener:Func<MSGestureEvent,obj> * ?useCapture:bool -> unit
    abstract member addEventListener_MSGotPointerCapture : listener:Func<MSPointerEvent,obj> * ?useCapture:bool -> unit
    ...
  end

Full name: Fable.Import.Browser.HTMLElement
val worldWidth : int

Full name: WebGLTerrain.worldWidth
val worldDepth : int

Full name: WebGLTerrain.worldDepth
val worldHalfWidth : int

Full name: WebGLTerrain.worldHalfWidth
val worldHalfDepth : int

Full name: WebGLTerrain.worldHalfDepth
val clock : Three.Clock

Full name: WebGLTerrain.clock
Multiple items
type Clock =
  new : ?autoStart:bool -> Clock
  member getDelta : unit -> float
  member getElapsedTime : unit -> float
  member autoStart : bool
  member elapsedTime : float
  member oldTime : float
  member running : bool
  member startTime : float
  member autoStart : bool with set
  member elapsedTime : float with set
  ...

Full name: Fable.Import.Three.Clock

--------------------
new : ?autoStart:bool -> Three.Clock
val rand : unit -> float

Full name: WebGLTerrain.rand
module JS

from Fable.Import
Multiple items
val Math : JS.Math

Full name: Fable.Import.JS.Math

--------------------
type Math =
  interface
    abstract member abs : x:float -> float
    abstract member acos : x:float -> float
    abstract member acosh : x:float -> float
    abstract member asin : x:float -> float
    abstract member asinh : x:float -> float
    abstract member atan : x:float -> float
    abstract member atan2 : y:float * x:float -> float
    abstract member atanh : x:float -> float
    abstract member cbrt : x:float -> float
    abstract member ceil : x:float -> float
    ...
  end

Full name: Fable.Import.JS.Math
val generateHeight : width:int32 -> height:int32 -> float []

Full name: WebGLTerrain.generateHeight
val width : int32
val height : int32
val size : int
val data : float []
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val zeroCreate : count:int -> 'T []

Full name: Microsoft.FSharp.Collections.Array.zeroCreate
val perlin : IPerlin
val mutable quality : float
val z : float
val j : int32
val i : int32
val x : int32
val y : int32
val noise : float
abstract member IPerlin.noise : x:float * y:float * z:float -> float
val abs : value:'T -> 'T (requires member Abs)

Full name: Microsoft.FSharp.Core.Operators.abs
val generateTexture : data:float [] -> width:int -> height:int -> Browser.HTMLCanvasElement

Full name: WebGLTerrain.generateTexture
val width : int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
val height : int
val vector3 : Three.Vector3
Multiple items
type Vector3 =
  interface Vector
  new : ?x:float * ?y:float * ?z:float -> Vector3
  member add : a:Vector3 -> Vector3
  member addScalar : s:float -> Vector3
  member addScaledVector : v:Vector3 * s:float -> Vector3
  member addVectors : a:Vector3 * b:Vector3 -> Vector3
  member angleTo : v:Vector3 -> float
  member applyAxisAngle : axis:Vector3 * angle:float -> Vector3
  member applyEuler : euler:Euler -> Vector3
  member applyMatrix3 : m:Matrix3 -> Vector3
  ...

Full name: Fable.Import.Three.Vector3

--------------------
new : ?x:float * ?y:float * ?z:float -> Three.Vector3
val sun : Three.Vector
type Vector =
  interface
    abstract member add : v:Vector -> Vector
    abstract member addVectors : a:Vector * b:Vector -> Vector
    abstract member clone : unit -> Vector
    abstract member copy : v:Vector -> Vector
    abstract member distanceTo : v:Vector -> float
    abstract member distanceToSquared : v:Vector -> float
    abstract member divideScalar : s:float -> Vector
    abstract member dot : v:Vector -> float
    abstract member equals : v:Vector -> bool
    abstract member getComponent : index:float -> float
    ...
  end

Full name: Fable.Import.Three.Vector
val canvas : Browser.HTMLCanvasElement
val document : Browser.Document

Full name: Fable.Import.Browser.document
property Browser.HTMLCanvasElement.width: float
property Browser.HTMLCanvasElement.height: float
val context : Browser.CanvasRenderingContext2D
abstract member Browser.HTMLCanvasElement.getContext_2d : unit -> Browser.CanvasRenderingContext2D
property Browser.CanvasRenderingContext2D.fillStyle: U3<string,Browser.CanvasGradient,Browser.CanvasPattern>
type U3<'a,'b,'c> =
  | Case1 of 'a
  | Case2 of 'b
  | Case3 of 'c

Full name: Fable.Core.U3<_,_,_>
union case U3.Case1: 'a -> U3<'a,'b,'c>
abstract member Browser.CanvasRenderingContext2D.fillRect : x:float * y:float * w:float * h:float -> unit
val image : Browser.ImageData
abstract member Browser.CanvasRenderingContext2D.getImageData : sx:float * sy:float * sw:float * sh:float -> Browser.ImageData
val imageData : JS.Uint8ClampedArray
property Browser.ImageData.data: JS.Uint8ClampedArray
val mutable i : int
val mutable j : int
val mutable l : int
property JS.Uint8ClampedArray.length: float
property Three.Vector3.x: float
property Three.Vector3.y: float
property Three.Vector3.z: float
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
val shade : float
member Three.Vector3.dot : v:Three.Vector3 -> float
abstract member Browser.CanvasRenderingContext2D.putImageData : imagedata:Browser.ImageData * dx:float * dy:float * ?dirtyX:float * ?dirtyY:float * ?dirtyWidth:float * ?dirtyHeight:float -> unit
val canvasScaled : Browser.HTMLCanvasElement
abstract member Browser.CanvasRenderingContext2D.scale : x:float * y:float -> unit
abstract member Browser.CanvasRenderingContext2D.drawImage : image:U3<Browser.HTMLImageElement,Browser.HTMLCanvasElement,Browser.HTMLVideoElement> * offsetX:float * offsetY:float * ?width:float * ?height:float * ?canvasOffsetX:float * ?canvasOffsetY:float * ?canvasImageWidth:float * ?canvasImageHeight:float -> unit
union case U3.Case2: 'b -> U3<'a,'b,'c>
val v : float
val init : unit -> Three.WebGLRenderer * Three.Scene * Three.PerspectiveCamera * IFirstPersonControls

Full name: WebGLTerrain.init
val getWidth : (unit -> float)
val window : Browser.Window

Full name: Fable.Import.Browser.window
val getHeight : (unit -> float)
val container : Browser.HTMLElement
val camera : Three.PerspectiveCamera
Multiple items
type PerspectiveCamera =
  inherit Camera
  new : ?fov:float * ?aspect:float * ?near:float * ?far:float -> PerspectiveCamera
  member clone : unit -> PerspectiveCamera
  member copy : source:PerspectiveCamera -> PerspectiveCamera
  member aspect : float
  member far : float
  member focalLength : float
  member fov : float
  member near : float
  member zoom : float
  ...

Full name: Fable.Import.Three.PerspectiveCamera

--------------------
new : ?fov:float * ?aspect:float * ?near:float * ?far:float -> Three.PerspectiveCamera
val scene : Three.Scene
Multiple items
type Scene =
  inherit Object3D
  new : unit -> Scene
  member copy : source:Scene * ?recursive:bool -> Scene
  member autoUpdate : bool
  member fog : IFog
  member overrideMaterial : Material
  member autoUpdate : bool with set
  member fog : IFog with set
  member overrideMaterial : Material with set

Full name: Fable.Import.Three.Scene

--------------------
new : unit -> Three.Scene
val renderer : Three.WebGLRenderer
Multiple items
type WebGLRenderer =
  interface Renderer
  new : ?parameters:WebGLRendererParameters -> WebGLRenderer
  member clear : ?color:bool * ?depth:bool * ?stencil:bool -> unit
  member clearColor : unit -> unit
  member clearDepth : unit -> unit
  member clearStencil : unit -> unit
  member clearTarget : renderTarget:WebGLRenderTarget * color:bool * depth:bool * stencil:bool -> unit
  member dispose : unit -> unit
  member enableScissorTest : boolean:obj -> obj
  member forceContextLoss : unit -> unit
  ...

Full name: Fable.Import.Three.WebGLRenderer

--------------------
new : ?parameters:Three.WebGLRendererParameters -> Three.WebGLRenderer
member Three.WebGLRenderer.setClearColor : color:Three.Color * ?alpha:float -> unit
member Three.WebGLRenderer.setClearColor : color:string * ?alpha:float -> unit
member Three.WebGLRenderer.setClearColor : color:float * ?alpha:float -> unit
type Renderer =
  interface
    abstract member domElement : HTMLCanvasElement
    abstract member render : scene:Scene * camera:Camera -> unit
    abstract member setSize : width:float * height:float * ?updateStyle:bool -> unit
    abstract member domElement : HTMLCanvasElement with set
  end

Full name: Fable.Import.Three.Renderer
val domElement : Browser.HTMLCanvasElement
property Browser.HTMLElement.innerHTML: string
abstract member Browser.Node.appendChild : newChild:Browser.Node -> Browser.Node
val controls : IFirstPersonControls
property IFirstPersonControls.movementSpeed: float
property IFirstPersonControls.lookSpeed: float
property Three.Object3D.position: Three.Vector3
val geometry : Three.PlaneBufferGeometry
Multiple items
type PlaneBufferGeometry =
  inherit BufferGeometry
  new : width:float * height:float * ?widthSegments:float * ?heightSegments:float -> PlaneBufferGeometry
  member parameters : obj
  member parameters : obj with set

Full name: Fable.Import.Three.PlaneBufferGeometry

--------------------
new : width:float * height:float * ?widthSegments:float * ?heightSegments:float -> Three.PlaneBufferGeometry
member Three.BufferGeometry.applyMatrix : matrix:Three.Matrix4 -> Three.BufferGeometry
Multiple items
type Matrix4 =
  interface Matrix
  new : unit -> Matrix4
  member applyToBuffer : buffer:BufferAttribute * ?offset:float * ?length:float -> BufferAttribute
  member applyToVector3Array : array:ResizeArray<float> * ?offset:float * ?length:float -> ResizeArray<float>
  member compose : translation:Vector3 * rotation:Quaternion * scale:Vector3 -> Matrix4
  member copy : m:Matrix4 -> Matrix4
  member copyPosition : m:Matrix4 -> Matrix4
  member crossVector : v:obj -> unit
  member decompose : ?translation:Vector3 * ?rotation:Quaternion * ?scale:Vector3 -> ResizeArray<obj>
  member equals : matrix:Matrix4 -> bool
  ...

Full name: Fable.Import.Three.Matrix4

--------------------
new : unit -> Three.Matrix4
property JS.Math.PI: float
val vertices : Three.BufferAttribute
member Three.BufferGeometry.getAttribute : name:string -> U2<Three.BufferAttribute,Three.InterleavedBufferAttribute>
val unbox : value:obj -> 'T

Full name: Microsoft.FSharp.Core.Operators.unbox
Multiple items
type BufferAttribute =
  new : array:ArrayLike<float> * itemSize:float -> BufferAttribute
  member clone : unit -> BufferAttribute
  member copy : source:BufferAttribute -> BufferAttribute
  member copyArray : array:ArrayLike<float> -> BufferAttribute
  member copyAt : index1:float * attribute:BufferAttribute * index2:float -> BufferAttribute
  member copyColorsArray : colors:ResizeArray<obj> -> BufferAttribute
  member copyIndicesArray : indices:ResizeArray<obj> -> BufferAttribute
  member copyVector2sArray : vectors:ResizeArray<obj> -> BufferAttribute
  member copyVector3sArray : vectors:ResizeArray<obj> -> BufferAttribute
  member copyVector4sArray : vectors:ResizeArray<obj> -> BufferAttribute
  ...

Full name: Fable.Import.Three.BufferAttribute

--------------------
new : array:JS.ArrayLike<float> * itemSize:float -> Three.BufferAttribute
val vertices : JS.ArrayLike<float>
type 'T array = 'T []

Full name: Microsoft.FSharp.Core.array<_>
val l : int
property JS.ArrayLike.length: float
val texCanvas : Browser.HTMLCanvasElement
val texture : Three.Texture
Multiple items
type Texture =
  new : image:U3<HTMLImageElement,HTMLCanvasElement,HTMLVideoElement> * ?mapping:Mapping * ?wrapS:Wrapping * ?wrapT:Wrapping * ?magFilter:TextureFilter * ?minFilter:TextureFilter * ?format:PixelFormat * ?type:TextureDataType * ?anisotropy:float -> Texture
  member addEventListener : type:string * listener:Func<Event,unit> -> unit
  member clone : unit -> Texture
  member copy : source:Texture -> Texture
  member dispatchEvent : event:obj -> unit
  member dispose : unit -> unit
  member DEFAULT_IMAGE : obj
  member DEFAULT_MAPPING : obj
  member anisotropy : float
  member encoding : TextureEncoding
  ...

Full name: Fable.Import.Three.Texture

--------------------
new : image:U3<Browser.HTMLImageElement,Browser.HTMLCanvasElement,Browser.HTMLVideoElement> * ?mapping:Three.Mapping * ?wrapS:Three.Wrapping * ?wrapT:Three.Wrapping * ?magFilter:Three.TextureFilter * ?minFilter:Three.TextureFilter * ?format:Three.PixelFormat * ?type:Three.TextureDataType * ?anisotropy:float -> Three.Texture
val UVMapping : Three.Mapping

Full name: Fable.Import.Three.UVMapping
val ClampToEdgeWrapping : Three.Wrapping

Full name: Fable.Import.Three.ClampToEdgeWrapping
property Three.Texture.needsUpdate: bool
val matProps : Three.MeshBasicMaterialParameters
val createEmpty<'T> : 'T

Full name: Fable.Core.JsInterop.createEmpty
type MeshBasicMaterialParameters =
  interface
    inherit MaterialParameters
    abstract member alphaMap : Texture option
    abstract member aoMap : Texture option
    abstract member aoMapIntensity : float option
    abstract member blending : Blending option
    abstract member color : U2<float,string> option
    abstract member combine : Combine option
    abstract member envMap : Texture option
    abstract member fog : bool option
    abstract member map : Texture option
    ...
  end

Full name: Fable.Import.Three.MeshBasicMaterialParameters
property Three.MeshBasicMaterialParameters.map: Three.Texture option
union case Option.Some: Value: 'T -> Option<'T>
val mesh : Three.Mesh
Multiple items
type Mesh =
  inherit Object3D
  new : ?geometry:BufferGeometry * ?material:Material -> Mesh
  member clone : unit -> Mesh
  member copy : source:Mesh -> Mesh
  member getMorphTargetIndexByName : name:string -> float
  member drawMode : TrianglesDrawModes
  member geometry : U2<Geometry,BufferGeometry>
  member material : Material
  member raycast : raycaster:Raycaster * intersects:obj -> unit
  member setDrawMode : drawMode:TrianglesDrawModes -> unit
  ...

Full name: Fable.Import.Three.Mesh

--------------------
new : ?geometry:Three.BufferGeometry * ?material:Three.Material -> Three.Mesh
Multiple items
type MeshBasicMaterial =
  inherit Material
  new : ?parameters:MeshBasicMaterialParameters -> MeshBasicMaterial
  member clone : unit -> MeshBasicMaterial
  member copy : source:MeshBasicMaterial -> MeshBasicMaterial
  member alphaMap : Texture
  member aoMap : Texture
  member aoMapIntensity : float
  member blending : Blending
  member color : Color
  member combine : Combine
  ...

Full name: Fable.Import.Three.MeshBasicMaterial

--------------------
new : ?parameters:Three.MeshBasicMaterialParameters -> Three.MeshBasicMaterial
member Three.Object3D.add : object:Three.Object3D -> unit
val onWindowResize : (Browser.UIEvent -> obj)
val e : Browser.UIEvent
Multiple items
val UIEvent : Browser.UIEventType

Full name: Fable.Import.Browser.UIEvent

--------------------
type UIEvent =
  interface
    inherit Event
    abstract member detail : float
    abstract member view : Window
    abstract member initUIEvent : typeArg:string * canBubbleArg:bool * cancelableArg:bool * viewArg:Window * detailArg:float -> unit
    abstract member detail : float with set
    abstract member view : Window with set
  end

Full name: Fable.Import.Browser.UIEvent
type obj = Object

Full name: Microsoft.FSharp.Core.obj
property Three.PerspectiveCamera.aspect: float
member Three.PerspectiveCamera.updateProjectionMatrix : unit -> unit
abstract member IFirstPersonControls.handleResize : unit -> unit
Multiple items
type Func<'TResult> =
  delegate of unit -> 'TResult

Full name: System.Func<_>

--------------------
type Func<'T,'TResult> =
  delegate of 'T -> 'TResult

Full name: System.Func<_,_>

--------------------
type Func<'T1,'T2,'TResult> =
  delegate of 'T1 * 'T2 -> 'TResult

Full name: System.Func<_,_,_>

--------------------
type Func<'T1,'T2,'T3,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 -> 'TResult

Full name: System.Func<_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 -> 'TResult

Full name: System.Func<_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 -> 'TResult

Full name: System.Func<_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'T13,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'T13,'T14,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'T13,'T14,'T15,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'T13,'T14,'T15,'T16,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_>
val renderer : Three.WebGLRenderer

Full name: WebGLTerrain.renderer
val scene : Three.Scene

Full name: WebGLTerrain.scene
val camera : Three.PerspectiveCamera

Full name: WebGLTerrain.camera
val controls : IFirstPersonControls

Full name: WebGLTerrain.controls
val render : unit -> unit

Full name: WebGLTerrain.render
abstract member IFirstPersonControls.update : float -> unit
member Three.Clock.getDelta : unit -> float
member Three.WebGLRenderer.render : scene:Three.Scene * camera:Three.Camera * ?renderTarget:Three.RenderTarget * ?forceClear:bool -> unit
val animate : dt:float -> unit

Full name: WebGLTerrain.animate
val dt : float
Fork me on GitHub