2016-05-22 3 views
6

Я работал над этим довольно долго и застрял в этой ошибке.Ray Tracing F # - Отсутствующие треугольники создают отверстия в фигуре: Хит правильно?

Мы построили луч-трассировщик в F # для школьного проекта. (Ссылка, объясняющая Ray tracer: https://blog.frogslayer.com/kd-trees-for-faster-ray-tracing-with-triangles/)

У нас есть сделанная функция удара для треугольников, ограничивающих боксов, дерево KD для обработки фигур с тысячами треугольников, таких как Stanford Bunny и алгоритм траверсы для дерева KD.

Мы отлаживали и создание дерева KD, чтобы добавить значение epsilon для точек с плавающей точкой и проверили, что дубликаты между ограничивающими ячейками не удаляются. Мы уверены, что мы раскроем список фигур на сцене, но мы получим «дыры» в фигуре, которую мы пытаемся сделать.

Это наша К.Д. реализация дерева и Я приложил фотографии отверстий:

Stanford Bunny

Helix

module TmKdtree 

open Point 
open Shapes 

type BoundingBox = BasicShape.BoundingBox 
type Shape = BasicShape.Shape 

type TmKdtree = 
    | Leaf of BasicShape.Triangle list * BoundingBox 
    | Node of BasicShape.Triangle list * TmKdtree * TmKdtree * BoundingBox * (string*Point) 

let epsilon = 0.001 

//Making a boundingbox for the KD-tree, by finding max H point in the boundingboxlist and min l point in the boundingbox list. 
let mkKdBbox (shapes : BasicShape.Triangle list) : BoundingBox = 
    let shapeX = List.map(fun x -> x:> Shape) shapes 
    let sbbox = List.map (fun (c:Shape) -> c.getBounding().Value) shapeX 
    let bL = List.map (fun (b:BasicShape.BoundingBox) -> b.getL) sbbox 
    let bH = List.map (fun (b:BasicShape.BoundingBox) -> b.getH) sbbox 

    let minX = List.minBy (fun x -> Point.getX x) bL 
    let minY = List.minBy (fun x -> Point.getY x) bL 
    let minZ = List.minBy (fun x -> Point.getZ x) bL 

    let maxX = List.maxBy (fun x -> Point.getX x) bH 
    let maxY = List.maxBy (fun x -> Point.getY x) bH 
    let maxZ = List.maxBy (fun x -> Point.getZ x) bH 
    {p1=(mkPoint (Point.getX minX - epsilon) (Point.getY minY - epsilon) (Point.getZ minZ - epsilon)) 
           ; p2=(mkPoint (Point.getX maxX + epsilon) (Point.getY maxY + epsilon) (Point.getZ maxZ + epsilon))} 

//Splitting existing boundingbox according to left and right list of shapes 
let BoundingBoxL (bbox:BoundingBox) axis midp : BoundingBox = 
    match axis with 
    | "x" -> {p1 = bbox.getL - epsilon; p2 = Point.mkPoint ((Point.getX midp)) ((Point.getY (bbox.getH))) ((Point.getZ (bbox.getH))) + epsilon} 
    | "y" -> {p1 = bbox.getL - epsilon; p2 = Point.mkPoint (Point.getX (bbox.getH)) ((Point.getY midp)+epsilon) ((Point.getZ (bbox.getH))) + epsilon } 
    | "z" -> {p1 = bbox.getL - epsilon; p2 = Point.mkPoint (Point.getX (bbox.getH)) (Point.getY (bbox.getH)) (Point.getZ midp) + epsilon} 

let BoundingBoxR (bbox:BoundingBox) axis midp : BoundingBox = 
    match axis with 
    | "x" -> {p1 = (Point.mkPoint (Point.getX midp) (Point.getY (bbox.getL)) (Point.getZ (bbox.getL))) - epsilon; p2 = bbox.getH + epsilon} 
    | "y" -> {p1 = (Point.mkPoint (Point.getX (bbox.getL)) (Point.getY midp) (Point.getZ (bbox.getL))) - epsilon; p2 = bbox.getH + epsilon} 
    | "z" -> {p1 = (Point.mkPoint (Point.getX (bbox.getL)) (Point.getY (bbox.getL)) (Point.getZ midp)) - epsilon; p2 = bbox.getH + epsilon} 


//Get left node 
let getLeft s = 
    match s with 
    | Node(_,l,_,_,_) -> l 
    | Leaf(_,_) as leaf -> leaf 

let getRight s = 
    match s with 
    | Node(_,_,r,_,_) -> r 
    | Leaf(_,_) as leaf -> leaf 


//Get the triangle list 
let getShapes s = 
    match s with 
    | Node(b,_,_,_,_) -> b 
    | Leaf(b,_) -> b 

let getAxis s = 
    match s with 
    | Node(_,_,_,_,a) -> a 
    | Leaf(_,_) -> failwith "leaf ramt af axis" 


//Get bounding box 
let getBox s = 
    match s with 
    | Node(_,_,_,b,_) -> Some b 
    | Leaf(_,b) -> Some b 

let closestHit (triList : BasicShape.Triangle list) ray = 
    let sndRects = List.map(fun x -> x:> Shape) triList 
    let min = List.map(fun (x:Shape) -> x.hit ray) sndRects |> List.choose id 
    match min with 
    |[] -> None 
    |_ -> Some(List.minBy (fun (di, nV, mat) -> di) min) 

let searchLeaf leaf ray t' = 
    match leaf with 
    | Leaf(s,_) -> let hit = closestHit s ray 
       match hit with 
       |Some(f,_,_) -> if (f<t') then Some hit else None 
       |None -> None 
    | Node(_,_,_,_,_) -> failwith "Expected leaf" 

let order(d, left, right) = 
    if d > 0.0 
    then (left, right) 
    else (right, left) 

let rec search node ray t t' = 
    match node with 
    |Leaf(_,_) -> searchLeaf node ray t' 
    |Node(_,_,_,_,a') -> 
     let direction = Ray.getDirection ray (fst a') 
     let origin = Ray.getOrigin ray (fst a') 
     let nodeValue = Point.getFromAxis (snd a') (fst a') 
     if(direction) = 0.0 then 
      printfn("%s") "flatsite" 
      if(origin <= nodeValue) then search (getLeft node) ray t t' 
      else search (getRight node) ray t t' 
     else 
      let tHit = (nodeValue - origin)/direction 
      let (fst, snd) = order(direction,getLeft node, getRight node) 
      if tHit <= t || tHit < 0.0 then 
       search snd ray t t' 
      else if tHit >= t' then 
       search fst ray t t' 
      else 
      match search fst ray t tHit with 
      |Some hit -> Some hit 
      |_ -> search snd ray tHit t' 


let traverse tree ray (bawx:BasicShape.BoundingBox) = 
    match(bawx).hit(ray) with 
    |Some(t,t') -> search tree ray t t' 
    |None -> None 


//Finding the midpoint in the triangles in Shapes-list - we do this (recursively) to find out what axis to split 
let rec mkTmKdtree (shapes : BasicShape.Triangle list) (box:BasicShape.BoundingBox) =    
    //Finding biggest dimension in the shapes list 
    let axis = snd (box.getLongestAxis) 
    let axisMidPoint = 
     let midPoint = List.fold (fun acc (ele:BasicShape.Triangle) -> (acc + ele.getMidPoint())) (Point.mkPoint 0.0 0.0 0.0) shapes 
     let avgMid = midPoint/float(shapes.Length) 
     avgMid 

    let rec largerThanSplit (xs:BasicShape.Triangle list) = 
     let results = List.choose(fun (elem:BasicShape.Triangle) -> 
      match axis with 
      |"x" -> if (Point.getX (elem.getMidPoint())) >= (Point.getX axisMidPoint) then Some elem else None 
      |"y" -> if (Point.getY (elem.getMidPoint())) >= (Point.getY axisMidPoint) then Some elem else None 
      |"z" -> if (Point.getZ (elem.getMidPoint())) >= (Point.getZ axisMidPoint) then Some elem else None) xs 
     results 


    let rec lessThanSplit (xs:BasicShape.Triangle list) = 
     let results = List.choose(fun (elem:BasicShape.Triangle) -> 
      match axis with 
      |"x" -> if ((Point.getX (elem.getMidPoint())) <= (Point.getX (axisMidPoint))) then Some elem else None 
      |"y" -> if ((Point.getY (elem.getMidPoint())) <= (Point.getY (axisMidPoint))) then Some elem else None 
      |"z" -> if ((Point.getZ (elem.getMidPoint())) <= (Point.getZ (axisMidPoint))) then Some elem else None) xs 
     results 

    //Creating the left and right list from the above 
    let rightTest = largerThanSplit shapes 
    let leftTest = lessThanSplit shapes 

    //If one of the trees are empty, we add make left and right equivelant. 
    let left = if(leftTest.IsEmpty && rightTest.Length > 0) then rightTest else leftTest 
    let right = if(rightTest.IsEmpty && leftTest.Length > 0) then leftTest else rightTest 

    //Check for duplicates among the lists. 
    if(((float(left.Length+right.Length-shapes.Length)/float(shapes.Length)) < 0.4) && left.Length <> shapes.Length && right.Length<>shapes.Length) then 
     let leftTree = mkTmKdtree left (BoundingBoxL box axis axisMidPoint) 
     let rightTree = mkTmKdtree right (BoundingBoxR box axis axisMidPoint) 
     Node(shapes,leftTree, rightTree, (box),(axis,axisMidPoint)) 

    else Leaf(shapes, (box)) 
+1

Хороший вопрос. Я знаю F #, и я понимаю треугольники, но я уверен, что есть другие здесь, в теге F # со мной, кто может понять вашу проблему, если бы у нас было больше объяснений того, что вы пытаетесь сделать. Другими словами, не предполагайте, что все мы знаем ограничительную рамку, дерево KD, Stanford Bunny, epsilon и т. Д. Большинство из них для меня новы. Если вы можете помочь тем, кто из нас хорошо знаком с F #, понять, что вы делаете, тогда мы можем посмотреть на код и посмотреть, делает ли он это. Я уверен, что есть люди, которые могут ответить на этот вопрос, как написано, но я не один из них. –

+0

Извините за путаницу :-) Понятия знакомы тем, кто работает с трассировкой лучей, но я могу понять, почему они не тривиальны для других. Я нашел, что эта ссылка объясняет это довольно хорошо: https://blog.frogslayer.com/kd-trees-for-faster-ray-tracing-with-triangles/ – monkally

+0

Спасибо за ссылку. Вы должны задать вопрос, потому что люди несколько раз не смотрят на комментарии. –

ответ

0

Спасибо за ответы! Я выяснил, что ошибка была в наших размышлениях о цифрах и не имела никакого отношения к структуре данных программы.

Но спасибо вам в любом случае! :-)