📄 interiorinstance.cc
字号:
continue;
Point3F center(0, 0, 0);
for(U32 j = 0; j < portal->triFanCount; j++)
{
const Interior::TriFan & fan = interior->mWindingIndices[portal->triFanStart + j];
const U32 numPoints = fan.windingCount;
if(!numPoints)
continue;
for(U32 k = 0; k < numPoints; k++)
{
const Point3F & a = interior->mPoints[interior->mWindings[fan.windingStart + k]].point;
center += a;
}
center /= numPoints;
portalCenters[numPortalCenters++] = center;
}
}
// 'magic' check here...
F32 magic = Con::getFloatVariable("Interior::insideDistanceFalloff", 10.f);
F32 val = 0.f;
for(i = 0; i < numPortalCenters; i++)
val += 1.f - mClampF(Point3F(portalCenters[i] - p).len() / magic, 0.f, 1.f);
*pScale = 1.f - mClampF(val, 0.f, 1.f);
FrameAllocator::setWaterMark(waterMark);
return(true);
}
//--------------------------------------------------------------------------
ColorF gInteriorFogColor(1, 1, 1);
void InteriorInstance::renderObject(SceneState* state, SceneRenderImage* sceneImage)
{
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
if(gEditingMission && isHidden())
return;
PROFILE_START(InteriorRenderObject);
PROFILE_START(IRO_GetZones);
U32 storedWaterMark = FrameAllocator::getWaterMark();
dglSetRenderPrimType(2);
InteriorRenderImage* interiorImage = static_cast<InteriorRenderImage*>(sceneImage);
Point3F osPoint = state->getCameraPosition();
mRenderWorldToObj.mulP(osPoint);
osPoint.convolveInverse(mObjScale);
// Get the object space y vector
Point3F osCamVector;
state->mModelview.getColumn(1, &osCamVector);
mRenderWorldToObj.mulV(osCamVector);
osCamVector.convolve(getScale());
osCamVector.normalize();
Point3F osZVec(0, 0, 1);
mRenderWorldToObj.mulV(osZVec);
osZVec.convolve(getScale());
// First, we want to test the planes and setup the fog...
U32 zoneOffset = mZoneRangeStart != 0xFFFFFFFF ? mZoneRangeStart : 0;
Interior* pInterior = mInteriorRes->getDetailLevel(interiorImage->mDetailLevel);
U32 baseZone = 0xFFFFFFFF;
if (getNumCurrZones() == 1)
{
baseZone = getCurrZone(0);
}
else
{
for (U32 i = 0; i < getNumCurrZones(); i++)
{
if (state->getZoneState(getCurrZone(i)).render == true)
{
if (baseZone == 0xFFFFFFFF)
{
baseZone = getCurrZone(i);
break;
}
}
}
if (baseZone == 0xFFFFFFFF)
baseZone = getCurrZone(0);
}
PROFILE_END();
PROFILE_START(IRO_ComputeActivePolys);
Point3F worldOrigin;
getRenderTransform().getColumn(3, &worldOrigin);
ZoneVisDeterminer zoneVis;
if (interiorImage->mDetailLevel == 0)
{
zoneVis.runFromState(state, zoneOffset, baseZone);
pInterior->setupActivePolyList(zoneVis, state, osPoint, osCamVector, osZVec, worldOrigin.z, getScale());
}
else
{
// Something else...
pInterior->prepTempRender(state,
getCurrZone(0),
0,
mRenderObjToWorld, mObjScale,
state->mFlipCull);
zoneVis.runFromRects(state, zoneOffset, baseZone);
pInterior->setupActivePolyList(zoneVis, state, osPoint, osCamVector, osZVec, worldOrigin.z, getScale());
}
PROFILE_END();
PROFILE_START(IRO_UpdateAnimatedLights);
// Update the animated lights...
if (!Interior::smUseVertexLighting)
{
LightInfo& rLightInfo = mLightInfo[interiorImage->mDetailLevel];
downloadLightmaps(state, pInterior, rLightInfo);
}
PROFILE_END();
PROFILE_START(IRO_RenderSolids);
if(mDoSimpleDynamicRender)
installLights();
// Set up the model view and the global render state...
RectI viewport;
dglGetViewport(&viewport);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
dglMultMatrix(&mRenderObjToWorld);
glScalef(mObjScale.x, mObjScale.y, mObjScale.z);
glEnable(GL_BLEND);
glDisable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);
// We need to decide if we're going to use the low-res textures
Point3F camPoint = state->getCameraPosition();
Point3F closestPoint = getRenderWorldBox().getClosestPoint(camPoint);
F32 dist = (camPoint - closestPoint).len();
if (dist != 0.0)
{
F32 length = dglProjectRadius(dist, 1.0f / pInterior->mAveTexGenLength);
if (length < (1.0 / 16.0))
{
TextureManager::setSmallTexturesActive(true);
}
}
pInterior->setupFog(state);
pInterior->setOSCamPosition(osPoint);
if (interiorImage->mBaseZone != 0)
state->setupZoneProjection(interiorImage->mBaseZone + mZoneRangeStart - 1);
else
state->setupObjectProjection(this);
gInteriorFogColor = state->getFogColor();
// make sure to build vertex color information in case interiors were
// added after the relight scene
if(&((*mVertexColorsNormal[interiorImage->mDetailLevel])[0]) == NULL)
rebuildVertexColors();
if(mDoSimpleDynamicRender)
{
pInterior->renderAsShape();
}
else
{
pInterior->render(mAlarmState, mMaterialMaps[interiorImage->mDetailLevel], mLMHandle,
mVertexColorsNormal[interiorImage->mDetailLevel],
mVertexColorsAlarm[interiorImage->mDetailLevel]);
}
pInterior->clearFog();
if(mDoSimpleDynamicRender)
uninstallLights();
PROFILE_END();
PROFILE_START(IRO_RenderDynamicLights);
// Do dynamic lights if appropriate.
if (smRenderDynamicLights == true)
{
// Are there any lights?
const S32 numLights = gClientSceneGraph->getLightManager()->getNumLights();
if (numLights > 0)
{
// Read out light info...
U32 lightWaterMark = FrameAllocator::getWaterMark();
::LightInfo** lightArray = (::LightInfo**)FrameAllocator::alloc(sizeof(::LightInfo*) * numLights);
gClientSceneGraph->getLightManager()->getLights(lightArray);
for (U32 i = 0; i < numLights; i++)
{
// Only consider point lights.
if (lightArray[i]->mType != ::LightInfo::Point)
continue;
Point3F lightPoint = lightArray[i]->mPos;
mRenderWorldToObj.mulP(lightPoint);
lightPoint.convolveInverse(mObjScale);
Box3F box;
box.min = lightPoint;
box.max = lightPoint;
box.min -= Point3F(lightArray[i]->mRadius, lightArray[i]->mRadius, lightArray[i]->mRadius);
box.max += Point3F(lightArray[i]->mRadius, lightArray[i]->mRadius, lightArray[i]->mRadius);
// TODO: Account for scale...
if (mObjBox.isOverlapped(box) == false)
continue;
// The number of light surfaces cannot exceed the total number of non-null surfaces in
// interior...
U32 subWaterMark = FrameAllocator::getWaterMark();
U32* lightSurfaces = (U32*)FrameAllocator::alloc(pInterior->mSurfaces.size() * sizeof(U32));
U32 numLightSurfaces = 0;
if (pInterior->buildLightPolyList(lightSurfaces, &numLightSurfaces,
box, mRenderWorldToObj, getScale()) == false)
{
FrameAllocator::setWaterMark(subWaterMark);
continue;
}
pInterior->renderLights(lightArray[i], mRenderWorldToObj, getScale(), lightSurfaces, numLightSurfaces);
FrameAllocator::setWaterMark(subWaterMark);
}
FrameAllocator::setWaterMark(lightWaterMark);
}
}
PROFILE_END();
glDisable(GL_BLEND);
if (dglDoesSupportARBMultitexture())
{
glActiveTextureARB(GL_TEXTURE1_ARB);
glDisable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glActiveTextureARB(GL_TEXTURE0_ARB);
glDisable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
else
{
glDisable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
glMatrixMode(GL_PROJECTION);
glPopMatrix();
dglSetViewport(viewport);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
FrameAllocator::setWaterMark(storedWaterMark);
dglSetRenderPrimType(0);
// Reset the small textures...
TextureManager::setSmallTexturesActive(false);
PROFILE_END();
}
//--------------------------------------------------------------------------
bool InteriorInstance::scopeObject(const Point3F& rootPosition,
const F32 /*rootDistance*/,
bool* zoneScopeState)
{
AssertFatal(isManagingZones(), "Error, should be a zone manager if we are called on to scope the scene!");
if (bool(mInteriorRes) == false)
return false;
Interior* pInterior = getDetailLevel(0);
AssertFatal(pInterior->mZones.size() <= csgMaxZoneSize, "Error, too many zones! Increase max");
bool* pInteriorScopingState = sgScopeBoolArray;
dMemset(pInteriorScopingState, 0, sizeof(bool) * pInterior->mZones.size());
// First, let's transform the point into the interior's space
Point3F interiorRoot = rootPosition;
getWorldTransform().mulP(interiorRoot);
interiorRoot.convolveInverse(getScale());
S32 realStartZone = getPointZone(rootPosition);
if (realStartZone != 0)
realStartZone = realStartZone - mZoneRangeStart + 1;
bool continueOut = pInterior->scopeZones(realStartZone,
interiorRoot,
pInteriorScopingState);
// Copy pInteriorScopingState to zoneScopeState
for (S32 i = 1; i < pInterior->mZones.size(); i++)
zoneScopeState[i + mZoneRangeStart - 1] = pInteriorScopingState[i];
return continueOut;
}
//--------------------------------------------------------------------------
U32 InteriorInstance::calcDetailLevel(SceneState* state, const Point3F& wsPoint)
{
AssertFatal(mInteriorRes, "Error, should not try to calculate the deatil level without a resource to work with!");
AssertFatal(getNumCurrZones() > 0, "Error, must belong to a zone for this to work");
if (smDetailModification < 0.3)
smDetailModification = 0.3;
if (smDetailModification > 1.0)
smDetailModification = 1.0;
// Early out for simple interiors
if (mInteriorRes->getNumDetailLevels() == 1)
return 0;
if((mForcedDetailLevel >= 0) && (mForcedDetailLevel < mInteriorRes->getNumDetailLevels()))
return(mForcedDetailLevel);
Point3F osPoint = wsPoint;
mRenderWorldToObj.mulP(osPoint);
osPoint.convolveInverse(mObjScale);
// First, see if the point is in the object space bounding box of the highest detail
// If it is, then the detail level is zero.
if (mObjBox.isContained(osPoint))
return 0;
// Otherwise, we're going to have to do some ugly trickery to get the projection.
// I've stolen the worldToScreenScale from dglMatrix, we'll have to calculate the
// projection of the bounding sphere of the lowest detail level.
// worldToScreenScale = (near * view.extent.x) / (right - left)
RectI viewport;
F64 frustum[4] = { 1e10, -1e10, 1e10, -1e10 };
bool init = false;
SceneObjectRef* pWalk = mZoneRefHead;
AssertFatal(pWalk != NULL, "Error, object must exist in at least one zone to call this!");
while (pWalk)
{
const SceneState::ZoneState& rState = state->getZoneState(pWalk->zone);
if (rState.render == true)
{
// frustum
if (rState.frustum[0] < frustum[0]) frustum[0] = rState.frustum[0];
if (rState.frustum[1] > frustum[1]) frustum[1] = rState.frustum[1];
if (rState.frustum[2] < frustum[2]) frustum[2] = rState.frustum[2];
if (rState.frustum[3] > frustum[3]) frustum[3] = rState.frustum[3];
// viewport
if (init == false)
viewport = rState.viewport;
else
viewport.unionRects(rState.viewport);
init = true;
}
pWalk = pWalk->nextInObj;
}
AssertFatal(init, "InteriorInstance::calcDetailLevel - Error, at least one zone must be rendered here!");
const F32 worldToScreenScale = (state->getNearPlane() * viewport.extent.x) / (frustum[1] - frustum[0]);
const SphereF& lowSphere = mInteriorRes->getDetailLevel(mInteriorRes->getNumDetailLevels() - 1)->mBoundingSphere;
const F32 dist = (lowSphere.center - osPoint).len();
F32 projRadius = (lowSphere.radius / dist) * worldToScreenScale;
// Scale the projRadius based on the objects maximum scale axis
projRadius *= getMax(mFabs(mObjScale.x), getMax(mFabs(mObjScale.y), mFabs(mObjScale.z)));
// Multiply based on detail preference...
projRadius *= smDetailModification;
// Ok, now we have the projected radius, we need to search through the interiors to
// find the largest interior that will support this projection.
U32 final = mInteriorRes->getNumDetailLevels() - 1;
for (U32 i = 0; i< mInteriorRes->getNumDetailLevels() - 1; i++)
{
Interior* pDetail = mInteriorRes->getDetailLevel(i);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -