SampledSpectrum PathTracingRenderer::Job::contribution(const Scene &scene, const WavelengthSamples &initWLs, const Ray &initRay, IndependentLightPathSampler &pathSampler, ArenaAllocator &mem) const {
        WavelengthSamples wls = initWLs;
        Ray ray = initRay;
        SurfacePoint surfPt;
        SampledSpectrum alpha = SampledSpectrum::One;
        float initY = alpha.importance(wls.selectedLambda);
        SampledSpectrumSum sp(SampledSpectrum::Zero);
        uint32_t pathLength = 0;
        
        Intersection isect;
        if (!scene.intersect(ray, &isect))
            return SampledSpectrum::Zero;
        isect.getSurfacePoint(&surfPt);
        
        Vector3D dirOut_sn = surfPt.shadingFrame.toLocal(-ray.dir);
        if (surfPt.isEmitting()) {
            EDF* edf = surfPt.createEDF(wls, mem);
            SampledSpectrum Le = surfPt.emittance(wls) * edf->evaluate(EDFQuery(), dirOut_sn);
            sp += alpha * Le;
        }
        if (surfPt.atInfinity)
            return sp;

        while (true) {
            ++pathLength;
            if (pathLength >= 100)
                break;
            Normal3D gNorm_sn = surfPt.shadingFrame.toLocal(surfPt.gNormal);
            BSDF* bsdf = surfPt.createBSDF(wls, mem);
            BSDFQuery fsQuery(dirOut_sn, gNorm_sn, wls.selectedLambda);
            
            // Next Event Estimation (explicit light sampling)
            if (bsdf->hasNonDelta()) {
                float lightProb;
                Light light;
                scene.selectLight(pathSampler.getLightSelectionSample(), &light, &lightProb);
                SLRAssert(!std::isnan(lightProb) && !std::isinf(lightProb), "lightProb: unexpected value detected: %f", lightProb);
                
                LightPosQuery lpQuery(ray.time, wls);
                LightPosQueryResult lpResult;
                SampledSpectrum M = light.sample(lpQuery, pathSampler.getLightPosSample(), &lpResult);
                SLRAssert(!std::isnan(lpResult.areaPDF)/* && !std::isinf(xpResult.areaPDF)*/, "areaPDF: unexpected value detected: %f", lpResult.areaPDF);
                
                if (scene.testVisibility(surfPt, lpResult.surfPt, ray.time)) {
                    float dist2;
                    Vector3D shadowDir = lpResult.surfPt.getDirectionFrom(surfPt.p, &dist2);
                    Vector3D shadowDir_l = lpResult.surfPt.shadingFrame.toLocal(-shadowDir);
                    Vector3D shadowDir_sn = surfPt.shadingFrame.toLocal(shadowDir);
                    
                    EDF* edf = lpResult.surfPt.createEDF(wls, mem);
                    SampledSpectrum Le = M * edf->evaluate(EDFQuery(), shadowDir_l);
                    float lightPDF = lightProb * lpResult.areaPDF;
                    SLRAssert(!Le.hasNaN() && !Le.hasInf(), "Le: unexpected value detected: %s", Le.toString().c_str());
                    
                    SampledSpectrum fs = bsdf->evaluate(fsQuery, shadowDir_sn);
                    float cosLight = absDot(-shadowDir, lpResult.surfPt.gNormal);
                    float bsdfPDF = bsdf->evaluatePDF(fsQuery, shadowDir_sn) * cosLight / dist2;
                    
                    float MISWeight = 1.0f;
                    if (!lpResult.posType.isDelta() && !std::isinf(lpResult.areaPDF))
                        MISWeight = (lightPDF * lightPDF) / (lightPDF * lightPDF + bsdfPDF * bsdfPDF);
                    SLRAssert(MISWeight <= 1.0f, "Invalid MIS weight: %g", MISWeight);
                    
                    float G = absDot(shadowDir_sn, gNorm_sn) * cosLight / dist2;
                    sp += alpha * Le * fs * (G * MISWeight / lightPDF);
                    SLRAssert(!std::isnan(G) && !std::isinf(G), "G: unexpected value detected: %f", G);
                }
            }
            
            // get a next direction by sampling BSDF.
            BSDFQueryResult fsResult;
            SampledSpectrum fs = bsdf->sample(fsQuery, pathSampler.getBSDFSample(), &fsResult);
            if (fs == SampledSpectrum::Zero || fsResult.dirPDF == 0.0f)
                break;
            if (fsResult.dirType.isDispersive()) {
                fsResult.dirPDF /= WavelengthSamples::NumComponents;
                wls.flags |= WavelengthSamples::LambdaIsSelected;
            }
            alpha *= fs * absDot(fsResult.dir_sn, gNorm_sn) / fsResult.dirPDF;
            SLRAssert(!alpha.hasInf() && !alpha.hasNaN(),
                      "alpha: %s\nlength: %u, cos: %g, dirPDF: %g",
                      alpha.toString().c_str(), pathLength, absDot(fsResult.dir_sn, gNorm_sn), fsResult.dirPDF);
            
            Vector3D dirIn = surfPt.shadingFrame.fromLocal(fsResult.dir_sn);
            ray = Ray(surfPt.p, dirIn, ray.time, Ray::Epsilon);
            
            // find a next intersection point.
            isect = Intersection();
            if (!scene.intersect(ray, &isect))
                break;
            isect.getSurfacePoint(&surfPt);
            
            dirOut_sn = surfPt.shadingFrame.toLocal(-ray.dir);
            
            // implicit light sampling
            if (surfPt.isEmitting()) {
                float bsdfPDF = fsResult.dirPDF;
                
                EDF* edf = surfPt.createEDF(wls, mem);
                SampledSpectrum Le = surfPt.emittance(wls) * edf->evaluate(EDFQuery(), dirOut_sn);
                float lightProb = scene.evaluateProb(Light(isect.obj));
                float dist2 = surfPt.getSquaredDistance(ray.org);
                float lightPDF = lightProb * surfPt.evaluateAreaPDF() * dist2 / absDot(ray.dir, surfPt.gNormal);
                SLRAssert(!Le.hasNaN() && !Le.hasInf(), "Le: unexpected value detected: %s", Le.toString().c_str());
                SLRAssert(!std::isnan(lightPDF)/* && !std::isinf(lightPDF)*/, "lightPDF: unexpected value detected: %f", lightPDF);
                
                float MISWeight = 1.0f;
                if (!fsResult.dirType.isDelta())
                    MISWeight = (bsdfPDF * bsdfPDF) / (lightPDF * lightPDF + bsdfPDF * bsdfPDF);
                SLRAssert(MISWeight <= 1.0f, "Invalid MIS weight: %g", MISWeight);
                
                sp += alpha * Le * MISWeight;
            }
            if (surfPt.atInfinity)
                break;
            
            // Russian roulette
            float continueProb = std::min(alpha.importance(wls.selectedLambda) / initY, 1.0f);
            if (pathSampler.getPathTerminationSample() < continueProb)
                alpha /= continueProb;
            else
                break;
        }
        
        return sp;
    }
Beispiel #2
0
    _Check_return_ VOODOO_METHODDEF(VSCore::Init)(_In_z_ CONST wchar_t * config)
    {
        if (config)
        {
            m_Parser->Add(VSTR("config"), config, VSVar_System);
        }
        else
        {
            m_Parser->Add(VSTR("config"), VSTR("VoodooShader.xml"), VSVar_System);
        }

        // Load variables, built-in first
        {
            wchar_t buffer[MAX_PATH];	ZeroMemory(buffer, MAX_PATH);

            // Global path
            GetVoodooPath(buffer);
            m_Parser->Add(VSTR("path"), buffer, VSVar_System);

            // Bin prefix
            GetVoodooBinPrefix(buffer);
            m_Parser->Add(VSTR("prefix"), buffer, VSVar_System);

            // Framework bin path
            GetVoodooBinPath(buffer);
            m_Parser->Add(VSTR("binpath"), buffer, VSVar_System);

            // Target
            HMODULE pTarget = GetModuleHandle(NULL);
            GetModuleFileName(pTarget, buffer, MAX_PATH);
            m_Parser->Add(VSTR("target"), buffer, VSVar_System);

            // Local path
            PathRemoveFileSpec(buffer);
            PathAddBackslash(buffer);
            m_Parser->Add(VSTR("local"), buffer, VSVar_System);

            // Startup path
            GetCurrentDirectory(MAX_PATH, buffer);
            PathAddBackslash(buffer);
            m_Parser->Add(VSTR("startup"), buffer, VSVar_System);

            GetModuleFileName(gCoreHandle, buffer, MAX_PATH);
            m_Parser->Add(VSTR("core"), buffer, VSVar_System);
        }

        // Command line processing
        LPWSTR cmdline = GetCommandLine();
        m_Parser->Add(VSTR("args"), cmdline, VSVar_System);

        int cmdargc = 0;
        LPWSTR * cmdargv = CommandLineToArgvW(cmdline, &cmdargc);
        m_Parser->Add(VSTR("argc"), StringFormat(VSTR("%d")) << cmdargc, VSVar_System);
        for (int i = 0; i < cmdargc; ++i)
        {
            m_Parser->Add(StringFormat(VSTR("argv_%d")) << i, cmdargv[i], VSVar_System);
        }

        // Load the config
        try
        {
            m_ConfigFile = new pugi::xml_document();

            // Try loading the config file from each major location
            String configPath = m_Parser->Parse(VSTR("$(config)"), VSParse_PathCanon);
            pugi::xml_parse_result result = m_ConfigFile->load_file(configPath.GetData());

            if (!result)
            {
                configPath = m_Parser->Parse(VSTR("$(startup)\\$(config)"), VSParse_PathCanon);
                result = m_ConfigFile->load_file(configPath.GetData());
                if (!result)
                {
                    configPath = m_Parser->Parse(VSTR("$(local)\\$(config)"), VSParse_PathCanon);
                    result = m_ConfigFile->load_file(configPath.GetData());
                    if (!result)
                    {
                        configPath = m_Parser->Parse(VSTR("$(path)\\$(config)"), VSParse_PathCanon);
                        result = m_ConfigFile->load_file(configPath.GetData());
                        if (!result)
                        {
                            Throw(VOODOO_CORE_NAME, VSTR("Unable to find or parse config file."), nullptr);
                        }
                    }
                }
            }

            // Start setting things up
            pugi::xml_node configRoot = static_cast<pugi::xml_node>(*m_ConfigFile);
            pugi::xml_node globalNode = configRoot.select_single_node(L"/VoodooConfig/Global").node();
            if (!globalNode)
            {
                Throw(VOODOO_CORE_NAME, VSTR("Could not find global config node."), nullptr);
            }

            // Create query for node text, used multiple times
            pugi::xpath_query xpq_getName(L"./@name");
            pugi::xpath_query xpq_getText(L"./text()");

            // Load variables
            {
                pugi::xpath_query xpq_getVariables(L"./Variables/Variable");
                pugi::xpath_node_set nodes = xpq_getVariables.evaluate_node_set(globalNode);
                pugi::xpath_node_set::const_iterator iter = nodes.begin();

                while (iter != nodes.end())
                {
                    String name = xpq_getName.evaluate_string(*iter).c_str();
                    String value = xpq_getText.evaluate_string(*iter).c_str();

                    m_Parser->Add(name, value);

                    ++iter;
                }
            }

            // Open the logger as early as possible
            pugi::xpath_query logfQuery(L"./Log/File/text()");
            pugi::xpath_query logaQuery(L"./Log/Append/text()");
            pugi::xpath_query loglQuery(L"./Log/Level/text()");

            String logFile  = m_Parser->Parse(logfQuery.evaluate_string(globalNode));
            String logLevelStr = m_Parser->Parse(loglQuery.evaluate_string(globalNode));
            String logAppendStr = m_Parser->Parse(logaQuery.evaluate_string(globalNode));

            LogLevel logLevel = VSLog_Default;
            try
            {
                logLevel = (LogLevel)stoi(logLevelStr.ToString());
            }
            catch (const std::exception & exc)
            {
                UNREFERENCED_PARAMETER(exc);
                logLevel = VSLog_Default;
            }

            bool logAppend = logAppendStr.Compare(VSTR("true"), false) || logAppendStr.StartsWith("1");

            m_Logger->Open(logFile, logAppend);
            m_Logger->SetFilter(logLevel);

            // Log extended build information
            String configMsg = m_Parser->Parse(VSTR("Config loaded from '$(config)'."));
            m_Logger->LogMessage(VSLog_CoreNotice, VOODOO_CORE_NAME, configMsg);
            m_Logger->LogMessage(VSLog_CoreNotice, VOODOO_CORE_NAME, VOODOO_GLOBAL_COPYRIGHT_FULL);


            // Load plugins, starting with the core
            m_Server->LoadPlugin(this, VSTR("$(core)"));

            {
                pugi::xpath_query xpq_getPluginPaths(L"./Plugins/Path");
                pugi::xpath_query xpq_getFilter(L"./@filter");
                pugi::xpath_node_set nodes = xpq_getPluginPaths.evaluate_node_set(globalNode);
                pugi::xpath_node_set::const_iterator iter = nodes.begin();

                while (iter != nodes.end())
                {
                    String filter = xpq_getFilter.evaluate_string(*iter);
                    String path = xpq_getText.evaluate_string(*iter);

                    m_Server->LoadPath(this, path, filter);

                    ++iter;
                }
            }

            {
                pugi::xpath_query xpq_getPluginFiles(L"./Plugins/File");
                pugi::xpath_node_set nodes = xpq_getPluginFiles.evaluate_node_set(globalNode);
                pugi::xpath_node_set::const_iterator iter = nodes.begin();

                while (iter != nodes.end())
                {
                    String file = xpq_getText.evaluate_string(*iter);

                    m_Server->LoadPlugin(this, file);

                    ++iter;
                }
            }

            // Lookup classes
            pugi::xpath_query fsQuery(L"./Classes/FileSystem/text()");
            pugi::xpath_query hookQuery(L"./Classes/HookManager/text()");
            String fsClass = m_Parser->Parse(fsQuery.evaluate_string(globalNode).c_str());
            String hookClass = m_Parser->Parse(hookQuery.evaluate_string(globalNode).c_str());

            // Load less vital classes
            ObjectRef coreplugin = m_Server->CreateObject(this, hookClass);
            IHookManager * phm = nullptr;
            if (coreplugin && SUCCEEDED(coreplugin->QueryInterface(IID_IHookManager, (IObject**)&phm)) && phm)
            {
                m_HookManager = phm;
                phm->Release();
            }
            else
            {
                StringFormat fmt(VSTR("Unable to create hook manager (class %1%).")); fmt << hookClass;
                Throw(VOODOO_CORE_NAME, fmt, this);
            }

            coreplugin = m_Server->CreateObject(this, fsClass);
            IFileSystem * pfs = nullptr;
            if (coreplugin && SUCCEEDED(coreplugin->QueryInterface(IID_IFileSystem, (IObject**)&pfs)) && pfs)
            {
                m_FileSystem = pfs;
                pfs->Release();
            }
            else
            {
                StringFormat fmt(VSTR("Unable to create file system (class %1%).")); fmt << fsClass;
                Throw(VOODOO_CORE_NAME, fmt, this);
            }

            // ICore done loading
            m_Logger->LogMessage(VSLog_CoreInfo, VOODOO_CORE_NAME, VSTR("Core initialization complete."));

            // Call finalization events
            this->CallEvent(EventIds::Finalize, 0, nullptr);

            // Return
            return VSF_OK;
        }
        catch (const Exception & exc)
        {
            if (m_Logger)
            {
                m_Logger->LogMessage(VSLog_CoreError, VOODOO_CORE_NAME, 
                    StringFormat(VSTR("Exception during Core creation: %1%")) << exc.strwhat());
            } else {
                GlobalLog(VSTR("Unlogged exception during core creation: %S\n"), exc.what());
            }

            return VSF_FAIL;
        }
        catch (const std::exception & exc)
        {
            if (m_Logger)
            {
                m_Logger->LogMessage(VSLog_CoreError, VOODOO_CORE_NAME, 
                    StringFormat(VSTR("Error during Core creation: %1%")) << exc.what());
			} else {
				GlobalLog(VSTR("Unlogged exception during core creation: %S\n"), exc.what());
			}

            return VSF_FAIL;
        }
    }