Jump to content
  • Advertisement
Sign in to follow this  
IsItSharp

Writing my own pathtracer on mobile device

This topic is 1283 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello forum and graphic geeks biggrin.png ,

 

i just registered myself on this wonderful site where kind of everything is posted i am interested in (games, graphics, programming). So the christmas holidays are imminent and i am currently searching for some programming stuff i could learn in the free days off from work.

 

Because i am really into android programming currently and i also really love the idea of pathtracing (i did a lot of CGI with Blender and LuxRender) i thought about writing a simple pathtracer for mobile devices (it don't have to be fast! smile.png)

 

Sadly i am a complete math idiot. Some months ago i started the first project "Try to write a pathtracer". After reading documents for hours and trying to understand the math calculations behind the letters i gave up. So in the next weeks i hope i have enough endurance to go through this second try and finally understand it (maybe it helps me in the future).

 

Currently i am working with Android Studio and a Galaxy Note 2 with Android 4.4.3 (Cyanogenmod).

 

There will probably be a lot of questions and i hope you will answer them ph34r.png

 

So here are some points i already understood of programming a pathtracer:

 

1. I need an abstract class from which the basic objects inherit (such as a Sphere and a Plane). Every object has its own definitions (radius, center point, etc.) and its own "checkIntersect" function

2. I need different classes, such as a Vector3D and a Ray (which has a origion Vector3D and a direction Vector3D)

3. Then i have to loop through the pixels of the image and generate a ray. Now i will loop through all basic objects and check if the ray intersects with one of these objects

4. if an object is in front of the intersected one (no idea how i could check this?) i skip this ray

5. if the ray hits the object i have to calculate the reflection and the resulting color depending on the object color (i will start with just a diffuse material). From that i have to calculate a second reflection ray which will also travel through the scene (sadly no idea how to calculate that second ray sad.png

6. If a given MAX_BOUNCE is reached, the ray disappears

 

These are the rough points i have in my mind for the topic "pathtracing".

 

So any tips you may have for me? I really appreciate all your answers smile.png

 

I will try to keep the latest progress updated.

Edited by IsItSharp

Share this post


Link to post
Share on other sites
Advertisement

Hi  Vilem Otte,

 

thank you very much for your detailed answer. Because everyone on the internet is talking about, how easy it is to write a pathtracer (climax is a pathtracer in 99 lines of C and i don't understand a single line of code) i first thought: well, it can't be that hard, even for me. But sadly, it is kind of complicated.

 

To the data storage topic:

 

do i really need a KD-Tree if i only use primitives such as spheres and planes?

Edited by IsItSharp

Share this post


Link to post
Share on other sites


do i really need a KD-Tree if i only use primitives such as spheres and planes?

 

If you only have a few, no. You can start out with a test scene of 5-6 spheres and won't need any special data structure to store the spheres. Once you get over a few hundred spheres (or triangles) though you quickly begin to realize how important it is for larger scenes!

Share this post


Link to post
Share on other sites

The key to usually anything is understanding the basics, without the basic mathematical knowledge and understanding behind path-tracing you are doomed to blind cut-paste/copy-paste  -> find tutorial/sample code and then back to copy and pasting again. All too often the same phrase have been mentioned, I want to do X but I do not comprehend the theory/principles underlying X. Then how are you going to implement something you don't understand, and what are you going to do when you run into issues during implementation. My advice, spend the time up front to understand the basics behind path-tracing, math and all and you will find that this will go a long way when you decide to start your implementation.

Share this post


Link to post
Share on other sites

[background=#fafbfc]I want to do X but I do not comprehend the theory/principles underlying X.[/background]

 
Yes, that's the problem sad.png
 

[background=#fafbfc]Then how are you going to implement something you don't understand, and what are you going to do when you run into issues during implementation.[/background]

 
As i wrote at my first post, i hoped you guys could help me out with some things?
 

[background=#fafbfc]My advice, spend the time up front to understand the basics behind path-tracing, math and all[/background]

 
The best method to learn something is if you practice it a lot (e.g. writing a pathtracer). "Learning by doing"
 
So here comes my first understanding problem:
 
Based on this letter: http://www.csee.umbc.edu/~olano/435f02/ray-sphere i tried to calculate the intersection for the sphere.
 
So far tried to calculate a, b, c and the discriminant. As it says in the text:
 
if the discriminant is below zero, there is not intersection. If it is 0, there is one intersection. If it is 1 there are two intersection (entry and exit).
 
So do i have to calculate the length of the resulting discriminant vector (and then check the stuff) or should i check if the coordinates of the vector are below zero? 
 
My code looks like this so far (based on 
b2 - 4 a c
a = d * d
b = 2 d * (p0 - pc)
c = (p0 - pc) * (p0 - pc) - r2):
        public override float Intersect(Ray ray)
        {
            Vector3D a = ray.direction.multiply(ray.direction);
            Vector3D twoDirection = ray.direction.multiply(new Vector3D { x = 2, y = 2, z = 2 });
            Vector3D b = twoDirection.multiply(ray.origin.subtract(this.center));
            Vector3D c = (ray.origin.subtract(this.center)).multiply(ray.origin.subtract(this.center)).subtract(
                          new Vector3D(this.radius*this.radius, this.radius*this.radius, this.radius*this.radius)
                          );
            Vector3D discriminant = b.multiply(b).subtract(new Vector3D(4,4,4).multiply(a).multiply(c));

        }
Edit:

Okay, i got it biggrin.png

Is this correct?

        public override float Intersect(Ray ray)
        {
            float a = ray.direction.Dotproduct(ray.direction);
            float b = 2.0f * ray.direction.Dotproduct(ray.origin.subtract(this.center));
            float c = ray.origin.subtract(this.center).Dotproduct(ray.origin.subtract(this.center)) - (this.radius * this.radius);

            float discriminant = (b * b) - (4.0f * a * c);

            if (discriminant < 0) //no hit
                return -1.0f;
            else if (discriminant == 0) //one hit
                return (-b + (float)Math.Sqrt(discriminant)) / 2.0f * a;
            else
            {
                float t1 = (-b - (float)Math.Sqrt(discriminant)) / 2.0f * a;
                float t2 = (-b + (float)Math.Sqrt(discriminant)) / 2.0f * a;

                return Math.Min(t1, t2); //get the smallest value
            }
        }
Edited by IsItSharp

Share this post


Link to post
Share on other sites
Probably you want to completely exclude results less than zero (i.e. if t1 is less than 0, return t2, and vice versa, and if they are both positive then return the smallest one). That will also handle cases where your ray starts inside the sphere, as well. Otherwise I haven't checked but the equation looks correct, it's just a standard quadratic. Also make sure your direction vectors are normalized.

Also since you seem to be using C# (correct me if I'm wrong) you would do yourself a favour to code proper arithmetic operators for your vector class rather than using .subtract, .add, etc... that'll make your code much easier to read and write.

Share this post


Link to post
Share on other sites

@Bacterius

Thanks for your reply smile.png
 

Also since you seem to be using C# (correct me if I'm wrong) you would do yourself a favour to code proper arithmetic operators for your vector class rather than using .subtract, .add, etc... that'll make your code much easier to read and write.

 
It is C# yes. I want to write the pathtracer step by step in c# because i am more familiar with this language. After i finished a code block (e.g. the intersection for the sphere) i will transfer it to Java for Android.
 
I didn't over overwrite the arithmetic operators because it is not possible in java.
 

Probably you want to completely exclude results less than zero (i.e. if t1 is less than 0, return t2, and vice versa, and if they are both positive then return the smallest one). That will also handle cases where your ray starts inside the sphere, as well. Otherwise I haven't checked but the equation looks correct, it's just a standard quadratic

 
So like this?

    public float intersect(Ray ray){
        Vector3D v = ray.origin.sub(this.center);

        float a = ray.direction.dot(ray.direction);
        float b = 2.0f * ray.direction.dot(v);
        float c = v.dot(v) - (this.radius * this.radius);

        float discriminant = (b*b) - (4.0f * a * c);

        if(discriminant > 0){
            float x1 = (-b - (float)Math.sqrt(discriminant) / (2.0f * a));
            float x2 = (-b + (float)Math.sqrt(discriminant) / (2.0f*a));

            return Math.min(x1,x2);
        }
        else if(discriminant == 0)
            return (-b + (float)Math.sqrt(discriminant) / (2.0f * a));
        else
            return -1.0f;
    }

Also make sure your direction vectors are normalized.

 
So like this?

Ray ray = new Ray(new Vector3D(0.0f,0.0f,0.0f), new Vector3D(5.0f,5.0f,1.0f).normalize());

Normalize function:

    public Vector3D normalize(){
        float magnitude = magnitude();
        return new Vector3D(this.x / magnitude, this.y / magnitude, this.z / magnitude);
    }

Magnitude function:

    public float magnitude(){
        return (float)Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
    }
Edited by IsItSharp

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!