~zjm/Moon3D

70b961cdfbe9b5cf14422178f43f565846bd9205 — Zack Michener 5 months ago 29e79d6
add spotlight hack
7 files changed, 103 insertions(+), 28 deletions(-)

M src/3d/3d.h
M src/3d/light.c
M src/3d/light.h
M src/3d/model.c
M src/3d/model.h
M src/3d/project.c
M src/sketch.c
M src/3d/3d.h => src/3d/3d.h +12 -0
@@ 54,11 54,23 @@ typedef struct Point {
	Color color;
} Point;

typedef enum LightType {
	POINT_LIGHT, SPOT_LIGHT
} LightType;

typedef struct LightSource {
	LightType type;
	Vertex position;
	double intensity;
} LightSource;

typedef struct SpotLightSource {
	LightSource light;
	Vector direction;
	double spread;
}
SpotLightSource;

typedef struct Scene {
	Object **objects;
	LightSource **lights;

M src/3d/light.c => src/3d/light.c +37 -5
@@ 3,6 3,8 @@
#include "../arraylist.h"
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include "render.h"

static double ambient = 0.2;



@@ 16,6 18,18 @@ LightSource *PointLight(Vector position, double intensity)
	LightSource *l = malloc(sizeof(LightSource));
	l->position = position;
	l->intensity = intensity;
	l->type = POINT_LIGHT;
	return l;
}

SpotLightSource *SpotLight(Vector position, Vector direction, double spread, double intensity)
{
	SpotLightSource *l = malloc(sizeof(SpotLightSource));
	l->light.position = position;
	l->light.intensity = intensity;
	l->light.type = SPOT_LIGHT;
	l->direction = direction;
	l->spread = spread;
	return l;
}



@@ 29,14 43,32 @@ double DiffuseLight(Polygon *polygon, LightSource **lights)
	double lightAmt = 0;
	Vector n = PolygonNormal(polygon);
	for (int i = 0; i < list_count(lights); i++) {
		Vertex *v = PolygonVertex(polygon, 0);
		Vector l = VecSub(lights[i]->position, *v);
		Vector v = PolygonCenter(polygon);
		Vector l = VecSub(lights[i]->position, v);
		Vector nl = NormalizeVector(l);
		double dist = VecLen(l);
		double attenuation = fmin(1/(0.5+0.5*dist+0*dist*dist), 1);
		double incidence = DotProd(n, NormalizeVector(l));
		if (incidence > 0) {
		double attenuation = fmin(1/(0.9+0.1*dist+0.001*dist*dist), 1);
		double incidence = DotProd(n, nl);

		if (IsLit(lights[i], incidence, nl)) {
			lightAmt += attenuation*incidence*lights[i]->intensity;
		}
	}
	return lightAmt;
}

bool IsLit(LightSource *light, double incidence, Vector l)
{
	if (incidence < 0) {
		return false;
	}

	if (light->type == SPOT_LIGHT) {
		SpotLightSource *spotlight = (SpotLightSource *)light;
		if (DotProd(spotlight->direction, NegVec(l)) < 1 - spotlight->spread) {
			return false;
		}
	}

	return true;
}

M src/3d/light.h => src/3d/light.h +2 -0
@@ 5,5 5,7 @@

void AmbientLight(double amb);
LightSource *PointLight(Vector position, double intensity);
SpotLightSource *SpotLight(Vector position, Vector direction, double spread, double intensity);
double LightPolygon(Polygon *polygon, Color color, double glow, LightSource **lights);
double DiffuseLight(Polygon *polygon, LightSource **lights);
bool IsLit(LightSource *light, double incidence, Vector l);

M src/3d/model.c => src/3d/model.c +26 -0
@@ 101,6 101,20 @@ Vertex *PolygonVertex(Polygon *polygon, int i)
	return polygon->vertices[polygon->vList[index]];
}

Vector PolygonCenter(Polygon *polygon)
{
	double x = 0, y = 0, z = 0;
	int n = NumVertices(polygon);
	for (int i = 0; i < n; i++) {
		Vertex *v = PolygonVertex(polygon, i);
		x += v->x;
		y += v->y;
		z += v->z;
	}

	return V(x/n, y/n, z/n);
}

int NumVertices(Polygon *polygon)
{
	return list_count(polygon->vList);


@@ 207,6 221,18 @@ Object *NewCube(Color color)
	return NewObject(geometry, color);
}

Object *NewGround(void)
{
	Mesh *geom = NewMesh();
	Polygon *ground = NewPolygon();
	AddVertex(ground, NewVector(1000, -1, 1000));
	AddVertex(ground, NewVector(1000, -1, -1000));
	AddVertex(ground, NewVector(-1000, -1, -1000));
	AddVertex(ground, NewVector(-1000, -1, 1000));
	AddFacet(geom, ground);
	return NewObject(geom, GRAY);
}

Point *NewPoint(Vector position, Color color)
{
	Point *p = malloc(sizeof(Point));

M src/3d/model.h => src/3d/model.h +2 -0
@@ 12,6 12,7 @@ void AddVertex(Polygon *polygon, Vertex *vertex);
Polygon *FromPolygon(Polygon *polygon, Transform transform);
Polygon *CopyPolygon(Polygon *polygon);
Vertex *PolygonVertex(Polygon *polygon, int i);
Vector PolygonCenter(Polygon *polygon);
int NumVertices(Polygon *polygon);
Vector PolygonNormal(Polygon *polygon);
void HomogenizePolygon(Polygon *polygon);


@@ 26,6 27,7 @@ Point *NewPoint(Vector position, Color color);

Object *NewObject(Mesh *geom, Color color);
Object *NewCube(Color color);
Object *NewGround(void);

void RotateObj(Object *obj, double rx, double ry, double rz);
void ScaleObj(Object *obj, double sx, double sy, double sz);

M src/3d/project.c => src/3d/project.c +6 -5
@@ 66,9 66,10 @@ void MoveCamera(Vector dv)

void RotateCamera(double rx, double ry, double rz)
{
	camera->direction = ApplyTransform(RotationX(rx), camera->direction);
	camera->direction = ApplyTransform(RotationY(ry), camera->direction);
	camera->direction = ApplyTransform(RotationZ(rz), camera->direction);
	Transform t = RotationX(rx);
	AddTransform(RotationY(ry), &t);
	AddTransform(RotationZ(rz), &t);
	camera->direction = NormalizeVector(ApplyTransform(t, camera->direction));
}

void PlaceCamera(Vector p)


@@ 81,8 82,8 @@ Transform AlignCameraToAxis(void)
{
	Vector Rx, Ry, Rz;
	Transform op = Identity();
	Rz = NormalizeVector(NegVec(camera->direction));
	Rx = NormalizeVector(CrossProd(camera->up, NegVec(camera->direction)));
	Rz = NegVec(camera->direction);
	Rx = CrossProd(camera->up, NegVec(camera->direction));
	Ry = CrossProd(Rz, Rx);
	op.m[0][0] = Rx.x;
	op.m[0][1] = Rx.y;

M src/sketch.c => src/sketch.c +18 -18
@@ 9,44 9,40 @@
#include <math.h>
#include "arraylist.h"

Polygon *ground;
Object *ground;
int debounce = 0;

bool dither = false;
Object *masterCube;

Point **stars = NULL;

Scene *scene;

int now, lastTime;
SpotLightSource *flashlight;

void sketch_setup(Pixel *pixels)
{
	scene = NewScene();
	// LightSource *zlight = DirectionLight(V(0, 0, -1), 1);
	// AddLight(scene, zlight);
	LightSource *sun = PointLight(V(0, 2, 0), 1);
	AddLight(scene, sun);
	AmbientLight(0.1);
	LightSource *cubeLight = PointLight(V(0, 2, 0), 1);
	AddLight(scene, cubeLight);

	ground = NewPolygon();
	AddVertex(ground, NewVector(1000, -1, 1000));
	AddVertex(ground, NewVector(1000, -1, -1000));
	AddVertex(ground, NewVector(-1000, -1, -1000));
	AddVertex(ground, NewVector(-1000, -1, 1000));
	AddObject(scene, NewGround());

	SetViewport(pixels, BLACK, 400, 240);
	// ShowZBuffer();
	// ShowWireframes();
	SetCamera(V(-100, 0, 6));
	SetCamera(V(0, 0, 6));
	LookAt(V(0, 0, 0));
	SetPerspective(60, 400/240.f, 1, 100);
	// SetOrtho(Vol(-5, 5, -5, 5, -10, 0.1));

	flashlight = SpotLight(CameraPosition(), CameraDirection(), 0.1, 0);
	AddLight(scene, (LightSource *)flashlight);

	for (int i = 0; i < 500; i++) {
		Object *cube = NewCube(WHITE);
		RotateObj(cube, 0, rand() % 360, 0);

		int azimuth = rand() % 360;
		int dist = rand() % 100+10;
		double x = dist*cos(Rad(azimuth));


@@ 84,9 80,8 @@ void sketch_draw(long ticks)
	ClearViewport();

	RotateObj(masterCube, 0, 0.01*dt, 0);
	RotateObj(masterCube, 0.01*dt, 0, 0);

	// DrawAxes();
	DrawPolygon(ground, GRAY);
	RenderScene(scene);

	for (int i = 0; i < list_count(stars); i++) {


@@ 102,19 97,24 @@ void sketch_input(InputState input)
{
	if (KeyPressed(input, KEY_LEFT)) {
		RotateCamera(0, 5, 0);
		flashlight->direction = CameraDirection();
	}
	if (KeyPressed(input, KEY_RIGHT)) {
		RotateCamera(0, -5, 0);
		flashlight->direction = CameraDirection();
	}
	if (KeyPressed(input, KEY_FWD)) {
		MoveCamera(VecMul(CameraDirection(), 0.5));
		((LightSource *)flashlight)->position = CameraPosition();
	}
	if (KeyPressed(input, KEY_BACK)) {
		MoveCamera(VecMul(CameraDirection(), -0.5));
		((LightSource *)flashlight)->position = CameraPosition();
	}
	if (debounce == 0 && KeyPressed(input, KEY_JUMP)) {
		debounce = 5;
		dither = !dither;
		debounce = 10;
		// dither = !dither;
		((LightSource *)flashlight)->intensity = (((LightSource *)flashlight)->intensity) ? 0 : 0.5;
	}

	if (debounce > 0) debounce--;