This is (an attempt at) a real-time software rasterizer. The graphics logic is mainly based on the renderer described in Tiny Renderer.
This project uses no dependencies other than the Java Class library.
Simply run Main.java with your IDE of choice, or from a terminal, then import a .obj file using the import button. You can import the .obj file found inside the assets folder for a quick start.
You can also configure texture paths by accessing model/pipeline/programmable/PhongShader.java, which is the default shader.
Keep in mind that some .obj files may not load properly, as this engine uses a fairly primitive way of loading objects. Since we do not intend to develop this engine further, we are unlikely to fix this. Feel free to implement your own model loader ;).
Alltesting done with a .PPM file.- Renderer has functions to draw lines, triangles, and set single pixels.
- Renderer has depth testing.
- Renderer displays to window.
- Renderer has model loader.
- Renderer can load textures and interpolate texture coordinates.
- Window can display rendering output in real time
- Renderer has transformations.
- Shader can shade any number of directional light sources.
- Renderer re-sizes object coordinates based on viewport dimensions, keeping the aspect ratio of the object intact.
- Pipeline has programmable vertex and fragment shaders.
- Shaders have specular mapping and Phong specular shading.
- GUI now reflects shader state.
- [More functionality will be appended here]
The following is a diary of any intersting thoughts I had during the development of this rasterizer.
Converting C++ to Java is hell. Java doesn't let you do anything. I miss const vec2&
T_T
Note to future self and developers : when loading huge data into a string inside a for loop, please use stringBuilder or stringBuffer. I was copying the same string literally millions of times with megabytes worth of data.
Finished setting up the basic model.renderer. Drawing 55 triangles took 7 seconds, seems kind of slow but won't know until we load actual model.
Another one in the "typos that cost me hours" section
It should be if (std::abs(orthogonal.z)>1e-2)
Erratic depth map
This is 3 errors working all at once. One is the typo above, the other is multiplying vertices in the wrong order to determine barycentric coordinates (this is why it looks triangulated), and the final error is that I forgot to initialize my depth buffer with the negative maximum float value, instead leaving it to the default of 0.
Cool bug.
I would kill this typo if I could.
minY should obviously take the y value. I had to deal with this typo the day before presenting my code, and I troubleshot it for at least an hour. Nothing beats the frustration of "How could I miss this?"
When I said I would kill that typo I might've been exaggerating. But this bug I would actually kill if I could.
What you are looking at is the RGB map of surface normals.
The story of how I struggled for 5 hours with this bug shall remain undisclosed, but suffice it to say the problem was depth buffer testing. This might seem obvious to you but it stumped me. Until Agab suggested the genius idea that it could be triangles rendering in the back. Even then I doubted it, after all my cpp code worked perfectly without depth buffer testing. Later on we loaded a spherical model (thanks, MIT!) :
What a sickly ball!
Most importantly, I decided to test every axis separately.
The x-axis. Seems right.
Y. Seems right!
Curse you Z-axis.
After implementing depth testing :
What a healthy ball!
In celebration of v0.1 of our rasterizer, here are some interesting images :
Texture sampling
This one might also feature in my bug report, I still don't know if this is what it should look like.
It turns out I was wrong. Everything was right. The bug eludes me. I just used my map()
function, instead of doing the operations directly, and the texture loaded perfectly.
I don't understand, but this is no time for understanding. The code worked, hurrah!
For future reference the texture was loading all fucked up when I didn't use map()
.
Finally! we have real-time rendering, but...at what cost? It's very slow. VERY. Currently only outputting about 0.5FPS with a single model loaded. I don't even have any ideas on how to make it faster anymore, other than multithreading.
I am lucky that I worked with OpenGL before. I was wondering why my model wasn't rendering every frame (even though I was clearing the color buffer), and it just occured to me that we also clear the depth buffer in OpenGL every frame. Bless LearnOpenGL!
No real updates today except some cool gifs :
Generally speaking, you get a lot of cool bugs in graphics, but this one really caught my eye. The most intentional looking bug I've had so far. I was forgetting to clear the color buffer every frame.
Long time no update! Let's get started with this funny bug :
Instead of copying the vertex coordinates, I was changing them every frame, thus applying the same transform cumulatively.
Also, he's rotating.
More rotaty ones :
The cube gif is not sped up!
You can also notice that we have 2 light sources instead of the usual 1 + ambient.
I can't believe it's been that long. We have done some fundamental changing to the structure of the codebase. Modifiyng shaders and texturing have never been easier!
As usual here are the cool bugs and gifs :
Hmm, yes. Normal mapping.
Now this is real normal mapping
Okay, in this one I projected the normal map as a light source, and did some funky shading
It's been a long time without an update. I don't have many interesting bugs this time around but here are some cool screenshots :
Note that the specular highlight changes according the angle we view the model from.