• 13
• 15
• 19
• 27
• 9

# Writing my own pathtracer on mobile device

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

## Recommended Posts

Hello forum and graphic geeks  ,

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! )

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

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

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

I will try to keep the latest progress updated.

Edited by IsItSharp

##### Share on other sites

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 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 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 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

[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(
);
Vector3D discriminant = b.multiply(b).subtract(new Vector3D(4,4,4).multiply(a).multiply(c));

}

Edit:

Okay, i got it

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 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 on other sites

So any tips here?

##### Share on other sites

No one here who wants to check the last function?

##### 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 on other sites

@Bacterius

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 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