📄 tsshapeinstance.cc
字号:
if (size<=mShape->mSmallestVisibleSize)
{
// don't render...
mCurrentDetailLevel=-1;
mCurrentIntraDetailLevel = 0.0f;
return -1;
}
// same detail level as last time?
// only search for detail level if the current one isn't the right one already
if ( mCurrentDetailLevel<0 ||
(mCurrentDetailLevel==0 && size<=mShape->details[0].size) ||
(mCurrentDetailLevel>0 && (size<=mShape->details[mCurrentDetailLevel].size || size>mShape->details[mCurrentDetailLevel-1].size)))
{
// scan shape for highest detail size smaller than us...
// shapes details are sorted from largest to smallest...
// a detail of size <= 0 means it isn't a renderable detail level (utility detail)
for (S32 i=0; i<mShape->details.size(); i++)
{
if (size>mShape->details[i].size)
{
mCurrentDetailLevel = i;
break;
}
if (i+1>=mShape->details.size() || mShape->details[i+1].size<0)
{
// We've run out of details and haven't found anything?
// Let's just grab this one.
mCurrentDetailLevel = i;
break;
}
}
}
F32 curSize = mShape->details[mCurrentDetailLevel].size;
F32 nextSize = mCurrentDetailLevel==0 ? 2.0f * curSize : mShape->details[mCurrentDetailLevel-1].size;
mCurrentIntraDetailLevel = nextSize-curSize>0.01f ? (size-curSize) / (nextSize-curSize) : 1.0f;
mCurrentIntraDetailLevel = mCurrentIntraDetailLevel>1.0f ? 1.0f : (mCurrentIntraDetailLevel<0.0f ? 0.0f : mCurrentIntraDetailLevel);
// now restrict chosen detail level by cutoff value
S32 cutoff = getMin(smNumSkipRenderDetails,mShape->mSmallestVisibleDL);
if (mCurrentDetailLevel>=0 && mCurrentDetailLevel<cutoff)
{
mCurrentDetailLevel = cutoff;
mCurrentIntraDetailLevel = 1.0f;
}
return mCurrentDetailLevel;
}
S32 TSShapeInstance::selectCurrentDetailEx(F32 errorTOL)
{
// note: we use 10 time the average error as the metric...this is
// more robust than the maxError...the factor of 10 is to put average error
// on about the same scale as maxError. The errorTOL is how much
// error we are able to tolerate before going to a more detailed version of the
// shape. We look for a pair of details with errors bounding our errorTOL,
// and then we select an interpolation parameter to tween betwen them. Ok, so
// this isn't exactly an error tolerance. A tween value of 0 is the lower poly
// model (higher detail number) and a value of 1 is the higher poly model (lower
// detail number).
// deal with degenerate case first...
// if smallest detail corresponds to less than half tolerable error, then don't even draw
F32 prevErr;
if (mShape->mSmallestVisibleDL<0)
prevErr=0.0f;
else
prevErr = 10.0f * mShape->details[mShape->mSmallestVisibleDL].averageError * 20.0f;
if (mShape->mSmallestVisibleDL<0 || prevErr<errorTOL)
{
// draw last detail
mCurrentDetailLevel=mShape->mSmallestVisibleDL;
mCurrentIntraDetailLevel = 0.0f;
return mCurrentDetailLevel;
}
// this function is a little odd
// the reason is that the detail numbers correspond to
// when we stop using a given detail level...
// we search the details from most error to least error
// until we fit under the tolerance (errorTOL) and then
// we use the next highest detail (higher error)
for (S32 i=mShape->mSmallestVisibleDL; i>=0; i--)
{
F32 err0 = 10.0f * mShape->details[i].averageError;
if (err0 < errorTOL)
{
// ok, stop here
// intraDL = 1 corresponds to fully this detail
// intraDL = 0 corresponds to the next lower (higher number) detail
mCurrentDetailLevel = i;
mCurrentIntraDetailLevel = 1.0f - (errorTOL-err0)/(prevErr-err0);
return mCurrentDetailLevel;
}
prevErr=err0;
}
// get here if we are drawing at DL==0
mCurrentDetailLevel = 1;
mCurrentIntraDetailLevel = 1.0f;
return mCurrentDetailLevel;
}
GBitmap * TSShapeInstance::snapshot(TSShape * shape, U32 width, U32 height, bool mip, MatrixF & cameraPos, S32 dl, F32 intraDL, bool hiQuality)
{
TSShapeInstance * shapeInstance = new TSShapeInstance(shape, true);
shapeInstance->setCurrentDetail(dl,intraDL);
shapeInstance->animate();
GBitmap * bmp = shapeInstance->snapshot(width,height,mip,cameraPos,hiQuality);
delete shapeInstance;
return bmp;
}
GBitmap * TSShapeInstance::snapshot(U32 width, U32 height, bool mip, MatrixF & cameraPos, S32 dl, F32 intraDL, bool hiQuality)
{
setCurrentDetail(dl,intraDL);
animate();
return snapshot(width,height,mip,cameraPos,hiQuality);
}
GBitmap * TSShapeInstance::snapshot(U32 width, U32 height, bool mip, MatrixF & cameraMatrix,bool hiQuality)
{
U32 screenWidth = Platform::getWindowSize().x;
U32 screenHeight = Platform::getWindowSize().y;
U32 xcenter = screenWidth >> 1;
U32 ycenter = screenHeight >> 1;
if (screenWidth==0 || screenHeight==0)
return NULL; // probably in exporter...
AssertFatal(width<screenWidth && height<screenHeight,"TSShapeInstance::snapshot: bitmap cannot be larger than screen resolution");
S32 scale = 1;
if (hiQuality)
while ((scale<<1)*width <= screenWidth && (scale<<1)*height <= screenHeight)
scale <<= 1;
if (scale>smMaxSnapshotScale)
scale = smMaxSnapshotScale;
// height and width of intermediate bitmaps
U32 bmpWidth = width*scale;
U32 bmpHeight = height*scale;
Point4F saveClearColor;
glGetFloatv(GL_COLOR_CLEAR_VALUE,(F32*)&saveClearColor);
// setup viewport and frustrum (do orthographic projection)
dglSetViewport(RectI(xcenter-(bmpWidth>>1),ycenter-(bmpHeight>>1),bmpWidth,bmpHeight));
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
dglSetFrustum(-mShape->radius, mShape->radius, -mShape->radius, mShape->radius, 1, 20.0f * mShape->radius,true);
// position camera...
glMatrixMode(GL_MODELVIEW);
Point3F y;
cameraMatrix.getColumn(1,&y);
y *= -10.0f * mShape->radius;
y += mShape->center;
cameraMatrix.setColumn(3,y);
cameraMatrix.inverse();
dglLoadMatrix(&cameraMatrix);
// set some initial gl states
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
// take a snapshot of the shape with a black background...
glClearColor(0,0,0,0);
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
GBitmap * blackBmp = new GBitmap;
blackBmp->allocateBitmap(bmpWidth,bmpHeight,false,GBitmap::RGB);
render(mCurrentDetailLevel,mCurrentIntraDetailLevel);
glReadPixels(xcenter-(bmpWidth>>1),ycenter-(bmpHeight>>1),bmpWidth,bmpHeight,GL_RGB,GL_UNSIGNED_BYTE,(void*)blackBmp->getBits(0));
// take a snapshot of the shape with a white background...
glClearColor(1,1,1,1);
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
GBitmap * whiteBmp = new GBitmap;
whiteBmp->allocateBitmap(bmpWidth,bmpHeight,false,GBitmap::RGB);
render(mCurrentDetailLevel,mCurrentIntraDetailLevel);
glReadPixels(xcenter-(bmpWidth>>1),ycenter-(bmpHeight>>1),bmpWidth,bmpHeight,GL_RGB,GL_UNSIGNED_BYTE,(void*)whiteBmp->getBits(0));
glDisable(GL_DEPTH_TEST);
glClearColor(saveClearColor.x,saveClearColor.y,saveClearColor.z,saveClearColor.w);
// now separate the color and alpha channels
GBitmap * bmp = new GBitmap;
bmp->allocateBitmap(width,height,mip,GBitmap::RGBA);
U8 * wbmp = (U8*)whiteBmp->getBits(0);
U8 * bbmp = (U8*)blackBmp->getBits(0);
U8 * dst = (U8*)bmp->getBits(0);
U32 i,j;
if (hiQuality)
{
for (i=0; i<height; i++)
{
for (j=0; j<width; j++)
{
F32 alphaTally = 0.0f;
S32 alphaIntTally = 0;
S32 alphaCount = 0;
F32 rTally = 0.0f;
F32 gTally = 0.0f;
F32 bTally = 0.0f;
for (S32 k=0; k<scale; k++)
{
for (S32 l=0; l<scale; l++)
{
// shape on black background is alpha * color, shape on white background is alpha * color + (1-alpha) * 255
// we want 255 * alpha, or 255 - (white - black)
U32 pos = 3*((i*scale+k)*bmpWidth+j*scale+l);
U32 alpha = 255 - (wbmp[pos+0] - bbmp[pos+0]);
alpha += 255 - (wbmp[pos+1] - bbmp[pos+1]);
alpha += 255 - (wbmp[pos+2] - bbmp[pos+2]);
F32 floatAlpha = ((F32)alpha)/(1.0f*255.0f);
if (alpha != 0)
{
rTally += bbmp[pos+0];
gTally += bbmp[pos+1];
bTally += bbmp[pos+2];
alphaCount++;
}
alphaTally += floatAlpha;
alphaIntTally += alpha;
}
}
F32 invAlpha = alphaTally > 0.01f ? 1.0f / alphaTally : 0.0f;
U32 pos = 4*(i*width+j);
dst[pos+0] = (U8)(rTally * invAlpha);
dst[pos+1] = (U8)(gTally * invAlpha);
dst[pos+2] = (U8)(bTally * invAlpha);
dst[pos+3] = (U8)(((F32)alphaIntTally) / (F32) (3*alphaCount));
}
}
}
else
{
// simpler, probably faster...
for (i=0; i<height*width; i++)
{
// shape on black background is alpha * color, shape on white background is alpha * color + (1-alpha) * 255
// we want 255 * alpha, or 255 - (white - black)
U32 alpha = 255 - (wbmp[i*3+0] - bbmp[i*3+0]);
alpha += 255 - (wbmp[i*3+1] - bbmp[i*3+1]);
alpha += 255 - (wbmp[i*3+2] - bbmp[i*3+2]);
if (alpha != 0)
{
F32 floatAlpha = ((F32)alpha)/(3.0f*255.0f);
dst[i*4+0] = (U8)(bbmp[i*3+0] / floatAlpha);
dst[i*4+1] = (U8)(bbmp[i*3+1] / floatAlpha);
dst[i*4+2] = (U8)(bbmp[i*3+2] / floatAlpha);
dst[i*4+3] = (U8)(alpha/3);
}
else
{
dst[i*4+0] = dst[i*4+1] = dst[i*4+2] = dst[i*4+3] = 0;
}
}
}
delete blackBmp;
delete whiteBmp;
if (mip)
bmp->extrudeMipLevels();
return bmp;
}
void TSShapeInstance::renderShadow(S32 dl, const MatrixF & mat, S32 dim, U32 * bits)
{
// if dl==-1, nothing to do
if (dl==-1)
return;
AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::renderShadow");
S32 i;
const TSDetail * detail = &mShape->details[dl];
S32 ss = detail->subShapeNum;
S32 od = detail->objectDetailNum;
// assert if we're a billboard detail
AssertFatal(ss>=0,"TSShapeInstance::renderShadow: not with a billboard detail level");
// set up render data
setStatics(dl);
// run through the meshes
smRenderData.currentTransform = NULL;
S32 start = mShape->subShapeFirstObject[ss];
S32 end = start + mShape->subShapeNumObjects[ss];
for (i=start; i<end; i++)
mMeshObjects[i].renderShadow(od,mat,dim,bits,mMaterialList);
// if we have a marix pushed, pop it now
if (smRenderData.currentTransform)
glPopMatrix();
clearStatics();
}
//-------------------------------------------------------------------------------------
// Object (MeshObjectInstance & PluginObjectInstance) render methods
//-------------------------------------------------------------------------------------
void TSShapeInstance::ObjectInstance::render(S32, TSMaterialList *)
{
AssertFatal(0,"TSShapeInstance::ObjectInstance::render: no default render method.");
}
void TSShapeInstance::ObjectInstance::renderEnvironmentMap(S32, TSMaterialList *)
{
AssertFatal(0,"TSShapeInstance::ObjectInstance::renderEnvironmentMap: no default render method.");
}
void TSShapeInstance::ObjectInstance::renderDetailMap(S32, TSMaterialList *)
{
AssertFatal(0,"TSShapeInstance::ObjectInstance::renderDetailMap: no default render method.");
}
void TSShapeInstance::ObjectInstance::renderFog(S32, TSMaterialList*)
{
AssertFatal(0,"TSShapeInstance::ObjectInstance::renderFog: no default render method.");
}
S32 TSShapeInstance::MeshObjectInstance::getSizeVB(S32 size)
{
TSMesh *mesh = getMesh(0);
if (mesh && mesh->getMeshType() == TSMesh::StandardMeshType && mesh->vertsPerFrame > 0)
{
mesh->vbOffset = size;
return mesh->numFrames*mesh->numMatFrames*mesh->vertsPerFrame;
}
else
return 0;
}
bool TSShapeInstance::MeshObjectInstance::hasMergeIndices()
{
TSMesh *mesh = getMesh(0);
return (mesh && mesh->getMeshType() == TSMesh::StandardMeshType && mesh->mergeIndices.size());
}
void TSShapeInstance::MeshObjectInstance::fillVB(S32 vb, TSMaterialList *materials)
{
TSMesh *mesh = getMesh(0);
if (!mesh || mesh->getMeshType() != TSMesh::StandardMeshType || mesh->vertsPerFrame <= 0)
return;
for (S32 f = 0; f < mesh->numFrames; ++f)
for (S32 m = 0; m < mesh->numMatFrames; ++m)
mesh->fillVB(vb,f,m,materials);
}
void TSShapeInstance::MeshObjectInstance::morphVB(S32 vb, S32 &previousMerge, S32 objectDetail, TSMaterialList *materials)
{
if (visible > 0.01f)
{
TSMesh *m0 = getMesh(0);
TSMesh *mesh = getMesh(objectDetail);
if (m0 && mesh)
{
// render TSSortedMesh's standard
if (m0->getMeshType() != TSMesh::StandardMeshType)
return;
GLuint foffset = (frame*m0->numMatFrames + matFrame)*m0->vertsPerFrame;
U32 morphSize = mesh->mergeIndices.size();
S32 merge = mesh->vertsPerFrame-morphSize;
if (!morphSize)
return;
if (previousMerge != -1 && previousMerge < merge)
{
S32 tmp = merge;
merge = previousMerge;
previousMerge = tmp;
morphSize = mesh->vertsPerFrame-merge;
}
else
previousMerge
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -