Coder Social home page Coder Social logo

nuno-jesus / 42_minirt Goto Github PK

View Code? Open in Web Editor NEW
4.0 2.0 2.0 29.96 MB

A small version of a Ray Tracer implemented in C

Makefile 2.84% C 84.15% Roff 5.24% Perl 0.16% Shell 0.42% Objective-C 7.18% R 0.01%
42 42-minirt 42born2code 42cursus 42porto 42portugal 42projects 42school c-programming graphics-programming

42_minirt's Introduction

About me

My name is Nuno, and I'm currently enrolled on the 1st year of my Master's degree in Informatics and Computation Engineering at FEUP. I'm also a student at 42Porto. My favourite areas are:

  • ๐ŸŒ Web Development
  • ๐Ÿ“ฑ Android Development
  • ๐Ÿ‘พ Game Development
  • ๐Ÿ’ป Linux and C language

I've worked with...

Languages Frameworks Tools
Java Python C/C++ C# HTML CSS Javascript Typescript PHP SQLite Dart Laravel Bootstrap Flutter AngularJS ThreeJS Python Pandas Git GitHub Docker Apache Solr Visual Studio Code IntelliJ Android Studio Unity Ubuntu Figma Slack Discord

Github stats

Anurag's GitHub stats Top Langs

42_minirt's People

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

maricard18

42_minirt's Issues

Phong Illumination Model

Add specular lighting to the play by following the following formula. Also take a look at diffuse coefficients, since we are only using light intensity.

Screenshot from 2023-08-18 12-37-03

Where the specular lighting is calculated using the following formula:
Screenshot from 2023-08-18 12-38-08

Introduce source light's color in the equation:

image

Refactoring: re-write ERROR macros

The error parameters are not constant, but the first part is across the different entities (A, C, L and so on).

	if (nc_matrix_size(tokens) != 3)
		return (ERROR("Wrong number of args in ambient (need 3)"), false);
	if (!parse_syntax(tokens, "001"))
		return (ERROR("Misconfiguration in commas/numbers in ambient"), false);
	if (!parse_rgb(tokens[2]))
		return (ERROR("Colors misformatting in ambient"), false);
	if (nc_atod(tokens[1]) < 0.0 || nc_atod(tokens[1]) > 1.0)
		return (ERROR("Ambient ratio out of bounds [0,1.0]"), false);

Maybe I can extract these macros to more generic ones:

# define ERROR_NUM_ARGS(x) ERROR("Wrong number of args in"x)
... 

Changes to header files

To do

  • Move libnc.h from includes folder back to libnc folder, due to the fact that libnc.h was erased from the original repo
  • Cluster similar macros in sections in macros.h
  • Rename any function that contains old struct names
  • Move debug functions in shapes.h to a new debug.h:
...

void		plane_print(t_plane *p);

void		sphere_print(t_sphere *s);

void		cylinder_print(t_cylinder *c);

...

void		shape_print(t_shape *shape);
  • Rename shapes.h to entities.h
  • Move debug functions from illumination.h to debug.h and light functions to entities.h. Eliminate illumination.h:
#ifndef ILLUMINATION_H
# define ILLUMINATION_H

# include "miniRT.h"

void			ambient_print(t_light *s);

void			camera_print(t_camera *s);

t_light	*source_new(char **point, char *ratio, char **color);

t_light	*source_copy(t_light *lightsource);

void			source_print(t_light *l);

#endif
  • Remove duplicate header functions from renderer.h
...
t_color	color_mult(t_color color, double k);

t_color	color_add(t_color c1, t_color c2);
...
  • Move color functions from miniRT.h to new color.h. Move color_print to debug.h:
...
t_color	color_new(int r, int g, int b);

t_color	color_add(t_color c1, t_color c2);

void	color_print(t_color *color);
  • Move normal functions from normal.h to entities.h. Eliminate normal.h
  • Change any variable named root to world
  • Rename some of the t_vec3 functions names

Changes to structs names and contents

To do

  • Merge t_lightsource (representing the light sources) and t_light (currently only representing the ambient light) into t_light only (with the fields from t_lightsource)
typedef struct s_lightsource
{
	t_vec3	origin;
	double	brightness;
	t_color	color;
}	t_lightsource;

typedef struct s_light
{
	double	ratio;
	t_color	color;
}	t_light;
  • Eliminate color and distance dead fields from the t_ray struct:
typedef struct s_ray
{
	double   distance;
	t_color	color;
	...
}	t_ray;
  • Normalize point names for t_camera, t_sphere and t_plane from origin and point to center
typedef struct s_camera
{
	t_vec3	origin;
	...
}	t_camera;

typedef struct s_sphere
{
	t_vec3	origin;
	...
}	t_sphere;

typedef struct s_plane
{
	t_vec3	point;
	...
}	t_plane;
  • Change t_inter and t_root to t_hit/t_intersection and t_world, respectively:
typedef struct s_inter
{
	...
}      t_inter;

typedef struct s_root
{
	...
}	t_root;

Change the parser to welcome specular parameters

Due to specular lighting working with parameters dependent on each shape, the parser must be able to receive new fields for each shape, specifying the Specular Coefficient (Ks between 0.0 and 1.0) and the Specular Power/Shininess (n a positive number)

Screenshot from 2023-08-18 17-02-21

The scene files should append 2 extra tokens to specify these parameters. For instance, the cylinder parsing line becomes:

# Name Center   Normal      Diameter  Height   Color      Ks     n
   cy  0,0,50   0,0,1       16        20       255,0,0    0.2    100

Also, this new change should be reflected on the t_shape struct, and not on each entity, since every shape must now have these fields. This will make it much easier to access these fields without having to know which kind of object we are dealing with.

Changes to functions locations

To do

  • Collect all debugging functions in debug.c
  • Move clamp function from color.c to libnc
static int	clamp(int n, int min, int max)
{
	if (n > max)
		return (max);
	else if (n < min)
		return (min);
	return (n);
}
  • Move calculate_global_illumination function from render.c to light.c
  • Move world_to_viewport, make_ray, ray_at to a new camera.c
  • Remove print dead function in read_map.c:
void	print(char *line)
{
	printf("%s\n", line);
}
  • Rename destroy folder and file to world to move world_new function from parser.c to the new world.c file
  • Move intersect functions to new intersect files

Changes to functions codes, behaviours, names and locations

To do

  • Move parse_utils.c from utils folder to parser folder
  • Move normal.c from utils to renderer folder
  • Create world_print to debug all fields at once, hence removing any loose prints like these:
void	init_viewport(t_world *w)
{
	...
	vec3_print(vec3_cross(r->camera.normal, UPGUIDE));
	vec3_print(r->camera.normal);
	printf("Right ");
	vec3_print(r->right);
	printf("Up ");
	vec3_print(r->up);
	printf("wview: %f\n", r->wview);
	printf("hview: %f\n", r->hview);
	printf("------------------------------\n");
}
  • Replace own macros in main with X11 ones:
int	main(int argc, char **argv)
{
	...
	mlx_hook(world->disp.win, ON_KEYPRESS, KEYPRESS_MASK, on_keypress, world);
	mlx_hook(world->disp.win, ON_CLOSE, CLOSE_MASK, quit, world);
	...
	return (0);
}
  • Replace nc_bzero call in render and world_hit functions with simple instructions, since it might be causing the program to run slower:
int	render(t_world *w)
{	
	...
	
	coords.y = -1;
	while (++coords.y < HEIGHT)
	{
		coords.x = -1;
		while (++coords.x < WIDTH)
		{
			...
			nc_bzero(&closest, sizeof(t_intersection));
			...
		}
	}
	mlx_put_image_to_window(w->disp.mlx, w->disp.win, w->disp.img, 0, 0);
	return (0);
}
bool	world_hit(t_vector *shapes, t_ray *ray, t_intersection *closest)
{
	t_shape		*shape;
	t_intersection		tmp;
	
        ...
	nc_bzero(&tmp, sizeof(t_intersection));
	while(++i < shapes->size)
	{
		...
	}
	...
  • Find a way to unite these intersection-related pieces of code from the intersects function and the rest of the intersection functions:
bool	intersects(t_shape *shape, t_ray *ray, t_intersection *inter)
{
	...
	if (shape->type == SPHERE)
		hit = sphere_intersect(&shape->data.sp, ray, inter);
	else if (shape->type == PLANE)
		hit = plane_intersect(&shape->data.pl, ray, inter);
	else if (shape->type == CYLINDER)
		hit = cylinder_intersect(&shape->data.cy, ray, inter);
	if (hit)
	{
		inter->ray = *ray;
		inter->shape = shape;
		inter->point = ray_at(ray, inter->t);
		inter->normal = vec3_normalize(shape_normal(inter, ray));
	}
	return (hit);
}
bool	sphere_intersect(t_sphere *sp, t_ray *ray, t_intersection *inter)
{
	...
	if (quadformula(&equation) > 0 && equation.t1 > EPSILON)
	{
		inter->t = equation.t1;
		inter->color = sp->color;
		return (true);
	}
	...
}
bool	plane_intersect(t_plane *pl, t_ray *ray, t_intersection *inter)
{
	...
		if (t > EPSILON)
		{
			inter->t = t;
			inter->color = pl->color;
			return (true);			
		}
	...
}
bool	cylinder_intersect(t_cylinder *cy, t_ray *ray, t_intersection *inter)
{
	...
	if (t > 0.0f)
	{
		inter->t = t;
		inter->color = cy->color;
		return (true);
	}
	...
}
  • Apply EPSILON correction on shape values on parsing-time to avoid complicated expressions like this:
bool	plane_intersect(t_plane *pl, t_ray *ray, t_intersection *inter)
{
	...

	if (vec3_dot(ray->direction, vec3_add(pl->normal, vec3_new(EPSILON, EPSILON, EPSILON))) != 0.0)
	{
		...
		numerator = vec3_dot(co, vec3_add(pl->normal, vec3_new(EPSILON, EPSILON, EPSILON)));
		denominator = vec3_dot(ray->direction, vec3_add(pl->normal, vec3_new(EPSILON, EPSILON, EPSILON)));
		...
        }
}
  • Transfer constant error messages on read_map, get_filesize, init_graphics, main and to macros.h:
char	**read_map(t_world *world, char *filename)
{
	...
		message(world, "Failed allocation on read_map.");
	...
		message(world, "Error opening file.");
}
int	get_filesize(t_world *world, char *filename)
{
	...
		message(world, "Error opening file.");
        ...
}
void	init_graphics(t_world *w)
{
	...
		message(r, "Failed allocation on mlx pointer\n");
	...
		message(r, "Failed allocation on window pointer\n");
}
int	main(int argc, char **argv)
{
	...
		message(NULL, "Usage: ./miniRT <scene>.rt");
        ...
  • Merge calculation of quadratic and linear equations (used across the shapes different intersection functions) by applying the following logic:
Given ax^2 + bx + c = 0

if a is 0:
      Use bx + c = 0 <=> x = -c/b
else:
      use ax^2 + bx + c = 0 <=> quadratic formula
  • Create a new plane function that returns a new t_plane with parameters which are not strings, in order to avoid duplicate code in cylinder.c:
double	cap_intersection(t_cylinder *cy, t_ray *ray, t_vec3 cap)
{
	t_vec3	co;
	t_vec3	vec;
	double 	numerator;
	double 	denominator;
	double 	t;

	t = -1;
	vec = vec3_sub(cy->normal, cap);
	if (vec3_dot(ray->direction, vec) != 0.0)
	{
		co = vec3_sub(ray->origin, cap);
		numerator = vec3_dot(co, vec3_add(cy->normal, \
						vec3_new(EPSILON, EPSILON, EPSILON)));
		denominator = vec3_dot(ray->direction, vec3_add(cy->normal, \
						vec3_new(EPSILON, EPSILON, EPSILON)));
		t = -(numerator / denominator);
		return (t);
	}
	return (t);
}
  • Normalize functions parameters for all shapes, just like the t_cylinder:
t_cylinder	cylinder_new(char **tokens);

t_plane	plane_new(char **point, char **normal, char **color);

t_sphere	sphere_new(char **center, char *diameter, char **color);
  • Change world_to_viewport function name, as it is misleading

Diffuse illumination not being correctly calculated

Here:

t_color	diffuse(t_ray *ray, t_color color, t_vec3 normal, double k)
{
	double	cos_angle;
	t_color	diff_color;

	cos_angle = vec3_cos(ray->direction, normal);
	diff_color = color_mult(color, k * cos_angle);
	return (diff_color);
}

The diffuse function is using the ray direction instead of the vector from the origin of the intersection and the light source to calculate the cossine.
Screenshot from 2023-08-05 18-08-03

Changes to t_vec3 library

To do

  • Simplify and normalize code for most functions. For instance, this one could be a one-liner:
t_vec3	vec3_add(t_vec3 v1, t_vec3 v2)
{
	t_vec3	res;

	res = vec3_new(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
	return (res);
}
  • Change file names according to the new function names

Separate mandatory from bonus

We need to have a folder for both mandatory and bonus sources to co-exist, since we can't submit the bonus into mandatory.

Enhancement: look at anti-aliasing

Our ray tracer currently has sharp edges because of the way we are painting the final image with the result from the trace of a ray directly to that point. In the real world, our eyes end up averaging the colors around a certain point. To do that we might need to skip pixels and re-run a loop to paint the "dead pixels" with the average of the colors around it.

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.