276 lines
7.2 KiB
C++
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();
|
|
}
|
|
//------------------------------------------------------------------------------
|