00001 #include <gra/scene/CornellBox.h>
00002 #include <esg/geometry/Polygon.h>
00003 #include <esg/geometry/Rectangle.h>
00004 #include <esg/DirLight.h>
00005 #include <esg/Material.h>
00006 #include <esg/RefrCoefs.h>
00007
00008 using namespace gra;
00009
00010 #define KB_CORNER 1.0
00011
00012 const int CornellBox::_upperLeftFar = 0;
00013 const int CornellBox::_upperLeftNear = 1;
00014 const int CornellBox::_upperRightNear = 2;
00015 const int CornellBox::_upperRightFar = 3;
00016 const int CornellBox::_lowerLeftNear = 4;
00017 const int CornellBox::_lowerLeftFar = 5;
00018 const int CornellBox::_lowerRightFar = 6;
00019 const int CornellBox::_lowerRightNear = 7;
00020
00021 const float CornellBox::_lightScale = .35;
00022
00023 const Vector3 CornellBox::_box [8] = {
00024 Vector3(-KB_CORNER, KB_CORNER,-KB_CORNER),
00025 Vector3(-KB_CORNER, KB_CORNER, KB_CORNER),
00026 Vector3( KB_CORNER, KB_CORNER, KB_CORNER),
00027 Vector3( KB_CORNER, KB_CORNER,-KB_CORNER),
00028 Vector3(-KB_CORNER,-KB_CORNER, KB_CORNER),
00029 Vector3(-KB_CORNER,-KB_CORNER,-KB_CORNER),
00030 Vector3( KB_CORNER,-KB_CORNER,-KB_CORNER),
00031 Vector3( KB_CORNER,-KB_CORNER, KB_CORNER)
00032 };
00033
00034 void CornellBox::_build_walls()
00035 {
00036 Vector3 wLeft [4] = { _box[_lowerLeftFar],
00037 _box[_lowerLeftNear],
00038 _box[_upperLeftNear],
00039 _box[_upperLeftFar] };
00040 Vector3 wFront [4] = { _box[_lowerLeftNear],
00041 _box[_lowerRightNear],
00042 _box[_upperRightNear],
00043 _box[_upperLeftNear] };
00044 Vector3 wRight [4] = { _box[_lowerRightNear],
00045 _box[_lowerRightFar],
00046 _box[_upperRightFar],
00047 _box[_upperRightNear] };
00048 Vector3 wBack [4] = { _box[_lowerRightFar],
00049 _box[_lowerLeftFar],
00050 _box[_upperLeftFar],
00051 _box[_upperRightFar] };
00052 Vector3 wTop [4] = { _box[_upperLeftNear],
00053 _box[_upperRightNear],
00054 _box[_upperRightFar],
00055 _box[_upperLeftFar] };
00056 Vector3 wBottom [4] = { _box[_lowerLeftNear],
00057 _box[_lowerLeftFar],
00058 _box[_lowerRightFar],
00059 _box[_lowerRightNear] };
00060
00061
00062 Shape * pWall;
00063
00064 pWall = new Shape(++_lastOID, "Left Wall");
00065 pWall->setPrivateGeometry(new esg::Polygon(wLeft, NULL, NULL, 4,
00066 Vector3(1,0,0), true));
00067 pWall->appendPrivateMaterial(new Specular(0,0,0));
00068 pWall->appendPrivateMaterial(new Diffuse(1.,.0,.0));
00069 pWall->appendPrivateMaterial(new Ambient(0,0,0));
00070
00071 appendObject(pWall);
00072
00073 pWall = new Shape(++_lastOID, "Front Wall");
00074 pWall->setPrivateGeometry(new esg::Polygon(wFront, NULL, NULL, 4,
00075 Vector3(0,0,-1), true));
00076 pWall->appendPrivateMaterial(new Specular(0,0,0));
00077 pWall->appendPrivateMaterial(new Diffuse(.0,.0,.0));
00078 pWall->appendPrivateMaterial(new Ambient(0,0,0));
00079
00080 appendObject(pWall);
00081
00082 pWall = new Shape(++_lastOID, "Right Wall");
00083 pWall->setPrivateGeometry(new esg::Polygon(wRight, NULL, NULL, 4,
00084 Vector3(-1,0,0), true));
00085 pWall->appendPrivateMaterial(new Specular(0,0,0));
00086 pWall->appendPrivateMaterial(new Diffuse(.0,.0,1.));
00087 pWall->appendPrivateMaterial(new Ambient(0,0,0));
00088
00089 appendObject(pWall);
00090
00091 pWall = new Shape(++_lastOID, "Back Wall");
00092 pWall->setPrivateGeometry(new esg::Polygon(wBack, NULL, NULL, 4,
00093 Vector3(0,0,1), true));
00094 pWall->appendPrivateMaterial(new Specular(0,0,0));
00095 pWall->appendPrivateMaterial(new Diffuse(1.,1.,1.));
00096 pWall->appendPrivateMaterial(new Ambient(0,0,0));
00097
00098 appendObject(pWall);
00099
00100 pWall = new Shape(++_lastOID, "Top Wall");
00101 pWall->setPrivateGeometry(new esg::Polygon(wTop, NULL, NULL, 4,
00102 Vector3(0,-1,0), true));
00103 pWall->appendPrivateMaterial(new Specular(0,0,0));
00104 pWall->appendPrivateMaterial(new Diffuse(1.,1.,1.));
00105 pWall->appendPrivateMaterial(new Ambient(0,0,0));
00106
00107 appendObject(pWall);
00108
00109 pWall = new Shape(++_lastOID, "Bottom Wall");
00110 pWall->setPrivateGeometry(new esg::Polygon(wBottom, NULL, NULL, 4,
00111 Vector3(0,1,0), true));
00112 pWall->appendPrivateMaterial(new Specular(0,0,0));
00113 pWall->appendPrivateMaterial(new Diffuse(1.,1.,1.));
00114 pWall->appendPrivateMaterial(new Ambient(0,0,0));
00115
00116 appendObject(pWall);
00117 }
00118
00119 void CornellBox::_build_lights()
00120 {
00121 Vector3 lp(_box[_upperLeftNear]);
00122 lp.add(_box[_upperRightFar]);
00123 lp.scale(.5);
00124 lp.y = KB_CORNER - .01;
00125
00126 Vector3 ud(_box[_upperRightNear]);
00127 ud.sub(_box[_upperLeftNear]);
00128 ud.scale(_lightScale);
00129
00130 Vector3 vd(_box[_upperRightNear]);
00131 vd.sub(_box[_upperRightFar]);
00132 vd.scale(_lightScale);
00133
00134 Vector3 cp(lp);
00135 cp.x -= ud.length() / 2.;
00136 cp.z -= vd.length() / 2.;
00137 cp.y += .005;
00138
00139 cp.z -= .4;
00140
00141 DirLight * pLight = new DirLight(lp,
00142 Vector3(0,-1,0),
00143 Vector3(1,1,1),
00144 0,
00145 1.5,
00146 ++_lastOID,
00147 "Light Source");
00148 pLight->setPrivateGeometry(new esg::Rectangle(cp, ud, vd,
00149 NULL,
00150 true,
00151 Vector3(0,-1,0)));
00152 appendLight(pLight);
00153 }
00154
00155 void CornellBox::_create_sf_object_set(Vector3 objset[9])
00156 {
00157
00158
00159
00160
00161
00162 Vector3 axis, trio_dir[3];
00163 double dist;
00164 Matrix4 mx;
00165
00166 dist = 1.0 / sqrt((double)2.0);
00167
00168 trio_dir[0].set(dist, dist, 0.0);
00169 trio_dir[1].set(dist, 0.0, -dist);
00170 trio_dir[2].set( 0.0, dist, -dist);
00171
00172 axis.set(dist, -dist, 0.0);
00173
00174 mx.rotationGL(asin((double)(2.0/sqrt((double)6.0))), axis);
00175
00176 for (int i = 0; i < 3; i++) mx.transform(trio_dir[i]);
00177
00178 for (int i = 0; i < 3; i++) {
00179 mx.rotZ(i*2.0*PI/3.0);
00180 for (int j = 0; j < 3; j++) mx.transform(trio_dir[j], objset[i*3+j]);
00181 }
00182 }
00183
00184 void CornellBox::_build_sphere_flake(unsigned depth,
00185 const Vector4& center,
00186 const Vector4& direction,
00187 Vector3 objset[9])
00188 {
00189 double angle, scale;
00190 Matrix4 mx;
00191 Vector3 axis, z_axis;
00192 Vector4 child_pt, child_dir;
00193
00194 Shape* pSphere = new Shape(++_lastOID, NULL);
00195 pSphere->setPrivateGeometry(new Sphere(center.x,
00196 center.y,
00197 center.z,
00198 center.w));
00199
00200 pSphere->appendPrivateMaterial(new Specular(0,0,0));
00201 pSphere->appendPrivateMaterial(new Diffuse(0,0,0));
00202 pSphere->appendPrivateMaterial(new Ambient(0,0,0));
00203
00204
00205 pSphere->appendPrivateMaterial(new Transparency(1,1,1));
00206 pSphere->appendPrivateMaterial(new Roughness((float).3));
00207 pSphere->appendPrivateMaterial(new IndexOfRefraction(REFR_GLASS));
00208 (void) appendObject(pSphere);
00209
00210
00211 if (depth > 0) {
00212 --depth;
00213
00214
00215 if (direction.z >= 1.0) {
00216 mx.setIdentity();
00217 } else if (direction.z <= -1.0) {
00218 mx.rotY(PI);
00219 } else {
00220 Vector3 aux(direction.x, direction.y, direction.z);
00221 z_axis.set(0.0, 0.0, 1.0);
00222 axis.cross(z_axis, aux);
00223 axis.normalize();
00224 angle = acos((double) z_axis.dot(aux));
00225 mx.rotationGL(angle, axis);
00226 }
00227
00228
00229 scale = center.w * (1.0 + direction.w);
00230
00231 for (int i = 0 ; i < 9 ; i++) {
00232 mx.transform(objset[i], child_pt);
00233 child_pt.scaleAdd(scale, center);
00234
00235 child_pt.w = center.w * direction.w;
00236 child_dir.set(child_pt);
00237 child_dir.sub(center);
00238 child_dir.x /= scale;
00239 child_dir.y /= scale;
00240 child_dir.z /= scale;
00241 child_dir.w = direction.w;
00242 _build_sphere_flake(depth,child_pt,child_dir,objset);
00243 }
00244 }
00245 }
00246
00247
00248 CornellBox::CornellBox(const SDS & proto)
00249 : Scene(proto)
00250 {
00251
00252
00253 _build_walls();
00254 _build_lights();
00255 }
00256
00257 void CornellBox::addMirrorSphere(float radius)
00258 {
00259 Shape * pSphere = new Shape(++_lastOID, "Mirror Sphere");
00260 pSphere->setPrivateGeometry(new Sphere(-.51, radius-KB_CORNER,-.5,radius));
00261 pSphere->appendPrivateMaterial(new Specular(0,0,0));
00262 pSphere->appendPrivateMaterial(new Diffuse(0,0,0));
00263 pSphere->appendPrivateMaterial(new Ambient(0,0,0));
00264 pSphere->appendPrivateMaterial(new Reflection(1.,1.,1.));
00265 pSphere->appendPrivateMaterial(new Roughness((float)0.04));
00266 appendObject(pSphere);
00267 }
00268
00269 void CornellBox::addCrystalicSphere(float radius)
00270 {
00271 Shape * pSphere = new Shape(++_lastOID, "Crystalic Sphere");
00272 pSphere->setPrivateGeometry(new Sphere(.53, radius-KB_CORNER,-.1,radius));
00273 pSphere->appendPrivateMaterial(new Specular(0,0,0));
00274 pSphere->appendPrivateMaterial(new Diffuse(0,0,0));
00275 pSphere->appendPrivateMaterial(new Ambient(0,0,0));
00276 pSphere->appendPrivateMaterial(new Transparency(1,1,1));
00277 pSphere->appendPrivateMaterial(new Roughness((float).3));
00278 pSphere->appendPrivateMaterial(new IndexOfRefraction(REFR_GLASS));
00279 appendObject(pSphere);
00280 }
00281
00282 void CornellBox::addSphereFlake(unsigned factor, float radius)
00283 {
00284 Vector3 objset[9];
00285 Vector4 center(0.0, 0.0, 0.0, radius/2.0);
00286 Vector4 direction(0.0, 0.0, 1.0, 1.0/3.0);
00287
00288 _create_sf_object_set(objset);
00289 _build_sphere_flake(factor, center, direction, objset);
00290 }