depth-of-field aadot

Post your FreeBASIC tips and tricks here. Please don’t post your code without including an explanation.
dafhi
Posts: 1357
Joined: Jun 04, 2005 9:51

depth-of-field aadot

Postby dafhi » Sep 19, 2020 7:28

- Depth of Field anti-aliased dots -

*** Note: if you don't want to save the include, you can

1. comment out #include
2. paste the code instead (defocus dot.bas)

have fun!

example 1 - basic 3d

Code: Select all

/'
 
  depth of field aadots - 2020 Sep 21 - by dafhi
 
  hard-coded "basic" 3d example
 
'/

#include "inc\defocus dot.bas"


dim shared as dotvars      a(9999)

sub initialize_dots
  for i int = 0 to ubound(a)
    a(i).o.rand_on_sphere '' .o (origin) or source data
    a(i).rad = (2 + rnd) * 1
    a(i).slope = 1.1 + rnd
    a(i).col = -1
  Next
End Sub


sub Main
 
  screenres 800,600,32
 
  dim as imagevars    buf: buf.get_info
  aadot.render_target @buf
 
  initialize_dots
 
  var scale = buf.diagonal  * .5
   
  dim sng object_z = 2.5
 
  dim sng obj_angle
  dim sng inc_focus

  var     tp = timer, tDemoEnd = tp + 20
 
  aadot.vie.iris_diam = 5
  aadot.alpha_thresh = 20 '' alpha value less than this will reduce dot radius.
                          '' defocus_dot.bas Namespace AaDot for hows and whys
 
  while inkey=""
   
    var cosa = cos(obj_angle)
    var sina = sin(obj_angle)
    aadot.vie.focus_z = object_z + 1*sin(inc_focus)
 
    screenlock
      cls
     
      for i int = 0 to ubound(a)
     
        static as v3 ptr o:  o = @a(i).o
        static as v3 ptr p:  p = @a(i).p '' defocus_draw reads x,y,z of .p
       
        p->z = o->z * cosa - o->x * sina
        p->z += object_z
       
        if p->z > .1 then
          p->x = o->x * cosa + o->z * sina
          p->y = o->y
          var z = scale / p->z
          p->x = buf.wh + p->x * z
          p->y = buf.hh - p->y * z
          #define rad_scalar z * .003
          aadot.defocus_draw @a(i), rad_scalar
        endif
       
      Next
    screenunlock

    locate 1,1 '' reset print position
   
    var t=timer, dt=t-tp
    tp=t
   
    obj_angle += dt * .07
    inc_focus += dt * .71
   
    if tp > tDemoEnd then ? "demo finished.  exiting ..": sleep 1700: end
    sleep 15
   
  wend
end sub

Main

example 2 - oop 3d

Code: Select all

/'
 
  depth of field aadots - 2020 Sep 21 - by dafhi
 
  structured (oop) 3d example
 
'/

#include "inc\defocus dot.bas"

type axis3
  sng             size = 1, _size
  as v3           ori
  as v3           vx, vy, vz
  sng             user_angle
  decl sub        v3op_calc(byref as dotvars ptr)
  decl sub        rot(a sng, byval as v3=type(0,1,0))
  decl sub        reset
  decl            csr(as v3=type(0,0,0), sng=1)
End Type

csr.axis3(_ori as v3, size sng): ori=_ori*size: _size=size: reset: end csr

sub axis3.reset:  size=_size: vx=type(size,0,0): vy=type(0,size,0): vz=type(0,0,size):  end sub

sub axis3.v3op_calc(byref p as dotvars ptr)
  p->p = p->o.x * vx + p->o.y * vy + p->o.z * vz
End Sub

def eps 1e-8

sub axis3.rot(a sng, byval norm as v3)
 
  static sng slen:  slen = norm.x*norm.x+norm.y*norm.y+norm.z*norm.z

  if slen < eps then
    norm.x=0:norm.y=0:norm.z=1
  elseif abs(1 - slen) > eps then
    slen = 1/sqr(slen): norm.x*=slen: norm.y*=slen: norm.z*=slen
  endif
 
  static sng cosa, sina:  cosa=cos(a): sina=sin(a)

  vx = vx.rodrigues(norm, sina, cosa)
  vy = vy.rodrigues(norm, sina, cosa)
  vz = vz.rodrigues(norm, sina, cosa)
 
End Sub


Dim shared int j

Sub QsortZ(array() As dotvars, begin As Integer, Finish As Uinteger) 'by dodicat
    j = finish
    Dim int i = begin   '' local i
    static As dotvars X '' reduce stack
    X = array(((I + J) \ 2))
    While I <= J
        While array(I).p.z > X .p.z : I += 1 : Wend
        While array(J).p.z < X .p.z : J -= 1 : Wend
        If I <= J Then Swap array(I), array(J) : I += 1 : J -= 1
   Wend
   If J > begin Then QsortZ(array(), begin, J) '' a global I would get destroyed
   If I < Finish Then QsortZ(array(), I, Finish)
End Sub


sub plot(byref im as imagevars ptr, a() as dotvars, axis as Axis3, scale sng=1)
 
 
  for i int = 0 to ubound(a)
    axis.v3op_calc @a(i)
  next
 
  qsortz a(), 0, ubound(a)
 
  static sng rad_scalar:  rad_scalar = .004
  var z_thresh = .01 - axis.ori.z
 
  line im->im, (0,0)-(im->wm,im->hm), rgb(0,0,0), bf
  for i int = 0 to ubound(a)
    a(i).p.z += axis.ori.z
    var z = a(i).p.z
    if z > z_thresh then
      z = scale / z
      with a(i).p
        .x = im->wh + .x * z
        .y = im->hh - .y * z
      end with
      aadot.defocus_draw @a(i), rad_scalar * z
    endif
  next
 
End Sub


dim shared as dotvars      a(49999)

sub initialize_dots(im as imagevars, cube_size sng)
  for i int = 0 to ubound(a)
    a(i).o = cube_size * type(rnd-.5,rnd-.5,rnd-.5)
    a(i).rad = (2+rnd) * .im.diagonal / 800
    a(i).slope = (1.5+rnd) * 1
    a(i).col = rgb(rnd*255,rnd*255,rnd*255)
  Next
  aadot.alpha_thresh = 20
  aadot.vie.iris_diam = 10
End Sub


sub Main
 
  screenres 800,600,32
 
  dim as imagevars    buf: buf.get_info
  dim as imagevars    im
  aadot.render_target @im
 
  var scalar = .7
  im.get_info imagecreate (buf.w * scalar ,buf.h * scalar)
 
  var cube_size = 3
  initialize_dots im, cube_size
 
  dim as Axis3        axis=type<v3>(0, 0, 5) '' z depth of 5
 
  var   iphys_fps = 1/89, phys_t = 0f
  var   ianim_fps = 1/24, anim_t = 0f
 
  var   tp = timer, tDemoEnd = tp + 30
  dim   sng t_focus_z

  scalar = im.diagonal * 2
 
  while inkey=""
   
    if anim_t<=0 then
      axis.reset
      axis.rot axis.user_angle, type<v3>(1/5, 1/9, 1/7)
      aadot.vie.focus_z = (axis.ori.z + cube_size * sin(t_focus_z) * .7)
     
      plot @im, a(), axis, scalar
      put (50,50), im.im, pset
     
      while anim_t<0:  anim_t+=ianim_fps:  wend
    endif
    locate 1,1 '' reset print position
   
    var t=timer, dt=t-tp
    tp=t
   
    anim_t -= dt
    phys_t += dt
   
    t_focus_z += dt * .2

    while phys_t>0
      phys_t -= iphys_fps
      axis.user_angle += iphys_fps * .15
    wend
   
    if tp > tDemoEnd then ? "demo finished.  exiting ..": sleep 1700: end
    sleep 15
   
  wend
end sub

Main


defocus dot.bas

Code: Select all

/' "defocus dot.bas" - 2020 Sep 21 - by dafhi
 
  inspired by "bokeh particles" effect.
  current favorite example - https://www.youtube.com/watch?v=v-Qv3R28aCk
 
  - updates -
 
    - Sep 21
  transferred o,p members from dotvars.v to dotvars
  removed dotvars.v
 
    - Sep 20
  #3
  fixed defocus_draw artifact
 
  #2
  UniP3 replaced with v3
  renamed Dotvars.op -> v
   
  #1 
  renamed UniP3.xyz -> .v
  renamed DotVars.v -> .op
  - some unused vars
  + namespace alpha_thresh comments
  ~ fiddled with dot radius in defocus_draw
 
    - Sep 19
 
  #4
  tweaked .defocus_draw to reduce radius on very dim dots
  fixed plot(). needed to call axis->v3op_calc for entire array before zsorting
 
  #3
  found .defocus_draw accident.  placed in #if for study.
  .. iris_diam adjusted
 
  #2
  renamed: iris -> iris_diam, iris_z -> focus_z, rodriguez -> rodrigues
  iris_diam works
 
  #1
  decoupled axis3 from v3op, freeing aadot from axis3's grip
  moved all "ori & pro.bas" codez to aadot and main

'/
 
  #Ifndef DEFOCUS_DOT_H
  #define DEFOCUS_DOT_H

'#include "imvars.bas"
/' -- "imvars.bas" - 2020 Sep 18 - by dafhi -- '/

#Ifndef IMVARS_H
#define IMVARS_H

type imagevars '2017 Oct 10 - by dafhi
  as integer            w,h,bpp,bypp,pitch,rate,  wm, hm, pitchBy 'helpers
  as any ptr            im, pixels
  as ulong ptr          p32
  as string             driver_name
  declare sub           get_info(im as any ptr=0)
  declare               destructor
  as single             wh, hh, diagonal '2017 Oct 10
end type

Destructor.imagevars
  If ImageInfo(im) = 0 Then ImageDestroy im:  im=0
End Destructor

sub imagevars.get_info(im as any ptr)
  if im=0 then
    ScreenInfo w,h, bpp, bypp, pitch, rate, driver_name
    pixels=screenptr
  elseif Imageinfo(im)=0 then
    ImageInfo im, w, h, bypp, pitch, pixels
    this.im = im:  bpp = bypp * 8
  endif: wm=w-1: hm=h-1:  pitchBy=pitch\bypp:  p32=pixels
  wh=w/2: hh=h/2:  diagonal = sqr(w*w+h*h)
end sub


#Macro Alpha256(ret,back, fore, a256) '2017 Mar 26
  ret=((_
  (fore And &Hff00ff) * a256 + _
  (back And &Hff00ff) * (256-a256) + &H800080) And &Hff00ff00 Or (_
  (fore And &H00ff00) * a256 + _
  (back And &H00ff00) * (256-a256) + &H008000) And &H00ff0000) Shr 8
#EndMacro

#endif ' -- imvars_h

'#include "fb 1337 h4x.bas"
/' -- "fb 1337 h4x.bas" - 2020 Jan 28 - by dafhi -- '/

#Ifndef FB_1337_H4X
#define FB_1337_H4X

#undef int
#define def   #define

def int     as Integer
def sng     as single
def dbl     as double
def bool    as boolean

def decl    declare
def virt    virtual
def func    function
def prop    property
def oper    operator
def csr     constructor
def ret     return
def float   single
def ac      as const
#endif ' -- FB_1337_H4X


' "defocus dot.bas" continued ..

const tau = 8 * Atn(1)


type v3
  sng           x,y,z
  decl prop     n as v3
  decl sub      normalize
  decl sub      rand_on_sphere
  decl func     rodrigues(as v3, sng, sng) as v3
End Type

prop v3.n as v3
  static sng s: s = 1/sqr(x*x+y*y+z*z)
  ret type(s*x,s*y,s*z)
end prop

sub v3.normalize:  var slen=x*x+y*y+z*z
  if slen < .5 then: x=0:y=1:z=0
  else: slen = 1/sqr(slen): x*=slen: y*=slen: z*=slen
  endif
End Sub

sub v3.rand_on_sphere:  y=2*(rnd-.5):  var r=sqr(1-y*y)
  z=rnd*tau: x=r*cos(z): z=r*sin(z)
End Sub

func v3.rodrigues(norm as v3, sina sng, cosa sng) as v3
  static sng dot:  dot=(1-cosa)*(norm.x*x+norm.y*y+norm.z*z)
  return type(_
    norm.x*dot + x*cosa + (norm.y*z - norm.z*y)*sina, _
    norm.y*dot + y*cosa + (norm.z*x - norm.x*z)*sina, _
    norm.z*dot + z*cosa + (norm.x*y - norm.y*x)*sina)
End func

oper *(l sng, r as v3)as v3:  ret type(l*r.x, l*r.y, l*r.z):  end oper
oper *(l as v3, r sng)as v3:  ret type(l.x*r, l.y*r, l.z*r):  end oper
oper +(l as v3, r as v3)as v3:  ret type(l.x+r.x, l.y+r.y, l.z+r.z):  end oper
oper -(l as v3, r as v3)as v3:  ret type(l.x-r.x, l.y-r.y, l.z-r.z):  end oper



type DotVars          '' 2020 Sep 20
  union
    Type:  As UByte   b,g,r,a
    End Type
    As ULong          col
  end union
  as v3               o,p
  as single           rad = 1, slope = 2
  as boolean          flag
End Type

type tView3D
  as single           iris_diam = 2
  as single           focus_z = 1
End Type

 
  namespace AaDot     '2020 Sep 20 - by dafhi
 
  /'
    when dotvars.a (alpha) is low, reduce radius.
    render-time hack.  useful for thicc point clouds
   
    Depending on dot size vs model scale,
    can look hollow at larger values.
  '/
 
  dim int alpha_thresh = 20
                   

dim as imagevars ptr  im
dim as tView3D        vie

sub render_target(byref buf as imagevars ptr):  im = buf
end sub

dim sng               dy,dxLeft,salpha,cone_h,coneSq,sq,salpha0,slope
dim as long           x0,y0,x1,y1,alph,alpha_max

dim as dotvars ptr    p

sub draw(x as single, y as single, col as ulong)

  dim as long y0=(y-p->rad):  if y0<0 then y0=0
  dim as long y1=(y+p->rad):  if y1>im->hm then y1=im->hm
 
'  if y1<y0 then exit sub '' Sep 20
 
  salpha0=(col shr 24)/255:  alpha_max=salpha0*256
  slope = p->slope
 
  '' slope = 1 .. 1 pixel aa edge
  '' slope = 2 .. 1/2 pixel (sharp)
  '' slope = 1/p->rad .. max blur
  '' slope < 1/p->rad .. rendering artifact
 
  'sq=1/p->rad                   '' clamp prevents artifact
  'slope=iif(slope<sq,sq,slope)  ''
 
  cone_h=slope*(p->rad+.5)     'pre-inverted aadot imagined as cone \/
  coneSq=cone_h*cone_h    'avoid sqr() at blit corners
  sq=(cone_h-1)*(cone_h-1)'avoid sqr() in dot center at max brightness
  dim as long x0=(x-p->rad):  if x0<0 then x0=0
  dim as long x1=(x+p->rad):  if x1>im->wm then x1=im->wm

  dy=(y0-y)*slope: dxLeft=(x0-x)*slope
  for py as long ptr = @im->p32[ y0*im->pitchBy ] to @im->p32[ y1*im->pitchBy ] step im->pitchBy
    dim as single dx=dxleft, dySq=dy*dy
    for px as ulong ptr = @py[x0] to @py[x1]
      salpha = dx*dx+dySq
      if salpha<sq then
          Alpha256(*px,*px,col,alpha_max)
      elseif salpha<=coneSq then
          alph=(cone_h-sqr(salpha))*alpha_max
          Alpha256(*px,*px,col,alph)
      endif:  dx+=slope
    next: dy+=slope
  next

end sub


dim sng               r_expan
dim as dotvars        q

sub defocus_draw(byref pdv as dotvars ptr, rad_scalar sng = 1)
  p = @q '' result
 
  static sng  rad_z
 
  with *pdv
 
    r_expan = vie.iris_diam * abs(.p.z - vie.focus_z)
   
    rad_z = .rad * rad_scalar
    q.rad = rad_z + r_expan
    q.col = .col
   
    '' Area_0 / Area_1
    q.a = -.5 + 255.999 * rad_z * rad_z / (q.rad * q.rad)
 
    '' Sep 19 - reduce radius if very dim alpha
    q.rad = iif(q.a < alpha_thresh, q.rad * q.a / iif(alpha_thresh=0,1,alpha_thresh), q.rad)
   
    q.slope = .slope / (q.rad+1)
    draw .p.x, .p.y, q.col
  End With

End Sub

end namespace
#endif ' -- defocus_dot_h
Last edited by dafhi on Sep 22, 2020 0:51, edited 13 times in total.
Tourist Trap
Posts: 2904
Joined: Jun 02, 2015 16:24

Re: depth-of-field aadot

Postby Tourist Trap » Sep 19, 2020 7:35

Hi dahfi,

it looks blurred at the foreground. Is this what it is meant to do, right?
dafhi
Posts: 1357
Joined: Jun 04, 2005 9:51

Re: depth-of-field aadot

Postby dafhi » Sep 19, 2020 13:22

in the beginning.

the focus plane animates via sine
Last edited by dafhi on Sep 19, 2020 21:29, edited 1 time in total.
UEZ
Posts: 618
Joined: May 05, 2017 19:59
Location: Germany

Re: depth-of-field aadot

Postby UEZ » Sep 19, 2020 16:39

Nice examples. :-)

Thx for sharing it... ^^

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 1 guest