Fixed error in flomap gradient calculation (borders were always getting 0.0, causing erroneous lighting)

Inset rendered deep-flomaps by 1px to harden against future border issues

Adjusted scatter-simulating blur (finally rid of edge sparklies!)
This commit is contained in:
Neil Toronto 2012-01-20 12:39:23 -07:00
parent f1add6929b
commit 07500b27f6
2 changed files with 94 additions and 67 deletions

View File

@ -69,11 +69,13 @@
;; ===================================================================================================
;; Pass 1: tracing from a directional light source
(: trace-directional-light (flomap flomap flomap flomap Integer Integer Integer Integer
-> (values flomap flomap)))
(define (trace-directional-light alpha-fm rgb-fm z-fm normal-fm x-min x-max y-min y-max)
(: trace-directional-light (flomap flomap flomap flomap
Integer Integer Integer Integer -> (values flomap flomap)))
(define (trace-directional-light alpha-fm rgb-fm z-fm normal-fm
x-min x-max y-min y-max)
(match-define (flomap alpha-vs 1 w h) alpha-fm)
(match-define (list rgb-vs z-vs normal-vs) (map flomap-values (list rgb-fm z-fm normal-fm)))
(match-define (list rgb-vs z-vs normal-vs)
(map flomap-values (list rgb-fm z-fm normal-fm)))
(define z-max (flomap-max-value z-fm))
(define opacity-z (/ z-max (transmission-density)))
@ -111,8 +113,12 @@
(define diffuse-fm (make-flomap 3 w h lz))
(define diffuse-vs (flomap-values diffuse-fm))
(define sx-vs (make-flvector (* w h) +nan.0))
(define sy-vs (make-flvector (* w h) +nan.0))
;(define sx-vs (make-flvector (* w h) +nan.0))
;(define sy-vs (make-flvector (* w h) +nan.0))
(define sx-fm (inline-build-flomap 1 w h (λ (k x y i) (+ (fx->fl x) 0.5))))
(define sy-fm (inline-build-flomap 1 w h (λ (k x y i) (+ (fx->fl y) 0.5))))
(define sx-vs (flomap-values sx-fm))
(define sy-vs (flomap-values sy-fm))
(define Irgb-vs (make-flvector (* 3 w h)))
(for*: ([int-y : Integer (in-range y-min y-max)]
@ -330,9 +336,10 @@
;; ===================================================================================================
;; Pass 2: tracing from a directional viewer
(: trace-directional-view (flomap flomap flomap flomap flomap Integer Integer Integer Integer
-> (values flomap flomap)))
(define (trace-directional-view alpha-fm rgb-fm z-fm normal-fm shadow-fm x-min x-max y-min y-max)
(: trace-directional-view (flomap flomap flomap flomap flomap
Integer Integer Integer Integer -> (values flomap flomap)))
(define (trace-directional-view alpha-fm rgb-fm z-fm normal-fm shadow-fm
x-min x-max y-min y-max)
(define-values (w h) (flomap-size alpha-fm))
(match-define (list alpha-vs rgb-vs z-vs normal-vs shadow-vs)
(map flomap-values (list alpha-fm rgb-fm z-fm normal-fm shadow-fm)))
@ -407,7 +414,10 @@
(unsafe-flvector-set! reflected-vs (fx+ j 2) b))))
;; transmission (refraction)
(when (Ti . > . 0.0)
(define-values (tx ty tz) (transmitted-vector nx ny nz 0.0 0.0 -1.0 1.0 η2))
(define snx (unsafe-flvector-ref normal-vs j))
(define sny (unsafe-flvector-ref normal-vs (fx+ j 1)))
(define snz (unsafe-flvector-ref normal-vs (fx+ j 2)))
(define-values (tx ty tz) (transmitted-vector snx sny snz 0.0 0.0 -1.0 1.0 η2))
;; sz = z + dist * tz, so dist = (sz - z) / tz
(define dist (/ (- 0.0 z) tz))
(when (and (dist . >= . 0.0) (dist . < . +inf.0))
@ -456,38 +466,43 @@
(case-lambda
[(dfm) (deep-flomap-render dfm #f)]
[(dfm background-fm)
(define-values (w h) (deep-flomap-size dfm))
(define argb-fm (flomap-divide-alpha (deep-flomap-argb dfm)))
(define alpha-fm (flomap-ref-component argb-fm 0))
(define rgb-fm (flomap-drop-components argb-fm 1))
(define z-fm (fmmax 0.0 (deep-flomap-z dfm)))
(define normal-fm (flomap-gradient-normal z-fm))
(define bg-fm (if background-fm (prep-background background-fm w h) #f))
(define-values (_1 x-min y-min _2 x-max y-max) (flomap-nonzero-rect alpha-fm))
;; pass 1: trace from the light source
(define-values (diffracted-fm raw-shadow-fm)
(trace-directional-light alpha-fm rgb-fm z-fm normal-fm x-min x-max y-min y-max))
;; blur the shadow to simulate internal scatter
(define σ (* (min w h) (shadow-blur)))
(define shadow-fm
(cond [bg-fm
;; two Gaussian blurs by half-σ is equivalent to one Gaussian blur by σ
(define half-σ (* (/ 1 (sqrt 2)) σ))
(let* ([fm (flomap-blur raw-shadow-fm half-σ)]
[fm (fm* fm bg-fm)]
[fm (flomap-blur fm half-σ)])
fm)]
[else
(flomap-blur raw-shadow-fm σ)]))
;; pass 2: trace from the viewer
(define-values (reflected-fm transmitted-fm)
(trace-directional-view alpha-fm rgb-fm z-fm normal-fm shadow-fm x-min x-max y-min y-max))
;; add all the light together, convert to premultiplied-alpha flomap
(let* ([fm (fm+ (fm+ diffracted-fm transmitted-fm) reflected-fm)]
[fm (flomap-append-components alpha-fm fm)]
[fm (flomap-multiply-alpha fm)])
fm)]))
(let ([dfm (deep-flomap-inset dfm 1)])
(define-values (w h) (deep-flomap-size dfm))
(define argb-fm (flomap-divide-alpha (deep-flomap-argb dfm)))
(define alpha-fm (flomap-ref-component argb-fm 0))
(define rgb-fm (flomap-drop-components argb-fm 1))
(define z-fm (fmmax 0.0 (deep-flomap-z dfm)))
(define normal-fm (flomap-gradient-normal z-fm))
(define bg-fm (if background-fm (prep-background background-fm w h) #f))
(define-values (x-min y-min x-max y-max)
(let-values ([(_1 x-min y-min _2 x-max y-max) (flomap-nonzero-rect alpha-fm)])
(values (max 0 (- x-min 1)) (max 0 (- y-min 1))
(min w (+ x-max 1)) (min h (+ y-max 1)))))
;; pass 1: trace from the light source
(define-values (diffracted-fm raw-shadow-fm)
(trace-directional-light alpha-fm rgb-fm z-fm normal-fm x-min x-max y-min y-max))
;; two Gaussian blurs by half of σ^2 is equivalent to one Gaussian blur by σ^2
(define σ^2 (sqr (* (min w h) (shadow-blur))))
;; blur the shadow to simulate internal scatter
(define shadow-fm
(cond [bg-fm
(let* ([fm (flomap-blur raw-shadow-fm (sqrt (* 1/3 σ^2)))]
[fm (fm* fm bg-fm)]
[fm (flomap-blur fm (sqrt (* 1/3 σ^2)))])
fm)]
[else
(flomap-blur raw-shadow-fm (sqrt (* 2/3 σ^2)))]))
;; pass 2: trace from the viewer
(define-values (reflected-fm raw-transmitted-fm)
(trace-directional-view alpha-fm rgb-fm z-fm normal-fm shadow-fm x-min x-max y-min y-max))
;; simulate scatter some more
(define transmitted-fm (flomap-blur raw-transmitted-fm (sqrt (* 1/3 σ^2))))
;; add all the light together, convert to premultiplied-alpha flomap
(let* ([fm (fm+ (fm+ diffracted-fm transmitted-fm) reflected-fm)]
[fm (flomap-append-components alpha-fm fm)]
[fm (flomap-multiply-alpha fm)])
(flomap-inset fm -1)))]))

View File

@ -14,44 +14,56 @@
(: flomap-gradient-x (flomap -> flomap))
(define (flomap-gradient-x fm)
(match-define (flomap vs c w h) fm)
(define cw (fx* c w))
(define d20 (fx- 1 cw))
(define d22 (fx+ cw 1))
(define +x (fx* c 1))
(define -x+y (fx* c (fx- w 1)))
(define +x+y (fx* c (fx+ w 1)))
(define w-1 (fx- w 1))
(define h-1 (fx- h 1))
(inline-build-flomap
c w h
(λ (_k x y i)
(λ (k x y i)
(cond [(and (x . fx> . 0) (x . fx< . w-1)
(y . fx> . 0) (y . fx< . h-1))
(+ (- (* 0.1875 (unsafe-flvector-ref vs (fx+ i d20)))
(* 0.1875 (unsafe-flvector-ref vs (fx- i d22))))
(- (* 0.6250 (unsafe-flvector-ref vs (fx+ i 1)))
(* 0.6250 (unsafe-flvector-ref vs (fx- i 1))))
(- (* 0.1875 (unsafe-flvector-ref vs (fx+ i d22)))
(* 0.1875 (unsafe-flvector-ref vs (fx- i d20)))))]
[else 0.0]))))
(+ (- (* 0.1875 (unsafe-flvector-ref vs (fx- i -x+y)))
(* 0.1875 (unsafe-flvector-ref vs (fx- i +x+y))))
(- (* 0.6250 (unsafe-flvector-ref vs (fx+ i +x)))
(* 0.6250 (unsafe-flvector-ref vs (fx- i +x))))
(- (* 0.1875 (unsafe-flvector-ref vs (fx+ i +x+y)))
(* 0.1875 (unsafe-flvector-ref vs (fx+ i -x+y)))))]
[else
(+ (- (* 0.1875 (flomap-ref fm k (+ x 1) (- y 1)))
(* 0.1875 (flomap-ref fm k (- x 1) (- y 1))))
(- (* 0.6250 (flomap-ref fm k (+ x 1) y))
(* 0.6250 (flomap-ref fm k (- x 1) y)))
(- (* 0.1875 (flomap-ref fm k (+ x 1) (+ y 1)))
(* 0.1875 (flomap-ref fm k (- x 1) (+ y 1)))))]))))
(: flomap-gradient-y (flomap -> flomap))
(define (flomap-gradient-y fm)
(match-define (flomap vs c w h) fm)
(define cw (fx* c w))
(define d02 (fx- cw 1))
(define d22 (fx+ cw 1))
(define +y (fx* c w))
(define -x+y (fx* c (fx- w 1)))
(define +x+y (fx* c (fx+ w 1)))
(define w-1 (fx- w 1))
(define h-1 (fx- h 1))
(inline-build-flomap
c w h
(λ (_k x y i)
(λ (k x y i)
(cond [(and (x . fx> . 0) (x . fx< . w-1)
(y . fx> . 0) (y . fx< . h-1))
(+ (- (* 0.1875 (unsafe-flvector-ref vs (fx+ i d02)))
(* 0.1875 (unsafe-flvector-ref vs (fx- i d22))))
(- (* 0.6250 (unsafe-flvector-ref vs (fx+ i cw)))
(* 0.6250 (unsafe-flvector-ref vs (fx- i cw))))
(- (* 0.1875 (unsafe-flvector-ref vs (fx+ i d22)))
(* 0.1875 (unsafe-flvector-ref vs (fx- i d02)))))]
[else 0.0]))))
(+ (- (* 0.1875 (unsafe-flvector-ref vs (fx+ i -x+y)))
(* 0.1875 (unsafe-flvector-ref vs (fx- i +x+y))))
(- (* 0.6250 (unsafe-flvector-ref vs (fx+ i +y)))
(* 0.6250 (unsafe-flvector-ref vs (fx- i +y))))
(- (* 0.1875 (unsafe-flvector-ref vs (fx+ i +x+y)))
(* 0.1875 (unsafe-flvector-ref vs (fx- i -x+y)))))]
[else
(+ (- (* 0.1875 (flomap-ref fm k (- x 1) (+ y 1)))
(* 0.1875 (flomap-ref fm k (- x 1) (- y 1))))
(- (* 0.6250 (flomap-ref fm k x (+ y 1)))
(* 0.6250 (flomap-ref fm k x (- y 1))))
(- (* 0.1875 (flomap-ref fm k (+ x 1) (+ y 1)))
(* 0.1875 (flomap-ref fm k (+ x 1) (- y 1)))))]))))
(: flomap-gradient (flomap -> (values flomap flomap)))
(define (flomap-gradient fm)