raytracer

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
bluatigro
Posts: 660
Joined: Apr 25, 2012 10:35
Location: netherlands

raytracer

Post by bluatigro »

this is my first try at a raytracer in fb

bug :
the spheres dont have random positions

Code: Select all

''RAYTRACER
''bluatigro 
''start : 19 apr 2012

type t3d
  x as single
  y as single
  z as single
  declare constructor()
  declare constructor ( x as single , y as single , z as single )
  declare sub fill( x as single , y as single , z as single )
  declare function dot( a as t3d , b as t3d ) as single
end type
constructor t3d()
  this.x = 0
  this.y = 0
  this.z = 0
end constructor 
constructor t3d( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end constructor 
operator +( a as t3d , b as t3d ) as t3d
  return type( a.x + b.x , a.y + b.y , a.z + b.z )
end operator
operator *( a as t3d , d as single ) as t3d
  return type( a.x * d , a.y * d , a.z * d )
end operator
operator -( a as t3d , b as t3d ) as t3d
  return type( a.x - b.x , a.y - b.y , a.z - b.z )
end operator
operator /( a as t3d , d as single ) as t3d
  return a * ( 1 / d )
end operator
sub t3d.fill( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end sub
function t3d.dot( a as t3d , b as t3d ) as single
   return a.x * b.x + a.y * b.y + a.z * b.z
end function

type tsphere
   m as t3d
   r as single
   clr as integer
   declare sub fill( x as single , y as single , z as single , r as single , clr as integer )
   declare function hit( q as t3d ) as integer
end type 
sub tsphere.fill( x as single , y as single , z as single , r as single , clr as integer )
   m.fill x , y , z
   this.r = r
   this.clr = clr
end sub
const as integer false = 0
const as integer true = not false
function tsphere.hit( q as t3d ) as integer
    return this.r * this.r > q.dot( q , q ) - q.dot( this.m , this.m ) 
end function

declare function ray( n as t3d , d as t3d ) as integer
declare function range( min as single , max as single ) as single

dim shared sphere( 10 ) as tsphere , light( 2 ) as t3d , i as integer

randomize timer 
for i = 0 to 10
   sphere( i ).fill range( -500 , 500 )  _
                              , range( -350 , 350 ) _
                              , range( 100 , 500 ) _
                              , 1 _
                              , rgb( rnd * 255  , rnd  * 255 , rnd * 255 )
next i
light( 0 ).fill 0 , 1000 , 0 

dim x as single , y as single , n as t3d , d as t3d
screen 20 , 32
  for x = -500 to 500
    for y = -350 to 350
      n.fill x , y , 0
      d.fill 0 , 0 , 1
      pset( x + 1024 / 2 , y + 768 / 2 ) , ray( n , d )
    next y
  next x
  print "ready"
  while inkey$ = ""
  wend
end
function ray( n as t3d , d as t3d ) as integer
    dim done as integer , i as integer , uit as integer , tel as integer
    while not done
       n += d
       for i = 0 to ubound( sphere )
          if sphere( i ).hit( n ) then
              uit = sphere( i ).clr
              done = true
          end if
       next i
       tel += 1
       if tel > 1000 then done = true
    wend
    return uit
end function
function range( min as single , max as single ) as single
    return rnd * ( max - min ) + min
end function 
bluatigro
Posts: 660
Joined: Apr 25, 2012 10:35
Location: netherlands

Re: raytracer

Post by bluatigro »

update :
- place bug fount

it runs verry slow

i dont think i gone extend this

or has someone a idea how to speed this up ?

Code: Select all

''RAYTRACER
''bluatigro 
''start : 19 apr 2012
''sphere on place : 9 may 2012

type t3d
  x as single
  y as single
  z as single
  declare constructor()
  declare constructor ( x as single , y as single , z as single )
  declare sub fill( x as single , y as single , z as single )
  declare function dot( a as t3d , b as t3d ) as single
end type
constructor t3d()
  this.x = 0
  this.y = 0
  this.z = 0
end constructor 
constructor t3d( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end constructor 
operator +( a as t3d , b as t3d ) as t3d
  return type( a.x + b.x , a.y + b.y , a.z + b.z )
end operator
operator *( a as t3d , d as single ) as t3d
  return type( a.x * d , a.y * d , a.z * d )
end operator
operator -( a as t3d , b as t3d ) as t3d
  return type( a.x - b.x , a.y - b.y , a.z - b.z )
end operator
operator /( a as t3d , d as single ) as t3d
  return a * ( 1 / d )
end operator
sub t3d.fill( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end sub
function t3d.dot( a as t3d , b as t3d ) as single
   return a.x * b.x + a.y * b.y + a.z * b.z
end function

type tsphere
   m as t3d
   r as single
   clr as integer
   declare sub fill( x as single , y as single , z as single , r as single , clr as integer )
   declare function hit( q as t3d ) as integer
end type 
sub tsphere.fill( x as single , y as single , z as single , r as single , clr as integer )
   m.fill x , y , z
   this.r = r
   this.clr = clr
end sub
const as integer false = 0
const as integer true = not false
function tsphere.hit( q as t3d ) as integer
    return this.r  > sqr( ( this.m.x - q.x ) ^ 2 _
    + ( this.m.y - q.y ) ^ 2 + ( this.m.z - q.z ) ^ 2 )
end function

declare function ray( n as t3d , d as t3d ) as integer
declare function range( min as single , max as single ) as single

dim shared sphere( 10 ) as tsphere , light( 2 ) as t3d , i as integer

randomize timer 
for i = 0 to ubound( sphere )
  sphere( i ).fill range( -500 , 500 )  _
                  , range( -350 , 350 ) _
                  , range( 100 , 500 ) _
                  , range( 10 , 300 ) _
                  , rgb( rnd * 255  , rnd  * 255 , rnd * 255 )
next i
light( 0 ).fill 0 , 1000 , 0 

dim x as single , y as single , n as t3d , d as t3d
screen 20 , 32
  for x = -500 to 500
    for y = -350 to 350
      n.fill x , y , 0
      d.fill 0 , 0 , 1
      pset( x + 1024 / 2 , y + 768 / 2 ) , ray( n , d )

    next y
    if inkey <> "" then exit for
  next x
  print "ready"
  while inkey = ""
  wend
end
function ray( n as t3d , d as t3d ) as integer
    dim done as integer , i as integer , uit as integer , tel as integer
    while not done
       n += d
       for i = 0 to ubound( sphere )
          if sphere( i ).hit( n ) then
              uit = sphere( i ).clr
              done = true
          end if
       next i
       tel += 1
       if tel > 1000 then done = true
    wend
    return uit
end function
function range( min as single , max as single ) as single
    return rnd * ( max - min ) + min
end function 
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: raytracer

Post by fxm »

A very little speed improvement without change any principle.

Code: Select all

function tsphere.hit( q as t3d ) as integer
'    return this.r  > sqr( ( this.m.x - q.x ) ^ 2 _
'    + ( this.m.y - q.y ) ^ 2 + ( this.m.z - q.z ) ^ 2 )
    return this.r * this.r > ( this.m.x - q.x ) * ( this.m.x - q.x ) _
                           + ( this.m.y - q.y ) * ( this.m.y - q.y ) _
                           + ( this.m.z - q.z ) * ( this.m.z - q.z )
end function
bluatigro
Posts: 660
Joined: Apr 25, 2012 10:35
Location: netherlands

Re: raytracer

Post by bluatigro »

thanks
that improves the draw-speed many times !!

update :
now trying to get a lightsource to work

error :
al my spheres look black

Code: Select all

''RAYTRACER
''bluatigro 
declare function mix( kla as integer , f as single , klb as single ) as integer
const as single pi = atn( 1 ) * 4

type t3d
  x as single
  y as single
  z as single
  declare constructor()
  declare constructor ( x as single , y as single , z as single )
  declare sub fill( x as single , y as single , z as single )
  declare function dot( a as t3d , b as t3d ) as single
end type
constructor t3d()
  this.x = 0
  this.y = 0
  this.z = 0
end constructor 
constructor t3d( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end constructor 
operator +( a as t3d , b as t3d ) as t3d
  return type( a.x + b.x , a.y + b.y , a.z + b.z )
end operator
operator *( a as t3d , d as single ) as t3d
  return type( a.x * d , a.y * d , a.z * d )
end operator
operator -( a as t3d , b as t3d ) as t3d
  return type( a.x - b.x , a.y - b.y , a.z - b.z )
end operator
operator /( a as t3d , d as single ) as t3d
  return a * ( 1 / d )
end operator
sub t3d.fill( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end sub
function t3d.dot( a as t3d , b as t3d ) as single
  return a.x * b.x + a.y * b.y + a.z * b.z
end function
declare function length( q as t3d ) as single
function length( q as t3d ) as single
  return sqr( q.x ^ 2 + q.y ^ 2 + q.z ^ 2 )
end function  
declare function anlge( a as t3d , b as t3d ) as single
function angle( a as t3d , b as t3d ) as single
  return acos( length( a ) * length( b ) / a.dot( a , b ) )
end function

type tsphere
   m as t3d
   r as single
   clr as integer
   declare sub fill( x as single , y as single , z as single , r as single , clr as integer )
   declare function hit( q as t3d ) as integer
   declare function normal( q as t3d ) as t3d
end type 
sub tsphere.fill( x as single , y as single , z as single , r as single , clr as integer )
   m.fill x , y , z
   this.r = r
   this.clr = clr
end sub
const as integer false = 0
const as integer true = not false
function tsphere.hit( q as t3d ) as integer
        return this.r * this.r > ( this.m.x - q.x ) * ( this.m.x - q.x ) _
                           + ( this.m.y - q.y ) * ( this.m.y - q.y ) _
                           + ( this.m.z - q.z ) * ( this.m.z - q.z )

end function
function tsphere.normal( q as t3d ) as t3d
  return q - this.m
end function

declare function ray( n as t3d , d as t3d ) as integer
declare function range( min as single , max as single ) as single

dim shared sphere( 10 ) as tsphere , light( 2 ) as t3d , i as integer

randomize timer 
''fill spheres with random values
for i = 0 to ubound( sphere )
  sphere( i ).fill range( -500 , 500 )  _
                  , range( -350 , 350 ) _
                  , range( 100 , 500 ) _
                  , range( 10 , 300 ) _
                  , rgb( rnd * 255  , rnd  * 255 , rnd * 255 )
next i
light( 0 ).fill 0 , 1000 , 0 

dim x as single , y as single , n as t3d , d as t3d
screen 20 , 32
  for x = -500 to 500
    for y = -350 to 350
      n.fill x , y , 0
      d.fill 0 , 0 , 1
      pset( x + 1024 / 2 , y + 768 / 2 ) , ray( n , d )

    next y
    if inkey <> "" then exit for
  next x
  print "ready"
  while inkey = ""
  wend
end
function ray( n as t3d , d as t3d ) as integer
''shoot a ray into the world and look if there is something
''retur coloe of object or if nothing then darkgray
  dim done as integer , i as integer , uit as integer , tel as integer , h as single
  uit = &h202020
  while not done
    n += d
    for i = 0 to ubound( sphere )
      if sphere( i ).hit( n ) then
        uit = sphere( i ).clr
        h = angle( sphere( i ).normal( n ) , light( 0 ) )
        uit = mix( uit , h / pi , 0 )
        done = true
      end if
    next i
    tel += 1
    if tel > 1000 then done = true
  wend
  return uit
end function
function mix( kla as integer , f as single , klb as single ) as integer
''mix 2 colors info 1 new color
''for colortransitions
  dim as integer ra , ga , ba , rb , gb , bb , r , g , b 
  ra = ( kla shr 16 ) and 255
  ga = ( kla shr 8 ) and 255
  ba = kla and 255
  rb = ( klb shr 16 ) and 255
  gb = ( klb shr 8 ) and 255
  bb = klb and 255
  r = ra + ( rb - ra ) * f
  g = ga + ( gb - ga ) * f
  b = ba + ( bb - ba ) * f
  return rgb( r , g , b )
end function
function range( min as single , max as single ) as single
''returns a random number between min and max
    return rnd * ( max - min ) + min
end function 
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: raytracer

Post by fxm »

bluatigro wrote:error :
al my spheres look black
This is when you spend a long time looking for your bugs as you progress.
And this is true for anyone (from beginner up to hero)!
frisian
Posts: 249
Joined: Oct 08, 2009 17:25

Re: raytracer

Post by frisian »

bluatigro

I was planning to offer some small speedups and a few remarks about your program but reading that you have a little problem with it I will wait for you to straiten then out .

Maybe this webpage will help http://www.intmath.com/vectors/7-vector ... -space.php
Close but no cigar.

On personal note this posting doesn't belong here but in Beginners or General, or even better added to your first posting about raytracing.
bluatigro
Posts: 660
Joined: Apr 25, 2012 10:35
Location: netherlands

Re: raytracer

Post by bluatigro »

tryed :
- altering tsphere.normal( td3 ) t3d
- altering angle( t3d , t3d ) single

i cant find the error i left in
- a hint wil be welkome

added : const's color's

same output :

Code: Select all

''RAYTRACER
''bluatigro 
declare function mix( kla as integer , f as single , klb as single ) as integer
const as single pi = atn( 1 ) * 4

const as integer black   = &h000000
const as integer red     = &hff0000
const as integer green   = &h00ff00
const as integer yellow  = &hffff00
const as integer blue    = &h0000ff
const as integer magenta = &hff00ff
const as integer cyan    = &h00ffff
const as integer white   = &hffffff

const as integer gray    = &h7f7f7f
const as integer pink    = &hff7f7f
const as integer orange  = &hff7f00
const as integer purple  = &h7f007f
dim shared as integer backcolor

type t3d
  x as single
  y as single
  z as single
  declare constructor()
  declare constructor ( x as single , y as single , z as single )
  declare sub fill( x as single , y as single , z as single )
  declare function dot( a as t3d , b as t3d ) as single
end type
constructor t3d()
  this.x = 0
  this.y = 0
  this.z = 0
end constructor 
constructor t3d( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end constructor 
operator +( a as t3d , b as t3d ) as t3d
  return type( a.x + b.x , a.y + b.y , a.z + b.z )
end operator
operator *( a as t3d , d as single ) as t3d
  return type( a.x * d , a.y * d , a.z * d )
end operator
operator -( a as t3d , b as t3d ) as t3d
  return type( a.x - b.x , a.y - b.y , a.z - b.z )
end operator
operator /( a as t3d , d as single ) as t3d
  return a * ( 1 / d )
end operator
sub t3d.fill( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end sub
function t3d.dot( a as t3d , b as t3d ) as single
  return a.x * b.x + a.y * b.y + a.z * b.z
end function
declare function length( q as t3d ) as single
function length( q as t3d ) as single
  return sqr( q.x ^ 2 + q.y ^ 2 + q.z ^ 2 ) + 1e-7
end function  
declare function anlge( a as t3d , b as t3d ) as single
function angle( a as t3d , b as t3d ) as single
  return acos( a.dot( a , b ) / length( a ) * length( b ) )
end function

type tsphere
   m as t3d
   r as single
   clr as integer
   declare sub fill( x as single , y as single , z as single , r as single , clr as integer )
   declare function hit( q as t3d ) as integer
   declare function normal( q as t3d ) as t3d
end type 
sub tsphere.fill( x as single , y as single , z as single , r as single , clr as integer )
   m.fill x , y , z
   this.r = r
   this.clr = clr
end sub
const as integer false = 0
const as integer true = not false
function tsphere.hit( q as t3d ) as integer
        return this.r * this.r > ( this.m.x - q.x ) * ( this.m.x - q.x ) _
                           + ( this.m.y - q.y ) * ( this.m.y - q.y ) _
                           + ( this.m.z - q.z ) * ( this.m.z - q.z )

end function
function tsphere.normal( q as t3d ) as t3d
  return ( q - this.m ) / length( q - this.m )
end function

declare function ray( n as t3d , d as t3d ) as integer
declare function range( min as single , max as single ) as single

dim shared sphere( 10 ) as tsphere , light( 2 ) as t3d , i as integer

randomize timer 
''fill spheres with random values
for i = 0 to ubound( sphere )
  sphere( i ).fill range( -500 , 500 )  _
                  , range( -350 , 350 ) _
                  , range( 100 , 500 ) _
                  , range( 10 , 300 ) _
                  , rgb( rnd * 255  , rnd  * 255 , rnd * 255 )
next i
light( 0 ).fill 0 , 1000 , 0 

dim x as single , y as single , n as t3d , d as t3d
screen 20 , 32
  backcolor = gray
  for x = -500 to 500
    for y = -350 to 350
      n.fill x , y , 0
      d.fill 0 , 0 , 1
      pset( x + 1024 / 2 , y + 768 / 2 ) , ray( n , d )

    next y
    if inkey <> "" then exit for
  next x
  print "ready"
  while inkey = ""
  wend
end
function ray( n as t3d , d as t3d ) as integer
''shoot a ray into the world and look if there is something
''retur color of object or if nothing then darkgray
  dim done as integer , i as integer , uit as integer , tel as integer , h as single
  uit = backcolor
  while not done
    n += d
    for i = 0 to ubound( sphere )
      if sphere( i ).hit( n ) then
        uit = sphere( i ).clr
        h = angle( sphere( i ).normal( n ) , light( 0 ) )
        uit = mix( uit , h / pi , 0 )
        done = true
      end if
    next i
    tel += 1
    if tel > 1000 then done = true
  wend
  return uit
end function
function mix( kla as integer , f as single , klb as single ) as integer
''mix 2 colors info 1 new color
''for colortransitions
  dim as integer ra , ga , ba , rb , gb , bb , r , g , b 
  ra = ( kla shr 16 ) and 255
  ga = ( kla shr 8 ) and 255
  ba = kla and 255
  rb = ( klb shr 16 ) and 255
  gb = ( klb shr 8 ) and 255
  bb = klb and 255
  r = ra + ( rb - ra ) * f
  g = ga + ( gb - ga ) * f
  b = ba + ( bb - ba ) * f
  return rgb( r , g , b )
end function
function range( min as single , max as single ) as single
''returns a random number between min and max
    return rnd * ( max - min ) + min
end function 
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: raytracer

Post by fxm »

bluatigro wrote:i cant find the error i left in
- a hint wil be welkome

At least inside the function 'angle()', maybe it lacks parentheses (inducing an undefined 'acos()'):

Code: Select all

declare function anlge( a as t3d , b as t3d ) as single
function angle( a as t3d , b as t3d ) as single
  return acos( a.dot( a , b ) / ( length( a ) * length( b ) ) )
end function
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: raytracer

Post by fxm »

I do not see the interest to have a member procedure 'dot()' inside the type 't3d' (it is just the dot product of two vectors)

Code: Select all

''RAYTRACER
''bluatigro
declare function mix( kla as integer , f as single , klb as single ) as integer
const as single pi = atn( 1 ) * 4

const as integer black   = &h000000
const as integer red     = &hff0000
const as integer green   = &h00ff00
const as integer yellow  = &hffff00
const as integer blue    = &h0000ff
const as integer magenta = &hff00ff
const as integer cyan    = &h00ffff
const as integer white   = &hffffff

const as integer gray    = &h7f7f7f
const as integer pink    = &hff7f7f
const as integer orange  = &hff7f00
const as integer purple  = &h7f007f
dim shared as integer backcolor

type t3d
  x as single
  y as single
  z as single
  declare constructor()
  declare constructor ( x as single , y as single , z as single )
  declare sub fill( x as single , y as single , z as single )
end type
constructor t3d()
  this.x = 0
  this.y = 0
  this.z = 0
end constructor
constructor t3d( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end constructor
operator +( a as t3d , b as t3d ) as t3d
  return type( a.x + b.x , a.y + b.y , a.z + b.z )
end operator
operator *( a as t3d , d as single ) as t3d
  return type( a.x * d , a.y * d , a.z * d )
end operator
operator -( a as t3d , b as t3d ) as t3d
  return type( a.x - b.x , a.y - b.y , a.z - b.z )
end operator
operator /( a as t3d , d as single ) as t3d
  return a * ( 1 / d )
end operator
sub t3d.fill( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end sub
function dot( a as t3d , b as t3d ) as single
  return a.x * b.x + a.y * b.y + a.z * b.z
end function
declare function length( q as t3d ) as single
function length( q as t3d ) as single
  return sqr( q.x ^ 2 + q.y ^ 2 + q.z ^ 2 ) + 1e-7
end function 
declare function anlge( a as t3d , b as t3d ) as single
function angle( a as t3d , b as t3d ) as single
  return acos( dot( a , b ) / ( length( a ) * length( b ) ) )
end function

type tsphere
   m as t3d
   r as single
   clr as integer
   declare sub fill( x as single , y as single , z as single , r as single , clr as integer )
   declare function hit( q as t3d ) as integer
   declare function normal( q as t3d ) as t3d
end type
sub tsphere.fill( x as single , y as single , z as single , r as single , clr as integer )
   m.fill x , y , z
   this.r = r
   this.clr = clr
end sub
const as integer false = 0
const as integer true = not false
function tsphere.hit( q as t3d ) as integer
        return this.r * this.r > ( this.m.x - q.x ) * ( this.m.x - q.x ) _
                           + ( this.m.y - q.y ) * ( this.m.y - q.y ) _
                           + ( this.m.z - q.z ) * ( this.m.z - q.z )

end function
function tsphere.normal( q as t3d ) as t3d
  return ( q - this.m ) / length( q - this.m )
end function

declare function ray( n as t3d , d as t3d ) as integer
declare function range( min as single , max as single ) as single

dim shared sphere( 10 ) as tsphere , light( 2 ) as t3d , i as integer

randomize timer
''fill spheres with random values
for i = 0 to ubound( sphere )
  sphere( i ).fill range( -500 , 500 )  _
                  , range( -350 , 350 ) _
                  , range( 100 , 500 ) _
                  , range( 10 , 300 ) _
                  , rgb( rnd * 255  , rnd  * 255 , rnd * 255 )
next i
light( 0 ).fill 0 , 1000 , 0

dim x as single , y as single , n as t3d , d as t3d
screen 20 , 32
  backcolor = gray
  for x = -500 to 500
    for y = -350 to 350
      n.fill x , y , 0
      d.fill 0 , 0 , 1
      pset( x + 1024 / 2 , y + 768 / 2 ) , ray( n , d )

    next y
    if inkey <> "" then exit for
  next x
  print "ready"
  while inkey = ""
  wend
end
function ray( n as t3d , d as t3d ) as integer
''shoot a ray into the world and look if there is something
''retur color of object or if nothing then darkgray
  dim done as integer , i as integer , uit as integer , tel as integer , h as single
  uit = backcolor
  while not done
    n += d
    for i = 0 to ubound( sphere )
      if sphere( i ).hit( n ) then
        uit = sphere( i ).clr
        h = angle( sphere( i ).normal( n ) , light( 0 ) )
        uit = mix( uit , h / pi , 0 )
        done = true
      end if
    next i
    tel += 1
    if tel > 1000 then done = true
  wend
  return uit
end function
function mix( kla as integer , f as single , klb as single ) as integer
''mix 2 colors info 1 new color
''for colortransitions
  dim as integer ra , ga , ba , rb , gb , bb , r , g , b
  ra = ( kla shr 16 ) and 255
  ga = ( kla shr 8 ) and 255
  ba = kla and 255
  rb = ( klb shr 16 ) and 255
  gb = ( klb shr 8 ) and 255
  bb = klb and 255
  r = ra + ( rb - ra ) * f
  g = ga + ( gb - ga ) * f
  b = ba + ( bb - ba ) * f
  return rgb( r , g , b )
end function
function range( min as single , max as single ) as single
''returns a random number between min and max
    return rnd * ( max - min ) + min
end function 
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: raytracer

Post by fxm »

A new very small execution time improvement: 18%
(measured putting in comment the line 'randomize timer')

Code: Select all

function tsphere.hit( q as t3d ) as integer
   if this.r <= abs( this.m.x - q.x ) then
      return 0
   elseif this.r <= abs( this.m.y - q.y ) then
      return 0
   elseif this.r <= abs( this.m.z - q.z ) then
      return 0
   else
      return this.r * this.r > ( this.m.x - q.x ) * ( this.m.x - q.x ) _
                             + ( this.m.y - q.y ) * ( this.m.y - q.y ) _
                             + ( this.m.z - q.z ) * ( this.m.z - q.z )
   end if
end function

Code: Select all

function length( q as t3d ) as single
  return sqr( q.x * q.x + q.y * q.y + q.z * q.z ) + 1e-7
end function

Code: Select all

operator /( a as t3d , d as single ) as t3d
  return type( a.x / d , a.y / d , a.z / d )
end operator
frisian
Posts: 249
Joined: Oct 08, 2009 17:25

Re: raytracer

Post by frisian »

Here are some of my idea's for speedup's
I have removed some thing ore altered then so look careful.

Code: Select all

    randomize Timer 
    ' randomize 37 for a fast one
    ' randomize 466 for a slow one, nearly 6 times slower than 37
    
    ''fill spheres with random values
    for i = 0 to ubound( sphere )
      sphere( i ).fill range( -500 , 500 )  _
                      , range( -350 , 350 ) _
                      , range( 100 , 500 ) _
                      , range( 10 , 300 ) _
                      , rgb( rnd * 255  , rnd  * 255 , rnd * 255 )
    next i
    light( 0 ).fill 0 , 1000 , 0

    Dim As Integer x, y  '### change single to integer
    Dim As t3d n         '### dropped d not needed 
    screen 20 , 32
      backcolor = gray
      for y = -350 to 350     '### flipped x and y 
        for x = -500 to 500
          n.fill x , y , 0
        '  d.fill 0 , 0 , 1   '### not longer needed
          pset( x + 1024 \ 2 , y + 768 \ 2 ) , ray( n ) ' removed d in ray (n, d)

        next x
        if inkey <> "" then exit for
      next y
      print "ready time ";Timer-t
      while inkey = ""
      wend
    End
    

Code: Select all

    function ray( n as t3d ) as Integer  '### remove d as t3d
    ''shoot a ray into the world and look if there is something
    ''return color of object or if nothing then darkgray
      dim done as integer , i as integer , uit as integer , tel as integer , h as single
      uit = backcolor
      while not done
        n.z += 1  '### only z is increased, n.x and n.y do not alter  
        for i = 0 to ubound( sphere )
          if sphere( i ).hit( n ) then
            uit = sphere( i ).clr
            h = angle( sphere( i ).normal( n ) , light( 0 ) )
            uit = mix( uit , h / pi  )	'### 0 is constant so drop it 
            done = true
          end if
        next i
        tel += 1
        if tel > 1000 then done = true
      wend
      return uit
    end Function
    

Code: Select all

    ' as long the color is mixed with black (&h000000)
    function mix( kla as integer , f as single) as Integer '### removed klb as single, is allways zero
       f = 1 - f      '### total rewrite since the second color is allways 0
       Return RGB((( kla shr 16 ) and 255) * f, (( kla shr 8 ) and 255 ) * f, (kla and 255 ) * f)
    end Function
    

Don't forget to alter the declare's for ray() and mix()

Speed increase differs due to the Randomize some are faster than others but for Randomize 37 the speed increase is about 13%.

Option:
Change Function range into a macro (trading memory for speed is never a bad idea).
Speed gain is very low because of the very low use of range.

missed one, at the beginning of function ray remove
uit = backcolor
and replace
if tel > 1000 then done = true
with
if tel > 1000 then return backcolor

The speed gain is on average 1%.

EDIT: had a mix up of timing on the last tip.
bluatigro
Posts: 660
Joined: Apr 25, 2012 10:35
Location: netherlands

Re: raytracer

Post by bluatigro »

@ fxm :
- al smal speedups give [ hopefuly ] 1 big one
@ frisian :
- in the future i wil add reflection and refraction
- then i wil need a recusive ray( n , d )
- and 2e color in mix( kla , d , klb )

update :
- added perspertive

error :
- my spheres are stil black why ?

Code: Select all

''RAYTRACER
''bluatigro 
''start : 19 apr 2012
declare function mix( kla as integer , f as single , klb as single ) as integer
const as single pi = atn( 1 ) * 4

const as integer black   = &h000000
const as integer red     = &hff0000
const as integer green   = &h00ff00
const as integer yellow  = &hffff00
const as integer blue    = &h0000ff
const as integer magenta = &hff00ff
const as integer cyan    = &h00ffff
const as integer white   = &hffffff

const as integer gray    = &h7f7f7f
const as integer pink    = &hff7f7f
const as integer orange  = &hff7f00
const as integer purple  = &h7f007f
dim shared as integer backcolor

type t3d
  x as single
  y as single
  z as single
  declare constructor()
  declare constructor ( x as single , y as single , z as single )
  declare sub fill( x as single , y as single , z as single )
  declare function dot( a as t3d , b as t3d ) as single
end type
constructor t3d()
  this.x = 0
  this.y = 0
  this.z = 0
end constructor 
constructor t3d( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end constructor 
operator +( a as t3d , b as t3d ) as t3d
  return type( a.x + b.x , a.y + b.y , a.z + b.z )
end operator
operator *( a as t3d , d as single ) as t3d
  return type( a.x * d , a.y * d , a.z * d )
end operator
operator -( a as t3d , b as t3d ) as t3d
  return type( a.x - b.x , a.y - b.y , a.z - b.z )
end operator
operator /( a as t3d , d as single ) as t3d
  return type( a.x / d , a.y / d , a.z / d )
end operator
sub t3d.fill( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end sub
function t3d.dot( a as t3d , b as t3d ) as single
  return a.x * b.x + a.y * b.y + a.z * b.z
end function
declare function length( q as t3d ) as single
function length( q as t3d ) as single
   return sqr( q.x * q.x + q.y * q.y + q.z * q.z ) + 1e-7
end function  
declare function anlge( a as t3d , b as t3d ) as single
function angle( a as t3d , b as t3d ) as single
  return acos( a.dot( a , b ) / length( a ) * length( b ) )
end function

type tsphere
   m as t3d
   r as single
   clr as integer
   declare sub fill( x as single , y as single , z as single , r as single , clr as integer )
   declare function hit( q as t3d ) as integer
   declare function normal( q as t3d ) as t3d
end type 
sub tsphere.fill( x as single , y as single , z as single , r as single , clr as integer )
   m.fill x , y , z
   this.r = r
   this.clr = clr
end sub
const as integer false = 0
const as integer true = not false
function tsphere.hit( q as t3d ) as integer
    if this.r <= abs( this.m.x - q.x ) then
      return 0
   elseif this.r <= abs( this.m.y - q.y ) then
      return 0
   elseif this.r <= abs( this.m.z - q.z ) then
      return 0
   end if

        return this.r * this.r > ( this.m.x - q.x ) * ( this.m.x - q.x ) _
                           + ( this.m.y - q.y ) * ( this.m.y - q.y ) _
                           + ( this.m.z - q.z ) * ( this.m.z - q.z )

end function
function tsphere.normal( q as t3d ) as t3d
  return ( q - this.m ) / length( q - this.m )
end function

declare function ray( n as t3d , d as t3d ) as integer
declare function range( min as single , max as single ) as single

dim shared sphere( 10 ) as tsphere , light( 2 ) as t3d , i as integer

randomize timer
''fill spheres with random values
for i = 0 to ubound( sphere )
  sphere( i ).fill range( -500 , 500 )  _
                  , range( -350 , 350 ) _
                  , range( 100 , 500 ) _
                  , range( 10 , 300 ) _
                  , rgb( rnd * 255  , rnd  * 255 , rnd * 255 )
next i
light( 0 ).fill 0 , 1000 , 0 

dim x as single , y as single , n as t3d , d as t3d
screen 20 , 32
  backcolor = gray
  for x = -500 to 500
    for y = -350 to 350
      n.fill x , y , 0
      d.fill x/500 , y/350 , 1
      pset( x + 1024 / 2 , y + 768 / 2 ) , ray( n , d )

    next y
    if inkey <> "" then exit for
  next x
  print "ready"
  while inkey = ""
  wend
end
function ray( n as t3d , d as t3d ) as integer
''shoot a ray into the world and look if there is something
''retur color of object or if nothing then darkgray
  dim done as integer , i as integer , uit as integer , tel as integer , h as single
  uit = backcolor
  while not done
    n += d
    for i = 0 to ubound( sphere )
      if sphere( i ).hit( n ) then
        uit = sphere( i ).clr
        h = angle( sphere( i ).normal( n ) , light( 0 ) )
        uit = mix( uit , h / pi , 0 )
        done = true
      end if
    next i
    tel += 1
    if tel > 1000 then return backcolor
  wend
  return uit
end function
function mix( kla as integer , f as single , klb as single ) as integer
''mix 2 colors info 1 new color
''for colortransitions
  dim as integer ra , ga , ba , rb , gb , bb , r , g , b 
  ra = ( kla shr 16 ) and 255
  ga = ( kla shr 8 ) and 255
  ba = kla and 255
  rb = ( klb shr 16 ) and 255
  gb = ( klb shr 8 ) and 255
  bb = klb and 255
  r = ra + ( rb - ra ) * f
  g = ga + ( gb - ga ) * f
  b = ba + ( bb - ba ) * f
  return rgb( r , g , b )
end function
function range( min as single , max as single ) as single
''returns a random number between min and max
    return rnd * ( max - min ) + min
end function 
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: raytracer

Post by fxm »

bluatigro wrote:error :
- my spheres are stil black why ?
Have you well read one of my yesterday posts (see below)? http://www.freebasic.net/forum/viewtopi ... 54#p174154
bluatigro wrote:i cant find the error i left in
- a hint wil be welkome

At least inside the function 'angle()', maybe it lacks parentheses (inducing an undefined 'acos()'):

Code: Select all

declare function anlge( a as t3d , b as t3d ) as single
function angle( a as t3d , b as t3d ) as single
  return acos( a.dot( a , b ) / ( length( a ) * length( b ) ) )
end function
angle(V1, V2) = arcos( ( V1.V2 ) / ( |V1| * |V2| ) )
bluatigro
Posts: 660
Joined: Apr 25, 2012 10:35
Location: netherlands

Re: raytracer

Post by bluatigro »

@ fxm :
i now see it
[ i have a eyeproblem ]

update :
- added lightsources [ red , green , blue ]

Code: Select all

''RAYTRACER
''bluatigro 
''start : 19 apr 2012
declare function mix( kla as integer , f as single , klb as single ) as integer
const as single pi = atn( 1 ) * 4

const as integer black   = &h000000
const as integer red     = &hff0000
const as integer green   = &h00ff00
const as integer yellow  = &hffff00
const as integer blue    = &h0000ff
const as integer magenta = &hff00ff
const as integer cyan    = &h00ffff
const as integer white   = &hffffff

const as integer gray    = &h7f7f7f
const as integer pink    = &hff7f7f
const as integer orange  = &hff7f00
const as integer purple  = &h7f007f
dim shared as integer backcolor

type t3d
  x as single
  y as single
  z as single
  declare constructor()
  declare constructor ( x as single , y as single , z as single )
  declare sub fill( x as single , y as single , z as single )
  declare function dot( a as t3d , b as t3d ) as single
end type
constructor t3d()
  this.x = 0
  this.y = 0
  this.z = 0
end constructor 
constructor t3d( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end constructor 
operator +( a as t3d , b as t3d ) as t3d
  return type( a.x + b.x , a.y + b.y , a.z + b.z )
end operator
operator *( a as t3d , d as single ) as t3d
  return type( a.x * d , a.y * d , a.z * d )
end operator
operator -( a as t3d , b as t3d ) as t3d
  return type( a.x - b.x , a.y - b.y , a.z - b.z )
end operator
operator /( a as t3d , d as single ) as t3d
  return type( a.x / d , a.y / d , a.z / d )
end operator
sub t3d.fill( x as single , y as single , z as single )
  this.x = x
  this.y = y
  this.z = z
end sub
function t3d.dot( a as t3d , b as t3d ) as single
  return a.x * b.x + a.y * b.y + a.z * b.z
end function
declare function length( q as t3d ) as single
function length( q as t3d ) as single
   return sqr( q.x * q.x + q.y * q.y + q.z * q.z ) + 1e-7
end function  
declare function anlge( a as t3d , b as t3d ) as single
function angle( a as t3d , b as t3d ) as single
  return acos( a.dot( a , b ) _
  / ( length( a ) * length( b ) ) )
end function

type tsphere
   m as t3d
   r as single
   clr as integer
   declare sub fill( x as single , y as single , z as single , r as single , clr as integer )
   declare function hit( q as t3d ) as integer
   declare function normal( q as t3d ) as t3d
end type 
sub tsphere.fill( x as single , y as single , z as single , r as single , clr as integer )
   m.fill x , y , z
   this.r = r
   this.clr = clr
end sub
const as integer false = 0
const as integer true = not false
function tsphere.hit( q as t3d ) as integer
    if this.r <= abs( this.m.x - q.x ) then
      return 0
   elseif this.r <= abs( this.m.y - q.y ) then
      return 0
   elseif this.r <= abs( this.m.z - q.z ) then
      return 0
   end if

        return this.r * this.r > ( this.m.x - q.x ) * ( this.m.x - q.x ) _
                           + ( this.m.y - q.y ) * ( this.m.y - q.y ) _
                           + ( this.m.z - q.z ) * ( this.m.z - q.z )

end function
function tsphere.normal( q as t3d ) as t3d
  return ( q - this.m ) / length( q - this.m )
end function

declare function ray( n as t3d , d as t3d ) as integer
declare function range( min as single , max as single ) as single

dim shared sphere( 10 ) as tsphere , light( 2 ) as t3d , i as integer

randomize timer
''fill spheres with random values
for i = 0 to ubound( sphere )
  sphere( i ).fill range( -500 , 500 )  _
                  , range( -350 , 350 ) _
                  , range( 100 , 500 ) _
                  , range( 10 , 300 ) _
                  , rgb( rnd * 255  , rnd  * 255 , rnd * 255 )
next i
declare function shade( kl as integer _
, f as t3d ) as integer
function shade( kl as integer , f as t3d ) as integer
  dim as integer r , g , b
  r = ( kl shr 16 ) and 255
  g = ( kl shr 8 ) and 255
  b = kl and 255
  return rgb( r * f.x , g * f.y , b * f.z )
end function
light( 0 ).fill -500,1000,0
light( 1 ).fill 0 , 1000 , 0 
light( 2 ).fill 500,1000,0

dim x as single , y as single , n as t3d , d as t3d
screen 20 , 32
  backcolor = black
  for x = -500 to 500
    for y = -350 to 350
      n.fill x , y , 0
      d.fill x/500 , y/500 , 1
      pset( x + 1024 / 2 , 768 / 2 - y ) , ray( n , d )

    next y
    if inkey <> "" then exit for
  next x
  print "ready"
  while inkey = ""
  wend
end
function ray( n as t3d , d as t3d ) as integer
''shoot a ray into the world and look if there is something
''retur color of object or if nothing then darkgray
  dim done as integer , i as integer , uit as integer _
  , tel as integer , h as t3d , t as t3d
  t.fill 1 , 1 , 1
  uit = backcolor
  while not done
    n += d
    for i = 0 to ubound( sphere )
      if sphere( i ).hit( n ) then
        uit = sphere( i ).clr
        h.x = angle( sphere( i ).normal( n ) , light( 0 ) )
        h.y = angle( sphere( i ).normal( n ) , light( 1 ) )
        h.z = angle( sphere( i ).normal( n ) , light( 2 ) )
        uit = shade( uit , t - h / pi )
        done = true
      end if
    next i
    tel += 1
    if tel > 1000 then return backcolor
  wend
  return uit
end function
function mix( kla as integer , f as single , klb as single ) as integer
''mix 2 colors info 1 new color
''for colortransitions
  dim as integer ra , ga , ba , rb , gb , bb , r , g , b 
  ra = ( kla shr 16 ) and 255
  ga = ( kla shr 8 ) and 255
  ba = kla and 255
  rb = ( klb shr 16 ) and 255
  gb = ( klb shr 8 ) and 255
  bb = klb and 255
  r = ra + ( rb - ra ) * f
  g = ga + ( gb - ga ) * f
  b = ba + ( bb - ba ) * f
  return rgb( r , g , b )
end function
function range( min as single , max as single ) as single
''returns a random number between min and max
    return rnd * ( max - min ) + min
end function 

Post Reply