|
So, I got interested in 3D graphics programming a while ago and decided to write a raytracer in pure java after reading a bit about raytracing. I'm just posting this small project of mine here for no particular reason, but hopefully someone will learn something from it or something. If you don't know what raytracing is then I highly suggest you read a bit about it because it's such a simple way of rendering a 3D scene which will give nearly photorealistic results.
It currently supports mathematical spheres, planes and triangles. .obj Models are supported too on a basic level (The vertex data has to be as triangles so no quads, no textures yet or anything like that) and they are built of obviously triangles. I wrote a simple "scene" loading system too, so you can easily just setup whatever objects or light sources you want in your scene using a text editor and then render it. Camera can be moved/rotated in realtime using a keyboard.
Github link: https://github.com/Harha/JRay (My Java tracer)
Github link: https://github.com/Harha/JRay-GLSL (My GLSL tracer)
I'm also planning to develop this further using OpenGL and have already a basic working raytracer written in pure GLSL. I haven't figured out how to pass thousands of primitives to the shader program from the main java program yet though so the scene must be set inside the shader's source code. Well why am I then writing this whole thing over again so that it will be computed on a GPU instead of CPU? Well performace obviously, while my CPU tracer can render very simple scenes realtime with like 100fps in resolutions 256x256 and below this GLSL version can do much more in 1080p resolution while still maintaining framerates above 50 (Depending on the type of GPU used obviously). GLSL doesn't allow functions to be recursive though and my java tracer is basicly doing all the light bouncing recursively by calling the same function over and over inside itself so I had to write this thing using iterative recursion instead (in a loop) which wasn't that different tbh though.
So yeah, that's it, decided to just post something in here for fun since I haven't really visited here after I lost interest in Runescape and it's private server scene.
Just some random scene I rendered with the purely Java based raytracer. The teapot is weirdly missing some vertices in this picture and I really don't know why, possibly there was some "limit" exceeded or something since it had quite many of them. Haven't happened since rendering that picture though.
I might still develop the Java version further and so on.... So I might update this thread once in a while with new additions to either programs.
Some images rendered using a way older version of the java tracer:
Hi, did you do all the lightings and shadows? Nice raytracing bro
"Did I do all the lightings and shadows?" ?
What do you exactly mean by that? Yes, I made this program completely by myself after reading about the concept behind raytracing, if that's what you're asking. Lighting works simplifiedly and in a nutshell by calculating the distance from the desired surface you want to lit up to the lightsource and then taking the intensity of that specific lightsource and doing some other calculations and then dividing the whole number by the square of the |distance| to the light from the surface. During that calculation I also check if something blocks the way between the surface (Which is a point in 3D space) and the lightsource (Which is also obviously a point in 3D space) and if it happens so that something is between them, the color for the surface at that particular point won't be calculated so it's final color black + ambient lighting.
That's like, the most simple way you can calculate shadows and shade a surface, at least when doing raytracing, as far as I know. I don't know much about rasterization but probably if you're writing a rasterizer instead of a raytracer you take the surface which is made of triangles and then calculate the color of all point on the triangle's surface by doing the exact same shading calculation as I told earlier but this time you only do it for the 3 vertices of the triangle and the colors on the surface of the triangle are calculated by interpolating between the results of the colors of the three vertices.
I don't know why I started wondering about shading in a rasterizing based 3d renderer but whatever...
Edit: Got rid of phong shading and implemented Cook-Torrance shading to my GLSL tracer which is way more realistic.
My shading function:
Code://// Color shading //// References: //// http://content.gpwiki.org/index.php/D3DBook:%28Lighting%29_Cook-Torrance //// http://ruh.li/GraphicsCookTorrance.html vec3 shadeCookTorrance(in Ray r, in Intersection x, in Light l) { // Specify some variables float R = x.mat.roughness; float RR = R * R; float F = x.mat.fresnel; float K = x.mat.density; vec3 VD = -r.dir; vec3 L = normalize(l.pos - x.pos); vec3 H = normalize(VD + L); float NdotL = clamp(dot(x.norm, L), 0.0, 1.0); float NdotH = clamp(dot(x.norm, H), 0.0, 1.0); float NdotV = clamp(dot(x.norm, VD), 0.0, 1.0); float VdotH = clamp(dot(H, VD), 0.0, 1.0); // Geometric attenuation float NH2 = 2.0 * NdotH / VdotH; float geo_b = NH2 * NdotV; float geo_c = NH2 * NdotL; float geo = min(1.0, min(geo_b, geo_c)); // Roughness (Beckmann distribution function) float r1 = 1.0 / (4.0 * RR * pow(NdotH, 4.0)); float r2 = (NdotH * NdotH - 1.0) / (RR * NdotH * NdotH); float roughness = r1 * exp(r2); // Fresnel float fresnel = pow(1.0 - VdotH, 5.0); fresnel *= (1.0 - F); fresnel += F; // Color calculations vec3 color_spec = vec3(0.0); if (NdotV * NdotL <= -EPSILON || NdotV * NdotL >= EPSILON) color_spec = vec3(fresnel * geo * roughness) / (NdotV * NdotL); vec3 color_final = NdotL * ((1.0 - K) * color_spec + K * x.mat.col) * l.col; return color_final; }
Thanks, though there isn't that much work put into this yet but I guess it's something...
Proper refraction support, material density can be set for each solid primitive. Each ray knows whether it's inside a medium or not.
Edit: Some progress, shading works way better now.
this is hot
Are you really the guy I think you are? I find that a bit hard to believe... Anyways, cool to see that you still lurk around here.
I made a WebGL version for fun, it can be played realtime in shadertoy: https://www.shadertoy.com/view/MdSSRc
Doesn't require you to install anything, works if your device supports modern OpenGL.
Glad to hear so positive opinions about it.
I remade the whole color shading part of my GLSL tracer because it was really unaccurate and didn't take light distances and things like that in account too well.
That piece of code leads to results like in the screenshots below. Notice the yellow reflective floor in the first picture, it's supposed to be like some really shiny and polished metal'ish material.Code://// Color shading //// References: //// http://content.gpwiki.org/index.php/D3DBook:%28Lighting%29_Cook-Torrance //// http://ruh.li/GraphicsCookTorrance.html vec3 shadeCookTorrance(in Ray r, in Intersection x, in Light l) { // Attenuation threshold, return vec3(0.0) if we fall below this limit vec3 L = l.pos - x.pos; float dist = length(L); float A = (1.0 + l.intensity) / dist; if (A < ATTENUATE_THRESHOLD) return vec3(0.0); // Specify surface material values float R = x.mat.roughness; float F = x.mat.fresnel; float K = x.mat.density; // Specify some other variables L = normalize(L); vec3 N = normalize(x.norm); vec3 V = normalize(-r.dir); vec3 LCOL = l.col * l.intensity; float NdotL = max(dot(N, L), 0.0); float specular = 0.0; if (NdotL > 0.0) { // Calculate intermediary values vec3 H = normalize(V + L); float NdotH = max(dot(N, H), 0.0); float NdotV = max(dot(N, V), 0.0); float VdotH = max(dot(V, H), 0.0); float RR = R * R; // Geometric attenuation float NH2 = 2.0 * NdotH; float g1 = (NH2 * NdotV) / VdotH; float g2 = (NH2 * NdotL) / VdotH; float geo = min(1.0, min(g1, g2)); // Roughness (Microfacet/Beckmann distribution function) float r1 = 1.0 / (4.0 * RR * pow(NdotH, 4.0)); float r2 = (NdotH * NdotH - 1.0) / (RR * NdotH * NdotH); float rough = r1 * exp(r2); // Fresnel (Schlick approximation) float fresnel = pow(1.0 - VdotH, 5.0); fresnel *= (1.0 - F); fresnel += F; // Final specular highlight specular = (fresnel * geo * rough) / (NdotV * NdotL); } return smoothstep(vec3(0.0), vec3(1.0), A * LCOL * NdotL * (K * x.mat.col + specular * (1.0 - K))); }
Short low quality video for the more curious people: https://www.dropbox.com/s/37otyilgk4...bmhd.webm?dl=0
Edit: Playing around with some trigonometric functions for fun. It seems to be quite easy to simulate a 'liquid' type of surface by assigning a simple mixture of sine and cosine waves modulated over time to a surface's y coordinate as example and make it depend on the current surface x and z coordinates or whatever you wish.
WebGL version: https://www.shadertoy.com/view/lsBXzt
« Previous Thread | Next Thread » |
Thread Information |
Users Browsing this ThreadThere are currently 1 users browsing this thread. (0 members and 1 guests) |