📄 tube.cpp
字号:
if (i == m_headProfile)
{
box.maxX = bounds.center.x + bounds.radius;
box.minX = bounds.center.x - bounds.radius;
box.maxY = bounds.center.y + bounds.radius;
box.minY = bounds.center.y - bounds.radius;
box.maxZ = bounds.center.z + bounds.radius;
box.minZ = bounds.center.z - bounds.radius;
}
else
{
Stuff::ExtentBox local_box;
local_box.maxX = bounds.center.x + bounds.radius;
local_box.minX = bounds.center.x - bounds.radius;
local_box.maxY = bounds.center.y + bounds.radius;
local_box.minY = bounds.center.y - bounds.radius;
local_box.maxZ = bounds.center.z + bounds.radius;
local_box.minZ = bounds.center.z - bounds.radius;
box.Union(box, local_box);
}
//
//---------------------------------------------------------------------------
// Move to the previous profile and wrap to the end of the list if necessary
//---------------------------------------------------------------------------
//
++profile_count;
if (--i < 0)
i = spec->m_maxProfileCount-1;
} while (i != m_tailProfile);
m_activeProfileCount = profile_count;
//
//-----------------------------------------------
// Put the age back and run the base effect stuff
//-----------------------------------------------
//
m_age = prev_age;
if (!Effect::Execute(info))
return false;
//
//--------------------------------------------
// Now, build a info->m_bounds around this box
//--------------------------------------------
//
Verify(box.maxX >= box.minX);
Verify(box.maxY >= box.minY);
Verify(box.maxZ >= box.minZ);
Stuff::OBB local_bounds = Stuff::OBB::Identity;
local_bounds.axisExtents.x = 0.5f * (box.maxX - box.minX);
local_bounds.axisExtents.y = 0.5f * (box.maxY - box.minY);
local_bounds.axisExtents.z = 0.5f * (box.maxZ - box.minZ);
local_bounds.localToParent(3,0) = box.minX + local_bounds.axisExtents.x;
local_bounds.localToParent(3,1) = box.minY + local_bounds.axisExtents.y;
local_bounds.localToParent(3,2) = box.minZ + local_bounds.axisExtents.z;
local_bounds.sphereRadius = local_bounds.axisExtents.GetLength();
Stuff::OBB parent_bounds;
parent_bounds.Multiply(local_bounds, m_localToParent);
info->m_bounds->Union(*info->m_bounds, parent_bounds);
return true;
}
//------------------------------------------------------------------------------
//
void gosFX::Tube::Kill()
{
Check_Object(this);
//
//-------------------------------------------------------------
// Destroy all the profiles and set up an empty profile cloud
//-------------------------------------------------------------
//
Specification *spec = GetSpecification();
Check_Object(spec);
if (m_activeProfileCount>0)
{
do
{
DestroyProfile(m_headProfile--);
if (m_headProfile<0)
m_headProfile = spec->m_maxProfileCount-1;
} while (m_headProfile != m_tailProfile);
}
m_activeProfileCount = 0;
m_headProfile = -1;
m_tailProfile = -1;
m_birthAccumulator = 0.0f;
//
//----------------------------------------
// Now let the base effect handle stopping
//----------------------------------------
//
Effect::Kill();
}
//------------------------------------------------------------------------------
//
bool gosFX::Tube::HasFinished()
{
Check_Object(this);
return Effect::HasFinished() && (m_activeProfileCount == 0);
}
//------------------------------------------------------------------------------
//
void
gosFX::Tube::CreateNewProfile(
unsigned index,
const Stuff::LinearMatrix4D &origin
)
{
Check_Object(this);
Check_Object(&origin);
//
//----------------------------------------------------
// Figure out the age and age rate of the new profile
//----------------------------------------------------
//
Specification *spec = GetSpecification();
Check_Object(spec);
Profile *profile = GetProfile(index);
Check_Object(profile);
profile->m_age = 0.0f;
Stuff::Scalar min_seed =
spec->m_minimumChildSeed.ComputeValue(m_age, m_seed);
Stuff::Scalar seed_range =
spec->m_maximumChildSeed.ComputeValue(m_age, m_seed) - min_seed;
Stuff::Scalar seed =
Stuff::Random::GetFraction()*seed_range + min_seed;
Clamp(seed, 0.0f, 1.0f);
profile->m_seed = seed;
Stuff::Scalar lifetime =
spec->m_pLifeSpan.ComputeValue(m_age, seed);
Min_Clamp(lifetime, 0.0333333f);
profile->m_ageRate = 1.0f / lifetime;
//
//------------------------------------------------------------------
// Establish the base position and figure out the direction of drift
//------------------------------------------------------------------
//
profile->m_profileToWorld = origin;
Stuff::Scalar pitch_min =
spec->m_minimumDeviation.ComputeValue(m_age, seed);
Stuff::Scalar pitch_range =
spec->m_maximumDeviation.ComputeValue(m_age, seed) - pitch_min;
if (pitch_range < 0.0f)
pitch_range = 0.0f;
Stuff::Radian angle = pitch_min + Stuff::Random::GetFraction() * pitch_range;
Stuff::SinCosPair xy(angle);
profile->m_direction.x = (Stuff::Random::GetFraction() >= 0.5f) ? xy.sine : -xy.sine;
profile->m_direction.y = 0.0f;
profile->m_direction.z = xy.cosine;
Check_Object(&profile->m_direction);
}
//------------------------------------------------------------------------------
//
bool
gosFX::Tube::AnimateProfile(
unsigned index,
unsigned profile_index,
const Stuff::LinearMatrix4D &world_to_new_local,
Stuff::Time till,
Stuff::Sphere *bounds
)
{
Check_Object(this);
//
//----------------------------------------------------
// If the profile gets too old, don't do anything else
//----------------------------------------------------
//
Profile *profile = GetProfile(index);
Check_Object(profile);
Stuff::Scalar age = profile->m_age;
if (age >= 1.0f)
return false;
//
//--------------------------------------------------------------------
// Figure out the scale and displacement of the profile in world space
//--------------------------------------------------------------------
//
Set_Statistic(Profile_Count, Profile_Count+1);
Stuff::Scalar seed = profile->m_seed;
Specification *spec = GetSpecification();
Check_Object(spec);
Stuff::Scalar scale = spec->m_pScale.ComputeValue(age, seed);
Verify(scale >= 0.0f);
Stuff::Scalar disp = spec->m_pDisplacement.ComputeValue(age, seed);
Stuff::Point3D offset;
offset.Multiply(profile->m_direction, disp);
//
//-------------------------------------------------
// Now build the template to new local space matrix
//-------------------------------------------------
//
Stuff::AffineMatrix4D template_to_profile(true);
template_to_profile(0,0) = scale;
template_to_profile(1,1) = scale;
template_to_profile(2,2) = scale;
template_to_profile.BuildTranslation(offset);
Stuff::AffineMatrix4D template_to_world;
template_to_world.Multiply(template_to_profile, profile->m_profileToWorld);
Stuff::AffineMatrix4D template_to_new_local;
template_to_new_local.Multiply(template_to_world, world_to_new_local);
bounds->center = template_to_new_local;
bounds->radius = scale;
//
//------------------------------------------------------------------------
// Now we just multiply the template through to the vertices unless we are
// doing the aligned ribbon
//------------------------------------------------------------------------
//
unsigned i;
unsigned vertex_count = spec->m_vertices.GetLength();
Verify(vertex_count < 8);
unsigned vertex_index = profile_index * vertex_count;
if (spec->m_profileType != Specification::e_AlignedRibbon)
{
Check_Pointer(m_P_vertices);
for (i=0; i<vertex_count; ++i)
{
m_P_vertices[vertex_index+i].Multiply(
spec->m_vertices[i],
template_to_new_local
);
}
}
//
//------------------------------
// Figure out the UV adjustments
//------------------------------
//
Check_Pointer(m_P_uvs);
Stuff::Scalar u = spec->m_pUOffset.ComputeValue(age, seed);
Stuff::Scalar v = spec->m_pVOffset.ComputeValue(age, seed);
Stuff::Scalar u2 = spec->m_pUSize.ComputeValue(age, seed);
Stuff::Scalar v2 = spec->m_pVSize.ComputeValue(age, seed);
u += u2*profile_index + spec->m_UBias;
for (i=0; i<vertex_count; ++i)
{
m_P_uvs[vertex_index+i].x = u;
m_P_uvs[vertex_index+i].y = spec->m_uvs[i].y*v2 + v;
}
//
//---------------------------
// Lastly, animate the colors
//---------------------------
//
Check_Pointer(m_P_colors);
Stuff::RGBAColor color;
color.red = spec->m_pRed.ComputeValue(age, seed);
color.green = spec->m_pGreen.ComputeValue(age, seed);
color.blue = spec->m_pBlue.ComputeValue(age, seed);
color.alpha = spec->m_pAlpha.ComputeValue(age, seed);
for (i=0; i<vertex_count; ++i)
m_P_colors[vertex_index+i] = color;
return true;
}
//------------------------------------------------------------------------------
//
void gosFX::Tube::DestroyProfile(unsigned index)
{
Profile *profile = GetProfile(index);
Check_Object(profile);
profile->m_age = 1.0f;
}
//------------------------------------------------------------------------------
//
void gosFX::Tube::Draw(DrawInfo *info)
{
Check_Object(this);
Check_Object(info);
//
//---------------------------------------------------------
// If we have active particles, set up the draw information
//---------------------------------------------------------
//
if (m_activeProfileCount>1)
{
MidLevelRenderer::DrawEffectInformation dInfo;
dInfo.effect = m_mesh;
Specification *spec = GetSpecification();
Check_Object(spec);
dInfo.state.Combine(info->m_state, spec->m_state);
dInfo.clippingFlags = info->m_clippingFlags;
Stuff::LinearMatrix4D local_to_world;
local_to_world.Multiply(m_localToParent, *info->m_parentToWorld);
dInfo.effectToWorld = &local_to_world;
unsigned vertex_count = spec->m_vertices.GetLength();
m_vertexCount = m_activeProfileCount * vertex_count;
m_triangleCount = 2 * (m_activeProfileCount-1) * (vertex_count-1);
//
//-------------------------------------------------------------------
// If we are doing the aligned ribbon, we will have to orient each of
// the profiles and then compute its vertex positions accordingly
//-------------------------------------------------------------------
//
if (spec->m_profileType == Specification::e_AlignedRibbon)
{
int i = m_headProfile;
int vertex = 0;
unsigned vertex_count = spec->m_vertices.GetLength();
Verify(vertex_count < 8);
Stuff::Point3D
camera_in_world(info->m_clipper->GetCameraToWorldMatrix());
Stuff::LinearMatrix4D world_to_local;
world_to_local.Invert(local_to_world);
//
//----------------------------------------------------------------
// go thru all the profiles and figure out where they are in local
// space
//----------------------------------------------------------------
//
Verify(i >= 0);
do
{
Profile *profile = GetProfile(i);
Check_Object(profile);
Stuff::Point3D camera_in_profile;
camera_in_profile.MultiplyByInverse(camera_in_world, profile->m_profileToWorld);
//
//---------------------------------------------------------
// Figure out the scale and displacement of the template in
// profile space
//---------------------------------------------------------
//
Stuff::Scalar age = profile->m_age;
Stuff::Scalar seed = profile->m_seed;
Stuff::Scalar scale = spec->m_pScale.ComputeValue(age, seed);
Stuff::Scalar disp = spec->m_pDisplacement.ComputeValue(age, seed);
Stuff::Point3D offset_in_profile;
offset_in_profile.Multiply(profile->m_direction, disp);
//
//----------------------------------------------------------
// Figure out the direction that we want the profile to face
// and build a rotation vector that does it
//----------------------------------------------------------
//
Stuff::Vector3D direction;
direction.Subtract(camera_in_profile, offset_in_profile);
Stuff::LinearMatrix4D template_rotation(true);
template_rotation.AlignLocalAxisToWorldVector(
direction,
Stuff::Z_Axis,
Stuff::Y_Axis,
-1
);
//
//-------------------------------------------------
// Now build the template to new local space matrix
//-------------------------------------------------
//
Stuff::AffineMatrix4D template_to_profile;
template_to_profile(0,0) = scale*template_rotation(0,0);
template_to_profile(0,1) = scale*template_rotation(0,1);
template_to_profile(0,2) = scale*template_rotation(0,2);
template_to_profile(1,0) = scale*template_rotation(1,0);
template_to_profile(1,1) = scale*template_rotation(1,1);
template_to_profile(1,2) = scale*template_rotation(1,2);
template_to_profile(2,0) = scale*template_rotation(2,0);
template_to_profile(2,1) = scale*template_rotation(2,1);
template_to_profile(2,2) = scale*template_rotation(2,2);
template_to_profile.BuildTranslation(offset_in_profile);
Stuff::AffineMatrix4D template_to_world;
template_to_world.Multiply(template_to_profile, profile->m_profileToWorld);
Stuff::AffineMatrix4D template_to_local;
template_to_local.Multiply(template_to_world, world_to_local);
//
//------------------------------------
// Multiply the points thru the matrix
//------------------------------------
//
for (int v=0; v<vertex_count; ++v)
{
m_P_vertices[vertex++].Multiply(
spec->m_vertices[v],
template_to_local
);
}
//
//---------------------------------------------------------------------------
// Move to the previous profile and wrap to the end of the list if necessary
//---------------------------------------------------------------------------
//
if (--i < 0)
i = spec->m_maxProfileCount-1;
} while (i != m_tailProfile);
}
//
//--------------------
// Now draw the effect
//--------------------
//
info->m_clipper->DrawEffect(&dInfo);
}
Effect::Draw(info);
}
//------------------------------------------------------------------------------
//
void
gosFX::Tube::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -