2016-06-29 14 views
1

Ich versuche, ein einfaches OpenGL-Programm in Elm-Webgl zu machen. Ich nahm eines der Beispiele, bei denen eine Box rotiert, und ich wollte mit dem Schablonentest nur jeweils eine Pixelzeile rendern.Stencil Buffering in Elm-Webgl

Ich konnte erreichen, die Linie zu zeichnen, die ich wollte, und ich versuchte, es einzurichten, nur auf dem Stencil-Puffer zu rendern. Dann richte ich das Rendering des Würfels so ein, dass es den Schablonentest nur für die Zeile im Stencil-Puffer besteht, aber es scheint nicht zu funktionieren. Es macht nur den Würfel wie normal.

Hier ist meine Elm Programm (modifizierte Version von 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); 
} 

|] 

ich eine modifizierte Version von Ulme-webgl verwenden, die ein paar Funktionsaufrufe wie ColorMask und StencilMask hinzufügt. Diese Karten eins zu eins mit ihren JavaScript WebGL Counter Parts.

Ich bin nicht super ausgebildet, wie der Stencil-Puffer funktioniert, und ich habe wenig Erfahrung mit OpenGL. Ich habe zwei Tutorials über Stencil-Puffer gelesen: this one und this one, und soweit ich das beurteilen kann, gibt es keinen Grund, warum das nicht funktionieren sollte.

Jede Hilfe wird geschätzt. Vielen Dank!

+1

Sie haben nur nachgefragt, aber haben Sie nach einem Stencil Buffer gefragt? Standardmäßig verwendet WebGL * nicht *. Sie können beim Erstellen des Webgl-Kontexts nach einem solchen fragen, indem Sie '{stencil: true}' als zweiten Parameter für 'getContext' in JavaScript übergeben. Ich habe keine Ahnung von Ulme. – gman

+0

Das ist absolut was es war, danke! Setzen Sie das als Antwort und ich werde es markieren. – EmptyFlash

Antwort

1

Sie haben nur nachgefragt, aber haben Sie nach einem Stencil Buffer gefragt? WebGL hat standardmäßig keinen. Sie können beim Erstellen des Webgl-Kontexts nach einem solchen fragen, indem Sie als zweiten Parameter an getContext in JavaScript übergeben.

Verwandte Themen