This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/intern/elbeem/intern/ntl_ray.cpp
2013-02-26 21:58:06 +00:00

916 lines
28 KiB
C++

/** \file elbeem/intern/ntl_ray.cpp
* \ingroup elbeem
*/
/******************************************************************************
*
* El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
* Copyright 2003-2006 Nils Thuerey
*
* main renderer class
*
*****************************************************************************/
#include "utilities.h"
#include "ntl_ray.h"
#include "ntl_world.h"
#include "ntl_geometryobject.h"
#include "ntl_geometryshader.h"
/* Minimum value for refl/refr to be traced */
#define RAY_THRESHOLD 0.001
#if GFX_PRECISION==1
// float values
//! Minimal contribution for rays to be traced on
#define RAY_MINCONTRIB (1e-04)
#else
// double values
//! Minimal contribution for rays to be traced on
#define RAY_MINCONTRIB (1e-05)
#endif
/******************************************************************************
* Constructor
*****************************************************************************/
ntlRay::ntlRay( void )
: mOrigin(0.0)
, mDirection(0.0)
, mvNormal(0.0)
, mDepth(0)
, mpGlob(NULL)
, mIsRefracted(0)
{
errFatal("ntlRay::ntlRay()","Don't use uninitialized rays !", SIMWORLD_GENERICERROR);
return;
}
/******************************************************************************
* Copy - Constructor
*****************************************************************************/
ntlRay::ntlRay( const ntlRay &r )
{
// copy it! initialization is not enough!
mOrigin = r.mOrigin;
mDirection = r.mDirection;
mvNormal = r.mvNormal;
mDepth = r.mDepth;
mIsRefracted = r.mIsRefracted;
mIsReflected = r.mIsReflected;
mContribution = r.mContribution;
mpGlob = r.mpGlob;
// get new ID
if(mpGlob) {
mID = mpGlob->getCounterRays()+1;
mpGlob->setCounterRays( mpGlob->getCounterRays()+1 );
} else {
mID = 0;
}
}
/******************************************************************************
* Constructor with explicit parameters and global render object
*****************************************************************************/
ntlRay::ntlRay(const ntlVec3Gfx &o, const ntlVec3Gfx &d, unsigned int i, gfxReal contrib, ntlRenderGlobals *glob)
: mOrigin( o )
, mDirection( d )
, mvNormal(0.0)
, mDepth( i )
, mContribution( contrib )
, mpGlob( glob )
, mIsRefracted( 0 )
, mIsReflected( 0 )
{
// get new ID
if(mpGlob) {
mID = mpGlob->getCounterRays()+1;
mpGlob->setCounterRays( mpGlob->getCounterRays()+1 );
} else {
mID = 0;
}
}
/******************************************************************************
* Destructor
*****************************************************************************/
ntlRay::~ntlRay()
{
/* nothing to do... */
}
/******************************************************************************
* AABB
*****************************************************************************/
/* for AABB intersect */
#define NUMDIM 3
#define RIGHT 0
#define LEFT 1
#define MIDDLE 2
//! intersect ray with AABB
#ifndef ELBEEM_PLUGIN
void ntlRay::intersectFrontAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const
{
char inside = true; /* inside box? */
char hit = false; /* ray hits box? */
int whichPlane; /* intersection plane */
gfxReal candPlane[NUMDIM]; /* candidate plane */
gfxReal quadrant[NUMDIM]; /* quadrants */
gfxReal maxT[NUMDIM]; /* max intersection T for planes */
ntlVec3Gfx coord; /* intersection point */
ntlVec3Gfx dir = mDirection;
ntlVec3Gfx origin = mOrigin;
ntlVec3Gfx normal(0.0, 0.0, 0.0);
t = GFX_REAL_MAX;
/* check intersection planes for AABB */
for(int i=0;i<NUMDIM;i++) {
if(origin[i] < mStart[i]) {
quadrant[i] = LEFT;
candPlane [i] = mStart[i];
inside = false;
} else if(origin[i] > mEnd[i]) {
quadrant[i] = RIGHT;
candPlane[i] = mEnd[i];
inside = false;
} else {
quadrant[i] = MIDDLE;
}
}
/* inside AABB? */
if(!inside) {
/* get t distances to planes */
/* treat too small direction components as paralell */
for(int i=0;i<NUMDIM;i++) {
if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
maxT[i] = (candPlane[i] - origin[i]) / dir[i];
} else {
maxT[i] = -1;
}
}
/* largest max t */
whichPlane = 0;
for(int i=1;i<NUMDIM;i++) {
if(maxT[whichPlane] < maxT[i]) whichPlane = i;
}
/* check final candidate */
hit = true;
if(maxT[whichPlane] >= 0.0) {
for(int i=0;i<NUMDIM;i++) {
if(whichPlane != i) {
coord[i] = origin[i] + maxT[whichPlane] * dir[i];
if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
(coord[i] > mEnd[i] +getVecEpsilon() ) ) {
/* no hit... */
hit = false;
}
}
else {
coord[i] = candPlane[i];
}
}
/* AABB hit... */
if( hit ) {
t = maxT[whichPlane];
if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0;
else normal[whichPlane] = -1.0;
}
}
} else {
/* inside AABB... */
t = 0.0;
coord = origin;
return;
}
if(t == GFX_REAL_MAX) t = -1.0;
retnormal = normal;
retcoord = coord;
}
//! intersect ray with AABB
void ntlRay::intersectBackAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const
{
char hit = false; /* ray hits box? */
int whichPlane; /* intersection plane */
gfxReal candPlane[NUMDIM]; /* candidate plane */
gfxReal quadrant[NUMDIM]; /* quadrants */
gfxReal maxT[NUMDIM]; /* max intersection T for planes */
ntlVec3Gfx coord; /* intersection point */
ntlVec3Gfx dir = mDirection;
ntlVec3Gfx origin = mOrigin;
ntlVec3Gfx normal(0.0, 0.0, 0.0);
t = GFX_REAL_MAX;
for(int i=0;i<NUMDIM;i++) {
if(origin[i] < mStart[i]) {
quadrant[i] = LEFT;
candPlane [i] = mEnd[i];
} else if(origin[i] > mEnd[i]) {
quadrant[i] = RIGHT;
candPlane[i] = mStart[i];
} else {
if(dir[i] > 0) {
quadrant[i] = LEFT;
candPlane [i] = mEnd[i];
} else
if(dir[i] < 0) {
quadrant[i] = RIGHT;
candPlane[i] = mStart[i];
} else {
quadrant[i] = MIDDLE;
}
}
}
/* get t distances to planes */
/* treat too small direction components as paralell */
for(int i=0;i<NUMDIM;i++) {
if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
maxT[i] = (candPlane[i] - origin[i]) / dir[i];
} else {
maxT[i] = GFX_REAL_MAX;
}
}
/* largest max t */
whichPlane = 0;
for(int i=1;i<NUMDIM;i++) {
if(maxT[whichPlane] > maxT[i]) whichPlane = i;
}
/* check final candidate */
hit = true;
if(maxT[whichPlane] != GFX_REAL_MAX) {
for(int i=0;i<NUMDIM;i++) {
if(whichPlane != i) {
coord[i] = origin[i] + maxT[whichPlane] * dir[i];
if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
(coord[i] > mEnd[i] +getVecEpsilon() ) ) {
/* no hit... */
hit = false;
}
}
else {
coord[i] = candPlane[i];
}
}
/* AABB hit... */
if( hit ) {
t = maxT[whichPlane];
if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0;
else normal[whichPlane] = -1.0;
}
}
if(t == GFX_REAL_MAX) t = -1.0;
retnormal = normal;
retcoord = coord;
}
#endif // ELBEEM_PLUGIN
//! intersect ray with AABB
void ntlRay::intersectCompleteAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &tmin, gfxReal &tmax) const
{
char inside = true; /* inside box? */
char hit = false; /* ray hits box? */
int whichPlane; /* intersection plane */
gfxReal candPlane[NUMDIM]; /* candidate plane */
gfxReal quadrant[NUMDIM]; /* quadrants */
gfxReal maxT[NUMDIM]; /* max intersection T for planes */
ntlVec3Gfx coord; /* intersection point */
ntlVec3Gfx dir = mDirection;
ntlVec3Gfx origin = mOrigin;
gfxReal t = GFX_REAL_MAX;
/* check intersection planes for AABB */
for(int i=0;i<NUMDIM;i++) {
if(origin[i] < mStart[i]) {
quadrant[i] = LEFT;
candPlane [i] = mStart[i];
inside = false;
} else if(origin[i] > mEnd[i]) {
quadrant[i] = RIGHT;
candPlane[i] = mEnd[i];
inside = false;
} else {
/* intersect with backside */
if(dir[i] > 0) {
quadrant[i] = LEFT;
candPlane [i] = mStart[i];
} else
if(dir[i] < 0) {
quadrant[i] = RIGHT;
candPlane[i] = mEnd[i];
} else {
quadrant[i] = MIDDLE;
}
}
}
/* get t distances to planes */
for(int i=0;i<NUMDIM;i++) {
if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
maxT[i] = (candPlane[i] - origin[i]) / dir[i];
} else {
maxT[i] = GFX_REAL_MAX;
}
}
/* largest max t */
whichPlane = 0;
for(int i=1;i<NUMDIM;i++) {
if( ((maxT[whichPlane] < maxT[i])&&(maxT[i]!=GFX_REAL_MAX)) ||
(maxT[whichPlane]==GFX_REAL_MAX) )
whichPlane = i;
}
/* check final candidate */
hit = true;
if(maxT[whichPlane]<GFX_REAL_MAX) {
for(int i=0;i<NUMDIM;i++) {
if(whichPlane != i) {
coord[i] = origin[i] + maxT[whichPlane] * dir[i];
if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
(coord[i] > mEnd[i] +getVecEpsilon() ) ) {
/* no hit... */
hit = false;
}
}
else { coord[i] = candPlane[i]; }
}
/* AABB hit... */
if( hit ) {
t = maxT[whichPlane];
}
}
tmin = t;
/* now the backside */
t = GFX_REAL_MAX;
for(int i=0;i<NUMDIM;i++) {
if(origin[i] < mStart[i]) {
quadrant[i] = LEFT;
candPlane [i] = mEnd[i];
} else if(origin[i] > mEnd[i]) {
quadrant[i] = RIGHT;
candPlane[i] = mStart[i];
} else {
if(dir[i] > 0) {
quadrant[i] = LEFT;
candPlane [i] = mEnd[i];
} else
if(dir[i] < 0) {
quadrant[i] = RIGHT;
candPlane[i] = mStart[i];
} else {
quadrant[i] = MIDDLE;
}
}
}
/* get t distances to planes */
for(int i=0;i<NUMDIM;i++) {
if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
maxT[i] = (candPlane[i] - origin[i]) / dir[i];
} else {
maxT[i] = GFX_REAL_MAX;
}
}
/* smallest max t */
whichPlane = 0;
for(int i=1;i<NUMDIM;i++) {
if(maxT[whichPlane] > maxT[i]) whichPlane = i;
}
/* check final candidate */
hit = true;
if(maxT[whichPlane] != GFX_REAL_MAX) {
for(int i=0;i<NUMDIM;i++) {
if(whichPlane != i) {
coord[i] = origin[i] + maxT[whichPlane] * dir[i];
if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
(coord[i] > mEnd[i] +getVecEpsilon() ) ) {
/* no hit... */
hit = false;
}
}
else {
coord[i] = candPlane[i];
}
}
/* AABB hit... */
if( hit ) {
t = maxT[whichPlane];
}
}
tmax = t;
}
/******************************************************************************
* Determine color of this ray by tracing through the scene
*****************************************************************************/
const ntlColor ntlRay::shade() //const
{
#ifndef ELBEEM_PLUGIN
ntlGeometryObject *closest = NULL;
gfxReal minT = GFX_REAL_MAX;
vector<ntlLightObject*> *lightlist = mpGlob->getLightList();
mpGlob->setCounterShades( mpGlob->getCounterShades()+1 );
bool intersectionInside = 0;
if(mpGlob->getDebugOut() > 5) errorOut(std::endl<<"New Ray: depth "<<mDepth<<", org "<<mOrigin<<", dir "<<mDirection );
/* check if this ray contributes enough */
if(mContribution <= RAY_MINCONTRIB) {
//return ntlColor(0.0);
}
/* find closes object that intersects */
ntlTriangle *tri = NULL;
ntlVec3Gfx normal;
mpGlob->getRenderScene()->intersectScene(*this, minT, normal, tri, 0);
if(minT>0) {
closest = mpGlob->getRenderScene()->getObject( tri->getObjectId() );
}
/* object hit... */
if (closest != NULL) {
ntlVec3Gfx triangleNormal = tri->getNormal();
if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) errorOut("ntlRay warning: trinagle normal= 0 "); // DEBUG
/* intersection on inside faces? if yes invert normal afterwards */
gfxReal valDN; // = mDirection | normal;
valDN = dot(mDirection, triangleNormal);
if( valDN > 0.0) {
intersectionInside = 1;
normal = normal * -1.0;
triangleNormal = triangleNormal * -1.0;
}
/* ... -> do reflection */
ntlVec3Gfx intersectionPosition(mOrigin + (mDirection * (minT)) );
ntlMaterial *clossurf = closest->getMaterial();
/*if(mpGlob->getDebugOut() > 5) {
errorOut("Ray hit: at "<<intersectionPosition<<" n:"<<normal<<" dn:"<<valDN<<" ins:"<<intersectionInside<<" cl:"<<((unsigned int)closest) );
errorOut(" t1:"<<mpGlob->getRenderScene()->getVertex(tri->getPoints()[0])<<" t2:"<<mpGlob->getRenderScene()->getVertex(tri->getPoints()[1])<<" t3:"<<mpGlob->getScene()->getVertex(tri->getPoints()[2]) );
errorOut(" trin:"<<tri->getNormal() );
} // debug */
/* current transparence and reflectivity */
gfxReal currTrans = clossurf->getTransparence();
gfxReal currRefl = clossurf->getMirror();
/* correct intersectopm position */
intersectionPosition += ( triangleNormal*getVecEpsilon() );
/* reflection at normal */
ntlVec3Gfx reflectedDir = getNormalized( reflectVector(mDirection, normal) );
int badRefl = 0;
if(dot(reflectedDir, triangleNormal)<0.0 ) {
badRefl = 1;
if(mpGlob->getDebugOut() > 5) { errorOut("Ray Bad reflection...!"); }
}
/* refraction direction, depending on in/outside hit */
ntlVec3Gfx refractedDir;
int refRefl = 0;
/* refraction at normal is handled by inverting normal before */
gfxReal myRefIndex = 1.0;
if((currTrans>RAY_THRESHOLD)||(clossurf->getFresnel())) {
if(intersectionInside) {
myRefIndex = 1.0/clossurf->getRefracIndex();
} else {
myRefIndex = clossurf->getRefracIndex();
}
refractedDir = refractVector(mDirection, normal, myRefIndex , (gfxReal)(1.0) /* global ref index */, refRefl);
}
/* calculate fresnel? */
if(clossurf->getFresnel()) {
// for total reflection, just set trans to 0
if(refRefl) {
currRefl = 1.0; currTrans = 0.0;
} else {
// calculate fresnel coefficients
clossurf->calculateFresnel( mDirection, normal, myRefIndex, currRefl,currTrans );
}
}
ntlRay reflectedRay(intersectionPosition, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
reflectedRay.setNormal( normal );
ntlColor currentColor(0.0);
ntlColor highlightColor(0.0);
/* first add reflected ambient color */
currentColor += (clossurf->getAmbientRefl() * mpGlob->getAmbientLight() );
/* calculate lighting, not on the insides of objects... */
if(!intersectionInside) {
for (vector<ntlLightObject*>::iterator iter = lightlist->begin();
iter != lightlist->end();
iter++) {
/* let light illuminate point */
currentColor += (*iter)->illuminatePoint( reflectedRay, closest, highlightColor );
} // for all lights
}
// recurse ?
if ((mDepth < mpGlob->getRayMaxDepth() )&&(currRefl>RAY_THRESHOLD)) {
if(badRefl) {
ntlVec3Gfx intersectionPosition2;
ntlGeometryObject *closest2 = NULL;
gfxReal minT2 = GFX_REAL_MAX;
ntlTriangle *tri2 = NULL;
ntlVec3Gfx normal2;
ntlVec3Gfx refractionPosition2(mOrigin + (mDirection * minT) );
refractionPosition2 -= (triangleNormal*getVecEpsilon() );
ntlRay reflectedRay2 = ntlRay(refractionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
mpGlob->getRenderScene()->intersectScene(reflectedRay2, minT2, normal2, tri2, 0);
if(minT2>0) {
closest2 = mpGlob->getRenderScene()->getObject( tri2->getObjectId() );
}
/* object hit... */
if (closest2 != NULL) {
ntlVec3Gfx triangleNormal2 = tri2->getNormal();
gfxReal valDN2;
valDN2 = dot(reflectedDir, triangleNormal2);
if( valDN2 > 0.0) {
triangleNormal2 = triangleNormal2 * -1.0;
intersectionPosition2 = ntlVec3Gfx(intersectionPosition + (reflectedDir * (minT2)) );
/* correct intersection position and create new reflected ray */
intersectionPosition2 += ( triangleNormal2*getVecEpsilon() );
reflectedRay = ntlRay(intersectionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
} else {
// ray seems to work, continue normally ?
}
}
}
// add mirror color multiplied by mirror factor of surface
if(mpGlob->getDebugOut() > 5) errorOut("Reflected ray from depth "<<mDepth<<", dir "<<reflectedDir );
ntlColor reflectedColor = reflectedRay.shade() * currRefl;
currentColor += reflectedColor;
}
/* Trace another ray on for transparent objects */
if(currTrans > RAY_THRESHOLD) {
/* position at the other side of the surface, along ray */
ntlVec3Gfx refraction_position(mOrigin + (mDirection * minT) );
refraction_position += (mDirection * getVecEpsilon());
refraction_position -= (triangleNormal*getVecEpsilon() );
ntlColor refracCol(0.0); /* refracted color */
/* trace refracted ray */
ntlRay transRay(refraction_position, refractedDir, mDepth+1, mContribution*currTrans, mpGlob);
transRay.setRefracted(1);
transRay.setNormal( normal );
if(mDepth < mpGlob->getRayMaxDepth() ) {
// full reflection should make sure refracindex&fresnel are on...
if((0)||(!refRefl)) {
if(mpGlob->getDebugOut() > 5) errorOut("Refracted ray from depth "<<mDepth<<", dir "<<refractedDir );
refracCol = transRay.shade();
} else {
//we shouldnt reach this!
if(mpGlob->getDebugOut() > 5) errorOut("Fully reflected ray from depth "<<mDepth<<", dir "<<reflectedDir );
refracCol = reflectedRay.shade();
}
}
//errMsg("REFMIR","t"<<currTrans<<" thres"<<RAY_THRESHOLD<<" mirr"<<currRefl<<" refRefl"<<refRefl<<" md"<<mDepth);
/* calculate color */
// use transadditive setting!?
/* additive transparency "light amplification" */
//? ntlColor add_col = currentColor + refracCol * currTrans;
/* mix additive and subtractive */
//? add_col += sub_col;
//? currentColor += (refracCol * currTrans);
/* subtractive transparency, more realistic */
ntlColor sub_col = (refracCol * currTrans) + ( currentColor * (1.0-currTrans) );
currentColor = sub_col;
}
/* add highlights (should not be affected by transparence as the diffuse reflections */
currentColor += highlightColor;
/* attentuate as a last step*/
/* check if we're on the inside or outside */
if(intersectionInside) {
gfxReal kr,kg,kb; /* attentuation */
/* calculate attentuation */
ntlColor attCol = clossurf->getTransAttCol();
kr = exp( attCol[0] * minT );
kg = exp( attCol[1] * minT );
kb = exp( attCol[2] * minT );
currentColor = currentColor * ntlColor(kr,kg,kb);
}
/* done... */
if(mpGlob->getDebugOut() > 5) { errorOut("Ray "<<mDepth<<" color "<<currentColor ); }
return ntlColor(currentColor);
}
#endif // ELBEEM_PLUGIN
/* no object hit -> ray goes to infinity */
return mpGlob->getBackgroundCol();
}
/******************************************************************************
******************************************************************************
******************************************************************************
* scene implementation
******************************************************************************
******************************************************************************
*****************************************************************************/
/******************************************************************************
* Constructor
*****************************************************************************/
ntlScene::ntlScene( ntlRenderGlobals *glob, bool del ) :
mpGlob( glob ), mSceneDel(del),
mpTree( NULL ),
mSceneBuilt( false ), mFirstInitDone( false )
{
}
/******************************************************************************
* Destructor
*****************************************************************************/
ntlScene::~ntlScene()
{
if(mpTree != NULL) delete mpTree;
// cleanup lists, only if this is the rendering cleanup scene
if(mSceneDel)
{
for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
iter != mGeos.end(); iter++) {
//errMsg("ntlScene::~ntlScene","Deleting obj "<<(*iter)->getName() );
delete (*iter);
}
for (vector<ntlLightObject*>::iterator iter = mpGlob->getLightList()->begin();
iter != mpGlob->getLightList()->end(); iter++) {
delete (*iter);
}
for (vector<ntlMaterial*>::iterator iter = mpGlob->getMaterials()->begin();
iter != mpGlob->getMaterials()->end(); iter++) {
delete (*iter);
}
}
errMsg("ntlScene::~ntlScene","Deleted, ObjFree:"<<mSceneDel);
}
/******************************************************************************
* Build the scene arrays (obj, tris etc.)
*****************************************************************************/
void ntlScene::buildScene(double time,bool firstInit)
{
const bool buildInfo=true;
if(firstInit) {
mObjects.clear();
/* init geometry array, first all standard objects */
for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
iter != mGeos.end(); iter++) {
bool geoinit = false;
int tid = (*iter)->getTypeId();
if(tid & GEOCLASSTID_OBJECT) {
ntlGeometryObject *geoobj = (ntlGeometryObject*)(*iter);
geoinit = true;
mObjects.push_back( geoobj );
if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added GeoObj "<<geoobj->getName()<<" Id:"<<geoobj->getObjectId(), 5 );
}
//if(geoshad) {
if(tid & GEOCLASSTID_SHADER) {
ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter);
geoinit = true;
if(!mFirstInitDone) {
// only on first init
geoshad->initializeShader();
}
for (vector<ntlGeometryObject*>::iterator siter = geoshad->getObjectsBegin();
siter != geoshad->getObjectsEnd();
siter++) {
if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName()<<" Id:"<<(*siter)->getObjectId(), 5 );
mObjects.push_back( (*siter) );
}
}
if(!geoinit) {
errFatal("ntlScene::BuildScene","Invalid geometry class!", SIMWORLD_INITERROR);
return;
}
}
}
// collect triangles
mTriangles.clear();
mVertices.clear();
mVertNormals.clear();
/* for test mode deactivate transparencies etc. */
if( mpGlob->getTestMode() ) {
debugOut("ntlScene::buildScene : Test Mode activated!", 2);
// assign random colors to dark materials
int matCounter = 0;
ntlColor stdCols[] = { ntlColor(0,0,1.0), ntlColor(0,1.0,0), ntlColor(1.0,0.7,0) , ntlColor(0.7,0,0.6) };
int stdColNum = 4;
for (vector<ntlMaterial*>::iterator iter = mpGlob->getMaterials()->begin();
iter != mpGlob->getMaterials()->end(); iter++) {
(*iter)->setTransparence(0.0);
(*iter)->setMirror(0.0);
(*iter)->setFresnel(false);
// too dark?
if( norm((*iter)->getDiffuseRefl()) <0.01) {
(*iter)->setDiffuseRefl( stdCols[matCounter] );
matCounter ++;
matCounter = matCounter%stdColNum;
}
}
// restrict output file size to 400
float downscale = 1.0;
if(mpGlob->getResX() > 400){ downscale = 400.0/(float)mpGlob->getResX(); }
if(mpGlob->getResY() > 400){
float downscale2 = 400.0/(float)mpGlob->getResY();
if(downscale2<downscale) downscale=downscale2;
}
mpGlob->setResX( (int)(mpGlob->getResX() * downscale) );
mpGlob->setResY( (int)(mpGlob->getResY() * downscale) );
}
/* collect triangles from objects */
int idCnt = 0; // give IDs to objects
bool debugTriCollect = false;
if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Start...",5);
for (vector<ntlGeometryObject*>::iterator iter = mObjects.begin();
iter != mObjects.end();
iter++) {
/* only add visible objects */
if(firstInit) {
if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Collect init of "<<(*iter)->getName()<<" idCnt:"<<idCnt, 4 );
(*iter)->initialize( mpGlob ); }
if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Collecting tris from "<<(*iter)->getName(), 4 );
int vstart = mVertNormals.size();
(*iter)->setObjectId(idCnt);
(*iter)->getTriangles(time, &mTriangles, &mVertices, &mVertNormals, idCnt);
(*iter)->applyTransformation(time, &mVertices, &mVertNormals, vstart, mVertices.size(), false );
if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Done with "<<(*iter)->getName()<<" totTris:"<<mTriangles.size()<<" totVerts:"<<mVertices.size()<<" totNorms:"<<mVertNormals.size(), 4 );
idCnt ++;
}
if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"End",5);
/* calculate triangle normals, and initialize flags */
for (vector<ntlTriangle>::iterator iter = mTriangles.begin();
iter != mTriangles.end();
iter++) {
// calculate normal from triangle points
ntlVec3Gfx normal =
cross( (ntlVec3Gfx)( (mVertices[(*iter).getPoints()[2]] - mVertices[(*iter).getPoints()[0]]) *-1.0), // BLITZ minus sign right??
(ntlVec3Gfx)(mVertices[(*iter).getPoints()[1]] - mVertices[(*iter).getPoints()[0]]) );
normalize(normal);
(*iter).setNormal( normal );
}
// scene geometry built
mSceneBuilt = true;
// init shaders that require complete geometry
if(!mFirstInitDone) {
// only on first init
for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
iter != mGeos.end(); iter++) {
if( (*iter)->getTypeId() & GEOCLASSTID_SHADER ) {
ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter);
if(geoshad->postGeoConstrInit( mpGlob )) {
errFatal("ntlScene::buildScene","Init failed for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR );
return;
}
}
}
mFirstInitDone = true;
}
// check unused attributes (for classes and objects!)
for (vector<ntlGeometryObject*>::iterator iter = mObjects.begin(); iter != mObjects.end(); iter++) {
if((*iter)->getAttributeList()->checkUnusedParams()) {
(*iter)->getAttributeList()->print(); // DEBUG
errFatal("ntlScene::buildScene","Unused params for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR );
return;
}
}
for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin(); iter != mGeos.end(); iter++) {
if((*iter)->getAttributeList()->checkUnusedParams()) {
(*iter)->getAttributeList()->print(); // DEBUG
errFatal("ntlScene::buildScene","Unused params for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR );
return;
}
}
}
/******************************************************************************
* Prepare the scene triangles and maps for raytracing
*****************************************************************************/
void ntlScene::prepareScene(double time)
{
/* init triangles... */
buildScene(time, false);
// what for currently not used ???
if(mpTree != NULL) delete mpTree;
mpTree = new ntlTree(
# if FSGR_STRICT_DEBUG!=1
mpGlob->getTreeMaxDepth(), mpGlob->getTreeMaxTriangles(),
# else
mpGlob->getTreeMaxDepth()/3*2, mpGlob->getTreeMaxTriangles()*2,
# endif
this, TRI_GEOMETRY );
//debMsgStd("ntlScene::prepareScene",DM_MSG,"Stats - tris:"<< (int)mTriangles.size()<<" verts:"<<mVertices.size()<<" vnorms:"<<mVertNormals.size(), 5 );
}
/******************************************************************************
* Do some memory cleaning, when frame is finished
*****************************************************************************/
void ntlScene::cleanupScene( void )
{
mTriangles.clear();
mVertices.clear();
mVertNormals.clear();
if(mpTree != NULL) delete mpTree;
mpTree = NULL;
}
/******************************************************************************
* Intersect a ray with the scene triangles
*****************************************************************************/
void ntlScene::intersectScene(const ntlRay &r, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri,int flags) const
{
distance = -1.0;
mpGlob->setCounterSceneInter( mpGlob->getCounterSceneInter()+1 );
mpTree->intersect(r, distance, normal, tri, flags, false);
}