📄 radgen.cpp
字号:
// Bottom row for the [M]ask and [C]olor maps (for convenience)...
geom::Color3 * bmRow = static_cast<geom::Color3 *>(0);
geom::Color3 * bcRow = static_cast<geom::Color3 *>(0);
if (v < lh-1)
{
bmRow = cmRow + lw;
bcRow = ccRow + lw;
}
for (unsigned int u = 0; u < lw; ++u)
{
// We're only averaging non-masked (i.e. un-occupied) pixels
if (cmRow[u].r()) continue;
// Average each of the 8 neighboring pixels (that have mask colors)
unsigned int count = 0;
geom::Color3 totalColor(0,0,0);
// Top row
if (tmRow)
{
if (u > 0 && tmRow[u-1].r()) totalColor += tcRow[u-1], ++count;
if ( tmRow[u ].r()) totalColor += tcRow[u ], ++count;
if (u < lw-1 && tmRow[u+1].r()) totalColor += tcRow[u+1], ++count;
}
// Current row
{
if (u > 0 && cmRow[u-1].r()) totalColor += ccRow[u-1], ++count;
if (u < lw-1 && cmRow[u+1].r()) totalColor += ccRow[u+1], ++count;
}
// Bottom row
if (bmRow)
{
if (u > 0 && bmRow[u-1].r()) totalColor += bcRow[u-1], ++count;
if ( bmRow[u ].r()) totalColor += bcRow[u ], ++count;
if (u < lw-1 && bmRow[u+1].r()) totalColor += bcRow[u+1], ++count;
}
// The average
if (count) ccRow[u] = totalColor / static_cast<float>(count);
else ccRow[u] = geom::Color3(0,0,0);
}
}
}
}
}
}
// ---------------------------------------------------------------------------------------------------------------------------------
void RadGen::addAmbient()
{
if (ambient() == geom::Color3(0,0,0)) return;
progress()->setCurrentStatus("Adding post-processing ambient light");
for (unsigned int i = 0; i < geometry().lightmaps().size(); ++i)
{
if (!(i&0xf))
{
progress()->setCurrentPercent(static_cast<float>(i) / static_cast<float>(geometry().lightmaps().size()) * 100.0f);
if (progress()->stopRequested()) throw "";
}
geometry().lightmaps()[i].addAmbient(ambient());
}
}
// ---------------------------------------------------------------------------------------------------------------------------------
void RadGen::doGammaCorrection()
{
if (gamma() == 1.0f) return;
progress()->setCurrentStatus("Gamma correction");
for (unsigned int i = 0; i < geometry().lightmaps().size(); ++i)
{
if (!(i&0xf))
{
progress()->setCurrentPercent(static_cast<float>(i) / static_cast<float>(geometry().lightmaps().size()) * 100.0f);
if (progress()->stopRequested()) throw "";
}
geometry().lightmaps()[i].applyGamma(gamma());
}
}
// ---------------------------------------------------------------------------------------------------------------------------------
void RadGen::doClamping()
{
if (clamping() == ClampSaturate)
{
progress()->setCurrentStatus("Clamping with saturation");
for (unsigned int i = 0; i < geometry().lightmaps().size(); ++i)
{
if (!(i&0xf))
{
progress()->setCurrentPercent(static_cast<float>(i) / static_cast<float>(geometry().lightmaps().size()) * 100.0f);
if (progress()->stopRequested()) throw "";
}
geometry().lightmaps()[i].clampSaturate();
}
}
else if (clamping() == ClampRetain)
{
progress()->setCurrentStatus("Clamping with color ratio");
for (unsigned int i = 0; i < geometry().lightmaps().size(); ++i)
{
if (!(i&0xf))
{
progress()->setCurrentPercent(static_cast<float>(i) / static_cast<float>(geometry().lightmaps().size()) * 100.0f);
if (progress()->stopRequested()) throw "";
}
geometry().lightmaps()[i].clampRetainColorRatio();
}
}
}
// ---------------------------------------------------------------------------------------------------------------------------------
void RadGen::go(ProgressDlg * owner)
{
try
{
// Put up the progress dialog...
progress() = owner;
// Load up the geometry
{
//SK:
if (!geometry().readSCENE(inputFilename(), writeOctFilename(), *progress(), defaultReflectivity()))
{
// Error if they didn't ask to stop
if (!progress()->stopRequested())
{
throw "Unable to load the geometry";
}
}
}
// Generate lightmaping coordinates and lightmaps for these polygons
{
LMapGen lmg;
lmg.lightmapWidth() = lightmapWidth();
lmg.lightmapHeight() = lightmapHeight();
lmg.uTexelsPerUnit() = uTexelsPerUnit();
lmg.vTexelsPerUnit() = vTexelsPerUnit();
if (!lmg.generate(*progress(), geometry().polys(), geometry().lightmaps()))
{
throw "Unable to generate lightmap coordinates & lightmaps";
}
}
// Initial energy goes into the lightmaps to color the lights of their own color
distributeInitialEnergy();
// Count up the total patches & elements
countPatchesAndElements();
// Build the octree
SOctree octree;
SOctree::sBuildInfo bi;
{
bi.thresholdLimiter = octreeThreshold();
bi.minRadiusLimiter = octreeMinRadius();
bi.maxDepthLimiter = octreeMaxDepth();
bi.bspQuantizeResolution = bspGaussianResolution();
bi.bspLeastDepthErrorBoundsPercent = bspMinSplitRange();
bi.progressDialog = progress();
bi.patchSubdivisionU = subdivisionU();
bi.patchSubdivisionV = subdivisionV();
if (!octree.build(geometry(), bi))
{
// Error if they didn't ask to stop
if (!progress()->stopRequested()) throw "Unable to build the Octree";
// If they _did_ ask to stop, bail without an error
else throw "";
}
}
// Initial stats
totalAbsorbedEnergy() = geom::Color3(0,0,0);
totalEscapedEnergy() = geom::Color3(0,0,0);
iterationsProcessed() = 0;
initialEnergy() = calcTotalEnergy();
energyThisPass() = 0;
updateStats(*progress());
lightsToProcess() = geometry().lights().size() != 0;
// Run the ratiosity process
octree.traverse(_processEnergy, static_cast<void *>(this));
// Check for a request to bail...
if (progress()->stopRequested())
{
if (progress()->saveResults())
progress()->resetStopped();
else
throw "";
}
// Ambient term estimation for unshot light
geom::Color3 estimatedAmbientTerm(0,0,0);
if (ambientTerm()) estimatedAmbientTerm = calcAmbientTerm();
// Correct polygon edges within the lightmap & add the ambient term
expandEdges();
// Ambient light (yech!)
addAmbient();
// Gamma correction
doGammaCorrection();
// Clamping/Saturation
doClamping();
// Output the .scene file
if (writeOctFile())
{
progress()->setCurrentStatus("Writing scene file");
geometry().writeSCENE(writeOctFilename(), *progress());
}
// Write the raw data?
if (writeRawLightmaps())
{
progress()->setCurrentStatus("Writing lightmaps");
for (unsigned int i = 0; i < geometry().lightmaps().size(); ++i)
{
if (!(i&0xf))
{
progress()->setCurrentPercent(static_cast<float>(i) / static_cast<float>(geometry().lightmaps().size()) * 100.0f);
if (progress()->stopRequested()) throw "";
}
// Write the lightmap
geometry().lightmaps()[i].writePNG(writeRawLightmapsFolder());
}
}
// Deal with results
{
progress()->setFinished();
// Cleanup the progress dialog
progress()->setCurrentStatus("FINISHED");
progress()->setCurrentPercent(0);
}
}
catch(const char *err)
{
if (err && *err) progress()->error(err);
}
//SK:delete progress();
progress() = NULL;
}
// ---------------------------------------------------------------------------------------------------------------------------------
void RadGen::readDefaultParms()
{
// Desktop
/*SK:
char desktopPath[MAX_PATH];
memset(desktopPath, 0, sizeof(desktopPath));
SHGetSpecialFolderPath(NULL, desktopPath, CSIDL_DESKTOPDIRECTORY, 0);
fstl::string defaultOctOutput = fstl::string(desktopPath) + "\\output.oct";
// Lightmap parms
lightmapWidth() = theApp.GetProfileInt("Options", "lightmapWidth", 128);
lightmapHeight() = theApp.GetProfileInt("Options", "lightmapHeight", 128);
uTexelsPerUnit() = 1 / static_cast<float>(atof(theApp.GetProfileString("Options", "uTexelsPerUnitInverse", "16")));
vTexelsPerUnit() = 1 / static_cast<float>(atof(theApp.GetProfileString("Options", "vTexelsPerUnitInverse", "16")));
// Octree parameters
octreeThreshold() = theApp.GetProfileInt("Options", "OctreePolysPerNode", 50000);
octreeMaxDepth() = theApp.GetProfileInt("Options", "OctreeMaxDepth", 50);
octreeMinRadius() = static_cast<float>(atof(theApp.GetProfileString("Options", "OctreeMinRadius", "5.0")));
// Reflectivity
float rr = static_cast<float>(atof(theApp.GetProfileString("Options", "rReflectivity", "0.78")));
float rg = static_cast<float>(atof(theApp.GetProfileString("Options", "rReflectivity", "0.78")));
float rb = static_cast<float>(atof(theApp.GetProfileString("Options", "rReflectivity", "0.78")));
defaultReflectivity() = geom::Color3(rr, rg, rb);
// BSP parameters
bspMinSplitRange() = static_cast<float>(atof(theApp.GetProfileString("Options", "BSPMinSplitRange", "5.0")));
bspGaussianResolution() = theApp.GetProfileInt("Options", "BSPGaussianResolution", 8);
// Input/output parameters
writeRawLightmapsFolder() = fstl::string(theApp.GetProfileString("Options", "outputRawDirectory", desktopPath));
writeRawLightmaps() = theApp.GetProfileInt("Options", "outputRawDirectoryFlag", 0) ? true:false;
writeOctFile() = theApp.GetProfileInt("Options", "outputOctFileFlag", 1) ? true:false;
writeOctFilename() = fstl::string(theApp.GetProfileString("Options", "outputOctFilename", defaultOctOutput.asArray()));
inputFilename() = fstl::string(theApp.GetProfileString("Options", "inputFilename", ""));
// General parms
convergence() = theApp.GetProfileInt("Options", "convergence", 10);
maxIterations() = theApp.GetProfileInt("Options", "enableMaxIterations", 0) ? true:false;
maxIterationsCount() = theApp.GetProfileInt("Options", "maxIterationsCount", 1000);
areaLightMultiplier() = theApp.GetProfileInt("Options", "areaLightMultiplier", 1000000);
pointLightMultiplier() = static_cast<float>(atof(theApp.GetProfileString("Options", "pointLightMultiplier", "0.6")));
subdivisionU() = theApp.GetProfileInt("Options", "subdivisionU", 4);
subdivisionV() = theApp.GetProfileInt("Options", "subdivisionV", 4);
ambientTerm() = theApp.GetProfileInt("Options", "ambientTerm", 1) ? true:false;
useNusselt() = theApp.GetProfileInt("Options", "useNusselt", 0) ? true:false;
directLightOnly() = theApp.GetProfileInt("Options", "directLightOnly", 0) ? true:false;
adaptiveMaxSubdivisionU() = theApp.GetProfileInt("Options", "adaptiveMaxSubdivisionU", 256);
adaptiveMaxSubdivisionV() = theApp.GetProfileInt("Options", "adaptiveMaxSubdivisionV", 256);
adaptivePatchSubdivision() = theApp.GetProfileInt("Options", "adaptivePatchSubdivision", 1) ? true:false;
adaptiveThreshold() = theApp.GetProfileInt("Options", "adaptiveThreshold", 15);
leaveResults() = false;
// Post-processing parms
gamma() = static_cast<float>(theApp.GetProfileInt("Options", "gamma", 0)) / 100.0f;
ambient().r() = static_cast<float>(theApp.GetProfileInt("Options", "rAmbient", 0));
ambient().g() = static_cast<float>(theApp.GetProfileInt("Options", "gAmbient", 0));
ambient().b() = static_cast<float>(theApp.GetProfileInt("Options", "bAmbient", 0));
switch(theApp.GetProfileInt("Options", "clamping", RadGen::ClampNone))
{
case ClampSaturate: clamping() = ClampSaturate; break;
case ClampRetain: clamping() = ClampRetain; break;
default: clamping() = ClampNone; break;
}
*/
}
// ---------------------------------------------------------------------------------------------------------------------------------
// RadGen.cpp - End of file
// ---------------------------------------------------------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -