2016-06-29 2 views
1

私はelm-webglで簡単なOpenGLプログラムを作成しようとしています。私は周りに回転するボックスを持つサンプルの1つをとりました。そして、一度に1行のピクセルだけをレンダリングするためにステンシルテストを使いたいと思っていました。elm-webglのステンシルバッファリング

私が望む線を描くことができました。ステンシルバッファ上にのみレンダリングするように設定しました。次に、ステンシルバッファ内の行についてはステンシルテストに合格するだけで、動作するようには見えないキューブのレンダリングを設定します。キューブは通常のようにレンダリングされます。

は、ここに私のエルムプログラム(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); 
} 

|] 

私はColorMaskStencilMaskのような関数呼び出しのカップルを追加ELM-のWebGLの修正版を使用しています。これらは、JavaScriptのWebGLカウンターパートを使用して1対1で対応します。

私は、ステンシルバッファがどのように機能するかについては十分に教育されておらず、OpenGLでの経験はほとんどありません。私はステンシルバッファに関する2つのチュートリアルを読んでいます:this onethis one、私が知る限り、これは動作してはならない理由はありません。

何か助けていただければ幸いです。ありがとう!

+1

ステンシルバッファーを確認しましたか? WebGLはデフォルトでは*持っていません。 JavaScriptの 'getContext'の2番目のパラメータとして' {stencil:true} 'を渡すことで、webglコンテキストを作成するときにリクエストすることができます。私はエルムについては考えていません。 – gman

+0

それは本当にありがとう!それを答えに入れて、私はそれに印を付けます。 – EmptyFlash

答えて

1

ステンシルバッファを確認しましたが、確認しましたか? WebGLはデフォルトでWebGLを持っていません。 JavaScriptのgetContextの2番目のパラメータとして{stencil: true}を渡すことで、webglコンテキストを作成するときに1つを求めることができます。

関連する問題