Files
Webcam/include/modules/raytracer/raytracer_scene.cpp

276 lines
7.2 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "raytracer/raytracer_scene.h"
#include "scene3d/mobject.h"
#include "scene3d/mlight.h"
#include "scene3d/scene.h"
#include "scene3d/instance.h"
#include "scene3d/group.h"
#include "core/geometry_bih.h"
#include "metafile/nml_object.h"
using namespace GS;
using namespace GS::Core;
using namespace GS::Raytrace;
//------------------------------------------------------------------------------
void SceneBIH::ResetStats()
{
ray_count = 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void SceneBIH::TraceLeaf(BIH::Node *leaf, float tmin, float tmax, BIH::Trace &trace, void *parm)
{
Vector4 &s = trace.s, &d = trace.d;
Trace *s_trace = (Trace *)parm;
uint *leaf_indice = (uint *)leaf->p;
for (uint n = 0; n < leaf->count; ++n)
{
Core::Object *o = obj[leaf_indice[n]].o;
IGeometryTree *tree = obj[leaf_indice[n]].tree;
// Raytrace object in local space.
Vector4 local_s = s * o->GetInverseMatrix(), local_d;
o->GetInverseMatrix().ApplyRotation(&local_d, &d);
GeometryTrace geo_trace;
tree->RaytraceGeometry(geo_trace, local_s, local_d, tmax);
if (!geo_trace.has_i)
continue;
// Integrate result.
if (!s_trace->has_i || (geo_trace.i_t < s_trace->i_t))
{
/*
Note: Do not copy the complete geo_trace, we do not want
to duplicate trace stacks.
*/
*((GeometryTraceBase *)s_trace) = ((GeometryTraceBase &)geo_trace);
s_trace->has_i = true;
s_trace->o = o;
s_trace->tri_test += geo_trace.tri_test;
}
}
}
void SceneBIH::RaytraceScene(Trace &trace, const Vector4 &s, const Vector4 &d, float l)
{
ray_count++;
trace.s = s;
trace.d = d;
BIH::Trace bih_trace;
Tree::Raytrace(bih_trace, s, d, l, (void *)&trace);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Geometry *SceneBIH::TranslateGeometry(Geometry *g) const
{
if (obj && g)
for (uint n = 0; n < obj.GetCount(); ++n)
if (obj[n].g == g)
return obj[n].og;
return g;
}
void SceneBIH::AddObject(ResourceFactory &gf, S3D::MObject *o, uint &obj_count, MinMax *varray, bool shadow)
{
if (!o->isActive())
return;
if (o->geometry.IsEmpty() || !o->GetBaseItem()->opacity)
return;
if (o->mitem_flags.IsSet(S3D::MItem::Flag_IsHelper | S3D::MItem::Flag_EditorHidden | S3D::MItem::Flag_EditorLocked))
return;
// Grab object geometry.
Geometry *g = gf.LoadGeometry(o->geometry);
if (!g)
return;
obj[obj_count].og = g; // Store original geometry to map back from skinned geometry.
if (!g->material_table.GetCount() || !g->pol.GetCount())
return;
if (shadow)
{
if (g->flag.IsSet(Geometry::FlagNullShadowProxy))
return;
if (!g->shadow_proxy.IsEmpty())
g = gf.LoadGeometry(g->shadow_proxy);
}
// Perform skinning.
if (o->HasSkin() && g->skin)
{
Skin *skin = o->GetSkin();
// Serialize geometry.
using namespace NML;
File file;
file.AddRoot(g->AsMetaTag());
Geometry *sg = new Geometry;
LoadFromFile(*sg, file);
// Build required structures upfront.
sg->ComputeVertexNormal();
sg->ComputeVertexTangent();
// Vertex skinning.
for (uint n = 0; n < sg->vtx.GetCount(); ++n)
{
Vector4 v(0, 0, 0);
for (int b = 0; b < 4; ++b)
{
if (!sg->skin[n].w[b])
break;
v += (sg->vtx[n] * skin->bones_mtx[sg->skin[n].bone_index[b]]) * sg->skin[n].w[b];
}
sg->vtx[n] = v;
}
// Normal skinning.
Vector4 s, w;
int tt = 0;
for (uint p = 0; p < sg->pol.GetCount(); ++p)
for (uint n = 0; n < sg->pol[p].vtx_count; ++n)
{
s.Set(0, 0, 0);
for (int b = 0; b < 4; ++b)
{
int i = sg->pol[p].binding[n];
if (!sg->skin[i].w[b])
break;
skin->bones_mtx[sg->skin[i].bone_index[b]].ApplyRotation(&w, &sg->vtx_normal[tt]);
s += w * sg->skin[i].w[b];
}
sg->vtx_normal[tt++] = s;
}
// Tangent base skinning.
Vector4 _b, _t;
tt = 0;
for (uint p = 0; p < sg->pol.GetCount(); ++p)
for (uint n = 0; n < sg->pol[p].vtx_count; ++n)
{
_b.Set(0, 0, 0);
_t.Set(0, 0, 0);
for (int b = 0; b < 4; ++b)
{
int i = sg->pol[p].binding[n];
if (!sg->skin[i].w[b])
break;
skin->bones_mtx[sg->skin[i].bone_index[b]].ApplyRotation(&w, &sg->vtx_tangent[tt].B);
_b += w * sg->skin[i].w[b];
skin->bones_mtx[sg->skin[i].bone_index[b]].ApplyRotation(&w, &sg->vtx_tangent[tt].T);
_t += w * sg->skin[i].w[b];
}
sg->vtx_tangent[tt].B = _b;
sg->vtx_tangent[tt].T = _t;
tt++;
}
// Use as the base geometry.
// but first copy the material from the base material
sg->material_table.Allocate(g->material_table.GetCount());
for (uint k = 0; k < g->material_table.GetCount(); ++k)
sg->material_table[k] = g->material_table[k];
g = sg;
}
// Prepare geometry.
IGeometryTree *tree = new GeometryBIHTree;
tree->BuildFromGeometry(gf, g);
// Build minmax for the transformed geometry.
varray[obj_count] = g->ComputeMinMax(&o->GetMatrix());
obj[obj_count].g = g;
obj[obj_count].tree = tree;
obj[obj_count++].o = o;
}
bool SceneBIH::SetScene(ResourceFactory &gf, const S3D::Scene *s, bool shadow)
{
Free();
using namespace S3D;
SharedList <MObject *> objects;
s->GetItemListByType(objects);
SharedList <Instance *> instances;
s->GetItemListByType(instances);
// Grab the scene content.
uint obj_count = 0;
ListForeachPtr(MObject *, o, objects)
if (!o->geometry.IsEmpty())
obj_count++;
// Count the instance objects.
ListForeachPtr(Instance *, i, instances)
{
if (!i->instance_scene)
{
if (!(i->instance_scene = new Scene(s->GetVM())))
continue;
i->instance_scene->FromMetaFileStoreGroup(i->template_path, &i->instance_group, SceneIOObject | SceneIOLight);
if (i->instance_group != NULL)
i->instance_group->SetRootItem(i);
}
if (i->instance_group)
ListForeachPtr(MItem *, ig, i->instance_group->GetItemList())
if (ig->GetItemType() == Type_Object && !((MObject *)ig)->geometry.IsEmpty())
obj_count++;
}
if (!obj_count)
return true;
if (!obj.Allocate(obj_count))
__ERR__(__LOG_E__ << "Failed to grab scene to raytracer.\n", false)
// Build scene tree and object trees.
Array <MinMax> varray(obj_count);
if (!varray)
__ERR__(__LOG_E__ << "Failed to allocate volume array to build scene tree.\n", false)
obj_count = 0;
ListForeachPtr(MObject *, o, objects)
AddObject(gf, o, obj_count, varray, shadow);
// Add the instance objects.
ListForeachPtr(Instance *, i, instances)
if (i->instance_group)
ListForeachPtr(MItem *, ig, i->instance_group->GetItemList())
if (ig->GetItemType() == Type_Object && !((MObject *)ig)->geometry.IsEmpty())
AddObject(gf, ((MObject *)ig), obj_count, varray, shadow);
// Build tree.
if (!Build(obj_count, varray))
return false;
return true;
}
void SceneBIH::Free()
{
obj.Free();
Tree::Free();
}
//------------------------------------------------------------------------------