#Diffuse Lighting in Custom Graphics Engine

7 messages · Page 1 of 1 (latest)

sweet sundial
#

The way my engine is supposed to work is by reading in .ini files that contain the information about the scene. For this example I am working with the following scene which consists of ambient light, diffuse light and an orange icosahedron. (See the attached images for more information). Everything works fine up to diffuse lighting (ambient light, or when no lighting is specified (ambient is just cranked up to 1)).

[General]
size = 1024
backgroundcolor = (0, 0, 0)
type = "LightedZBuffering"
nrLights = 1
eye = (100, 50, 75)
nrFigures = 1

[Light0]
infinity = TRUE
direction = (-1, -1, -1)
ambientLight = (1, 1, 1)
diffuseLight = (1, 1, 1)

[Figure0]
type = "Icosahedron"
scale = 1
rotateX = 0
rotateY = 0
rotateZ = 0
center = (0, 0, 0)
ambientReflection = (0.50, 0.25, 0.00)
diffuseReflection = (0.50, 0.25, 0.00)
brisk parcelBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

sweet sundial
#

First it will read in this ini file and generate the required objects and process the lights. (The figures work fine so here is the light parsing:)

    const int nrLights = configuration["General"]["nrLights"].as_int_or_die();
    for (int lightI = 0; lightI < nrLights; lightI++) {
        const ini::Section lightSection = configuration["Light" + std::to_string(lightI)];

        std::vector<double> ambient = lightSection["ambientLight"].as_double_tuple_or_default({0, 0, 0});
        std::vector<double> diffuse = lightSection["diffuseLight"].as_double_tuple_or_default({0, 0, 0});
        std::vector<double> specular = lightSection["specularLight"].as_double_tuple_or_default({0, 0, 0});

        const bool infinity = lightSection["infinity"].as_bool_or_default(false);
        std::vector<double> directionData = lightSection["direction"].as_double_tuple_or_default({});

        // Infinite light
        if (infinity && !directionData.empty()) {
            Vector3D direction = Vector3D::vector(directionData[0], directionData[1], directionData[2]);
            direction *= eyePointMatrix; // <--- notable
            direction.normalise(); // <--- notable
            direction = -direction; // <--- notable

            this->lights.push_back(new InfiniteLight(ambient, diffuse, specular, direction));
            continue;
        }

        std::vector<double> locationData = lightSection["location"].as_double_tuple_or_default({});
        double angle = lightSection["angle"].as_double_or_default(0);

        // Spot light
        if (!locationData.empty()) {
            Vector3D location = Vector3D::vector(locationData[0], locationData[1], locationData[2]);

            this->lights.push_back(new PointLight(ambient, diffuse, specular, location, angle));
            continue;
        }

        // Ambient light
        this->lights.push_back(new Light(ambient, diffuse, specular));
    }
#

The real rendering happens here:

void img::EasyImage::drawZBuffedTriangle(std::vector<double>& zBuffer, const Triangle& triangle, const double& d, const double& dx, const double& dy, const std::vector<Light*>& lights) {
    Vector3D A = triangle.A;
    Vector3D B = triangle.B;
    Vector3D C = triangle.C;

    Vector3D normal = Vector3D::cross(B - A, C - A);
    normal.normalise();

    // [...] other code to calculate triangle points and bounding boxes    

    const Color color = getColor(triangle, lights, normal);
    for (int y = ymin; y <= ymax; y++) {
        // [...] more code for boudning boxes

    for (int x = xstart; x <= xend; x++) {
        const double z = a * x + b * y + c;

        const int idx = y * width + x;
        if (z <= zBuffer[idx]) continue;
            zBuffer[idx] = z;
            (*this)(x, y) = color;
        }
    }
}
#

And then my getColor function

img::Color img::EasyImage::getColor(const Triangle &triangle, const std::vector<Light*> &lights, const Vector3D& normal) {
    double red = 0, green = 0, blue = 0;

    for (Light *light: lights) {
        red += triangle.ambientReflection[0] * light->getAmbientLight()[0];
        green += triangle.ambientReflection[1] * light->getAmbientLight()[1];
        blue += triangle.ambientReflection[2] * light->getAmbientLight()[2];

        if (light->getType() == LightType::INFINITELIGHT) {
            const double alpha = Vector3D::dot(normal, light->getDirection());

            if (alpha > 0) {
                red += triangle.diffuseReflection[0] * light->getDiffuseLight()[0] * alpha;
                green += triangle.diffuseReflection[1] * light->getDiffuseLight()[1] * alpha;
                blue += triangle.diffuseReflection[2] * light->getDiffuseLight()[2] * alpha;
            }
        }
    }

    red = std::min(1.0, std::max(0.0, red));
    green = std::min(1.0, std::max(0.0, green));
    blue = std::min(1.0, std::max(0.0, blue));

    return Color(static_cast<int>(red * 255), static_cast<int>(green * 255), static_cast<int>(blue * 255));
}

Attached is a side by side comparison of my current result (left) and the expected result (right). Please ping me and ask for any elaborations, I have been losing a lot of time on this.

sweet sundial
brisk parcelBOT
#

This question is being automatically marked as stale.
If your question has been answered, type !solved.
If your question is not answered feel free to bump the post or re-ask.
Take a look at !howto ask for tips on improving your question.