Build a basic 3D Render Engine

Started by stevmjon, May 03, 2022, 10:25:50 PM

Previous topic - Next topic

kevin

#45
 Excellent dude!     was playing with it yesterday, then picked through the code a bit more last night..  had some ideas to simplify some bits here and there.    Mostly things like removing code repetition by building helper functions here and there. was going to make a video but ran out steam last night..  


  Edit: that's annoying my post pushed yours off this page  -   to download 3D Ray Tracing Engine_v0.37_Demo 2  back here


  Code tidbits

   In Menu.pba
PlayBASIC Code: [Select]
         state = array(lp).state

Select state
Case 0 : image = array(lp).image1 ; image (default)
Case 1 : image = array(lp).image2 ; image (default mouseover)
Case 2 : image = array(lp).image3 ; image (clicked)
Case 3 : image = array(lp).image4 ; image (clicked mouseover)
EndSelect





    This could just be, if the images field was defined as an array .  ie. images(4)
PlayBASIC Code: [Select]
         state = array(lp).state
image = array(lp).image(state)





    Boolean expressions can help in places also.  

PlayBASIC Code: [Select]
    ; so this
If z1# < znear# Then Inc out
If z2# < znear# Then Inc out

; can be
out= (z1# < znear#) + (z2# < znear#)




      Compares return a true(1) or false(0) which is just an integer.    If one is bellow out will be 1 and if they're both it'll be two

      You could also, just make a region coded out of the two compares and then unroll for all possible outcomes.  


PlayBASIC Code: [Select]
      ; something like this
out= ((z1# < znear#) << 1) + (z2# < znear#)

select out
case 0 // no clip required

eitfunction stuff


case 1 // Z2 needs clipping but Z1 is front of plane

clip Z2

case 2 // Z1 needs clipping but Z2 is front of plane

clip Z1

case 3 // both are behind the plane so reject them




   
      So clip could be more like this.  Notice that when the line is fully in front or behind, we just pass back the original parameters.       Could most likely get rid of the ix1/iy/iz etc versions also 

PlayBASIC Code: [Select]
Function clip_nearz(x1#,y1#,z1#,x2#,y2#,z2#)

;--- clip border 'nearz' ONLY for perspective mode ---
;--- NOTE: must be calculated before perspective projection ---

; NOTE: orthographic mode displays all of z buffer depths (no clipping) ---

; point(1) = x1 , y1 , z1
; point(2) = x2 , y2 , z2


select ((z1# < znear#)<<1) + (z2# < znear#)

case 0,3 ; both points inside border (keep)
exitfunction x1#,y1#,z1#,x2#,y2#,z2#,out=3

case 1
ix1# = x1# : iy1# = y1# : iz1# = z1# ; a (source point)
ix2# = x2# : iy2# = y2# : iz2# = z2# ; b (destination point)

case 2
ix1# = x2# : iy1# = y2# : iz1# = z2# ; a (source point)
ix2# = x1# : iy2# = y1# : iz2# = z1# ; b (destination point)
swap_value = 1

endselect

d1# = iz1#-znear# ; NOTE: no dot product required as nearz border is perpendicular to z axis
d2# = iz2#-znear#
t# = d1#/(d1#-d2#)

; i = a + t(b-a)
ix2# = ix1# + t#*(ix2#-ix1#) ; x, y, z
iy2# = iy1# + t#*(iy2#-iy1#)
iz2# = iz1# + t#*(iz2#-iz1#)

If swap_value = 1 ; place points back in original order
exitfunction ix2#,iy2#,iz2#,ix1#,iy1#,iz1#,Skip
EndIf

EndFunction ix1#,iy1#,iz1#,ix2#,iy2#,iz2#,skip





stevmjon

thanks for the tips kev, it's always handy to optimise.

i am glad you like the program too. i am still working on another update that will have more geometry included.
so far i have already added cylinders. you can so far create them and they will display as wireframe mode. i am currently working on being able to select them, then i will add render ability.

the more i am programming this the more i am enjoying the program, and i am coming up with more idea's too.

  stevmjon
It's easy to start a program, but harder to finish it...

I think that means i am getting old and get side tracked too easy.

kevin


Quotethanks for the tips kev, it's always handy to optimise.

    Sorta,  This sort of stuff is  refactoring bits to reduce the code foot print.    What tends to happen is our as project gets larger, we end up spending more time maintaining the code base as changes are mode.   So just a good idea to occasional go back and pick through the older code/approaches and try and do some clean up.     

stevmjon

just excited to share a screenshot of my progress.
i have just added cylinders in wireframe mode.

i now need to have them visible in the render itself, which is next.
i already know how to calculate this, just need to code it.

at the moment i am keeping all the code to see the objects mathematically, rather than using polygons. this way the objects stay high resolution when rendered.

   stevmjon
It's easy to start a program, but harder to finish it...

I think that means i am getting old and get side tracked too easy.

stevmjon

i have added the cylinder to the renderer now, yay.

i just need to adjust it so it registers height. the cylinder is currently infinite in height, lol.
getting this routine added took a lot more than i thought to calculate.
now i know why they stick to spheres and planes.

after i get the cylinder height done, i will add it to fast render view, so it shows up in shaded color mode in the editor.

   stevmjon
It's easy to start a program, but harder to finish it...

I think that means i am getting old and get side tracked too easy.

stevmjon

just added the cylinders to be able to be seen in 'fast shaded color mode' in the editor.

also it can be selected in the editor too.

adding the cylinder was a good learning curve for me to better understand the maths behind 3D.
i like learning new things, it keeps the mind active.

   stevmjon
It's easy to start a program, but harder to finish it...

I think that means i am getting old and get side tracked too easy.

kevin

 Hey Steve;

 
Quotejust added the cylinders to be able to be seen in 'fast shaded color mode' in the editor.

    That'd be a nice challenge given there's no nice easy mesh to render

     Looking good dude !


stevmjon

yeah, i needed to go through a bit of maths to find the collision.

full method:
> find skew line minimum distance between the camera ray and cylinder direction ray (direction cylinder is standing)
   > this gives the minimum distance between the 2 rays where a line is perpendicular to both rays
   > also gives this perpendicular lines as a vector
> find point on the camera ray where the minimum distance is located
   > turn the cylinder direction ray into a plane so it passes through the 'shared' perpendicular line
   > do camera ray to above plane collision check (gives location)
> find point on cylinder direction ray
   > turn the camera ray into a plane so it passes through the 'shared' perpendicular line
   > do cylinder direction ray to above plane collision check (gives location)
> calc intersection point on cylinder surface
   > find distance the camera ray is from the cylinder center vector, then calc remaining distance along the camera ray to the cylinder edge (gives distance like a shadow cast directly down from the ray)
   > calc angle the ray is from the cylinder center vector to get actual distance 'along' the ray
> check if collision is behind or in front of camera ray
> check if collision point is within the cylinder height
   > if inside height then calc surface point normal at this collision point on cylinder
   > if outside then calc both the upper cylinder face & lower cylinder face for a collision and calc the surface point normal at this collision point

this is why it took a bit to implement this into the code to show up on the renderer and shaded mode.
the good thing is it also detects a collision when i click on the screen to select the object in the editor.

i leart more about vector calculations doing this cylinder.

   stevmjon
It's easy to start a program, but harder to finish it...

I think that means i am getting old and get side tracked too easy.

stevmjon

#53
time for an upgrade to v0.43

this has had a few bug fixes i found, plus a few modifications too.

* added cylinders
* added rotation of objects (in editor)
* added size of objects with separate width/height (in editor)
* modified rendering of reflections order (last to first)
* added a different extra default scene
* better checking for save & load files

take it for a spin and see what you think.

i will update again with new objects: cones & boxes.
also will modify the surface editor to be more flexible. currently if you select 'multiple' objects then open surface editor it applies current default color to all selected objects (may add ability to see surface settings for each selected object in a list?).

  stevmjon

EDIT: see updated version in reply #58 (this fixes a clipping bug).
It's easy to start a program, but harder to finish it...

I think that means i am getting old and get side tracked too easy.

kevin

 Steve,

Without wanting to sound like a broken record,  that's fantastic  !!


 

stevmjon

thanks kev. glad you like it.
i fixed every bug i could find in this one. seems to run smoothly.

i should be able to update this with new shapes easier now that all the routines are working properly.
when i add boxes that should make better scenes because you will be able to shape the boxes and make more detailed objects with them.

this has been a learning experience as i have applied my mind more deeply into 3D. gotta keep the mind active.

i'm looking forward to making more updates.

  stevmjon
It's easy to start a program, but harder to finish it...

I think that means i am getting old and get side tracked too easy.

kevin

#56
It's amazing...  Noticed what looks like plane clipping problem when moving the camera forward in the default scene though.



stevmjon

oh, thanks for the input kev.
that should only effect the wireframe model, and not the render itself (hopefully).

i will take a look at it and post a fixed version.
It's easy to start a program, but harder to finish it...

I think that means i am getting old and get side tracked too easy.

stevmjon

here is the fixed version v0.44

i had clipping for the cylinder top & bottom faces, but didn't properly clip the sides. thanks for spotting that kev.

this version should be stable (fingers crossed).

   stevmjon
It's easy to start a program, but harder to finish it...

I think that means i am getting old and get side tracked too easy.

stevmjon

thought i would share a screenshot of the boxes i have added to the ray tracer.

i am calculating the box collision similar to planes.
i calculate each side of the box by calc collision with a plane, then if a pos value, calc around the plane border to see if collision point is inside/outside.
seems to work quite fast, but in this screenshot pic it goes very slow when i turn on reflections and they are a bit funny too. same with shadows turned on plus it's even slower again. guess there is more work to be done.

maybe if i use line - box collision instead (not planes)?

   stevmjon
It's easy to start a program, but harder to finish it...

I think that means i am getting old and get side tracked too easy.