SkyEmitter(Stream *stream, InstanceManager *manager)
		    : Emitter(stream, manager) {
		m_scale = stream->readFloat();
		m_turbidity = stream->readFloat();
		m_stretch = stream->readFloat();
		m_resolution = stream->readInt();
		m_extend = stream->readBool();
		m_albedo = Spectrum(stream);
		m_sun = SphericalCoordinates(stream);

		Float sunElevation = 0.5f * M_PI - m_sun.elevation;
		#if SPECTRUM_SAMPLES == 3
			for (int i=0; i<SPECTRUM_SAMPLES; ++i)
				m_state[i] = arhosek_rgb_skymodelstate_alloc_init(
					m_turbidity, m_albedo[i], sunElevation);
		#else
			for (int i=0; i<SPECTRUM_SAMPLES; ++i)
				m_state[i] = arhosekskymodelstate_alloc_init(
					m_turbidity, m_albedo[i], sunElevation);
		#endif

		configure();
	}
	SkyEmitter(const Properties &props)
			: Emitter(props) {
		m_scale = props.getFloat("scale", 1.0f);
		m_turbidity = props.getFloat("turbidity", 3.0f);
		m_stretch = props.getFloat("stretch", 1.0f);
		m_resolution = props.getInteger("resolution", 512);
		m_albedo = props.getSpectrum("albedo", Spectrum(0.2f));
		m_sun = computeSunCoordinates(props);
		m_extend = props.getBoolean("extend", false);

		if (m_turbidity < 1 || m_turbidity > 10)
			Log(EError, "The turbidity parameter must be in the range [1,10]!");
		if (m_stretch < 1 || m_stretch > 2)
			Log(EError, "The stretch parameter must be in the range [1,2]!");
		for (int i=0; i<SPECTRUM_SAMPLES; ++i) {
			if (m_albedo[i] < 0 || m_albedo[i] > 1)
				Log(EError, "The albedo parameter must be in the range [0,1]!");
		}

		Float sunElevation = 0.5f * M_PI - m_sun.elevation;

		if (sunElevation < 0)
			Log(EError, "The sun is below the horizon -- this is not supported by the sky model.");

		#if SPECTRUM_SAMPLES == 3
			for (int i=0; i<SPECTRUM_SAMPLES; ++i)
				m_state[i] = arhosek_rgb_skymodelstate_alloc_init(
					m_turbidity, m_albedo[i], sunElevation);
		#else
			for (int i=0; i<SPECTRUM_SAMPLES; ++i)
				m_state[i] = arhosekskymodelstate_alloc_init(
					m_turbidity, m_albedo[i], sunElevation);
		#endif

		configure();
	}
Exemple #3
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)
            };
    }