Ejemplo n.º 1
0
void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[4], Vec3f pos, Vec3f norm)
{
    Color4 in(colorIn);

    const Color4 *ambient;
    if (materialUpdate_ & 1)
        ambient = ∈
    else
        ambient = &materialAmbient;

    const Color4 *diffuse;
    if (materialUpdate_ & 2)
        diffuse = ∈
    else
        diffuse = &materialDiffuse;

    const Color4 *specular;
    if (materialUpdate_ & 4)
        specular = ∈
    else
        specular = &materialSpecular;

    Color4 lightSum0 = globalAmbient * *ambient + materialEmissive;
    Color4 lightSum1(0, 0, 0, 0);

    for (int l = 0; l < 4; l++)
    {
        // can we skip this light?
        if (!gstate.isLightChanEnabled(l))
            continue;

        GELightType type = gstate.getLightType(l);

        Vec3f toLight(0,0,0);
        Vec3f lightDir(0,0,0);

        if (type == GE_LIGHTTYPE_DIRECTIONAL)
            toLight = Vec3f(gstate_c.lightpos[l]);  // lightdir is for spotlights
        else
            toLight = Vec3f(gstate_c.lightpos[l]) - pos;

        bool doSpecular = gstate.isUsingSpecularLight(l);
        bool poweredDiffuse = gstate.isUsingPoweredDiffuseLight(l);

        float distanceToLight = toLight.Length();
        float dot = 0.0f;
        float angle = 0.0f;
        float lightScale = 0.0f;

        if (distanceToLight > 0.0f) {
            toLight /= distanceToLight;
            dot = Dot(toLight, norm);
        }
        // Clamp dot to zero.
        if (dot < 0.0f) dot = 0.0f;

        if (poweredDiffuse)
            dot = powf(dot, specCoef_);

        // Attenuation
        switch (type) {
        case GE_LIGHTTYPE_DIRECTIONAL:
            lightScale = 1.0f;
            break;
        case GE_LIGHTTYPE_POINT:
            lightScale = clamp(1.0f / (gstate_c.lightatt[l][0] + gstate_c.lightatt[l][1]*distanceToLight + gstate_c.lightatt[l][2]*distanceToLight*distanceToLight), 0.0f, 1.0f);
            break;
        case GE_LIGHTTYPE_SPOT:
        case GE_LIGHTTYPE_UNKNOWN:
            lightDir = gstate_c.lightdir[l];
            angle = Dot(toLight.Normalized(), lightDir.Normalized());
            if (angle >= gstate_c.lightangle[l])
                lightScale = clamp(1.0f / (gstate_c.lightatt[l][0] + gstate_c.lightatt[l][1]*distanceToLight + gstate_c.lightatt[l][2]*distanceToLight*distanceToLight), 0.0f, 1.0f) * powf(angle, gstate_c.lightspotCoef[l]);
            break;
        default:
            // ILLEGAL
            break;
        }

        Color4 lightDiff(gstate_c.lightColor[1][l], 0.0f);
        Color4 diff = (lightDiff * *diffuse) * dot;

        // Real PSP specular
        Vec3f toViewer(0,0,1);
        // Better specular
        // Vec3f toViewer = (viewer - pos).Normalized();

        if (doSpecular)
        {
            Vec3f halfVec = (toLight + toViewer);
            halfVec.Normalize();

            dot = Dot(halfVec, norm);
            if (dot > 0.0f)
            {
                Color4 lightSpec(gstate_c.lightColor[2][l], 0.0f);
                lightSum1 += (lightSpec * *specular * (powf(dot, specCoef_) * lightScale));
            }
        }

        if (gstate.isLightChanEnabled(l))
        {
            Color4 lightAmbient(gstate_c.lightColor[0][l], 0.0f);
            lightSum0 += (lightAmbient * *ambient + diff) * lightScale;
        }
    }

    // 4?
    for (int i = 0; i < 4; i++) {
        colorOut0[i] = lightSum0[i] > 1.0f ? 1.0f : lightSum0[i];
        colorOut1[i] = lightSum1[i] > 1.0f ? 1.0f : lightSum1[i];
    }
}
Ejemplo n.º 2
0
vec3 color(const ray& r, hitable *world, int depth)
{
    depth = 0;

    vec3 clearclr(0.0f, 0.0f, 0.0f);
    vec3 coeff(1.0f, 1.0f, 1.0f);

    ray _ray = r;

    vec3 ret(0.0f, 0.0f, 0.0f);
    float pdfb = 0.0f;

    xz_rect ligth_shape(213, 343, 227, 332, 554, nullptr);

#ifdef ENABLE_RUSSIAN_ROULETTE
    for (;;) {
#else
    while (depth < g_maxdepth) {
#endif
        hit_record rec;

        if (world->hit(_ray, 0.001f, 10000, rec)) {
            if (rec.mat_ptr->isEmssive()) {
                // Random direction hits light.

                float w = 1.0f;

                if (depth > 0) {
                    // Compute PDF of area light.
                    hitable_pdf p0(&ligth_shape, _ray.org);
                    float pdfl = p0.value(_ray.dir);

                    // Compute weight by using PDF of this ray which the previous hitted object fired.
                    // ライトにヒットしたレイを飛ばしてきたオブジェクトのマテリアル特性によるレイの拡散に関するPDFを使ってウエイトを計算する.
                    //w = pdfb / (pdfb + pdfl);
                    w = ComputeHeuristic(pdfb, pdfl);
                }

                auto emit = rec.mat_ptr->emit(rec.u, rec.v, rec.p);

                ret += coeff * emit * w;

                return ret;
            }
            else {
                vec3 rr(1.0f, 1.0f, 1.0f);
#ifdef ENABLE_RUSSIAN_ROULETTE
                if (depth > g_rrdepth) {
#if 1
                    auto c = unit_vector(coeff);
                    auto p = math::CMath::Max(c.r(), math::CMath::Max(c.g(), c.b()));

                    auto r = drand48();

                    if (r > p) {
#else
                    auto r = drand48();

                    if (r > 0.5f) {
#endif
                        r = 1.0f / r;
                        rr = vec3(r, r, r);
                    }
                    else {
                        break;
                    }
                }
#endif

                // Just only getting albedo color.
                ray scattered;
                vec3 albedo;
                float pdf;
                rec.mat_ptr->scatter(_ray, rec, albedo, scattered, pdf);

                {
                    // Only for lambert material.
                    cosine_pdf p1(rec.normal);

                    // Generate next ray.
                    auto direction = p1.generate();
                    scattered = ray(rec.p, direction);

                    // Compute PDF of next ray by this object's material.
                    pdfb = p1.value(scattered.dir);

                    // Compute BRDF of this object's material.
                    auto brdf = rec.mat_ptr->scattering_pdf(r, rec, scattered);

                    coeff *= rr * albedo * brdf / pdfb;
                }

                {
                    hitable_pdf p0(&ligth_shape, rec.p);

                    // Generate direction to light.
                    auto lightdir = p0.generate();
                    ray toLight(rec.p, lightdir);

                    hit_record rec_tolight;

                    if (world->hit(toLight, 0.001f, 10000, rec_tolight)) {
                        if (rec_tolight.mat_ptr->isEmssive()) {
                            // Compute PDF of area light.
                            float pdfl = p0.value(toLight.dir);

                            //float w = pdfl / (pdfb + pdfl);
                            float w = w = ComputeHeuristic(pdfl, pdfb);

                            auto emit = rec_tolight.mat_ptr->emit(rec_tolight.u, rec_tolight.v, rec_tolight.p);

                            ret += coeff * emit / pdfl * w;
                        }
                    }
                }

                // Set next ray.
                _ray = scattered;
            }
        }
        else {
            return clearclr;
        }

        depth++;
    }

    return ret;
}

static void errorCallback(int error, const char* description)
{
    PRINTF("Error: %s\n", description);
}