Esempio n. 1
0
Vector3
Lambert::shade(const Ray& ray, const HitInfo& hit, const Scene& scene) const
{
	Vector3 L = Vector3(0.0f, 0.0f, 0.0f);

	const Vector3 viewDir = -ray.d; // d is a unit vector

	const Lights *lightlist = scene.lights();

	// loop over all of the lights
	Lights::const_iterator lightIter;
	for (lightIter = lightlist->begin(); lightIter != lightlist->end(); lightIter++)
	{
		PointLight* pLight = *lightIter;

		Vector3 l = pLight->position() - hit.P;

		// the inverse-squared falloff
		float falloff = l.length2();

		// normalize the light direction
		l /= sqrt(falloff);

		// get the irradiance
		Vector3 irradiance = (pLight->color() * pLight->wattage()) * std::max(0.0f, dot(hit.N, l)) / (4.0 * PI * falloff);

		L += irradiance * (m_kd / PI);
	}

	return L;
}
Vector3
SpecularRefractionShading::shade(const Ray& ray, const HitInfo& hit, const Scene& scene) const
{
	Vector3 L = Vector3(0.0f, 0.0f, 0.0f);

	const Vector3 viewDir = -ray.d; // d is a unit vector

	const Lights *lightlist = scene.lights();

	// loop over all of the lights
	Lights::const_iterator lightIter;
	for (lightIter = lightlist->begin(); lightIter != lightlist->end(); lightIter++)
	{
		PointLight* pLight = *lightIter;

		Vector3 l = pLight->position() - hit.P;

		// the inverse-squared falloff
		float falloff = l.length2();

		// normalize the light direction
		l /= sqrt(falloff);

		// get the diffuse component
		float nDotL = dot(hit.N, l);
		Vector3 result = pLight->color();
		result *= m_kd;

		L += std::max(0.0f, nDotL / falloff * pLight->wattage() / PI) * result;

		Vector3 r = (-l + 2 * dot(l, hit.N) * hit.N).normalized();

		float eDotR = dot(viewDir, r);
		eDotR = 0.0f > eDotR ? 0.0f : 1.0f < eDotR ? 1.0f : eDotR; // clamp it to [0..1]
		eDotR = pow(eDotR, 3);
		L += std::max(0.0f, eDotR * falloff * pLight->wattage());
	}

	// add the ambient component
	L += m_ka;

	return L;
}
Esempio n. 3
0
Vector3
Lambert::shade(const Ray& ray, const HitInfo& hit, const Scene& scene, int bounce)
{
    Vector3 L = Vector3(0.0f, 0.0f, 0.0f);
    
    const Vector3 viewDir = -ray.d; // d is a unit vector
    
    const PointLights *lightlist = scene.lights();
    
    // loop over all of the lights
    PointLights::const_iterator lightIter;
    for (lightIter = lightlist->begin(); lightIter != lightlist->end(); lightIter++)
    {
        PointLight* pLight = *lightIter;
    
        Vector3 l = pLight->position() - hit.P;
        
        // the inverse-squared falloff
        float falloff = l.length2();
        
        // normalize the light direction
        l /= sqrt(falloff);

        // get the diffuse component
        float nDotL = dot(hit.N, l);
        Vector3 result = pLight->color();
        result *= m_kd;
        
        L += std::max(0.0f, nDotL/falloff * pLight->wattage() / PI) * result;
    }
    
    // add the ambient component
    L += m_ka;
    
    return L;
}
Esempio n. 4
0
Vector3
Lambert::shade(const Ray& ray, const HitInfo& hit, const Scene& scene) const
{
    Vector3 L = Vector3(0.0f, 0.0f, 0.0f);
    
    const Vector3 viewDir = -ray.d; // d is a unit vector
    
    const Lights *lightlist = scene.lights();

    // reflectance
    if (m_ks != 0 && ray.times <3) {
      Vector3 Wr = -2 * dot(ray.d, hit.N) * hit.N + ray.d;
      Wr.normalize();
      Ray r(hit.P + (EPSILON * Wr), Wr);
      HitInfo hi;
      r.times = ray.times + 1;

      if(scene.trace(hi, r))
          L += m_spec * m_ks * hi.material->shade(r, hi, scene);
    }

    // cellular noise texture
    if(m_noisiness > 0) {
      float at[3] = { hit.P.x, hit.P.y, hit.P.z };
      const long mO = 3;
      float F[mO];
      float delta[mO][3];
      unsigned long *ID = new unsigned long();

      WorleyNoise::noise3D(at, mO, F, delta, ID);
      L += m_noisiness * (0.5f * (F[2] - F[1]));// + PerlinNoise::noise(at[0], at[1], at[2]));
    }

    // loop over all of the lights
    Lights::const_iterator lightIter;
    for (lightIter = lightlist->begin(); lightIter != lightlist->end(); lightIter++)
    {
        PointLight* pLight = *lightIter;
    
        Vector3 l = pLight->position() - hit.P;
        
        // the inverse-squared falloff
        float falloff = l.length2();
        
        // normalize the light direction
        l /= sqrt(falloff);

        // get the diffuse component
        float nDotL = dot(hit.N, l);
        Vector3 result = pLight->color();
        result *= f_diff * m_kd;
        
        L += std::max(0.0f, nDotL/falloff * pLight->wattage() / PI) * result;

        // highlights
        //if (m_ks != 0)
        L += m_spec * pLight->color() * m_ks * max(0.f, pow(dot(viewDir, l), SPECULAR_CONST));
          // / dot(hit.N, l);
    }

    // refraction
    if (m_trans != 0 && ray.times <3) {
      float n = (ray.times % 2 == 0) ? (ENV_INDEX / m_refInd) : (m_refInd / ENV_INDEX);
      float wn = dot(viewDir, hit.N);
      if (wn < 0) wn = -wn;

      Vector3 Wt = -1 * n * (viewDir - wn * hit.N) -
        sqrtf(1 - (n * n) * (1 - wn * wn)) * hit.N;
      Wt.normalize();

      Ray r(hit.P + (EPSILON * Wt), Wt);
      r.times = ray.times + 1;
      HitInfo hi;

      if (scene.trace(hi, r))
        L += m_trans * m_kt * hi.material->shade(r, hi, scene);
    }
    
    // add the ambient component
    L += m_ka;

    if(DO_BOUNCE && ray.times < BOUNCES) {
      float v = rand() / (float)RAND_MAX;
      float u = rand() / (float)RAND_MAX;
      Vector3 coord = hemisphereSample_cos(u,v);

      Vector3 unv = Vector3(rand() / (float)RAND_MAX, rand() / (float)RAND_MAX, rand() / (float)RAND_MAX);
      Vector3 v1 = cross(hit.N, unv);
      Vector3 v2 = cross(v1, hit.N);
      Vector3 dir = coord.x * v1 + coord.z * hit.N + coord.y * v2;
      dir.normalize();
      Ray r(hit.P, dir);
      r.times = ray.times + 1;
      HitInfo hi;

      if(scene.trace(hi, r))
        L+= m_kd * dot(r.d, hit.N) * hit.material->shade(r, hi, scene);
    }
    
    return L;
}
Vector3
RefractiveInterface::shade(const Ray& ray, const HitInfo& hit, const Scene& scene, const bool& isFront) const
{
    Ray rayLight;
    HitInfo hitLight;
    Vector3 L = Vector3(0.0f, 0.0f, 0.0f);

    const Vector3 viewDir = -ray.d; // d is a unit vector

    const PointLights *plightlist = scene.pointLights();
    // loop over all of the POINT lights
    PointLights::const_iterator plightIter;
    for (plightIter = plightlist->begin(); plightIter != plightlist->end(); plightIter++)
    {
        PointLight* pLight = *plightIter;
        Vector3 l = pLight->position() - hit.P;
        rayLight.o = hit.P;
        rayLight.d = l.normalized();
        Vector3 brdf = BRDF(rayLight.d, hit.N, -ray.d, isFront);
        if (brdf == 0) continue;
        if (scene.trace(hitLight, rayLight, 0.0001, l.length())) continue;

        // the inverse-squared falloff
        float falloff = l.length2();

        float nDotL = fabs(dot(hit.N, l));
        Vector3 result = pLight->color();

        L += nDotL / falloff * pLight->wattage() *brdf * result;
    }

    const AreaLights *alightlist = scene.areaLights();
    // loop over all of the lights
    AreaLights::const_iterator alightIter;
    for (alightIter = alightlist->begin(); alightIter != alightlist->end(); alightIter++)
    {
        AreaLight* aLight = *alightIter;
        vec3pdf vp = aLight->randPt();
        Vector3 l = vp.v - hit.P; // shoot a shadow ray to a random point on the area light
        rayLight.o = hit.P;
        rayLight.d = l.normalized();

        Vector3 brdf = BRDF(rayLight.d, hit.N, -ray.d, isFront);
        if (brdf == 0) continue;
        // if the shadow ray hits the "backside of the light" continue to the next area light
        if (!aLight->intersect(hitLight, rayLight)){
            continue;
        }
        // if the shadow ray is occluded by another (hence the "skip") object continue the next light
        if (scene.trace(hitLight, rayLight, aLight, 0.0001, l.length())){
            continue;
        }

        // the inverse-squared falloff
        float falloff = l.length2();

        float nDotL = fabs(dot(hit.N, l));
        Vector3 result = aLight->color();

        L += std::max(0.0f, dot(hitLight.N, -l))* 0.0f, nDotL / falloff*
            aLight->wattage() / aLight->area() *brdf * result / (vp.p);
    }

    // add the ambient component
    L += m_ka;

    return L;
}
Esempio n. 6
0
//Blinn-Phong shading model
Vector3
Specular::shade(Ray& ray, const HitInfo& hit, const Scene& scene) const
{
    Vector3 reflected = Vector3(0.0f, 0.0f, 0.0f);
    Vector3 L = Vector3(0.0f, 0.0f, 0.0f);
    
    //scale down intensity of light in proportion to num of ray bounces
    Vector3 attenuation = k_s * ( 1 / (ray.numBounces+1));
    
    const Lights *lightlist = scene.lights();
    
    // loop over all of the lights
    Lights::const_iterator lightIter;
    for (lightIter = lightlist->begin(); lightIter != lightlist->end(); lightIter++)
    {
        //find reflected vector, given normal and incident light direction
        PointLight* pLight = *lightIter;
        
        //light vector points from hit point to light
        Vector3 l = pLight->position() - hit.P;
        
        //why did we use ray.d here instead of l? Would just need to change calculation a bit
        //to use l
        reflected = ray.d - 2.0f * (dot(hit.N, ray.d)) * hit.N;

        if (ray.numBounces < maxBounces)
        {
            //trace from reflected vector now
            Ray reflect(ray.numBounces + 1);
            reflect.o = hit.P;
            reflect.d = reflected;
            HitInfo hitReflect;
        
            if (scene.trace(hitReflect, reflect, 0.008f))
            {
                //get color from object hit
                //printf("Bounced reflected ray hit something!\n");
                L += attenuation * hitReflect.material->shade(reflect, hitReflect, scene);
            }
            else
            {
                //get color from background
                L += Vector3(0,0,0.5f);//bgColor;
            }
        }

        //Get halfway vector
        Vector3 h = (L + -1 * ray.d).normalize();
        
        Ray shadow_ray(0);
        HitInfo hi;
        
        shadow_ray.o = hit.P;
        shadow_ray.d = l;
        
        //std::cout<<"M = "<<M<< " hit.N = "<<hit.N<<std::endl;

        if (scene.trace(hi, shadow_ray, 0.001f, sqrt(l.length2())))
        {
            // We are in shadow
        }
        else
        {
            //get color of light
            Vector3 color = pLight->color();
            
            //flip vector from eye so points from hit point back to eye
            //L += k_s * color * pow(std::max(0.0f, dot(h, hit.N)), shinyExp);
            //L += attenuation * color * pow(std::max(0.0f, dot(reflected, -ray.d)), shinyExp);
            
            //Specular Highlights
            //This is separate from the reflection calculation because it
            //needs to be dependent on just the shinyExp
            //https://en.wikipedia.org/wiki/Specular_highlight
            
            //Specular calculation for ABSORBED light
            L += attenuation * pow(std::max(0.0f, dot(h, hit.N)), 50* shinyExp);

	    //check entering or exiting and change n1/n2 n2/n1
           //dot product ray.dot.normal  
            //Specular Refraction
            //L += attenuation * color * pow(std::max(0.0f, dot(wt, -ray.d)), shinyExp);
            //std::cout<<"Final Refraction vector = "<<(k_s * color * pow(std::max(0.0f,
            //dot(wt,ray.d)), shinyExp))<<std::endl;
        }
    }
    
    return L;
}
Esempio n. 7
0
Vector3
Phong::shade(const Ray& ray, const HitInfo& rhit, const Scene& scene) const
{
    Vector3 L = Vector3(0.0f, 0.0f, 0.0f);
 	Vector3 randvect(randone(g_rng), randone(g_rng), randone(g_rng));
    const Lights *lightlist = scene.lights();
    
	HitInfo bm_hit = bumpHit(rhit);
    
    // loop over all of the lights
    Lights::const_iterator lightIter;
	Vector3 diffcolor = m_kd * m_texture_kd->shade(ray, bm_hit, scene);
    Vector3 speccolor = m_ks * m_texture_ks->shade(ray, bm_hit, scene);
    // float irrad[3];
    // g_global_illum_map->irradiance_estimate(irrad, bm_hit.P.array(), bm_hit.N.array(), 1.f, 100);
    // L += Vector3(irrad) * diffcolor;
	for (lightIter = lightlist->begin(); lightIter != lightlist->end(); lightIter++)
    {
        PointLight* pLight = *lightIter;

        float shadow_mul = 0.f;

        Vector3 tolight = pLight->position() - bm_hit.P;
        tolight.normalize();
        Vector3 xaxis = randvect.cross(tolight);
        xaxis.normalize();
        Vector3 yaxis = xaxis.cross(tolight);
        yaxis.normalize();
        float xdisk, ydisk;
        do
        {
            xdisk = 1 - 2*randone(g_rng);
            ydisk = 1 - 2*randone(g_rng);
        } while (xdisk*xdisk + ydisk*ydisk > 1);
        Vector3 posinlight = pLight->position() + xdisk*pLight->sphere()*xaxis + ydisk*pLight->sphere()*yaxis;
        Ray lightray;
        lightray.d = (posinlight - bm_hit.P);
        float raylength = lightray.d.length();
        float remaininglength = raylength;
        lightray.d /= raylength;
        lightray.o = bm_hit.P;
        while (true)
        {
            HitInfo lighthit;

            if (!scene.trace(lighthit, lightray, EPSILON, remaininglength))
            {
                shadow_mul = 1;
                break;
            }
            if (lighthit.material->castShadow())
                break;
            remaininglength -= lighthit.t;
            lightray.o = lighthit.P;
        }

        if (shadow_mul < EPSILON)
            continue;

        // Diffuse
        Vector3 result = pLight->color()*shadow_mul;

        // the inverse-squared falloff
        float falloff = raylength*raylength;

        // normalize the light direction

        float nDotL = dot(bm_hit.N, lightray.d);

        if (m_kd.max() > EPSILON)
        {
            L += std::max(0.0f, nDotL/falloff * pLight->wattage() / (4*PI)) * result * diffcolor;
        }
        if (m_ks.max() > EPSILON && nDotL > 0)
        {
            Vector3 refl = -lightray.d + 2*nDotL*bm_hit.N;
            L += std::max(0.f, powf((-ray.d).dot(refl), m_phong)) * result * speccolor * (1 - m_tp);
            //Vector3 half = -ray.d + hit.N;
            //half.normalize();
            //L += std::max(0.f, powf(half.dot(hit.N), 1000)) * result * speccolor * m_sp;
        }
    }

    float caustic[3] = {0, 0, 0};
    g_caustics_map->irradiance_estimate(caustic, bm_hit.P.array(), bm_hit.N.array(), 3.0f, 200); // TODO: customize these parameters
    Vector3 caustic_color(caustic);
    L += caustic_color;

	// Indirect diffuse sampling (method 2)
	if (m_indirect && m_kd.max() > EPSILON && ray.iter < MAX_RAY_ITER)
	{
		float theta = asinf((randone(g_rng)));
		float phi = 2 * PI * randone(g_rng);
		Vector3 const &yaxis = bm_hit.N;
		Vector3 xaxis = yaxis.cross(randvect);
		xaxis.normalize();
		Vector3 zaxis = yaxis.cross(xaxis);
		zaxis.normalize();
		Ray diffuse_ray;
        diffuse_ray.refractionIndex = ray.refractionIndex;
        diffuse_ray.refractionStack = ray.refractionStack;
		diffuse_ray.iter = ray.iter + 1;
		diffuse_ray.o = bm_hit.P;
		diffuse_ray.d = 0;
		diffuse_ray.d += sinf(theta) * cosf(phi) * xaxis;
		diffuse_ray.d += sinf(theta) * sinf(phi) * zaxis;
		diffuse_ray.d += cosf(theta) * yaxis;
        diffuse_ray.d.normalize();

		HitInfo diff_hit;
		Vector3 diff_res;
		if (scene.trace(diff_hit, diffuse_ray, EPSILON))
        {
            float irrad[3];
            g_global_illum_map->irradiance_estimate(irrad, diff_hit.P.array(), diff_hit.N.array(), 100.f, 50); // TODO: customize these parameters
            diff_res = Vector3(irrad);
        }
			// diff_res = diff_hit.material->shade(diffuse_ray, diff_hit, scene);
		else
            diff_res = scene.bgColor();
        L += (diffcolor * diff_res) / PI;
	}

    float roulette = randone(g_rng);

    if (roulette > m_tp && (1 - m_tp) * m_ks.max() > EPSILON && ray.iter < MAX_RAY_ITER)
    {
        Ray newray;
		newray.iter = ray.iter + 1;
		newray.refractionIndex = ray.refractionIndex;
		newray.refractionStack = ray.refractionStack;
		newray.o = bm_hit.P;

		if (m_is_glossy)
		{
			Vector3 R = ray.d - 2 * ray.d.dot(bm_hit.N) * bm_hit.N;

			Vector3 u = R.cross(randvect);
			u.normalize();
			Vector3 v = R.cross(u);
			v.normalize();

			float theta = acos(powf(1.0f - randone(g_rng), (1.0f / (m_phong + 1))));
			float phi = 2.0f * PI * randone(g_rng);
					
			newray.d = 0;
			newray.d += sinf(theta) * cosf(phi) * u;
			newray.d += sinf(theta) * sinf(phi) * v;
			newray.d += cosf(theta) * R;
		}
		else
			newray.d = ray.d - 2 * ray.d.dot(bm_hit.N) * bm_hit.N;

		newray.d.normalize();
        HitInfo minHit;
        if (scene.trace(minHit, newray, EPSILON))
        {
			L += minHit.material->shade(newray, minHit, scene) * speccolor;
        }
        else
        {
            L += scene.bgColor() * speccolor;
        }
    }

    if (roulette < m_tp && m_tp * m_ks.max() > EPSILON && ray.iter < MAX_RAY_ITER)
	{
		Ray newray;
        newray.refractionStack = ray.refractionStack;
        newray.refractionIndex = ray.refractionIndex;
        float ratio = 1.0;
		if ((*ray.refractionStack)[ray.refractionIndex] == m_refr && m_refr != 1.0)
        {
            newray.refractionIndex = ray.refractionIndex - 1;
            ratio = m_refr / (*newray.refractionStack)[newray.refractionIndex];
        }
        else if ((*ray.refractionStack)[ray.refractionIndex] != m_refr)
        {
            newray.refractionIndex = ray.refractionIndex + 1;
            newray.refractionStack->push_back(m_refr);
            ratio = (*ray.refractionStack)[ray.refractionIndex] / m_refr;
        }
        newray.o = bm_hit.P;
        Vector3 w = -ray.d;
        float dDotN = w.dot(bm_hit.N);
        if (dDotN < 0)
            dDotN = -dDotN;
		if (1 - ratio*ratio*(1 - dDotN*dDotN) >= 0)
		{
			newray.d = -ratio * (w - dDotN*bm_hit.N) - sqrtf(1 - ratio*ratio*(1 - dDotN*dDotN)) * bm_hit.N;
			newray.d.normalize();
			newray.iter = ray.iter + 1;
			HitInfo minHit;
			if (scene.trace(minHit, newray, EPSILON))
			{
				L += minHit.material->shade(newray, minHit, scene) * speccolor;
			}
			else
			{
				L += scene.bgColor() * m_tp * speccolor;
			}
		}
    }

	L += m_ka * m_texture_ka->shade(ray, bm_hit, scene);

    return L;
}
Esempio n. 8
0
Vector3
Specular::shade(const Ray& ray, const HitInfo& hit, const Scene& scene) const
{
    printf("Shading specular\n");
    Vector3 L = Vector3(0.0f, 0.0f, 0.0f);

    const Vector3 viewDir = -ray.d; // d is a unit vector

    const Lights *lightlist = scene.lights();
    Vector3 color = Vector3(m_kd);
    if (hit.material->hasTexture()) {
        Vector3 c = Vector3(hit.P);
		color = m_texture->getColor(c);
    }

    // loop over all of the lights

    HitInfo lightHitReflect = HitInfo(hit);
    HitInfo lightHitRefract = HitInfo(hit);
    lightHitReflect.hitNum = hit.hitNum;
    lightHitRefract.hitNum = hit.hitNum;

    Lights::const_iterator lightIter;
    for (lightIter = lightlist->begin(); lightIter != lightlist->end(); lightIter++)
    {
        PointLight* pLight = *lightIter;
        Ray lightRay;

        Vector3 l = pLight->position() - hit.P;
        float falloff = l.length2();
        l /= sqrt(falloff);

        /* Calculate the diffuse component - From Labertian Shading Model */
        float nDotL = dot(hit.N, l);
        Vector3 diffuseResult = pLight->color();
        diffuseResult *= color;
        L += std::max(0.0f, nDotL/falloff * pLight->wattage() / PI) * diffuseResult;

        /* Calculate the specular highlight - From Phong Shading Model */
        Vector3 h = (viewDir + l).normalize();
        float nDotH = dot(hit.N, h);
        Vector3 specResult = pLight->color();
        specResult *= m_ks;
        L += pow(std::max(0.0f, nDotH/falloff * pLight->wattage() / PI), m_p) * specResult;

        /* Calculate the specular reflectance */
        if(lightHitReflect.hitNum < 1){
            Vector3 r = reflect(hit.N, ray.d);
            lightRay.d = r.normalize();
            lightRay.o = hit.P;
            if(scene.trace(lightHitReflect, lightRay, 0.0001, r.length())){
                lightHitReflect.hitNum = lightHitReflect.hitNum+1;
                L += lightHitReflect.material->shade(lightRay, lightHitReflect, scene)*m_rl;
            }
        }

        /* Calculate the specular refractance */
        // Vector3 incident = viewDir - hit.P;

        if(lightHitRefract.hitNum < 1 && m_rf > 0.0f ){
            Vector3 t = refract(hit.N, ray.d, hit.material->n(), m_n);
            if(t != Vector3(0.0f))
            lightRay.d = t.normalize();
            else lightRay.d = t;
            lightRay.o = hit.P;
            if(scene.trace(lightHitRefract, lightRay, 0.0001, t.length())){
                lightHitRefract.hitNum = lightHitRefract.hitNum+1;
                    L+=lightHitRefract.material->shade(lightRay, lightHitRefract, scene)*m_rf;
            } else {
                L+=scene.getBGColor()*m_rf;
            }
        }
    }

    return L;
}
void PointLightnigRenderPass::perform()
{
    if (!m_initialized) {
        return;
    }

    m_pPointLightsSelector->select(Object::Type_PointLight);
    const std::vector<Object*> &lights = m_pPointLightsSelector->selectedObjects();
    if (lights.size() == 0) {
        // No lights selected
        return;
    }

    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
    glViewport(0, 0, m_pRenderer->width(), m_pRenderer->height());

    // clear frame buffer
    glClearDepth(1.0f);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    GLenum buffers[] = {
        GL_COLOR_ATTACHMENT0
    };
    glDrawBuffers(1, buffers);

    m_pShaderProgram->use();
    Camera *pCamera = m_pScene->activeCamera();

    glm::mat4 cameraWorldMatrix = pCamera->worldMatrix();
    glm::vec3 cameraPosition = cameraWorldMatrix[3].xyz();
    (*m_pShaderProgram)["CameraPosition"] = cameraPosition;

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, *m_pColorTexureHandle);
    (*m_pShaderProgram)["ColorTexture"] = 0;

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, *m_pPositionTextureHandle);
    (*m_pShaderProgram)["PositionTexture"] = 1;

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, *m_pNormalTextureHandle);
    (*m_pShaderProgram)["NormalTexture"] = 2;

    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_ONE);

    DS_CHECK_GL_ERROR

    glViewport(0, 0, m_pRenderer->width(), m_pRenderer->height());

    glBindVertexArray(m_vertexArray);

    for (int i = 0; i < lights.size(); i++) {
        PointLight *pLight = dynamic_cast<PointLight*>(lights[i]);
        if (pLight != nullptr) {
            (*m_pShaderProgram)["LightPosition"] = pLight->worldMatrix()[3].xyz();
            (*m_pShaderProgram)["LightColor"] = pLight->color();
        }

        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    }

    glBindVertexArray(0);
    glDisable(GL_BLEND);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}