当前位置: 首页 > 工具软件 > blur_comment > 使用案例 >

Example 3 : motion blur And Shade(Shadow)

公良安邦
2023-12-01

下面是main.c

#include <stdio.h>
#include <math.h>

#include <il/il.h>
#pragma comment(lib,"DevIL.lib")
#pragma comment(lib,"ILU.lib")
#pragma comment(lib,"ILUT.lib")



#include "vec3.h"
#include "sample.h"
#include "shapes.h"

#define IMAGE_WIDTH		512
#define IMAGE_HEIGHT	384
#define NUM_SAMPLES		16

shape_t shapes[4];
light_t lights[1];

unsigned char floattochar(float c)
{
	int i = (int)c;
	if (i <= 0)
		return 0;
	if (i >= 255)
		return 255;
	else
		return (unsigned char)(c);
}

int main(int argc, int argv)
{
	int r, c, s;
	float x_samples[NUM_SAMPLES];
	float y_samples[NUM_SAMPLES];
	float t_samples[NUM_SAMPLES];
	unsigned char image[IMAGE_WIDTH * IMAGE_HEIGHT * 3];
	float aspect;
	vec3 total, color, hitpos;

	vec3 start, dir;
	hit_t hit;

	ILuint iname;

	ilInit();
	ilEnable(IL_FILE_OVERWRITE);

	aspect = (float) IMAGE_HEIGHT / (float)IMAGE_WIDTH;
	VectorSet(dir, 0, 0, -1);

	shapes[0].type = SHAPE_SPHERE;
	VectorSet(shapes[0].sphere.center, -0.3f, 0.3f, -2);
	shapes[0].sphere.radius = 0.25f;
	VectorSet(shapes[0].move_velocity, 0, -0.05f, 0);
	VectorSet(shapes[0].color, 1, 0, 0);

	shapes[1].type = SHAPE_SPHERE;
	VectorSet(shapes[1].sphere.center, 0.3f, 0.3f, -4);
	shapes[1].sphere.radius = 0.25f;
	VectorSet(shapes[1].move_velocity, 0.1f, 0, 0);
	VectorSet(shapes[1].color, 0, 1, 0);

	shapes[2].type = SHAPE_TRI;
	VectorSet(shapes[2].tri.verts[0], -0.9f, -0.5f,0);
	VectorSet(shapes[2].tri.verts[1], 0, 0, -6);
	VectorSet(shapes[2].tri.verts[2], 0.9f, -0.5f, 0);
	VectorSet(shapes[2].move_velocity, 0, 0, 0);
	VectorSet(shapes[2].color, 1, 1, 1);

	shapes[3].type = SHAPE_TRI;
	VectorSet(shapes[3].tri.verts[2], -0.3f, 0.2f, -5);
	VectorSet(shapes[3].tri.verts[1], 0.2f, 0.0f, -1);
	VectorSet(shapes[3].tri.verts[0], 0.3f, 0.6f, -2);
	VectorSet(shapes[3].move_velocity, 0, 0, 0.6f);
	VectorSet(shapes[3].color, 1, 1, 0);


	VectorSet(lights[0].ambient, 0.1f, 0.1f, 0.1f);
	VectorSet(lights[0].diffuse, 1, 1, 1);
	VectorSet(lights[0].specular, 0.1f, 0.1f, 0.1f);
	VectorSet(lights[0].pos, 0, 2, -2);



	for (r=0; r<IMAGE_HEIGHT; r++)
	{
		for (c=0; c<IMAGE_WIDTH; c++)
		{
			sample_multi_jitter_2d(NUM_SAMPLES, x_samples, y_samples);
			filter_cubic(NUM_SAMPLES, x_samples);
			filter_cubic(NUM_SAMPLES, y_samples);

			sample_jitter_1d(NUM_SAMPLES, t_samples);
			filter_cubic(NUM_SAMPLES, t_samples);
			sample_shuffle(NUM_SAMPLES, t_samples);


			VectorSet(total, 0, 0, 0);

			// 一个pixel中的Num_Samples
			for (s=0; s<NUM_SAMPLES; s++)
			{
				// 理解,下面可以理解为,
				// 640 / 480 = 1 / x  --> x = 480 / 640

				// 就是把屏幕宽度 映射到 [-1, 1], 
				// 那么,对应的屏幕高度就要映射到 [-1 * aspect(480 / 640), 1 * aspect(480 / 640)]
				start[0] = ((c + x_samples[s]) / (IMAGE_WIDTH/2)) - 1;
				// 注意 aspect = (float) IMAGE_HEIGHT / (float)IMAGE_WIDTH;
				start[1] = (((r + y_samples[s]) / (IMAGE_HEIGHT/2)) - 1)*aspect;

				start[2] = 0;
				// 1个pixel 就会执行NUM_SAMPLES次,NUM_SAMPLES次ray来确定1个pixel的颜色
				if (shape_intersect_all(start, dir, t_samples[s], &hit))
				{
					// 计算在shape上被射线击中的点,hitpos
					VectorMA(start, hit.t, dir, hitpos);
					// 阴影
					shape_shade(hit.shape, hitpos, t_samples[s], color);

					VectorAdd(total, color, total);
				}

				else
				{
					total[0] += 0.2f;
					total[1] += 0.2f;
					total[2] += 0.2f;
				}
			}

			// 这里平均颜色
			VectorScale(total, 255.0f / NUM_SAMPLES, total);
			image[(r*IMAGE_WIDTH + c)*3 + 0] = floattochar(total[0]);
			image[(r*IMAGE_WIDTH + c)*3 + 1] = floattochar(total[1]);
			image[(r*IMAGE_WIDTH + c)*3 + 2] = floattochar(total[2]);
		}
	}

	/* write the image */
	ilGenImages(1, &iname);
	ilBindImage(iname);

	ilTexImage(IMAGE_WIDTH, IMAGE_HEIGHT, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, image);

	ilSaveImage("out.png");
	ilDeleteImages(1, &iname);


	return 0;
}

1. 运动模糊 的主要思想

motion blur created by generating rays with different times. Spheres have center positions that vary with time. The sphere on the lower left is stationary and the rest have varying velocities.

Sphere:

int shape_intersect_sphere(shape_t *s, vec3 start, vec3 dir, float time, hit_t *h)
{
	vec3 temp, center;
	double a, b, c, discriminant, t;

	<span style="color:#ff0000;">VectorMA(s->sphere.center, time, s->move_velocity, center);</span>
	VectorSub(start, center, temp);
	a = DotProduct(dir, dir);
	b = 2*DotProduct(dir, temp);
	c = DotProduct(temp, temp) - s->sphere.radius*s->sphere.radius;
	discriminant = b*b - 4*a*c;

	// first check to see if ray intersects sphere
	if (discriminant > 0)
	{
		discriminant = sqrt(discriminant);
		t = (-b - discriminant) / (2*a);

		// now check for valid interval
		if (t < 0)
			t = (- b + discriminant) / (2*a);

		if (t < 0)
			return 0;


		// we have a valid hit
		h->t = (float)t;
		h->shape = s;
		return 1;
	}

	return 0;
}


Triangle:

int shape_intersect_tri(shape_t *s, vec3 start, vec3 dir, float time, hit_t *h)
{
	tri_t *tri = &s->tri;
	float beta, gamma, tval;
	float EIHF, GFDI, DHEG, denom;
	float AKJB, JCAL, BLKC;

	float A = tri->verts[0][0] - tri->verts[1][0];
	float B = tri->verts[0][1] - tri->verts[1][1];
	float C = tri->verts[0][2] - tri->verts[1][2];
	float D = tri->verts[0][0] - tri->verts[2][0];
	float E = tri->verts[0][1] - tri->verts[2][1];
	float F = tri->verts[0][2] - tri->verts[2][2];
	float G = dir[0];
	float H = dir[1];
	float I = dir[2];
	<span style="color:#ff0000;">float J = tri->verts[0][0] - start[0] + s->move_velocity[0]*time;
	float K = tri->verts[0][1] - start[1] + s->move_velocity[1]*time;
	float L = tri->verts[0][2] - start[2] + s->move_velocity[2]*time;</span>


	EIHF = E*I-H*F;
	GFDI = G*F-D*I;
	DHEG = D*H-E*G;
	denom = (A*EIHF + B*GFDI + C*DHEG);

	beta = (J*EIHF + K*GFDI + L*DHEG) / denom;
	if (beta <= 0.0f || beta >= 1.0f)
		return 0;

	AKJB = A*K - J*B;
	JCAL = J*C - A*L;
	BLKC = B*L - K*C;

	gamma = (I*AKJB + H*JCAL + G*BLKC)/denom;
	if ((gamma <= 0.0f) || ((beta + gamma) >= 1.0f))
		return 0;

	tval = -(F*AKJB + E*JCAL + D*BLKC) / denom;

	if (tval < 0)
		return 0;

	h->shape = s;
	h->t = tval;
	return 1;
}


2. Shadow 的主要思想:

举Triangle为例,开始,如果ray hit Triangle, 就可以确定hitPoint, 那么,计算Triangle normal, 就以hitPoint为起点,normal为方向,移动小小距离,确定为hitPoint2点,利用hitPoint2 为起点,hitPoint2  指向 light pos为方向确定一条射线,如果这条射线在未到light pos之前射到东西,就表示了,这个hitPoint是有阴影的。(为什么要hitPoint2, 是因为担心,以hitPoint为起点的时候,射线碰到的当前的trianle)

void shape_light_point(vec3 v, vec3 norm, float time, vec3 color)
{
	int i;
	float dist, intensity;
	vec3 dir;
	hit_t hit;

	VectorSet(color, 0, 0, 0);

	for (i=0; i<1; i++)
	{
		VectorSub(lights[i].pos, v, dir);
		dist = VectorNormalize(dir);
		// 注意,这里是没有intersect的话,才算光的颜色到这个pixel上
		if (!shape_intersect_all(v, dir, time, &hit) || (hit.t > dist))
		{
			intensity = 4 * DotProduct(norm, dir) / (float)sqrt(dist);
			VectorMA(color, intensity, lights[i].diffuse, color);
		}
		// 环境光
		VectorAdd(color, lights[i].ambient, color);
	}
}


 类似资料: