模板缓冲在elm-webgl中

时间:2016-06-29 21:51:51

标签: javascript webgl shader elm

我试图在elm-webgl中创建一个简单的OpenGL程序。我拿了一个有旋转框的示例,我想使用模板测试一次只渲染一行像素。

我能够实现绘制我想要的线,并且我尝试将其设置为仅在模板缓冲区上渲染。然后我设置立方体的渲染只传递模板测试,如果对于模板缓冲区中的线,但它似乎不起作用。它只是像平常一样呈现立方体。

这是我的榆树计划(this example的修改版本):

import Math.Vector2 exposing (Vec2)
import Math.Vector3 exposing (..)
import Math.Matrix4 exposing (..)
import Task
import Time exposing (Time)
import WebGL exposing (..)
import WebGL exposing (FunctionCall(..), CompareMode(..), Capability(..), ZMode(..))
import Html exposing (Html)
import Html.App as Html
import AnimationFrame
import Html.Attributes exposing (width, height)


type alias Model =
  { texture : Maybe Texture
  , theta : Float
  }


type Action
  = TextureError Error
  | TextureLoaded Texture
  | Animate Time


update : Action -> Model -> (Model, Cmd Action)
update action model =
  case action of
    TextureError err ->
      (model, Cmd.none)
    TextureLoaded texture ->
      ({model | texture = Just texture}, Cmd.none)
    Animate dt ->
      ({model | theta = model.theta + dt / 10000}, Cmd.none)


init : (Model, Cmd Action)
init =
  ( {texture = Nothing, theta = 0}
  , loadTexture "/woodCrate.jpg"
    |> Task.perform TextureError TextureLoaded
  )


main : Program Never
main =
  Html.program
    { init = init
    , view = view
    , subscriptions = (\model -> AnimationFrame.diffs Animate)
    , update = update
    }


-- MESHES

crate : Drawable { pos:Vec3, coord:Vec3 }
crate =
  Triangle <|
  List.concatMap rotatedFace [ (0,0), (90,0), (180,0), (270,0), (0,90), (0,-90) ]


fmod : Float -> Float -> Float
fmod a b =
  a - (toFloat <| floor <| a / b) * b


line : Float -> Drawable { pos: Vec3 }
line theta =
  let
    y = (fmod -theta 2) - 1
  in
    Lines
      [ ({ pos = vec3 -1 y 0 } , { pos = vec3 1 y 0 })
      ]


rotatedFace : (Float,Float) -> List ({ pos:Vec3, coord:Vec3 }, { pos:Vec3, coord:Vec3 }, { pos:Vec3, coord:Vec3 })
rotatedFace (angleX,angleY) =
  let
    x = makeRotate (degrees angleX) (vec3 1 0 0)
    y = makeRotate (degrees angleY) (vec3 0 1 0)
    t = x `mul` y `mul` makeTranslate (vec3 0 0 1)
    each f (a,b,c) =
      (f a, f b, f c)
  in
    List.map (each (\x -> {x | pos = transform t x.pos })) face


face : List ({ pos:Vec3, coord:Vec3 }, { pos:Vec3, coord:Vec3 }, { pos:Vec3, coord:Vec3 })
face =
  let
    topLeft     = { pos = vec3 -1  1 0, coord = vec3 0 1 0 }
    topRight    = { pos = vec3  1  1 0, coord = vec3 1 1 0 }
    bottomLeft  = { pos = vec3 -1 -1 0, coord = vec3 0 0 0 }
    bottomRight = { pos = vec3  1 -1 0, coord = vec3 1 0 0 }
  in
    [ (topLeft,topRight,bottomLeft)
    , (bottomLeft,topRight,bottomRight)
    ]


-- VIEW

perspective : Float -> Mat4
perspective angle =
  List.foldr mul Math.Matrix4.identity
    [ perspectiveMatrix
    , camera
    , makeRotate (3*angle) (vec3 0 1 0)
    , makeRotate (2*angle) (vec3 1 0 0)
    ]

perspectiveMatrix : Mat4
perspectiveMatrix =
  makePerspective 45 1 0.01 100


camera : Mat4
camera =
  makeLookAt (vec3 0 0 5) (vec3 0 0 0) (vec3 0 1 0)

lineFunctionCalls: List FunctionCall
lineFunctionCalls =
  [ Disable StencilTest
  , Enable StencilTest
  , StencilFunc (Always, 1, 0xFF)
  , StencilMask 0xFF
  , DepthMask 0x00
  , ColorMask (0x00, 0x00, 0x00, 0x00)
  ]

cubeFunctionCalls: List FunctionCall
cubeFunctionCalls =
  [ StencilFunc (Equal, 1, 0xFF)
  , StencilMask 0x00
  , DepthMask 0xFF
  , ColorMask (0xFF, 0xFF, 0xFF, 0xFF)
  ]

initFunctionCalls: List FunctionCall
initFunctionCalls =
  [ Enable DepthTest
  , DepthFunc Less
  ]

view : Model -> Html Action
view {texture, theta} =
  (case texture of
    Nothing ->
        []
    Just tex ->
        [ renderWithConfig lineFunctionCalls lineVertexShader lineFragmentShader (line theta) {}
        , renderWithConfig cubeFunctionCalls vertexShader fragmentShader crate { crate = tex, perspective = perspective theta }
        ]
  )
  |> WebGL.toHtmlWith initFunctionCalls [width 400, height 400]


-- SHADERS

vertexShader : Shader { pos:Vec3, coord:Vec3 } { u | perspective:Mat4 } { vcoord:Vec2 }
vertexShader = [glsl|

attribute vec3 pos;
attribute vec3 coord;
uniform mat4 perspective;
varying vec2 vcoord;

void main () {
  gl_Position = perspective * vec4(pos, 1.0);
  vcoord = coord.xy;
}

|]

lineVertexShader : Shader { pos: Vec3 } u {}
lineVertexShader = [glsl|
attribute vec3 pos;

void main() {
  gl_Position = vec4(pos, 1.0);
}
|]

lineFragmentShader : Shader a u {}
lineFragmentShader = [glsl|
precision mediump float;

void main() {
  gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
|]


fragmentShader : Shader {} { u | crate:Texture } { vcoord:Vec2 }
fragmentShader = [glsl|

precision mediump float;
uniform sampler2D crate;
varying vec2 vcoord;

void main () {
  gl_FragColor = texture2D(crate, vcoord);
}

|]

我使用elm-webgl的修改版本添加了一些函数调用,例如ColorMaskStencilMask。这些与他们的JavaScript WebGL计数器部分一对一地映射。

我对模板缓冲区的工作方式没有超级教育,而且我对OpenGL的经验也很少。我已经阅读了关于模板缓冲区的两个教程:this onethis one,据我所知,没有理由不应该这样做。

感谢任何帮助。谢谢!

1 个答案:

答案 0 :(得分:1)

只是检查,但你是否要求模板缓冲区? WebGL默认没有。您可以在创建webgl上下文时通过将{stencil: true}作为第二个参数传递给JavaScript中的getContext来请求一个。