include/material.h
author Radek Brich <radek.brich@devl.cz>
Mon, 19 May 2008 22:59:04 +0200
branchpyrit
changeset 98 64638385798a
parent 96 9eb71e76c7fd
permissions -rw-r--r--
add sections about demos to README update doxygen comments

/**
 * @file  material.h
 * @brief Material and Texture classes
 *
 * This file is part of Pyrit Ray Tracer.
 *
 * Copyright 2006, 2007, 2008  Radek Brich
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef MATERIAL_H
#define MATERIAL_H

#include "common.h"
#include "vector.h"
#include "pixmap.h"

/**
 * perlin noise
 */
Float perlin(Float x, Float y, Float z);

/**
 * general texture
 */
class Texture
{
public:
	virtual ~Texture() {};

	/** evaluate texture colour in the point of space */
	virtual Colour evaluate(const Vector &point) = 0;
};

/**
 * general colour map
 */
class ColourMap
{
public:
	virtual ~ColourMap() {};

	/** map float value to colour */
	virtual Colour map(const Float &val) = 0;
};

/**
 * linear colour map
 * maps value lineary between two colours
 */
class LinearColourMap: public ColourMap
{
	Colour col, cdiff;
public:
	LinearColourMap(const Colour &clow, const Colour &chigh):
		col(clow), cdiff(chigh-clow) {};
	Colour map(const Float &val) { return col + cdiff*val; };
};

/**
 * bound colour map
 * initialize with two arrays, bounds and colours, of same size
 * bounds must contain numbers between 0 and 1 in rising order,
 * last number should be larger than max 'val'
 * colours are mapped to slices between bounds (with zero being
 * implicit bottom bound)
 */
class BoundColourMap: public ColourMap
{
	Float *bounds;
	Colour *colours;
public:
	BoundColourMap(Float *abounds, Colour *acolours):
		bounds(abounds), colours(acolours) {};
	Colour map(const Float &val)
	{
		Float *b = bounds;
		Colour *c = colours;
		while (val > *b)
		{
			b++;
			c++;
		}
		return *c;
	};
};

/**
 * general texture mapping
 */
class TextureMap
{
protected:
	Vector center;
	Float invsize;
public:
	/**
	 * texture map constructor
	 * @param[in] acenter  central point of texture mapping
	 * @param[in] size     Size of the texture.
	 *                     One world space unit is mapped to one texture size
	 *                     divided by this number.
	 */
	TextureMap(const Vector &acenter, const Float &size):
		center(acenter), invsize(1.0f/size) {};
	virtual ~TextureMap() {};

	/**
	 * map 3D space point to 2D u,v coordinates
	 * @param[in] point  a point in 3D space
	 * @param[out] u     horizontal texture coordinate
	 * @param[out] v     vertical texture coordinate
	 */
	virtual void map(const Vector &point, Float &u, Float &v) const = 0;
};

/**
 * planar mapping
 */
class PlanarMap: public TextureMap
{
public:
	PlanarMap(const Vector &acenter, const Float &size):
		TextureMap(acenter, size) {};
	void map(const Vector &point, Float &u, Float &v) const
	{
		const Vector p = point - center;
		u = p.x*invsize;
		v = p.y*invsize;
	};
};

/**
 * cubic mapping
 */
class CubicMap: public TextureMap
{
public:
	CubicMap(const Vector &acenter, const Float &size):
		TextureMap(acenter, size) {};
	void map(const Vector &point, Float &u, Float &v) const
	{
		const Vector p = point - center;
		if (fabs(p.x) > fabs(p.y))
		{
			if (fabs(p.x) > fabs(p.z))
			{
				if (p.x < 0)
					u = -p.y;
				else
					u = p.y;
				v = p.z;
			}
			else
			{
				if (p.z < 0)
					u = -p.x;
				else
					u = p.x;
				v = p.y;
			}
		}
		else
		{
			if (fabs(p.y) > fabs(p.z))
			{
				if (p.y < 0)
					u = -p.x;
				else
					u = p.x;
				v = p.z;
			}
			else
			{
				if (p.z < 0)
					u = -p.x;
				else
					u = p.x;
				v = p.y;
			}
		}
		u = u*invsize;
		v = v*invsize;
	};
};

/**
 * cylindrical mapping
 */
class CylinderMap: public TextureMap
{
public:
	CylinderMap(const Vector &acenter, const Float &size):
		TextureMap(acenter, size) {};
	void map(const Vector &point, Float &u, Float &v) const
	{
		const Vector p = point - center;
		u = ( PI + atan2(p.z, p.x) ) * invsize;
		v = p.y * invsize;
	};
};

/**
 * spherical mapping
 */
class SphereMap: public TextureMap
{
public:
	SphereMap(const Vector &acenter, const Float &size):
		TextureMap(acenter, size) {};
	void map(const Vector &point, Float &u, Float &v) const
	{
		const Vector p = point - center;
		u = ( PI + atan2(p.z, p.x) ) * invsize;
		v = acos(p.y / p.mag()) * invsize;
	};
};

/**
 * general 2D texture
 */
class Texture2D: public Texture
{
protected:
	const TextureMap *map;
public:
	Texture2D(const TextureMap *amap): map(amap) {};
};

/**
 * 2D image texture
 */
class ImageTexture: public Texture2D
{
	const Pixmap *pixmap;
public:
	ImageTexture(const TextureMap *tmap, const Pixmap *image):
		Texture2D(tmap), pixmap(image) {};
	Colour evaluate(const Vector &point)
	{
		Float u,v;
		map->map(point, u,v);
		u = u - 0.5f;
		u -= floor(u);
		v = -(v - 0.5f);
		v -= floor(v);
		return pixmap->get((int)(u*pixmap->getWidth()), (int)(v*pixmap->getHeight()));
	};
};

/**
 * 2D checkers texture
 */
class CheckersTexture: public Texture2D
{
	ColourMap *colourmap;
public:
	CheckersTexture(TextureMap *tmap, ColourMap *cmap):
		Texture2D(tmap), colourmap(cmap) {};
	Colour evaluate(const Vector &point)
	{
		Float u,v, val;
		map->map(point, u,v);
		val = 0.5f*(floor(0.5f + u - floor(u)) + floor(0.5f + v - floor(v)));
		return colourmap->map(val);
	};
};

/**
 * 3D perlin cloud texture
 */
class CloudTexture: public Texture
{
	ColourMap *colourmap;
	Float detail;
public:
	CloudTexture(const Float &adetail, ColourMap *cmap):
		colourmap(cmap), detail(adetail) {};
	Colour evaluate(const Vector &point)
	{
		Float sum = 0.0;
		for (int i = 1; i < detail; i++)
			sum += fabs(perlin(point.x*i, point.y*i, point.z*i))/i;
		//Float value = sinf(point.x + sum)/2 + 0.5;
		return colourmap->map(sum);
	};
};

/**
 * material
 */
class Material
{
public:
	Colour colour;
	Texture *texture;
	Float ambient, diffuse, specular, shininess; // Phong constants
	Float reflectivity; // how much reflective is the surface
	Float transmissivity, refract_index; // part of light which can be refracted; index of refraction
	int smooth; // triangle smoothing

	Material(const Colour &acolour): colour(acolour), texture(NULL), smooth(false)
	{
		ambient = 0.2f;
		diffuse = 0.8f;
		specular = 0.2f;
		shininess = 0.5f;
		reflectivity = 0.2f;
		transmissivity = 0.0f;
		refract_index = 1.3f;
	}

	/** set Phong parameters */
	void setPhong(const Float amb, const Float dif, const Float spec, const Float shin)
		{ ambient = amb; diffuse = dif; specular = spec; shininess = shin; };

	/** set fraction of light to be reflected */
	void setReflectivity(const Float refl) { reflectivity = refl; };

	/** set fraction of light to be refracted
	 * @param[in] trans  the transmissivity amount
	 * @param[in] rinde  index of refraction
	 */
	void setTransmissivity(const Float trans, const Float rindex)
		{ transmissivity = trans; refract_index = rindex; };

	/** allow triangle smoothing */
	void setSmooth(int sm) { smooth = sm; };

	/** set the texture */
	void setTexture(Texture *tex) { texture = tex; };
};

#endif