replace Plane with axis-aligned Box (because infinite Plane is not usable with kd-tree) pyrit
authorRadek Brich <radek.brich@devl.cz>
Sun, 25 Nov 2007 15:50:01 +0100
branchpyrit
changeset 14 fc18ac4833f2
parent 13 fbd1d2f7d94e
child 15 a0a3e334744f
replace Plane with axis-aligned Box (because infinite Plane is not usable with kd-tree) fix memory leak in KdTree::nearest_intersection rename BBox::R to BBox::H new file: common.h (Eps and Inf constants)
Makefile
README
TODO
demos/demo.py
demos/spheres_ao.py
demos/spheres_shadow.py
src/kdtree.cc
src/raytracer.cc
src/raytracermodule.cc
src/scene.cc
src/scene.h
src/vector.h
--- a/Makefile	Sat Nov 24 23:55:54 2007 +0100
+++ b/Makefile	Sun Nov 25 15:50:01 2007 +0100
@@ -45,7 +45,7 @@
 vector.o: src/vector.cc src/vector.h
 matrix.o: src/matrix.cc src/matrix.h src/vector.h
 noise.o: src/noise.cc src/noise.h
-scene.o: src/scene.cc src/scene.h src/vector.h src/noise.h
+scene.o: src/scene.cc src/scene.h src/vector.h src/noise.h src/common.h
 kdtree.o: src/kdtree.cc src/kdtree.h
 raytracer.o: src/raytracer.cc src/raytracer.h src/scene.h src/vector.h src/noise.h
 
--- a/README	Sat Nov 24 23:55:54 2007 +0100
+++ b/README	Sun Nov 25 15:50:01 2007 +0100
@@ -2,6 +2,11 @@
  Pyrit Ray Tracer
 ==================
 
+License
+-------
+Currently unlicensed, you may not redistribute or use this work for any purposes.
+Will be MIT licensed when ready.
+
 Pthreads
 --------
 Threads can be used to render rows of picture paralelly. Arbitrary number
--- a/TODO	Sat Nov 24 23:55:54 2007 +0100
+++ b/TODO	Sun Nov 25 15:50:01 2007 +0100
@@ -5,10 +5,10 @@
  * update Python binding, new classes
  * rename:
    - Ray.a -> Ray.o or Ray.origin
-   - BBox.R -> H
  * C++ demos
  * more complex demos
 
+
 New Classes?
 ============
 
--- a/demos/demo.py	Sat Nov 24 23:55:54 2007 +0100
+++ b/demos/demo.py	Sun Nov 25 15:50:01 2007 +0100
@@ -3,7 +3,7 @@
 import sys
 sys.path.append("..")
 
-from raytracer import Raytracer, Material, Plane, Sphere, Light
+from raytracer import Raytracer, Material, Box, Sphere, Light
 #, SphericalLight
 import Image
 
@@ -17,8 +17,8 @@
 rt.addlight(light2)
 
 mat0 = Material(colour=(0.1, 0.2, 0.9))
-plane = Plane(normal=(0.0, 1.0, 0.0), d=1.0, material=mat0)
-rt.addshape(plane)
+box = Box(L=(-20.0, -1.2, -20.0), H=(20.0, -1.0, 20.0), material=mat0)
+rt.addshape(box)
 
 mat1 = Material(colour=(1.0, 0.2, 0.1))
 bigsphere = Sphere(centre=(2.0, 2.0, 5.0), radius=2.5, material=mat1)
@@ -42,4 +42,4 @@
 rendersize = (800, 600)
 data = rt.render(rendersize)
 img = Image.fromstring("RGB", rendersize, data)
-img.save('out.png')
+img.save('demo.png')
--- a/demos/spheres_ao.py	Sat Nov 24 23:55:54 2007 +0100
+++ b/demos/spheres_ao.py	Sun Nov 25 15:50:01 2007 +0100
@@ -3,7 +3,7 @@
 import sys
 sys.path.append("..")
 
-from raytracer import Raytracer, Material, Plane, Sphere, Light
+from raytracer import Raytracer, Material, Box, Sphere, Light
 import Image
 
 rt = Raytracer()
@@ -19,8 +19,8 @@
 
 mat0 = Material(colour=(0.7, 0.7, 0.7))
 
-plane = Plane(normal=(0.0, 1.0, 0.0), d=1.0, material=mat0)
-rt.addshape(plane)
+box = Box(L=(-20.0, -1.2, -20.0), H=(20.0, -1.0, 20.0), material=mat0)
+rt.addshape(box)
 
 mat1 = Material(colour=(1.0, 0.0, 0.0))
 bigsphere = Sphere(centre=(3.0, 2.0, 7.0), radius=3.0, material=mat1)
--- a/demos/spheres_shadow.py	Sat Nov 24 23:55:54 2007 +0100
+++ b/demos/spheres_shadow.py	Sun Nov 25 15:50:01 2007 +0100
@@ -3,7 +3,7 @@
 import sys
 sys.path.append("..")
 
-from raytracer import Raytracer, Material, Plane, Sphere, Light
+from raytracer import Raytracer, Material, Box, Sphere, Light
 import Image
 
 rt = Raytracer()
@@ -16,8 +16,8 @@
 
 mat0 = Material(colour=(0.7, 0.7, 0.7))
 
-plane = Plane(normal=(0.0, 1.0, 0.0), d=1.0, material=mat0)
-rt.addshape(plane)
+box = Box(L=(-20.0, -1.2, -20.0), H=(20.0, -1.0, 20.0), material=mat0)
+rt.addshape(box)
 
 mat1 = Material(colour=(1.0, 0.0, 0.0))
 bigsphere = Sphere(centre=(3.0, 2.0, 7.0), radius=3.0, material=mat1)
--- a/src/kdtree.cc	Sat Nov 24 23:55:54 2007 +0100
+++ b/src/kdtree.cc	Sun Nov 25 15:50:01 2007 +0100
@@ -70,9 +70,9 @@
 		if (shapebb.L.x < bbox.L.x)  bbox.L.x = shapebb.L.x;
 		if (shapebb.L.y < bbox.L.y)  bbox.L.y = shapebb.L.y;
 		if (shapebb.L.z < bbox.L.z)  bbox.L.z = shapebb.L.z;
-		if (shapebb.R.x > bbox.R.x)  bbox.R.x = shapebb.R.x;
-		if (shapebb.R.y > bbox.R.y)  bbox.R.y = shapebb.R.y;
-		if (shapebb.R.z > bbox.R.z)  bbox.R.z = shapebb.R.z;
+		if (shapebb.H.x > bbox.H.x)  bbox.H.x = shapebb.H.x;
+		if (shapebb.H.y > bbox.H.y)  bbox.H.y = shapebb.H.y;
+		if (shapebb.H.z > bbox.H.z)  bbox.H.z = shapebb.H.z;
 	}
 };
 
@@ -112,7 +112,7 @@
 	for (sh = sslist.begin(); sh != sslist.end(); sh++)
 	{
 		splitlist.push_back(SplitPos(sh->bbox.L.cell[axis]));
-		splitlist.push_back(SplitPos(sh->bbox.R.cell[axis]));
+		splitlist.push_back(SplitPos(sh->bbox.H.cell[axis]));
 	}
 	sort(splitlist.begin(), splitlist.end());
 	// remove duplicate splits
@@ -131,9 +131,9 @@
 				continue;
 			}
 			// if shape is completely contained in split plane
-			if (spl->pos == sh->bbox.L.cell[axis] == sh->bbox.R.cell[axis])
+			if (spl->pos == sh->bbox.L.cell[axis] == sh->bbox.H.cell[axis])
 			{
-				if (spl->pos - bbox.L.cell[axis] < bbox.R.cell[axis] - spl->pos)
+				if (spl->pos - bbox.L.cell[axis] < bbox.H.cell[axis] - spl->pos)
 				{
 					// left subcell is smaller -> if not empty, put shape here
 					if (spl->lnum)
@@ -150,13 +150,13 @@
 				sh->setMark();
 			} else
 			// if shape is on left side of split plane
-			if (sh->bbox.R.cell[axis] <= spl->pos)
+			if (sh->bbox.H.cell[axis] <= spl->pos)
 			{
 				spl->lnum++;
 				sh->setMark();
 			} else
 			// if shape occupies both sides of split plane
-			if (sh->bbox.L.cell[axis] < spl->pos && sh->bbox.R.cell[axis] > spl->pos)
+			if (sh->bbox.L.cell[axis] < spl->pos && sh->bbox.H.cell[axis] > spl->pos)
 			{
 				spl->lnum++;
 				spl->rnum++;
@@ -181,7 +181,7 @@
 	for (spl = splitlist.begin(); spl != splitlist.end(); spl++)
 	{
 		// calculate SAH cost of this split
-		lbb.R.cell[axis] = spl->pos;
+		lbb.H.cell[axis] = spl->pos;
 		rbb.L.cell[axis] = spl->pos;
 		float SAL = 2*(lbb.w()*lbb.h() + lbb.w()*lbb.d() + lbb.h()*lbb.d());
 		float SAR = 2*(rbb.w()*rbb.h() + rbb.w()*rbb.d() + rbb.h()*rbb.d());
@@ -209,12 +209,12 @@
 	v.cell[(axis+2)%3] = bbox.L.cell[(axis+2)%3];
 	F << "v " << v.x << " " << v.y << " " << v.z << endl;
 	v.cell[(axis+1)%3] = bbox.L.cell[(axis+1)%3];
-	v.cell[(axis+2)%3] = bbox.R.cell[(axis+2)%3];
+	v.cell[(axis+2)%3] = bbox.H.cell[(axis+2)%3];
 	F << "v " << v.x << " " << v.y << " " << v.z << endl;
-	v.cell[(axis+1)%3] = bbox.R.cell[(axis+1)%3];
-	v.cell[(axis+2)%3] = bbox.R.cell[(axis+2)%3];
+	v.cell[(axis+1)%3] = bbox.H.cell[(axis+1)%3];
+	v.cell[(axis+2)%3] = bbox.H.cell[(axis+2)%3];
 	F << "v " << v.x << " " << v.y << " " << v.z << endl;
-	v.cell[(axis+1)%3] = bbox.R.cell[(axis+1)%3];
+	v.cell[(axis+1)%3] = bbox.H.cell[(axis+1)%3];
 	v.cell[(axis+2)%3] = bbox.L.cell[(axis+2)%3];
 	F << "v " << v.x << " " << v.y << " " << v.z << endl;
 	F << "f " << f+1 << " " << f+2 << " " << f+3 << " " << f+4 << endl;
@@ -238,11 +238,11 @@
 		}
 		if (state == 0)
 		{
-			if (sh->bbox.R.cell[axis] < split)
+			if (sh->bbox.H.cell[axis] < split)
 			{ // left
 				children[0].addShape(sh->shape);
 			} else
-			if (sh->bbox.R.cell[axis] > split)
+			if (sh->bbox.H.cell[axis] > split)
 			{
 				if (sh->bbox.L.cell[axis] < split)
 				{ // both
@@ -254,13 +254,13 @@
 					state = 1;
 				}
 			} else
-			{ // R == split
+			{ // H == split
 				if (sh->bbox.L.cell[axis] < split)
 				{ // left
 					children[0].addShape(sh->shape);
 				} else
 				{ // contained
-					if (split - bbox.L.cell[axis] < bbox.R.cell[axis] - split)
+					if (split - bbox.L.cell[axis] < bbox.H.cell[axis] - split)
 					{
 						// left subcell is smaller -> if not empty, put shape here
 						if (lnum)
@@ -279,7 +279,7 @@
 		}
 	}
 
-	lbb.R.cell[axis] = split;
+	lbb.H.cell[axis] = split;
 	rbb.L.cell[axis] = split;
 
 	children[0].subdivide(lbb, depth+1);
@@ -406,6 +406,7 @@
 		}
 
 		/* pop from the stack */
+		delete enPt;
 		enPt = exPt; /* the signed distance intervals are adjacent */
 
 		/* retrieve the pointer to the next node, it is possible that ray traversal terminates */
@@ -416,6 +417,8 @@
 		st.pop();
 	} /* while */
 
+	delete enPt;
+
 	/* ray leaves the scene */
 	return NULL;
 }
--- a/src/raytracer.cc	Sat Nov 24 23:55:54 2007 +0100
+++ b/src/raytracer.cc	Sun Nov 25 15:50:01 2007 +0100
@@ -11,7 +11,7 @@
 
 #include <stdio.h>
 #include <malloc.h>
-#include <float.h>
+#include "common.h"
 #include "raytracer.h"
 
 // Hammersley spherical point distribution
--- a/src/raytracermodule.cc	Sat Nov 24 23:55:54 2007 +0100
+++ b/src/raytracermodule.cc	Sun Nov 25 15:50:01 2007 +0100
@@ -224,27 +224,27 @@
 	return Py_FindMethod(SphereMethods, self, name);
 }
 
-//=========================== Plane Object ===========================
+//=========================== Box Object ===========================
 
 typedef struct {
 	PyObject_HEAD
-	Plane *shape;
-} PlaneObject;
+	Box *shape;
+} BoxObject;
 
-static PyObject *Plane_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
-static void Plane_Destructor(PyObject* self);
-static PyObject *Plane_Getattr(PyObject *self, char *name);
+static PyObject *Box_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+static void Box_Destructor(PyObject* self);
+static PyObject *Box_Getattr(PyObject *self, char *name);
 
-static PyTypeObject PlaneType = {
+static PyTypeObject BoxType = {
 	PyObject_HEAD_INIT(NULL)
 	0,				/*ob_size*/
-	"Plane",			/*tp_name*/
-	sizeof(PlaneObject),		/*tp_basicsize*/
+	"Box",			/*tp_name*/
+	sizeof(BoxObject),		/*tp_basicsize*/
 	0,				/*tp_itemsize*/
 	/* methods */
-	Plane_Destructor,		/*tp_dealloc*/
+	Box_Destructor,		/*tp_dealloc*/
 	0,				/*tp_print*/
-	Plane_Getattr,			/*tp_getattr*/
+	Box_Getattr,			/*tp_getattr*/
 	0,				/*tp_setattr*/
 	0,				/*tp_compare*/
 	0,				/*tp_repr*/
@@ -254,40 +254,44 @@
 	0,				/*tp_hash */
 };
 
-static PyMethodDef PlaneMethods[] = {
+static PyMethodDef BoxMethods[] = {
 	{NULL, NULL}
 };
 
-static PyObject* Plane_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+static PyObject* Box_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
 {
-	PlaneObject *v;
+	BoxObject *v;
 	MaterialObject *material;
-	static char *kwdlist[] = {"normal", "d", "material", NULL};
-	PyObject *TNorm = NULL;
-	float nx, ny, nz, d;
+	static char *kwdlist[] = {"L", "H", "material", NULL};
+	PyObject *TL = NULL;
+	PyObject *TH = NULL;
+	float lx, ly, lz, hx, hy, hz;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!fO!", kwdlist,
-		&PyTuple_Type, &TNorm, &d, &MaterialType, &material))
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!O!", kwdlist,
+		&PyTuple_Type, &TL, &PyTuple_Type, &TH, &MaterialType, &material))
 		return NULL;
 
-	if (!PyArg_ParseTuple(TNorm, "fff", &nx, &ny, &nz))
+	if (!PyArg_ParseTuple(TL, "fff", &lx, &ly, &lz))
 		return NULL;
 
-	v = PyObject_New(PlaneObject, &PlaneType);
-	v->shape = new Plane(Vector3(nx, ny, nz), d, material->material);
+	if (!PyArg_ParseTuple(TH, "fff", &hx, &hy, &hz))
+		return NULL;
+
+	v = PyObject_New(BoxObject, &BoxType);
+	v->shape = new Box(Vector3(lx, ly, lz), Vector3(hx, hy, hz), material->material);
 	Py_INCREF(material);
 	return (PyObject*)v;
 }
 
-static void Plane_Destructor(PyObject* self)
+static void Box_Destructor(PyObject* self)
 {
-	delete ((PlaneObject *)self)->shape;
+	delete ((BoxObject *)self)->shape;
 	PyObject_Del(self);
 }
 
-static PyObject *Plane_Getattr(PyObject *self, char *name)
+static PyObject *Box_Getattr(PyObject *self, char *name)
 {
-	return Py_FindMethod(PlaneMethods, self, name);
+	return Py_FindMethod(BoxMethods, self, name);
 }
 
 //=========================== Triangle Object ===========================
@@ -479,7 +483,7 @@
 		return NULL;
 
 	((RaytracerObject *)self)->raytracer->addshape(
-		((PlaneObject*)obj)->shape);
+		((BoxObject*)obj)->shape);
 
 	((RaytracerObject *)self)->children->push_back(obj);
 	Py_INCREF(obj);
@@ -526,8 +530,8 @@
 		METH_VARARGS | METH_KEYWORDS, "Material object constructor."},
 	{"Sphere", (PyCFunction) Sphere_Constructor,
 		METH_VARARGS | METH_KEYWORDS, "Sphere object constructor."},
-	{"Plane", (PyCFunction) Plane_Constructor,
-		METH_VARARGS | METH_KEYWORDS, "Plane object constructor."},
+	{"Box", (PyCFunction) Box_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "Box object constructor."},
 	{"Triangle", (PyCFunction) Triangle_Constructor,
 		METH_VARARGS | METH_KEYWORDS, "Triangle object constructor."},
 	{NULL, NULL}
--- a/src/scene.cc	Sat Nov 24 23:55:54 2007 +0100
+++ b/src/scene.cc	Sun Nov 25 15:50:01 2007 +0100
@@ -6,8 +6,8 @@
  */
 
 #include <math.h>
-#include <float.h>
 
+#include "common.h"
 #include "scene.h"
 
 /* http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm */
@@ -21,13 +21,13 @@
 	{
 		if (ray.dir.cell[i] == 0) {
 			/* ray is parallel to these planes */
-			if (ray.a.cell[i] < L.cell[i] || ray.a.cell[i] > R.cell[i])
+			if (ray.a.cell[i] < L.cell[i] || ray.a.cell[i] > H.cell[i])
 				return false;
 		} else
 		{
 			/* compute the intersection distance of the planes */
 			t1 = (L.cell[i] - ray.a.cell[i]) / ray.dir.cell[i];
-			t2 = (R.cell[i] - ray.a.cell[i]) / ray.dir.cell[i];
+			t2 = (H.cell[i] - ray.a.cell[i]) / ray.dir.cell[i];
 
 			if (t1 > t2)
 				swap(t1, t2);
@@ -114,32 +114,40 @@
 BBox Sphere::get_bbox()
 {
 	BBox bbox = BBox();
-	bbox.L.x = center.x - radius;
-	bbox.L.y = center.y - radius;
-	bbox.L.z = center.z - radius;
-	bbox.R.x = center.x + radius;
-	bbox.R.y = center.y + radius;
-	bbox.R.z = center.z + radius;
+	bbox.L = center - radius;
+	//bbox.L.y = center.y - radius;
+	//bbox.L.z = center.z - radius;
+	bbox.H = center + radius;
+	//bbox.H.y = center.y + radius;
+	//bbox.H.z = center.z + radius;
 	return bbox;
 }
 
-bool Plane::intersect(const Ray &ray, float &dist)
+bool Box::intersect(const Ray &ray, float &dist)
 {
-	float dir = dot(N, ray.dir);
-	if (dir != 0)
-	{
-		float newdist = -(dot(N, ray.a) + d) / dir;
-		if (newdist > 0 && newdist < dist) {
-			dist = newdist;
-			return true;
-		}
-	}
-	return false;
+	float b;
+	return get_bbox().intersect(ray, dist, b);
 }
 
-BBox Plane::get_bbox()
+Vector3 Box::normal(Vector3 &P)
 {
-	return BBox();
+	Vector3 N(0,1,0);
+	/*for (int i = 0; i < 3; i++)
+	{
+		if (P.cell[i] >= L.cell[i]-Eps && P.cell[i] <= L.cell[i]+Eps)
+		//if (P.cell[i] == L.cell[i])
+		{
+			N.cell[i] = -1.0;
+			break;
+		}
+		if (P.cell[i] >= H.cell[i]-Eps && P.cell[i] <= H.cell[i]+Eps)
+		//if (P.cell[i] == H.cell[i])
+		{
+			N.cell[i] = +1.0;
+			break;
+		}
+	}*/
+	return N;
 }
 
 // this initialization and following intersection methods implements
@@ -233,12 +241,12 @@
 	if (C.y < bbox.L.y)  bbox.L.y = C.y;
 	if (B.z < bbox.L.z)  bbox.L.z = B.z;
 	if (C.z < bbox.L.z)  bbox.L.z = C.z;
-	bbox.R = A;
-	if (B.x > bbox.R.x)  bbox.R.x = B.x;
-	if (C.x > bbox.R.x)  bbox.R.x = C.x;
-	if (B.y > bbox.R.y)  bbox.R.y = B.y;
-	if (C.y > bbox.R.y)  bbox.R.y = C.y;
-	if (B.z > bbox.R.z)  bbox.R.z = B.z;
-	if (C.z > bbox.R.z)  bbox.R.z = C.z;
+	bbox.H = A;
+	if (B.x > bbox.H.x)  bbox.H.x = B.x;
+	if (C.x > bbox.H.x)  bbox.H.x = C.x;
+	if (B.y > bbox.H.y)  bbox.H.y = B.y;
+	if (C.y > bbox.H.y)  bbox.H.y = C.y;
+	if (B.z > bbox.H.z)  bbox.H.z = B.z;
+	if (C.z > bbox.H.z)  bbox.H.z = C.z;
 	return bbox;
 };
--- a/src/scene.h	Sat Nov 24 23:55:54 2007 +0100
+++ b/src/scene.h	Sun Nov 25 15:50:01 2007 +0100
@@ -29,11 +29,12 @@
 {
 public:
 	Vector3 L;
-	Vector3 R;
-	BBox(): L(), R() {};
-	float w() { return R.x-L.x; };
-	float h() { return R.y-L.y; };
-	float d() { return R.z-L.z; };
+	Vector3 H;
+	BBox(): L(), H() {};
+	BBox(const Vector3 aL, const Vector3 aH): L(aL), H(aH) {};
+	float w() { return H.x-L.x; };
+	float h() { return H.y-L.y; };
+	float d() { return H.z-L.z; };
 	bool intersect(const Ray &ray, float &a, float &b);
 };
 
@@ -118,20 +119,22 @@
 	BBox get_bbox();
 };
 
-class Plane: public Shape
+class Box: public Shape
 {
+	Vector3 L;
+	Vector3 H;
 public:
-	Vector3 N;
-	float d;
-
-	Plane(const Vector3 &normal, const float ad, Material *amaterial):
-		N(normal), d(ad) { material = amaterial; };
-	Plane(const Vector3 &normal, const Vector3 &point):
-		N(normal), d(0) { /*TODO*/};
+	Box(const Vector3 &aL, const Vector3 &aH, Material *amaterial): L(aL), H(aH)
+	{
+		for (int i = 0; i < 3; i++)
+			if (L.cell[i] > H.cell[i])
+				swap(L.cell[i], H.cell[i]);
+		material = amaterial;
+	};
 	bool intersect(const Ray &ray, float &dist);
 	bool intersect_all(const Ray &ray, float dist, vector<float> &allts) {return false;};
-	Vector3 normal(Vector3 &) { return N; };
-	BBox get_bbox();
+	Vector3 normal(Vector3 &P);
+	BBox get_bbox() { return BBox(L, H); };
 };
 
 class Triangle: public Shape
--- a/src/vector.h	Sat Nov 24 23:55:54 2007 +0100
+++ b/src/vector.h	Sun Nov 25 15:50:01 2007 +0100
@@ -99,11 +99,23 @@
 		return Vector3(f * v.x, f * v.y, f * v.z);
 	}
 
-	friend Vector3 operator*(const float &f, Vector3 &v)
+	friend Vector3 operator*(const float &f, const Vector3 &v)
 	{
 		return v * f;
 	};
 
+	// vector plus scalar
+	friend Vector3 operator+(const Vector3 &v, const float &f)
+	{
+		return Vector3(v.x + f, v.y + f, v.z + f);
+	}
+
+	// vector minus scalar
+	friend Vector3 operator-(const Vector3 &v, const float &f)
+	{
+		return Vector3(v.x - f, v.y - f, v.z - f);
+	}
+
 	// cell by cell product (only usable for colours)
 	friend Vector3 operator*(const Vector3 &a,  const Vector3 &b)
 	{