move "smooth" attribute from Triangle to Material pyrit
authorRadek Brich <radek.brich@devl.cz>
Mon, 14 Apr 2008 12:51:50 +0200
branchpyrit
changeset 69 303583d2fb97
parent 68 2c154aad7f33
child 70 4b84e90325c5
move "smooth" attribute from Triangle to Material lwo reader enhancements - implement more chunk types, support for smoothing flag and SMAN (smoothing max. angle)
ccdemos/common_ply.h
ccdemos/realtime_bunny.cc
ccdemos/realtime_dragon.cc
demos/buddha.py
demos/bunny.py
demos/car.py
demos/dragon.py
demos/lworeader.py
demos/plyreader.py
include/scene.h
src/raytracermodule.cc
src/scene.cc
--- a/ccdemos/common_ply.h	Sat Apr 12 02:02:45 2008 +0200
+++ b/ccdemos/common_ply.h	Mon Apr 14 12:51:50 2008 +0200
@@ -59,7 +59,6 @@
 		f >> v1 >> v2 >> v3;
 		face = new Triangle(vertices.at(v1), vertices.at(v3), vertices.at(v2), mat);
 		rt.addshape(face);
-		face->setSmooth();
 
 		normals.at(v1) += face->getNormal();
 		vertex_face_num.at(v1)++;
--- a/ccdemos/realtime_bunny.cc	Sat Apr 12 02:02:45 2008 +0200
+++ b/ccdemos/realtime_bunny.cc	Mon Apr 14 12:51:50 2008 +0200
@@ -22,6 +22,7 @@
 	//rt.addlight(&light2);
 
 	Material mat(Colour(0.9, 0.9, 0.9));
+	mat.setSmooth(true);
 	load_ply(rt, "../models/ply/bunny/bun_zipper.ply", &mat, Vector3(-29,29,29), Vector3(-1,-3,0));
 
 	rt.setCamera(&cam);
--- a/ccdemos/realtime_dragon.cc	Sat Apr 12 02:02:45 2008 +0200
+++ b/ccdemos/realtime_dragon.cc	Mon Apr 14 12:51:50 2008 +0200
@@ -22,6 +22,7 @@
 	//rt.addlight(&light2);
 
 	Material mat(Colour(0.9, 0.9, 0.9));
+	mat.setSmooth(true);
 	load_ply(rt, "../models/ply/dragon/dragon_vrip.ply", &mat, Vector3(-29,29,-29), Vector3(0,-3.6,0));
 
 	rt.setCamera(&cam);
--- a/demos/buddha.py	Sat Apr 12 02:02:45 2008 +0200
+++ b/demos/buddha.py	Mon Apr 14 12:51:50 2008 +0200
@@ -9,8 +9,9 @@
 
 rt = Raytracer()
 mat = Material(colour=(0.9, 0.9, 0.9))
+mat.setSmooth(True)
 LoadStanfordPlyFile(rt, "../models/ply/happy/happy_vrip_res2.ply",
-	mat, smooth=True, scale=20.0, trans=(0,-3,0))
+	mat, scale=20.0, trans=(0,-3,0))
 
 light = Light(position=(-5.0, 2.0, 8.0), colour=(0.9, 0.3, 0.6))
 rt.addlight(light)
--- a/demos/bunny.py	Sat Apr 12 02:02:45 2008 +0200
+++ b/demos/bunny.py	Mon Apr 14 12:51:50 2008 +0200
@@ -12,8 +12,9 @@
 
 mat = Material(colour=(0.9, 0.9, 0.9))
 mat.setTransmissivity(0.8)
+mat.setSmooth(True)
 LoadStanfordPlyFile(rt, "../models/ply/bunny/bun_zipper.ply",
-	mat, smooth=True, scale=(-29.0, 29.0, 29.0), trans=(-1,-2.5,-3))
+	mat, scale=(-29.0, 29.0, 29.0), trans=(-1,-2.5,-3))
 
 mat0 = Material(colour=(0.1, 0.2, 0.6))
 box1 = Box(L=(-20.0, -1.7, -20.0), H=(20.0, -1.5, 20.0), material=mat0)
--- a/demos/car.py	Sat Apr 12 02:02:45 2008 +0200
+++ b/demos/car.py	Mon Apr 14 12:51:50 2008 +0200
@@ -7,16 +7,17 @@
 
 rt = Raytracer()
 
-cam = Camera(eye=(0.,5.,8.))
-rotx=0.3
+cam = Camera(eye=(0.,2.,8.))
+rotx=0.15
 cam.rotate((cos(rotx),-sin(rotx),0.,0.))
 rt.setcamera(cam)
 
-mat = Material(colour=(0.9, 0.9, 0.9))
-LoadLightwaveLwoFile(rt, "../models/lwo/Nissan300ZX.lwo", mat, smooth=False, scale=0.4)
+LoadLightwaveLwoFile(rt, "../models/lwo/Nissan300ZX.lwo", scale=0.4, trans=(-0.2,0,0.3))
 
-light = Light(position=(-5.0, 10.0, 8.0), colour=(0.9, 0.9, 0.9))
-rt.addlight(light)
+light1 = Light(position=(-5.0, 20.0, 8.0), colour=(0.9, 0.9, 0.9))
+rt.addlight(light1)
+light2 = Light(position=(5.0, 10.0, 10.0), colour=(0.9, 0.7, 0.7))
+rt.addlight(light2)
 
 imagesize = (800, 600)
 data = rt.render(imagesize)
--- a/demos/dragon.py	Sat Apr 12 02:02:45 2008 +0200
+++ b/demos/dragon.py	Mon Apr 14 12:51:50 2008 +0200
@@ -9,8 +9,9 @@
 
 rt = Raytracer()
 mat = Material(colour=(0.9, 0.9, 0.9))
+mat.setSmooth(True)
 LoadStanfordPlyFile(rt, "../models/ply/dragon/dragon_vrip_res2.ply",
-	mat, smooth=True, scale=(-29.0, 29.0, -29.0), trans=(0.0, -3.6, 0.0))
+	mat, scale=(-29.0, 29.0, -29.0), trans=(0.0, -3.6, 0.0))
 
 light1 = Light(position=(-5.0, 2.0, 8.0), colour=(0.9, 0.3, 0.2))
 rt.addlight(light1)
--- a/demos/lworeader.py	Sat Apr 12 02:02:45 2008 +0200
+++ b/demos/lworeader.py	Mon Apr 14 12:51:50 2008 +0200
@@ -1,5 +1,6 @@
 # LightWave .lwo file loader
 
+from math import *
 from struct import *
 from raytracer import Triangle, NormalVertex, Material
 
@@ -46,7 +47,7 @@
 	(ID,size) = read_chunk(f)
 	form = f.read(4)
 	if (ID != 'FORM' or form != 'LWOB'):
-		print 'not lwo file'
+		print 'unknown format'
 		return
 	(ID,size) = read_chunk(f)
 	while (ID != ''):
@@ -74,10 +75,18 @@
 					size -= 2
 				surf = read_int2(f)
 				size -= 2
-				faces.append((inds[0], inds[1], inds[2], surf))
+				if surf < 0:
+					# detail polygons
+					surf = abs(surf)
+					count = read_int2(f)
+					size -= 2
+					# ... FIXME
+				#print size, vertex_count
+				if vertex_count >= 3:
+					faces.append([inds[0], inds[1], inds[2], surf])
 				i = 0
 				while (vertex_count > 3):
-					faces.append((inds[0], inds[2+i], inds[3+i], surf))
+					faces.append([inds[0], inds[2+i], inds[3+i], surf])
 					vertex_count -= 1
 					i += 1
 		elif (ID == 'SURF'):
@@ -90,29 +99,101 @@
 				if (subID == 'COLR'):
 					col = f.read(subsize)
 					surf['color'] = (unpack('BBB',col[:3]))
+				elif (subID == 'FLAG'):
+					flags = read_int2(f)
+					surf['luminous'] = (flags >> 0) & 1;
+					surf['outline'] = (flags >> 1) & 1;
+					surf['smooth'] = (flags >> 2) & 1;
+					surf['color-highlights'] = (flags >> 3) & 1;
+					surf['color-filter'] = (flags >> 4) & 1;
+					surf['opaque-edge'] = (flags >> 5) & 1;
+					surf['transparent-edge'] = (flags >> 6) & 1;
+					surf['sharp-terminator'] = (flags >> 7) & 1;
+					surf['double-sided'] = (flags >> 8) & 1;
+					surf['additive'] = (flags >> 9) & 1;
+
+				# Base Shading (float)
+				elif (subID == 'VDIF'):
+					surf['diffuse'] = read_float4(f)
+				elif (subID == 'VSPC'):
+					surf['specular'] = read_float4(f)
+				elif (subID == 'VRFL'):
+					surf['reflection'] = read_float4(f)
+				elif (subID == 'VTRN'):
+					surf['transparency'] = read_float4(f)
+
+				# Base Shading (short)
+				elif (subID == 'DIFF'):
+					if not surf.has_key('diffuse'):
+						surf['diffuse'] = read_int2(f)/255.
+				elif (subID == 'SPEC'):
+					if not surf.has_key('specular'):
+						surf['specular'] = read_int2(f)/255.
+				elif (subID == 'REFL'):
+					if not surf.has_key('reflection'):
+						surf['reflection'] = read_int2(f)/255.
+				elif (subID == 'TRAN'):
+					if not surf.has_key('transparency'):
+						surf['transparency'] = read_int2(f)/255.
+
+				elif (subID == 'RIND'):
+					surf['refractive-index'] = read_float4(f)
+				elif (subID == 'GLOS'):
+					surf['glossiness'] = read_int2(f)
+				elif (subID == 'SMAN'):
+					surf['smoothing-max-angle'] = read_float4(f)
 				else:
-					print "Warning:", subID,"("+str(subsize),"B) ignored"
+					print "Warning: SURF sub chunk", subID,"("+str(subsize),"B) ignored"
 					f.read(subsize)
 				size -= subsize
 			surfaces.append(surf)
 		else:
-			print "Warning:", ID,"("+str(size),"B) ignored"
+			print "Warning: chunk", ID,"("+str(size),"B) ignored"
 			f.read(size)
 		(ID,size) = read_chunk(f)
 	return (points, faces, tags, surfaces)
 
-def LoadLightwaveLwoFile(rt, filename, defmat, smooth, scale=(1,1,1), trans=(0,0,0)):
+def dot(a,b):
+	sum = 0
+	for i in range(min(len(a),len(b))):
+		sum += a[i]*b[i]
+	return sum
+
+def LoadLightwaveLwoFile(rt, filename, scale=(1,1,1), trans=(0,0,0)):
 	if (type(scale) == float or type(scale) == int):
 		scale = (scale,)*3
 	(points, faces, tags, surfaces) = read_lwo(filename)
 
 	vertices = []
 	normals = []
-	vertex_face_num = []
+	vertex_faces = []
 	materials = []
 
 	for surf in surfaces:
 		mat = Material(colour=tuple(float(x)/255. for x in surf['color']))
+		if surf.has_key('smooth'):
+			mat.setSmooth(surf['smooth'])
+		diff = 1.
+		if surf.has_key('diffuse'):
+			diff = surf['diffuse']
+		spec = 0.
+		if surf.has_key('specular'):
+			spec = surf['specular']
+		gloss = 1.0
+		if surf.has_key('glossiness'):
+			gloss = surf['glossiness']
+		mat.setPhong(0.1, diff, spec, gloss)
+		refl = 0.
+		if surf.has_key('reflection'):
+			refl = surf['reflection']
+		mat.setReflectivity(refl)
+		transp = 0.
+		if surf.has_key('transparency'):
+			transp = surf['transparency']
+		rindex = 1.0
+		if surf.has_key('refractive-index'):
+			rindex = surf['refractive-index']
+		mat.setTransmissivity(transp, rindex)
 		materials.append(mat)
 
 	for point in points:
@@ -121,26 +202,77 @@
 		v2 = scale[2]*point[2] + trans[2]
 		vertices.append(NormalVertex((v2,v1,v0)))
 		normals.append([0.,0.,0.])
-		vertex_face_num.append(0)
+		vertex_faces.append([])
 
 	for f in faces:
-		v = [vertices[x] for x in f[0:3]]
-		matidx = f[3]-1
-		face = Triangle(v[0], v[1], v[2], materials[matidx])
-		n = face.getNormal()
 		for x in f[0:3]:
-			for i in range(3):
-				normals[x][i] += n[i]
-			vertex_face_num[x] += 1
-		if (smooth):
-			face.setSmooth()
-		rt.addshape(face)
+			vertex_faces[x].append(f)
 
 	# interpolate normals at vertices
 	num = 0
-	for vf in vertex_face_num:
-		if (vertex_face_num[num] > 0):
+	for vfaces in vertex_faces:
+		vert = vertices[num]
+		edges = {}
+		N = [0,0,0]
+		for f in vfaces:
+			for fvert in f[0:3]:
+				if edges.has_key(str(fvert)):
+					edges[str(fvert)].append(f)
+				else:
+					edges[str(fvert)] = [f]
+		for f in vfaces:
+			vv = [vertices[x] for x in f[0:3]]
+			fN = Triangle(vv[0], vv[1], vv[2], materials[f[3]-1]).getNormal()
 			for i in range(3):
-				normals[num][i] /= vertex_face_num[num]
-		vertices[num].setNormal(tuple(normals[num]))
+				N[i] += fN[i]
+			surf = surfaces[f[3]-1]
+			if not surf.has_key('smoothing-max-angle'):
+				continue
+			fNvert = list(fN)
+			Ncount = 1
+			copy_vertex = False
+			for fvert in f[0:3]:
+				for ef in edges[str(fvert)]:
+					if ef == f:
+						continue
+					# f - ref. face; ef - other face
+					vv = [vertices[x] for x in ef[0:3]]
+					efN = Triangle(vv[0], vv[1], vv[2], materials[ef[3]-1]).getNormal()
+					d = dot(fN, efN)
+					if d > 1:
+						d = 1
+					if d < -1:
+						d = -1
+					if acos(d) < surf['smoothing-max-angle']:
+						for i in range(3):
+							fNvert[i] += efN[i]
+						Ncount += 1
+					else:
+						copy_vertex = True
+			# here fNvert is normal for num'th vertex in face f
+			if copy_vertex:
+				for i in range(3):
+					fNvert[i] /= Ncount
+				new_vert = NormalVertex(vert)
+				new_vert.setNormal(tuple(fNvert))
+				f.append(f[0])
+				f.append(f[1])
+				f.append(f[2])
+				vertices.append(new_vert)
+				for i in range(3):
+					if f[i] == num:
+						f[i+4] = len(vertices)-1
+		if (len(vfaces) > 0):
+			for i in range(3):
+				N[i] /= len(vfaces)
+		vertices[num].setNormal(tuple(N))
 		num += 1
+
+	for f in faces:
+		if len(f) > 4:
+			v = [vertices[x] for x in f[4:7]]
+		else:
+			v = [vertices[x] for x in f[0:3]]
+		matidx = f[3]-1
+		face = Triangle(v[0], v[1], v[2], materials[matidx])
+		rt.addshape(face)
--- a/demos/plyreader.py	Sat Apr 12 02:02:45 2008 +0200
+++ b/demos/plyreader.py	Mon Apr 14 12:51:50 2008 +0200
@@ -2,7 +2,7 @@
 
 from raytracer import Triangle, NormalVertex
 
-def LoadStanfordPlyFile(rt, filename, mat, smooth, scale=(1,1,1), trans=(0,0,0)):
+def LoadStanfordPlyFile(rt, filename, mat, scale=(1,1,1), trans=(0,0,0)):
 	if (type(scale) == float or type(scale) == int):
 		scale = (scale,)*3
 	vertices = []
@@ -44,8 +44,6 @@
 			for i in range(3):
 				normals[int(x)][i] += n[i]
 			vertex_face_num[int(x)] += 1
-		if (smooth):
-			face.setSmooth()
 		rt.addshape(face)
 		face_num -= 1
 
--- a/include/scene.h	Sat Apr 12 02:02:45 2008 +0200
+++ b/include/scene.h	Mon Apr 14 12:51:50 2008 +0200
@@ -132,12 +132,13 @@
 {
 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
-	Texture *texture;
+	bool smooth; // triangle smoothing
 
-	Material(const Colour &acolour): colour(acolour), texture(NULL)
+	Material(const Colour &acolour): colour(acolour), texture(NULL), smooth(false)
 	{
 		ambient = 0.2;
 		diffuse = 0.8;
@@ -153,6 +154,7 @@
 	void setReflectivity(const Float refl) { reflectivity = refl; };
 	void setTransmissivity(const Float trans, const Float rindex)
 		{ transmissivity = trans; refract_index = rindex; };
+	void setSmooth(bool sm) { smooth = sm; };
 };
 
 /**
@@ -247,6 +249,7 @@
 {
 public:
 	Vector3 N;
+	NormalVertex(const NormalVertex *v): Vertex(v->P), N(v->N) {};
 	NormalVertex(const Vector3 &aP): Vertex(aP) {};
 	NormalVertex(const Vector3 &aP, const Vector3 &aN): Vertex(aP), N(aN) {};
 	const Vector3 &getNormal() { return N; };
@@ -271,7 +274,6 @@
 	Float pla[6], plb[6], plc[6];
 #endif
 	Vector3 N;
-	bool smooth;
 	const Vector3 smooth_normal(const Vector3 &P) const
 	{
 #ifdef TRI_BARI_PRE
@@ -300,11 +302,8 @@
 	bool intersect(const Ray &ray, Float &dist) const;
 	bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const {return false;};
 	bool intersect_bbox(const BBox &bbox) const;
-	const Vector3 normal(const Vector3 &P) const { return (smooth ? smooth_normal(P) : N); };
+	const Vector3 normal(const Vector3 &P) const { return (material->smooth ? smooth_normal(P) : N); };
 	const Vector3 getNormal() const { return N; };
-	void setSmooth() { smooth = true; };//(typeid(*A) == typeid(*B) == typeid(*C) == typeid(NormalVertex)); };
-	void setFlat() { smooth = false; };
-	bool getSmooth() const { return smooth; };
 	BBox get_bbox() const;
 };
 
--- a/src/raytracermodule.cc	Sat Apr 12 02:02:45 2008 +0200
+++ b/src/raytracermodule.cc	Mon Apr 14 12:51:50 2008 +0200
@@ -248,6 +248,7 @@
 static PyObject *Material_setPhong(PyObject* self, PyObject* args);
 static PyObject *Material_setReflectivity(PyObject* self, PyObject* args);
 static PyObject *Material_setTransmissivity(PyObject* self, PyObject* args);
+static PyObject *Material_setSmooth(PyObject* self, PyObject* args);
 
 static PyTypeObject MaterialType = {
 	PyObject_HEAD_INIT(NULL)
@@ -272,6 +273,7 @@
 	{"setPhong", (PyCFunction)Material_setPhong, METH_VARARGS, "Set ambient, diffuse, specular and shininess Phong model constants."},
 	{"setReflectivity", (PyCFunction)Material_setReflectivity, METH_VARARGS, "Set reflectivity."},
 	{"setTransmissivity", (PyCFunction)Material_setTransmissivity, METH_VARARGS, "Set transmissivity and refraction index."},
+	{"setSmooth", (PyCFunction)Material_setSmooth, METH_VARARGS, "Set triangle smoothing."},
 	{NULL, NULL}
 };
 
@@ -345,6 +347,20 @@
 	return Py_None;
 }
 
+static PyObject* Material_setSmooth(PyObject* self, PyObject* args)
+{
+	int smooth;
+
+	if (!PyArg_ParseTuple(args, "i", &smooth))
+		return NULL;
+
+	((MaterialObject *)self)->material->setSmooth(smooth);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
 //=========================== NormalVertex Object ===========================
 
 typedef struct {
@@ -389,19 +405,27 @@
 	PyObject *TNor = NULL;
 	Float vx, vy, vz, nx=0, ny=0, nz=0;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!|O!", kwdlist,
-		&PyTuple_Type, &TVer, &PyTuple_Type, &TNor))
-		return NULL;
-
-	if (!PyArg_ParseTuple(TVer, "fff", &vx, &vy, &vz))
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O|O!", kwdlist,
+		&TVer, &PyTuple_Type, &TNor))
 		return NULL;
 
-	if (TNor)
-		if (!PyArg_ParseTuple(TNor, "fff", &nx, &ny, &nz))
+	if (!TNor && TVer->ob_type == &NormalVertexType)
+	{
+		v = PyObject_New(NormalVertexObject, &NormalVertexType);
+		v->nvertex = new NormalVertex(((NormalVertexObject*)TVer)->nvertex);
+	}
+	else
+	{
+		if (!PyArg_ParseTuple(TVer, "fff", &vx, &vy, &vz))
 			return NULL;
 
-	v = PyObject_New(NormalVertexObject, &NormalVertexType);
-	v->nvertex = new NormalVertex(Vector3(vx, vy, vz), Vector3(nx, ny, nz));
+		if (TNor)
+			if (!PyArg_ParseTuple(TNor, "fff", &nx, &ny, &nz))
+				return NULL;
+
+		v = PyObject_New(NormalVertexObject, &NormalVertexType);
+		v->nvertex = new NormalVertex(Vector3(vx, vy, vz), Vector3(nx, ny, nz));
+	}
 	return (PyObject*)v;
 }
 
@@ -580,7 +604,6 @@
 static void Triangle_Destructor(PyObject* self);
 static PyObject *Triangle_Getattr(PyObject *self, char *name);
 static PyObject *Triangle_getNormal(PyObject* self, PyObject* args);
-static PyObject *Triangle_setSmooth(PyObject* self, PyObject* args);
 
 static PyTypeObject TriangleType = {
 	PyObject_HEAD_INIT(NULL)
@@ -603,7 +626,6 @@
 
 static PyMethodDef TriangleMethods[] = {
 	{"getNormal", (PyCFunction)Triangle_getNormal, METH_NOARGS, "Get normal of whole triangle."},
-	{"setSmooth", (PyCFunction)Triangle_setSmooth, METH_NOARGS, "Set the triangle smooth."},
 	{NULL, NULL}
 };
 
@@ -649,13 +671,6 @@
 	return obj;
 }
 
-static PyObject* Triangle_setSmooth(PyObject* self, PyObject* args)
-{
-	((TriangleObject *)self)->triangle->setSmooth();
-	Py_INCREF(Py_None);
-	return Py_None;
-}
-
 //=========================== Raytracer Object ===========================
 
 typedef struct {
--- a/src/scene.cc	Sat Apr 12 02:02:45 2008 +0200
+++ b/src/scene.cc	Mon Apr 14 12:51:50 2008 +0200
@@ -307,7 +307,7 @@
 #endif
 
 Triangle::Triangle(Vertex *aA, Vertex *aB, Vertex *aC, Material *amaterial)
-	: smooth(false), A(aA), B(aB), C(aC)
+	: A(aA), B(aB), C(aC)
 {
 	material = amaterial;