Ok thank you for your suggestion, I do the correction but a bit slow somewhat
However we see the shadow now ! I take a point at parameter into my ray to make ray colors to collide with object ... But there is some artifact to render too
Code: Select all
;
; Inspired from Ray Tracing in One Weekend :
; https://raytracing.github.io/books/RayTracingInOneWeekend.html
;
; Written and adapted in Purebasic by threedslider
;; Rewritten by threedslider Jun 10 2024
;; Added to color for sphere and background Jun 11 2024
;; Added to Pathtracing system (WIP) Jun 11 2024
;; Corrected typo and fixed some of my code Jun 12 2024
;; Fixed to Ray for random Jun 14 2024
; [Note] Jun 14 2024
;; Take a point at parameter on Ray, nice but very slow and it looks like as artifact :/ but some shadow here too... :)
;; Code inspired by pjay for fast rendering in OpenGL
;; Corrected from suggestion by pjay
; Vector
Structure Vec3
x.f
y.f
z.f
EndStructure
; Vector for 3D Macros
Macro rt_zero(v)
v\x = 0.0
v\y = 0.0
v\z = 0.0
EndMacro
Macro rt_near_zero(v)
near_zero(v)
EndMacro
Macro rt_clamp(v, m1, m2)
v = clamp(v, m1, m2)
EndMacro
Macro rt_surround(x, m1, m2)
surrounds(x, m1, m2)
EndMacro
Macro rt_norm(v,n)
n = Sqr(v\x * v\x + v\y * v\y + v\z * v\z)
If n <> 0.0
n = 1.0/n
v\x * n
v\y * n
v\z * n
EndIf
EndMacro
Macro rt_r_length(v)
Sqr(v\dir\x * v\dir\x + v\dir\y * v\dir\y + v\dir\z * v\dir\z)
EndMacro
Macro rt_v_length_squared(v)
(v\x * v\x + v\y * v\y + v\z * v\z)
EndMacro
Macro rt_dot(v1, v2)
(v1\x * v2\x + v1\y * v2\y + v1\z * v2\z)
EndMacro
Macro rt_copy(v, v1)
v\x = v1\x
v\y = v1\y
v\z = v1\z
EndMacro
Macro rt_add(v, v1, v2)
v\x = v1\x + v2\x
v\y = v1\y + v2\y
v\z = v1\z + v2\z
EndMacro
Macro rt_sub(v, v1, v2)
v\x = v1\x - v2\x
v\y = v1\y - v2\y
v\z = v1\z - v2\z
EndMacro
Macro rt_mul(v, v1, v2)
v\x = v1\x * v2\x
v\y = v1\y * v2\y
v\z = v1\z * v2\z
EndMacro
Macro rt_scale(v, v1, s)
v\x = v1\x * s
v\y = v1\y * s
v\z = v1\z * s
EndMacro
Macro rt_neg(v, v1)
v\x = -v1\x
v\y = -v1\y
v\z = -v1\z
EndMacro
; Ray
Structure Ray
orig.Vec3
dir.Vec3
EndStructure
; Sphere
Structure Sphere
center.Vec3
radius.f
color.Vec3
EndStructure
; Material
Structure Material
albedo.Vec3
EndStructure
; Clamp
Procedure.f clamp(x.f, min.f, max.f)
If(x < min)
ProcedureReturn min
EndIf
If(x > max)
ProcedureReturn max
EndIf
ProcedureReturn x
EndProcedure
; Random
Macro random_float()
Random(#MAXDWORD) / #MAXDWORD
EndMacro
Macro random_min_max_float(min, max)
(min + (max-min) * random_float())
EndMacro
; Procedure.f random_vec(*vx.Vec3)
; *vx\x = random_float()
; *vx\y = random_float()
; *vx\z = random_float()
;
; EndProcedure
Macro random_min_max_vec(min, max)
random_min_max_float(min, max)
EndMacro
Procedure.f unit_vector_vec(*v.Vec3, axe)
Protected n.f = 0.0
Protected p.Vec3
rt_norm(*v, n)
If axe = 1
ProcedureReturn *v\x
EndIf
If axe = 2
ProcedureReturn *v\y
EndIf
If axe = 3
ProcedureReturn *v\z
EndIf
EndProcedure
Procedure.f random_in_unit_sphere(axe)
Protected p.Vec3
While #True
p\x = random_min_max_vec(-1.0, 1.0)
p\y = random_min_max_vec(-1.0, 1.0)
p\z = random_min_max_vec(-1.0, 1.0)
r.f = rt_v_length_squared(p)
If r < 1.0
If axe = 1
ProcedureReturn p\x
EndIf
If axe = 2
ProcedureReturn p\y
EndIf
If axe = 3
ProcedureReturn p\z
EndIf
EndIf
Wend
EndProcedure
Procedure.f random_unit_vector(axe)
Protected p.Vec3
p\x = random_in_unit_sphere(1)
p\y = random_in_unit_sphere(2)
p\z = random_in_unit_sphere(3)
ProcedureReturn unit_vector_vec(p, axe)
EndProcedure
Procedure.f random_on_hemisphere(*in.Vec3, axe)
Protected on_unit_sphere.Vec3
on_unit_sphere\x = random_unit_vector(1)
on_unit_sphere\y = random_unit_vector(2)
on_unit_sphere\z = random_unit_vector(3)
;Debug on_unit_sphere\x
If rt_dot(on_unit_sphere, *in) > 0.0
;rt_copy(*out, on_unit_sphere)
If axe = 1
ProcedureReturn on_unit_sphere\x
EndIf
If axe = 2
ProcedureReturn on_unit_sphere\y
EndIf
If axe = 3
ProcedureReturn on_unit_sphere\z
EndIf
Else
;rt_neg(*out, on_unit_sphere)
If axe = 1
ProcedureReturn -on_unit_sphere\x
EndIf
If axe = 2
ProcedureReturn -on_unit_sphere\y
EndIf
If axe = 3
ProcedureReturn -on_unit_sphere\z
EndIf
EndIf
EndProcedure
; Surrounds
Procedure surrounds(x.f, min.f, max.f)
ProcedureReturn Bool( min < x And x < max)
EndProcedure
; Procedure surrounds(x.f, min.f, max.f)
; ProcedureReturn Bool( x <= min Or max <= x)
; EndProcedure
; Create Sphere primitve
Macro m_Sphere(id, center_x, center_y, center_z, radius_, color_x, color_y, color_z)
scene(id)\center\x = center_x
scene(id)\center\y = center_y
scene(id)\center\z = center_z
scene(id)\radius = radius_
scene(id)\color\x = color_x
scene(id)\color\y = color_y
scene(id)\color\z = color_z
EndMacro
Global Dim scene.Sphere(1)
m_Sphere(0, 0.0, 0.0, -1.0, 0.5, 1.0, 1.0, 1.0)
;m_Sphere(1, -1.0, 0.0, -1.0, 0.35, 1.0, 1.0, 1.0)
;m_Sphere(2, 1.0, 0.0, -1.0, 0.35, 1.0, 1.0, 1.0)
m_Sphere(1, 0.0, -100.0+0.005, -1.0, 100.0, 1.0, 1.0, 1.0)
;Near zero for pathtracing calculation
Procedure near_zero (*v.Vec3)
Protected e.f = 1e-8
ProcedureReturn Bool((Abs(*v\x) < e) And (Abs(*v\y) < e)And (Abs(*v\z) < e))
EndProcedure
; Init for vector
Procedure v_init(x.f, y.f, z.f, *v.Vec3)
*v\x = x
*v\y = y
*v\z = z
EndProcedure
; Scattering randomly
Procedure.f scatter(*r.Ray, *rec.Vec3, *attenuation.Vec3)
Protected scatter_direction.Vec3
Protected ran_dir.Vec3
ran_dir\x = random_unit_vector(1)
ran_dir\y = random_unit_vector(2)
ran_dir\z = random_unit_vector(3)
rt_add(scatter_direction, *rec, ran_dir)
If rt_near_zero(scatter_direction)
rt_copy(scatter_direction, *rec)
EndIf
*r\dir\x = unit_vector_vec(scatter_direction, 1)
*r\dir\y = unit_vector_vec(scatter_direction, 2)
*r\dir\z = unit_vector_vec(scatter_direction, 3)
EndProcedure
Procedure.f diffuse_scatter(*v1.Vec3, *v2.Vec3)
EndProcedure
; Hit for 3D objects
Procedure.f hit( *_s.Sphere, *_r.Ray, mx.f)
Protected oc.Vec3
Protected root.f = 0.0
Protected min.f = 0.0
Protected max.f = mx
rt_sub(oc, *_r\orig, *_s\center)
Protected a.f = rt_dot(*_r\dir, *_r\dir)
Protected b.f = rt_dot(oc,*_r\dir)
Protected c.f = rt_dot(oc,oc) - *_s\radius * *_s\radius
Protected discriminant.f = b*b - a*c
If discriminant < 0.0
ProcedureReturn 0.0
EndIf
root = (-b - Sqr(discriminant)) / (a)
If (Not rt_surround(root, min, max))
root = (-b + Sqr(discriminant)) / (2.0*a)
If ( Not rt_surround(root, min, max))
ProcedureReturn 0.0
EndIf
EndIf
ProcedureReturn root
EndProcedure
; Hit for intersection
Procedure.b intersect( *_r.Ray, *t.Float, *id.Integer )
Protected d.f, inf.f = 0.999
Protected i.i = ArraySize(scene())
*t\f = inf
While i >= 0
d = hit( scene(i), *_r, inf )
If d
*t\f = d
*id\i = i
EndIf
i - 1
Wend
ProcedureReturn Bool( *t\f < inf )
EndProcedure
; Unit vector Y for background
Procedure.f unit_vector_y(*vy.Ray)
Protected len.f
Static y.f : y.f = 0
len = rt_r_length(*vy)
If Not len = 0
y = *vy\dir\y / len
EndIf
ProcedureReturn y
EndProcedure
Procedure.f ray_color(*rr.Ray, *in.Vec3)
Protected a.f
Static color1.Vec3, color2.Vec3, unit_direction.Vec3
color1\x = 1.0 : color1\y = 1.0 : color1\z = 1.0
color2\x = 0.5 : color2\y = 0.7 : color2\z = 1.0
unit_direction\x = unit_vector_y(*rr)
a = 0.5 * (unit_direction\x + 1.0)
*in\x = (1.0 - a) * color1\x + a * color2\x
unit_direction\y = unit_vector_y(*rr)
a = 0.5 * (unit_direction\y + 1.0)
*in\y = (1.0 - a) * color1\y + a * color2\y
unit_direction\z = unit_vector_y(*rr)
a = 0.5 * (unit_direction\z + 1.0)
*in\z = (1.0 - a) * color1\z + a * color2\z
EndProcedure
; Procedure.f ray_color(*rr.Ray, *in.Vec3, axe)
; Protected a.f
; Static color1.Vec3, color2.Vec3, unit_direction.Vec3
;
; color1\x = 1.0 : color1\y = 1.0 : color1\z = 1.0
; color2\x = 0.5 : color2\y = 0.7 : color2\z = 1.0
;
; unit_direction\x = unit_vector_y(*rr)
; a = 0.5 * (unit_direction\x + 1.0)
; *in\x = (1.0 - a) * color1\x + a * color2\x
;
; unit_direction\y = unit_vector_y(*rr)
; a = 0.5 * (unit_direction\y + 1.0)
; *in\y = (1.0 - a) * color1\y + a * color2\y
;
; unit_direction\z = unit_vector_y(*rr)
; a = 0.5 * (unit_direction\z + 1.0)
; *in\z = (1.0 - a) * color1\z + a * color2\z
;
; If axe = 1
; ProcedureReturn *in\x
; EndIf
; If axe = 2
; ProcedureReturn *in\y
; EndIf
; If axe = 3
; ProcedureReturn *in\z
; EndIf
;
; EndProcedure
; Procedure.f ray_color_hit(*_r.Ray, *in.Vec3, depth)
; Protected x.Vec3
; Protected p.Vec3
; Protected ntemp.f
; Protected t.f = 0.0
; Protected id.i = 0
;
; If depth <= 0
; v_init(0.0, 0.0, 0.0, p)
; EndIf
;
; If intersect(*_r, @t, @id)
; Protected *obj.Sphere = scene(id)
;
; ; Point at parameter
; x\x = *_r\orig\x + t * *_r\dir\x
; x\y = *_r\orig\y + t * *_r\dir\y
; x\z = *_r\orig\z + t * *_r\dir\z
;
; ; Norm
; Protected n.Vec3
; rt_sub( n, x, *obj\center)
; rt_norm( n, ntemp )
;
; ; Set to normal
; Protected nl.Vec3
; If rt_dot( n, *_r\dir ) < 0.0
; rt_copy( nl, n )
; Else
; rt_neg( nl, n )
; EndIf
;
; *_r\dir\x = nl\x + random_unit_vector(1)
; *_r\dir\y = nl\y + random_unit_vector(2)
; *_r\dir\z = nl\z + random_unit_vector(3)
;
; ; *in\x = *in\x * ray_color_hit(*_r, *in, depth-1)
; ; *in\y = *in\y * ray_color_hit(*_r, *in, depth-1)
; ; *in\z = *in\z * ray_color_hit(*_r, *in, depth-1)
; ;
;
; *in\x = 0.1
; *in\y = 0.1
; *in\z = 0.1
;
; rt_mul(*in, *in, *in)
; ray_color_hit(*_r, *in , depth-1)
;
; Else
;
; ; Render to background
; ray_color(*_r, *in)
;
; EndIf
;
; EndProcedure
Procedure.f ray_color_hit(*_r.Ray, *in.Vec3, depth)
Protected x.Vec3
Protected p.Vec3
Protected ntemp.f
Protected t.f = 0.0
Protected id.i = 0
Protected rr.Ray
Protected unit_vector.Ray
If depth = 0
;If axe = 1
*in\x = 0.0
;ProcedureReturn *in\x
;EndIf
; If axe = 2
*in\y = 0.0
; ProcedureReturn *in\y
;EndIf
;If axe = 1
*in\z = 0.0
; ProcedureReturn *in\z
;EndIf
EndIf
If intersect(*_r, @t, @id)
Protected *obj.Sphere = scene(id)
; Point at parameter
x\x = *_r\orig\x + t * *_r\dir\x
x\y = *_r\orig\y + t * *_r\dir\y
x\z = *_r\orig\z + t * *_r\dir\z
; Norm
Protected n.Vec3
rt_sub( n, x, *obj\center)
rt_norm( n, ntemp )
; Set to normal
Protected nl.Vec3
If rt_dot( n, *_r\dir ) < 0.0
rt_copy( nl, n )
Else
rt_neg( nl, n )
EndIf
;;** VERY SLOW ** ;;
; rr\orig\x = x\x
; rr\orig\y = x\y
; rr\orig\z = x\z
rt_copy(rr\orig, x)
;; QUITE FAST ;;
; rr\orig\x = *_r\orig\x
; rr\orig\y = *_r\orig\y
; rr\orig\z = *_r\orig\z
rr\dir\x = nl\x + random_unit_vector(1)
rr\dir\y = nl\y + random_unit_vector(2)
rr\dir\z = nl\z + random_unit_vector(3)
p\x = 0
p\y = 0
p\z = 0
;If axe = 1
;*in\x = ((ray_color_hit(rr, *in , depth-1) + 0.1))
;rt_mul(*in, *in, *in)
;Debug *in\x
; ProcedureReturn *in\x
; EndIf
;If axe = 2
; *in\y = ((ray_color_hit(rr, *in , depth-1) + 0.1))
;rt_mul(*in, *in, *in)
;ProcedureReturn *in\y
; EndIf
; If axe = 3
; *in\z = ( (ray_color_hit(rr, *in , depth-1) + 0.1))
;rt_mul(*in, *in, *in)
; ProcedureReturn *in\z
;EndIf
*in\x * 0.5 * (ray_color_hit(rr, *in , depth-1) + 0.1) : *in\y * 0.5 : *in\z * 0.5
;ray_color_hit(rr, *in , depth-1) + 0.1
; If axe = 1
;
; *in\x = 0.5 * (nl\x + 1.0)
; ;rt_add(*in, p, *in)
; ;Debug *in\x
; ProcedureReturn *in\x
; EndIf
; If axe = 2
;
; *in\y = 0.5 * (nl\y + 1.0)
; ;rt_add(*in, p, *in)
; ProcedureReturn *in\y
; EndIf
; If axe = 3
;
; *in\z = 0.5 * (nl\z + 1.0)
; ;rt_add(*in, p, *in)
;
; ProcedureReturn *in\z
; EndIf
; ray_color_hit(*_r, *in , depth-1)
Else
; Render to background
; ray_color(*_r, *in)
unit_vector\dir\x = *_r\dir\x
unit_vector\dir\y = *_r\dir\y
unit_vector\dir\z = *_r\dir\z
ray_color(unit_vector, *in)
EndIf
EndProcedure
Define aspect_ratio.f = 16.0 / 9.0
Define image_width = 800
Define image_height = Int(image_width / aspect_ratio)
If image_height < 1
image_height = 1
Else
image_height = image_height
EndIf
; Render engine
Procedure render()
Shared image_width
Shared image_height
Static focal_length.f = 1.0
Static viewport_height.f = 2.0
Protected i_w.f = image_width
Protected i_h.f = image_height
Protected viewport_width.f = viewport_height * (i_w/i_h)
Protected point3.Vec3
point3\x = 0.0
point3\y = 0.0
point3\z = 0.0
Protected ray_direction.Vec3
ray_direction\x = 0
ray_direction\y = 0
ray_direction\z = 0
Protected viewport_u.Vec3
viewport_u\x = viewport_width
viewport_u\y = 0
viewport_u\z = 0
Protected viewport_v.Vec3
viewport_v\x = 0
viewport_v\y = -viewport_height
viewport_v\z = 0
Protected pixel_delta_u.Vec3
pixel_delta_u\x = viewport_u\x / i_w
pixel_delta_u\y = viewport_u\y / i_w
pixel_delta_u\z = viewport_u\z / i_w
Protected pixel_delta_v.Vec3
pixel_delta_v\x = viewport_v\x / i_h
pixel_delta_v\y = viewport_v\y / i_h
pixel_delta_v\z = viewport_v\z / i_h
Protected viewport_upper_left.Vec3
Protected v_f.Vec3
v_f\x = 0.0
v_f\y = 0.0
v_f\z = focal_length
viewport_upper_left\x = point3\x - v_f\x - viewport_u\x / 2 - viewport_v\x / 2
viewport_upper_left\y = point3\y - v_f\y - viewport_u\y / 2 - viewport_v\y / 2
viewport_upper_left\z = point3\z - v_f\z - viewport_u\z / 2 - viewport_v\z / 2
Protected pixel_100_loc.Vec3
pixel_100_loc\x = viewport_upper_left\x + 0.5 * (pixel_delta_u\x + pixel_delta_v\x)
pixel_100_loc\y = viewport_upper_left\y + 0.5 * (pixel_delta_u\y + pixel_delta_v\y)
pixel_100_loc\z = viewport_upper_left\z + 0.5 * (pixel_delta_u\z + pixel_delta_v\z)
Protected sample_per_pixel.i = 10
Protected pixel_sample_scale.f = 1.0 / sample_per_pixel
Protected max_depth.i = 5
Protected x.f, y.f, z.f, v.vec3
Static offset.Vec3, pixel_sample.Vec3
;If StartDrawing(ScreenOutput())
For j = 0 To image_height-1
glBegin_(#GL_POINTS)
For i = 0 To image_width-1
ii.f = i
jj.f = j
x = 0.0
y = 0.0
z = 0.0
For sample = 0 To sample_per_pixel
offset\x = random_float() -0.5
offset\y = random_float() -0.5
offset\z = 0.0
pixel_sample\x = pixel_100_loc\x + ( (ii+offset\x) * pixel_delta_u\x) + ( (jj+offset\y) * pixel_delta_v\x)
pixel_sample\y = pixel_100_loc\y + ( (ii+offset\x) * pixel_delta_u\y) + ( (jj+offset\y) * pixel_delta_v\y)
pixel_sample\z = pixel_100_loc\z + ( (ii+offset\x) * pixel_delta_u\z) + ( (jj+offset\y) * pixel_delta_v\z)
ray_direction\x = pixel_sample\x - point3\x
ray_direction\y = pixel_sample\y - point3\y
ray_direction\z = pixel_sample\z - point3\z
Define.Ray r
r\orig = point3
r\dir = ray_direction
ray_color_hit(r, @v, max_depth)
x = x + v\x
y = y + v\y
z = z + v\z
Next
;Plot(i, j, RGB(Int(255.999 * clamp(pixel_sample_scale * x, 0.0, 0.999)),Int(255.999 * clamp(pixel_sample_scale* y, 0.0, 0.999)),Int(255.999 * clamp(pixel_sample_scale * z, 0.0, 0.999))))
glColor3f_( clamp(pixel_sample_scale * x, 0.0, 0.999), clamp(pixel_sample_scale* y, 0.0, 0.999), clamp(pixel_sample_scale * z, 0.0, 0.999)) : glVertex2s_(i,j)
Next
glEnd_() : glFlush_()
Next
;EndIf
;StopDrawing()
EndProcedure
InitSprite()
OpenWindow(0, 0, 0, image_width / DesktopResolutionX(), image_height / DesktopResolutionY(), "Inspired from Raytracing in One Weekend", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
;OpenWindowedScreen(WindowID(0), 0, 0, image_width , image_height )
OpenGLGadget(0,0,0,image_width / DesktopResolutionX(),image_height / DesktopResolutionY(),#PB_OpenGL_NoFlipSynchronization)
glOrtho_(0,image_width,image_height,0,-1,1)
glDrawBuffer_(#GL_FRONT)
;ClearScreen(RGB(0,0,0))
Define time = ElapsedMilliseconds()
render()
time = ElapsedMilliseconds() - time
SetWindowTitle(0,"Inspired from Raytracing in One Weekend - RenderTime: "+Str(time)+"ms")
Define Event
Repeat
Event = WindowEvent()
Until Event = #PB_Event_CloseWindow
End
This recursive function is needed to make complex as diffuse and shadow to take account for rendering ... But there is somewhere broken to this code ... As you see my recently code I do only for x axis once ...