Пример #1
0
	~SkyEmitter() {
		#if SPECTRUM_SAMPLES == 3
			for (int i=0; i<SPECTRUM_SAMPLES; ++i)
				arhosek_tristim_skymodelstate_free(m_state[i]);
		#else
			for (int i=0; i<SPECTRUM_SAMPLES; ++i)
				arhosekskymodelstate_free(m_state[i]);
		#endif
	}
Пример #2
0
    TextureResult HosekWilkieSky(const BufferUploads::TextureDesc& desc, const ParameterBox& parameters)
    {
            // The "turbidity" parameter is Linke’s turbidity factor. Hosek and Wilkie give these example parameters:
            //      T = 2 yields a very clear, Arctic-like sky
            //      T = 3 a clear sky in a temperate climate
            //      T = 6 a sky on a warm, moist day
            //      T = 10 a slightly hazy day
            //      T > 50 represent dense fog

        auto defaultSunDirection = Normalize(Float3(1.f, 1.f, 0.33f));
        Float3 sunDirection = parameters.GetParameter<Float3>(ParameterBox::ParameterNameHash("SunDirection"), defaultSunDirection);
        sunDirection = Normalize(sunDirection);

        auto turbidity = (double)parameters.GetParameter(ParameterBox::ParameterNameHash("turbidity"), 3.f);
        auto albedo = (double)parameters.GetParameter(ParameterBox::ParameterNameHash("albedo"), 0.1f);
        auto elevation = (double)Deg2Rad(parameters.GetParameter(ParameterBox::ParameterNameHash("elevation"), XlASin(sunDirection[2])));
        auto* state = arhosek_rgb_skymodelstate_alloc_init(turbidity, albedo, elevation);

        auto pixels = std::make_unique<Float4[]>(desc._width*desc._height);
        for (unsigned y=0; y<desc._height; ++y)
            for (unsigned x=0; x<desc._width; ++x) {
                auto p = y*desc._width+x;
                pixels[p] = Float4(0.f, 0.f, 0.f, 1.f);

                Float3 direction(0.f, 0.f, 0.f);
                bool hitPanel = false;

                for (unsigned c = 0; c < 6; ++c) {
                    Float2 tc(x / float(desc._width), y / float(desc._height));
                    auto tcMins = s_verticalPanelCoords[c][0];
                    auto tcMaxs = s_verticalPanelCoords[c][1];
                    if (tc[0] >= tcMins[0] && tc[1] >= tcMins[1] && tc[0] <  tcMaxs[0] && tc[1] <  tcMaxs[1]) {
                        tc[0] = 2.0f * (tc[0] - tcMins[0]) / (tcMaxs[0] - tcMins[0]) - 1.0f;
                        tc[1] = 2.0f * (tc[1] - tcMins[1]) / (tcMaxs[1] - tcMins[1]) - 1.0f;

                        hitPanel = true;
                        auto plusX = s_verticalPanels[c][0];
                        auto plusY = s_verticalPanels[c][1];
                        auto center = s_verticalPanels[c][2];
                        direction = center + plusX * tc[0] + plusY * tc[1];
                    }
                }

                if (hitPanel) {
                    auto theta = CartesianToSpherical(direction)[0];
                    theta = std::min(.4998f * gPI, theta);
                    auto gamma = XlACos(std::max(0.f, Dot(Normalize(direction), sunDirection)));

                    auto R = arhosek_tristim_skymodel_radiance(state, theta, gamma, 0);
                    auto G = arhosek_tristim_skymodel_radiance(state, theta, gamma, 1);
                    auto B = arhosek_tristim_skymodel_radiance(state, theta, gamma, 2);

                    pixels[p][0] = (float)R;
                    pixels[p][1] = (float)G;
                    pixels[p][2] = (float)B;
                }
            }

        arhosekskymodelstate_free(state);

        return TextureResult
            {
                BufferUploads::CreateBasicPacket(
                    (desc._width*desc._height)*sizeof(Float4),
                    pixels.get(),
                    BufferUploads::TexturePitches(desc._width*sizeof(Float4), desc._width*desc._height*sizeof(Float4))),
                RenderCore::Metal::NativeFormat::R32G32B32A32_FLOAT,
                UInt2(desc._width, desc._height)
            };
    }
Пример #3
0
    Float3 SunLuminance(bool& cached)
    {
        Float3 sunDirection = AppSettings::SunDirection;
        sunDirection.y = Saturate(sunDirection.y);
        sunDirection = Float3::Normalize(sunDirection);
        const float turbidity = Clamp(AppSettings::Turbidity.Value(), 1.0f, 32.0f);
        const float intensityScale = AppSettings::SunIntensityScale;
        const Float3 tintColor = AppSettings::SunTintColor;
        const bool32 normalizeIntensity = AppSettings::NormalizeSunIntensity;
        const float sunSize = AppSettings::SunSize;

        static float turbidityCache = 2.0f;
        static Float3 sunDirectionCache = Float3(-0.579149902f, 0.754439294f, -0.308879942f);
        static Float3 luminanceCache = Float3(1.61212531e+009f, 1.36822630e+009f, 1.07235315e+009f);
        static Float3 sunTintCache = Float3(1.0f, 1.0f, 1.0f);
        static float sunIntensityCache = 1.0f;
        static bool32 normalizeCache = false;
        static float sunSizeCache = AppSettings::BaseSunSize;

        if(turbidityCache == turbidity && sunDirection == sunDirectionCache
            && intensityScale == sunIntensityCache && tintColor == sunTintCache
            && normalizeCache == normalizeIntensity && sunSize == sunSizeCache)
        {
            cached = true;
            return luminanceCache;
        }

        cached = false;

        float thetaS = std::acos(1.0f - sunDirection.y);
        float elevation = Pi_2 - thetaS;

        // Get the sun's luminance, then apply tint and scale factors
        Float3 sunLuminance;

        // For now, we'll compute an average luminance value from Hosek solar radiance model, even though
        // we could compute illuminance directly while we're sampling the disk
        SampledSpectrum groundAlbedoSpectrum = SampledSpectrum::FromRGB(GroundAlbedo);
        SampledSpectrum solarRadiance;

        const uint64 NumDiscSamples = 4;
        for(uint64 x = 0; x < NumDiscSamples; ++x)
        {
            for(uint64 y = 0; y < NumDiscSamples; ++y)
            {
                float u = (x + 0.5f) / NumDiscSamples;
                float v = (y + 0.5f) / NumDiscSamples;
                Float2 discSamplePos = SquareToConcentricDiskMapping(u, v);

                float theta = elevation + discSamplePos.y * DegToRad(AppSettings::BaseSunSize);
                float gamma = discSamplePos.x * DegToRad(AppSettings::BaseSunSize);

                for(int32 i = 0; i < NumSpectralSamples; ++i)
                {
                    ArHosekSkyModelState* skyState = arhosekskymodelstate_alloc_init(elevation, turbidity, groundAlbedoSpectrum[i]);
                    float wavelength = Lerp(float(SampledLambdaStart), float(SampledLambdaEnd), i / float(NumSpectralSamples));

                    solarRadiance[i] = float(arhosekskymodel_solar_radiance(skyState, theta, gamma, wavelength));

                    arhosekskymodelstate_free(skyState);
                    skyState = nullptr;
                }

                Float3 sampleRadiance = solarRadiance.ToRGB();
                sunLuminance += sampleRadiance;
            }
        }

        // Account for luminous efficiency, coordinate system scaling, and sample averaging
        sunLuminance *= 683.0f * 100.0f * (1.0f / NumDiscSamples) * (1.0f / NumDiscSamples);

        sunLuminance = sunLuminance * tintColor;
        sunLuminance = sunLuminance * intensityScale;

        if(normalizeIntensity)
        {
            // Normalize so that the intensity stays the same even when the sun is bigger or smaller
            const float baseIntegral = IlluminanceIntegral(DegToRad(AppSettings::BaseSunSize));
            const float currIntegral = IlluminanceIntegral(DegToRad(AppSettings::SunSize));
            sunLuminance *= (baseIntegral / currIntegral);
        }

        turbidityCache = turbidity;
        sunDirectionCache = sunDirection;
        luminanceCache = sunLuminance;
        sunIntensityCache = intensityScale;
        sunTintCache = tintColor;
        normalizeCache = normalizeIntensity;
        sunSizeCache = sunSize;

        return sunLuminance;
    }