src/raytracer.cc
branchpyrit
changeset 91 9d66d323c354
parent 90 f6a72eb99631
child 92 9af5c039b678
equal deleted inserted replaced
90:f6a72eb99631 91:9d66d323c354
    32 
    32 
    33 int pyrit_verbosity = 2;
    33 int pyrit_verbosity = 2;
    34 
    34 
    35 // Hammersley spherical point distribution
    35 // Hammersley spherical point distribution
    36 // http://www.cse.cuhk.edu.hk/~ttwong/papers/udpoint/udpoints.html
    36 // http://www.cse.cuhk.edu.hk/~ttwong/papers/udpoint/udpoints.html
    37 Vector3 Raytracer::SphereDistribute(int i, int n, Float extent, Vector3 &normal)
    37 Vector Raytracer::SphereDistribute(int i, int n, Float extent, const Vector &normal)
    38 {
    38 {
    39 	Float p, t, st, phi, phirad;
    39 	Float p, t, st, phi, phirad;
    40 	int kk;
    40 	int kk;
    41 
    41 
    42 	t = 0;
    42 	t = 0;
    65 	q = atan2f(normal.y, normal.x);
    65 	q = atan2f(normal.y, normal.x);
    66 	x = xx*cos(q) - yy*sin(q);
    66 	x = xx*cos(q) - yy*sin(q);
    67 	y = xx*sin(q) + yy*cos(q);
    67 	y = xx*sin(q) + yy*cos(q);
    68 	z = zz;
    68 	z = zz;
    69 
    69 
    70 	return Vector3(x, y, z);
    70 	return Vector(x, y, z);
    71 }
       
    72 
       
    73 // ---- tyto dve funkce budou v budouci verzi metody objektu PhongShader
       
    74 
       
    75 // calculate shader function
       
    76 // P is point of intersection, N normal in this point
       
    77 Colour PhongShader_ambient(const Material &mat, const Vector3 &P)
       
    78 {
       
    79 	Colour col;
       
    80 	if (mat.texture)
       
    81 		col = mat.texture->evaluate(P);
       
    82 	else
       
    83 		col = mat.colour;
       
    84 
       
    85 	// ambient
       
    86 	return mat.ambient * col;
       
    87 }
    71 }
    88 
    72 
    89 /*
    73 /*
    90  P is point of intersection,
    74  P is point of intersection,
    91  N normal in this point,
    75  N normal in this point,
    92  R direction of reflected ray,
    76  R direction of reflected ray,
    93  V direction to the viewer
    77  V direction to the viewer
    94 */
    78 */
    95 Colour PhongShader_calculate(const Material &mat,
    79 Colour Raytracer::PhongShader(const Shape *shape,
    96 	const Vector3 &P, const Vector3 &N, const Vector3 &R, const Vector3 &V,
    80 	const Vector &P, const Vector &N, const Vector &V)
    97 	const Light &light)
    81 {
    98 {
    82 	Colour col, acc;
    99 	Colour I = Colour();
    83 	Material * const &mat = shape->material;
   100 	Vector3 L = light.pos - P;
    84 
   101 	L.normalize();
    85 	if (mat->texture)
   102 	Float L_dot_N = dot(L, N);
    86 		col = mat->texture->evaluate(P);
   103 	Float R_dot_V = dot(R, V);
       
   104 
       
   105 	Colour col;
       
   106 	if (mat.texture)
       
   107 		col = mat.texture->evaluate(P);
       
   108 	else
    87 	else
   109 		col = mat.colour;
    88 		col = mat->colour;
   110 
    89 
   111 	// diffuse
    90 	// ambient
   112 	I = mat.diffuse * col * light.colour * L_dot_N;
    91 	acc = mat->ambient * col;
   113 
       
   114 	// specular
       
   115 	if (R_dot_V > 0)
       
   116 		I += mat.specular * light.colour * powf(R_dot_V, mat.shininess);
       
   117 	return I;
       
   118 }
       
   119 
       
   120 Colour Raytracer::shader_evalulate(const Ray &ray, int depth, Shape *origin_shape,
       
   121 	Float nearest_distance, Shape *nearest_shape)
       
   122 {
       
   123 	Colour col = Colour();
       
   124 	Vector3 P = ray.o + ray.dir * nearest_distance; // point of intersection
       
   125 	Vector3 normal = nearest_shape->normal(P);
       
   126 	bool from_inside = false;
       
   127 
       
   128 	// make shapes double sided
       
   129 	if (dot(normal, ray.dir) > 0.0)
       
   130 	{
       
   131 		normal = - normal;
       
   132 		from_inside = true;
       
   133 	}
       
   134 
       
   135 	col = PhongShader_ambient(*nearest_shape->material, P);
       
   136 
    92 
   137 	vector<Light*>::iterator light;
    93 	vector<Light*>::iterator light;
   138 	for (light = lights.begin(); light != lights.end(); light++) {
    94 	for (light = lights.begin(); light != lights.end(); light++)
   139 		Vector3 jo, L = (*light)->pos - P; // direction vector to light
    95 	{
   140 		L.normalize();
    96 		const Vector L = normalize((*light)->pos - P); // direction vector to light
   141 		Float L_dot_N = dot(L, normal);
    97 		const Float L_dot_N = dot(L, N);
   142 		if (L_dot_N > 0) {
    98 		if (L_dot_N > 0)
       
    99 		{
   143 			// test if this light is occluded (sharp shadows)
   100 			// test if this light is occluded (sharp shadows)
   144 			if ((*light)->cast_shadows) {
   101 			if ((*light)->cast_shadows) {
   145 				Ray shadow_ray = Ray(P, L);
   102 				const Ray shadow_ray = Ray(P, L);
   146 				Float dist = FLT_MAX;
   103 				Float dist = FLT_MAX;
   147 				if (top->nearest_intersection(nearest_shape, shadow_ray, dist))
   104 				if (top->nearest_intersection(shape, shadow_ray, dist))
   148 					continue;
   105 					continue;
   149 			}
   106 			}
   150 
   107 
   151 			// shading function
   108 			const Vector R = L - 2.0 * L_dot_N * N;
   152 			Vector3 R = L - 2.0 * L_dot_N * normal;
   109 			const Float R_dot_V = dot(R, V);
   153 			col += PhongShader_calculate(*nearest_shape->material,
   110 
   154 				P, normal, R, ray.dir, **light);
   111 			// diffuse
   155 		}
   112 			acc += mat->diffuse * col * (*light)->colour * L_dot_N;
   156 	}
   113 
   157 
   114 			// specular
       
   115 			if (R_dot_V > 0)
       
   116 				acc += mat->specular * (*light)->colour * powf(R_dot_V, mat->shininess);
       
   117 		}
       
   118 	}
       
   119 
       
   120 	return acc;
       
   121 }
       
   122 
       
   123 #ifndef NO_SSE
       
   124 VectorPacket Raytracer::PhongShader_packet(const Shape **shapes,
       
   125 	const VectorPacket &P, const VectorPacket &N, const VectorPacket &V)
       
   126 {
       
   127 	VectorPacket acc, colour;
       
   128 	union { __m128 ambient; float ambient_f[4]; };
       
   129 	union { __m128 diffuse; float diffuse_f[4]; };
       
   130 	union { __m128 specular; float specular_f[4]; };
       
   131 	union { __m128 shininess; float shininess_f[4]; };
       
   132 
       
   133 	for (int i = 0; i < 4; i++)
       
   134 		if (shapes[i] == NULL)
       
   135 		{
       
   136 			ambient_f[i] = 0;
       
   137 			diffuse_f[i] = 0;
       
   138 			specular_f[i] = 0;
       
   139 			shininess_f[i] = 0;
       
   140 		}
       
   141 		else
       
   142 		{
       
   143 			Material * const &mat = shapes[i]->material;
       
   144 			if (mat->texture)
       
   145 				colour.setVector(i, mat->texture->evaluate(P.getVector(i)));
       
   146 			else
       
   147 				colour.setVector(i, mat->colour);
       
   148 			ambient_f[i] = mat->ambient;
       
   149 			diffuse_f[i] = mat->diffuse;
       
   150 			specular_f[i] = mat->specular;
       
   151 			shininess_f[i] = mat->shininess;
       
   152 		}
       
   153 
       
   154 	// ambient
       
   155 	acc = colour * ambient;
       
   156 
       
   157 	Shape **shadow_shapes;
       
   158 	vector<Light*>::iterator light;
       
   159 	for (light = lights.begin(); light != lights.end(); light++)
       
   160 	{
       
   161 		 // direction vector to light
       
   162 		VectorPacket L = VectorPacket((*light)->pos) - P;
       
   163 		L.normalize();
       
   164 		const __m128 L_dot_N = dot(L, N);
       
   165 		__m128 valid = _mm_cmpgt_ps(L_dot_N, mZero);
       
   166 
       
   167 		// test if this light is occluded (sharp shadows)
       
   168 		if ((*light)->cast_shadows)
       
   169 		{
       
   170 			const RayPacket shadow_rays = RayPacket(P, L);
       
   171 			union { __m128 dists; float dists_f[4]; };
       
   172 			dists = mInf;
       
   173 			top->packet_intersection(shapes, shadow_rays,
       
   174 				dists_f, shadow_shapes);
       
   175 			valid = _mm_and_ps(valid, _mm_cmpeq_ps(dists, mInf));
       
   176 		}
       
   177 
       
   178 		const VectorPacket R = L - N * _mm_mul_ps(mTwo, L_dot_N);
       
   179 		const __m128 R_dot_V = dot(R, V);
       
   180 
       
   181 		// diffuse
       
   182 		acc.selectiveAdd(valid,
       
   183 			colour * VectorPacket((*light)->colour) * _mm_mul_ps(diffuse, L_dot_N));
       
   184 
       
   185 		// specular
       
   186 		valid = _mm_and_ps(valid, _mm_cmpgt_ps(R_dot_V, mZero));
       
   187 		__m128 spec = _mm_mul_ps(_mm_mul_ps(specular, _mm_set_ps1((*light)->colour.r)),
       
   188 			_mm_fastpow(R_dot_V, shininess));
       
   189 		acc.selectiveAdd(valid, spec);
       
   190 	}
       
   191 	return acc;
       
   192 }
       
   193 #endif
       
   194 
       
   195 void Raytracer::lightScatter(const Ray &ray, const Shape *shape, int depth,
       
   196 	const Vector &P, const Vector &normal, bool from_inside, Colour &col)
       
   197 {
   158 	if (depth < max_depth)
   198 	if (depth < max_depth)
   159 	{
   199 	{
   160 		Colour trans_col, refl_col;
   200 		Colour trans_col, refl_col;
   161 		Float trans = nearest_shape->material->transmissivity;
   201 		Float trans = shape->material->transmissivity;
   162 		Float refl = nearest_shape->material->reflectivity;
   202 		Float refl = shape->material->reflectivity;
   163 		const Float cos_i = - dot(normal, ray.dir);
   203 		const Float cos_i = - dot(normal, ray.dir);
   164 
   204 
   165 		// reflection
   205 		// reflection
   166 		if (refl > 0.01)
   206 		if (refl > 0.01)
   167 		{
   207 		{
   168 			Vector3 newdir = ray.dir + 2.0 * cos_i * normal;
   208 			Vector newdir = ray.dir + 2.0 * cos_i * normal;
   169 			Ray newray = Ray(P, newdir);
   209 			Ray newray = Ray(P, newdir);
   170 			refl_col = raytrace(newray, depth + 1, nearest_shape);
   210 			refl_col = raytrace(newray, depth + 1, shape);
   171 		}
   211 		}
   172 
   212 
   173 		// refraction
   213 		// refraction
   174 		if (trans > 0.01)
   214 		if (trans > 0.01)
   175 		{
   215 		{
   176 			Float n, n1, n2;
   216 			Float n, n1, n2;
   177 			if (from_inside)
   217 			if (from_inside)
   178 			{
   218 			{
   179 				n1 = nearest_shape->material->refract_index;
   219 				n1 = shape->material->refract_index;
   180 				n2 = 1.0;
   220 				n2 = 1.0;
   181 				n = n1;
   221 				n = n1;
   182 			}
   222 			}
   183 			else
   223 			else
   184 			{
   224 			{
   185 				n1 = 1.0;
   225 				n1 = 1.0;
   186 				n2 = nearest_shape->material->refract_index;
   226 				n2 = shape->material->refract_index;
   187 				n = 1.0 / n2;
   227 				n = 1.0 / n2;
   188 			}
   228 			}
   189 			const Float sin2_t = n*n * (1 - cos_i*cos_i);
   229 			const Float sin2_t = n*n * (1 - cos_i*cos_i);
   190 			if (sin2_t >= 1.0)
   230 			if (sin2_t >= 1.0)
   191 			{
   231 			{
   200 				const Float Rper = (n1*cos_i - n2*cos_t)*Rdiv;
   240 				const Float Rper = (n1*cos_i - n2*cos_t)*Rdiv;
   201 				const Float Rpar = (n2*cos_i - n1*cos_t)*Rdiv;
   241 				const Float Rpar = (n2*cos_i - n1*cos_t)*Rdiv;
   202 				const Float R = (Rper*Rper + Rpar*Rpar)/2;
   242 				const Float R = (Rper*Rper + Rpar*Rpar)/2;
   203 				refl += R*trans;
   243 				refl += R*trans;
   204 				trans = (1-R)*trans;
   244 				trans = (1-R)*trans;
   205 				Vector3 newdir = n * ray.dir + (n*cos_i - cos_t) * normal;
   245 				Vector newdir = n * ray.dir + (n*cos_i - cos_t) * normal;
   206 				Ray newray = Ray(P + 0.001*newdir, newdir);
   246 				Ray newray = Ray(P + 0.001*newdir, newdir);
   207 				trans_col = raytrace(newray, depth + 1, NULL);
   247 				trans_col = raytrace(newray, depth + 1, NULL);
   208 			}
   248 			}
   209 		}
   249 		}
   210 		col = (1-refl-trans)*col + refl*refl_col + trans*trans_col;
   250 		col = (1-refl-trans)*col + refl*refl_col + trans*trans_col;
   211 	}
   251 	}
   212 
   252 
   213 	// ambient occlusion
   253 	// ambient occlusion
   214 	if (!from_inside && ao_samples)
   254 	if (ao_samples && !from_inside)
   215 	{
   255 	{
   216 		Float miss = 0;
   256 		Float miss = 0;
   217 		for (int i = 0; i < ao_samples; i++) {
   257 		for (int i = 0; i < ao_samples; i++)
   218 			Vector3 dir = SphereDistribute(i, ao_samples, ao_angle, normal);
   258 		{
       
   259 			Vector dir = SphereDistribute(i, ao_samples, ao_angle, normal);
   219 			Ray ao_ray = Ray(P, dir);
   260 			Ray ao_ray = Ray(P, dir);
   220 			Float dist = ao_distance;
   261 			Float dist = ao_distance;
   221 			Shape *shape_in_way = top->nearest_intersection(nearest_shape, ao_ray, dist);
   262 			Shape *shape_in_way = top->nearest_intersection(shape, ao_ray, dist);
   222 			if (shape_in_way == NULL)
   263 			if (shape_in_way == NULL)
   223 				miss += 1.0;
   264 				miss += 1.0;
   224 			else
   265 			else
   225 				miss += dist / ao_distance;
   266 				miss += dist / ao_distance;
   226 		}
   267 		}
   227 		Float ao_intensity = miss / ao_samples;
   268 		Float ao_intensity = miss / ao_samples;
   228 		col = col * ao_intensity;
   269 		col = col * ao_intensity;
   229 	}
   270 	}
   230 
   271 }
   231 	return col;
   272 
   232 }
   273 Colour Raytracer::raytrace(Ray &ray, int depth, const Shape *origin_shape)
   233 
       
   234 Colour Raytracer::raytrace(Ray &ray, int depth, Shape *origin_shape)
       
   235 {
   274 {
   236 	Float nearest_distance = Inf;
   275 	Float nearest_distance = Inf;
   237 	Shape *nearest_shape = top->nearest_intersection(origin_shape, ray, nearest_distance);
   276 	Shape *nearest_shape = top->nearest_intersection(origin_shape, ray, nearest_distance);
   238 
   277 
   239 	if (nearest_shape == NULL)
   278 	if (nearest_shape == NULL)
   240 		return bg_colour;
   279 		return bg_colour;
   241 	else
   280 	else
   242 		return shader_evalulate(ray, depth, origin_shape, nearest_distance, nearest_shape);
   281 	{
   243 }
   282 		const Vector P = ray.o + ray.dir * nearest_distance; // point of intersection
   244 
   283 		Vector normal = nearest_shape->normal(P);
       
   284 		bool from_inside = false;
       
   285 
       
   286 		// make shapes double sided
       
   287 		if (dot(normal, ray.dir) > 0.0)
       
   288 		{
       
   289 			normal = - normal;
       
   290 			from_inside = true;
       
   291 		}
       
   292 
       
   293 		// shading function
       
   294 		Colour col = PhongShader(nearest_shape, P, normal, ray.dir);
       
   295 		lightScatter(ray, nearest_shape, depth, P, normal, from_inside, col);
       
   296 		return col;
       
   297 	}
       
   298 }
       
   299 
       
   300 #ifndef NO_SSE
   245 void Raytracer::raytracePacket(RayPacket &rays, Colour *results)
   301 void Raytracer::raytracePacket(RayPacket &rays, Colour *results)
   246 {
   302 {
   247 	Float nearest_distances[4] = {Inf,Inf,Inf,Inf};
   303 	union {
       
   304 		float nearest_distances[4];
       
   305 		__m128 m_nearest_distances;
       
   306 	};
       
   307 	__m128 mask;
   248 	Shape *nearest_shapes[4];
   308 	Shape *nearest_shapes[4];
   249 	static const Shape *origin_shapes[4] = {NULL, NULL, NULL, NULL};
   309 	static const Shape *origin_shapes[4] = {NULL, NULL, NULL, NULL};
       
   310 	m_nearest_distances = mInf;
       
   311 	mask = mAllSet;
       
   312 
   250 	top->packet_intersection(origin_shapes, rays, nearest_distances, nearest_shapes);
   313 	top->packet_intersection(origin_shapes, rays, nearest_distances, nearest_shapes);
   251 
   314 
       
   315 	mask = _mm_cmpneq_ps(m_nearest_distances, mInf);
       
   316 	if (!_mm_movemask_ps(mask))
       
   317 	{
       
   318 		for (int i = 0; i < 4; i++)
       
   319 			results[i] = bg_colour;
       
   320 		return;
       
   321 	}
       
   322 
       
   323 	const VectorPacket P = rays.o + rays.dir * m_nearest_distances; // point of intersection
       
   324 
       
   325 	VectorPacket normal;
   252 	for (int i = 0; i < 4; i++)
   326 	for (int i = 0; i < 4; i++)
   253 		if (nearest_shapes[i] == NULL)
   327 		if (nearest_shapes[i] != NULL)
       
   328 			normal.setVector(i, nearest_shapes[i]->normal(P.getVector(i)));
       
   329 
       
   330 	// make shapes double sided
       
   331 	__m128 from_inside = _mm_cmpgt_ps(dot(normal, rays.dir), mZero);
       
   332 	normal.mx = _mm_or_ps(_mm_and_ps(from_inside, _mm_sub_ps(mZero, normal.mx)),
       
   333 		_mm_andnot_ps(from_inside, normal.mx));
       
   334 	normal.my = _mm_or_ps(_mm_and_ps(from_inside, _mm_sub_ps(mZero, normal.my)),
       
   335 		_mm_andnot_ps(from_inside, normal.my));
       
   336 	normal.mz = _mm_or_ps(_mm_and_ps(from_inside, _mm_sub_ps(mZero, normal.mz)),
       
   337 		_mm_andnot_ps(from_inside, normal.mz));
       
   338 
       
   339 	// shading function
       
   340 	VectorPacket pres =
       
   341 		PhongShader_packet(const_cast<const Shape**>(nearest_shapes), P, normal, rays.dir);
       
   342 	//pres.mx = _mm_or_ps(_mm_and_ps(mask, pres.mx), _mm_andnot_ps(mask, _mm_set_ps1(bg_colour.r)));
       
   343 	//pres.my = _mm_or_ps(_mm_and_ps(mask, pres.my), _mm_andnot_ps(mask, _mm_set_ps1(bg_colour.g)));
       
   344 	//pres.mz = _mm_or_ps(_mm_and_ps(mask, pres.mz), _mm_andnot_ps(mask, _mm_set_ps1(bg_colour.b)));
       
   345 
       
   346 	for (int i = 0; i < 4; i++)
       
   347 		if (nearest_shapes[i] != NULL)
       
   348 		{
       
   349 			results[i] = pres.getVector(i);
       
   350 			lightScatter(rays[i], nearest_shapes[i], 0,
       
   351 				P.getVector(i), normal.getVector(i), (_mm_movemask_ps(from_inside)>>i)&1,
       
   352 				results[i]);
       
   353 		}
       
   354 		else
   254 			results[i] = bg_colour;
   355 			results[i] = bg_colour;
   255 		else
   356 }
   256 			results[i] = shader_evalulate(rays[i], 0, NULL,
   357 #endif
   257 				nearest_distances[i], nearest_shapes[i]);
       
   258 }
       
   259 
   358 
   260 void *Raytracer::raytrace_worker(void *d)
   359 void *Raytracer::raytrace_worker(void *d)
   261 {
   360 {
   262 	static const int my_queue_size = 256;
   361 	static const int my_queue_size = 256;
   263 	Raytracer *rt = (Raytracer*)d;
   362 	Raytracer *rt = (Raytracer*)d;
   264 	Sample my_queue[my_queue_size];
   363 	Sample my_queue[my_queue_size];
   265 	Colour my_colours[my_queue_size];
   364 	Colour my_colours[my_queue_size];
   266 	int my_count;
   365 	int my_count;
   267 	Ray ray;
   366 	Ray ray;
       
   367 #ifndef NO_SSE
   268 	RayPacket rays;
   368 	RayPacket rays;
   269 	const bool can_use_packets = (rt->use_packets && rt->sampler->packetableSamples());
   369 	const bool can_use_packets = (rt->use_packets && rt->sampler->packetableSamples());
       
   370 #endif
   270 	for (;;)
   371 	for (;;)
   271 	{
   372 	{
   272 		pthread_mutex_lock(&rt->sample_queue_mutex);
   373 		pthread_mutex_lock(&rt->sample_queue_mutex);
   273 		while (rt->sample_queue_count == 0)
   374 		while (rt->sample_queue_count == 0)
   274 		{
   375 		{
   304 		if (rt->sample_queue_count <= my_queue_size*2)
   405 		if (rt->sample_queue_count <= my_queue_size*2)
   305 			pthread_cond_signal(&rt->worker_ready_cond);
   406 			pthread_cond_signal(&rt->worker_ready_cond);
   306 		pthread_mutex_unlock(&rt->sample_queue_mutex);
   407 		pthread_mutex_unlock(&rt->sample_queue_mutex);
   307 
   408 
   308 		// do the work
   409 		// do the work
       
   410 #ifndef NO_SSE
   309 		if (can_use_packets)
   411 		if (can_use_packets)
   310 		{
   412 		{
   311 			// packet ray tracing
   413 			// packet ray tracing
   312 			assert((my_count % 4) == 0);
   414 			assert((my_count % 4) == 0);
   313 			for (int i = 0; i < my_count; i+=4)
   415 			for (int i = 0; i < my_count; i+=4)
   315 				rt->camera->makeRayPacket(my_queue + i, rays);
   417 				rt->camera->makeRayPacket(my_queue + i, rays);
   316 				rt->raytracePacket(rays, my_colours + i);
   418 				rt->raytracePacket(rays, my_colours + i);
   317 			}
   419 			}
   318 		}
   420 		}
   319 		else
   421 		else
       
   422 #endif
   320 		{
   423 		{
   321 			// single ray tracing
   424 			// single ray tracing
   322 			for (int i = 0; i < my_count; i++)
   425 			for (int i = 0; i < my_count; i++)
   323 			{
   426 			{
   324 				ray = rt->camera->makeRay(my_queue[i]);
   427 				ray = rt->camera->makeRay(my_queue[i]);