Beispiel #1
0
ColorRGB RayTracer::trace(const Ray& p_ray, const SceneList& p_scene, int p_bounce)
{
	if (p_bounce > m_settings.maxBounces)
	{
		return m_settings.clearColor;
	}
	
	std::pair<Shape*, float> closestInfo = getClosestShape(p_ray, p_scene);

	if (closestInfo.first != nullptr)
	{
		Point3 intersectionPoint = p_ray.origin + closestInfo.second * p_ray.direction;
		Vector3 intersectionNormal = closestInfo.first->getNormal(intersectionPoint);
		intersectionNormal.normalize();
		
		// Offset to prevent self intersection
		intersectionPoint += 0.0001f * intersectionNormal;
		
		//ColorRGB reflectedColor = ColorRGB(255, 255, 255);
		
		if (closestInfo.first->reflective)
		{
			// Trace reflection ray
			Ray reflectionRay(
				intersectionPoint,
				reflect(p_ray.direction, intersectionNormal));
			
			return trace(reflectionRay, p_scene, p_bounce + 1);
		}
		if (m_settings.lightEnabled == false)
		{
			return closestInfo.first->color.rgb();
		}
		
		// Compute shadow ray 
		const Point3 lightPosition(0, 500, 0);
		
		Vector3 shadowVector = lightPosition - intersectionPoint;
		shadowVector.normalize();
		Ray shadowRay(intersectionPoint, shadowVector);
		
		std::pair<Shape*, float> shadowInfo = getClosestShape(shadowRay, p_scene);
		
		float lightContribution = 0.2f; // Ambient light
		
		if (shadowInfo.first == nullptr)
		{
			// Compute diffuse light factor
			float diffuseFactor = dotProduct(intersectionNormal, shadowRay.direction);
			if (diffuseFactor > 0.0f)
			{
				lightContribution += diffuseFactor;
			}
		}
		return std::min(lightContribution, 1.0f) * closestInfo.first->color.rgb();
	}
	return m_settings.clearColor;
}
RGBQUAD TraceOneRay(CRay ray, CSphere S[], CVector3D lightsArray[],int level, CBox sceneBox)
{
	int n;
	RGBQUAD currentColor;
	currentColor.rgbBlue=20;
	currentColor.rgbGreen=20;
	currentColor.rgbRed=20;
	CVector3D hit,light,lightdir,snormal;

	if(checkIntersection(ray,S,&hit,&n,sceneBox)) 
	{	
		currentColor.rgbBlue=0;
		currentColor.rgbGreen=0;
		currentColor.rgbRed=0;
		//Вычисляем нормаль
		snormal.x=(hit.x-S[n].center.x);
		snormal.y=(hit.y-S[n].center.y);
		snormal.z=(hit.z-S[n].center.z);
		snormal.NormalizeVector();		
		//Проверяем каждый источник света
		for (int lightIndex=0; lightIndex<LIGHT_COUNT; lightIndex++)
		{
			light=lightsArray[lightIndex];
			lightdir.x=light.x-hit.x;
			lightdir.y=light.y-hit.y;
			lightdir.z=light.z-hit.z;
			lightdir.NormalizeVector();

			bool inShadow=false;
			//Находим коэффициент освещения
			float coefLight=snormal*lightdir;
			//Если коэффициент больше 0 то свет попадает
			if(coefLight>0){
				//луч от источника света к месту пересечения с объектом
				CRay lightRay(hit,lightdir);
				//Проверяем не затенен ли данный объект другим объектом
				for (int index=0; index<SPHERE_COUNT; index++)
				{
					
					/*if(index==n) 
						continue;*/
					CVector3D lightHit;
					int num;
					if (checkIntersection(lightRay,S,&lightHit,&num,sceneBox))
					{
						inShadow=true;
						break;
					}
				}
				if(!inShadow)
				{		
					//Создаем отражающий луч
					CVector3D reflectionVector=(ray.vector-2*(((ray.vector*snormal))*snormal));
					CRay reflectionRay(hit,reflectionVector);
					RGBQUAD reflectionColor;
					float coef=1;
					for (int i=0; i<level; i++)
					{
						//coef*=reflectionVector*ray.vector;
						coef*=0.5;
					}
					reflectionColor.rgbBlue=0;
					reflectionColor.rgbGreen=0;
					reflectionColor.rgbRed=0;
					if(level<7)
					{
						reflectionColor=TraceOneRay(reflectionRay,S,lightsArray,++level,sceneBox);
					}
					
					//Свет по Ламберту
					if (reflectionColor.rgbRed==20 && reflectionColor.rgbGreen==20 && reflectionColor.rgbBlue==20)
					{
						reflectionColor.rgbBlue=0;
						reflectionColor.rgbGreen=0;
						reflectionColor.rgbRed=0;
					}
					else
					{
						int k=1;
					}
					if ((int)currentColor.rgbRed+coefLight*S[n].color.rgbRed*0.5+reflectionColor.rgbRed*coef>=255)
					{
						currentColor.rgbRed=255;
					}
					else
					{
						currentColor.rgbRed+=coefLight*S[n].color.rgbRed*0.5+reflectionColor.rgbRed*coef;
					}					
					if ((int)currentColor.rgbGreen+coefLight*S[n].color.rgbGreen*0.5+reflectionColor.rgbGreen*coef>=255)
					{
						currentColor.rgbGreen=255;
					}
					else
					{
						currentColor.rgbGreen+=coefLight*S[n].color.rgbGreen*0.5+reflectionColor.rgbGreen*coef;
					}
					if ((int)currentColor.rgbBlue+coefLight*S[n].color.rgbBlue*0.5+reflectionColor.rgbBlue*coef>=255)
					{
						currentColor.rgbBlue=255;
					}
					else
					{
						currentColor.rgbBlue+=coefLight*S[n].color.rgbBlue*0.5+reflectionColor.rgbBlue*coef;
					}
					
					//Блинн-Фонг взято с http://www.codermind.com/articles/Raytracer-in-C++-Part-II-Specularity-post-processing.html
					float fViewProjection=ray.vector*snormal;
					CVector3D blinnVector=lightRay.vector-ray.vector;
					float temp=blinnVector*blinnVector;
					if (temp!=0)
					{
						float blinn=1/sqrtSSE(temp) * max(coefLight-fViewProjection,0.0f);
						blinn=coef*powf(blinn,20);
						if ((int)currentColor.rgbRed+blinn*S[n].color.rgbRed>=255)
						{
							currentColor.rgbRed=255;
						}
						else
						{
							currentColor.rgbRed+=blinn*S[n].color.rgbRed;
						}
						if ((int)currentColor.rgbGreen+blinn*S[n].color.rgbGreen>=255)
						{
							currentColor.rgbGreen=255;
						}
						else
						{
							currentColor.rgbGreen+=blinn*S[n].color.rgbGreen;
						}
						if ((int)currentColor.rgbBlue+blinn*S[n].color.rgbBlue>=255)
						{
							currentColor.rgbBlue=255;
						}
						else
						{
							currentColor.rgbBlue+=blinn*S[n].color.rgbBlue;
						}						
					}
				}
			}
		}		
	}	
	return currentColor;
}
Eigen::Vector4d getColor(const Ray &ray, unsigned int recursionLevel, unsigned int transDepth,
                         std::array<int, MAX_DEPTH + 1> &objStack) {
    BOOST_ASSERT_MSG(std::abs(1 - ray.dir.norm()) < EPSILON, "Got ray with non-unit direction");
    const intersection_t isect = getIntersection(ray);
    int objId;
    if ((objId = isect.objId) < 0) return Eigen::Vector4d::Zero();

    auto &objects = scene.getObjects();
    auto &lights = scene.getLights();
    Eigen::Vector4d I = Eigen::Vector4d::Zero();

    Eigen::Vector4d pointOfIntersection = ray.origin + isect.dist * ray.dir;

    Eigen::Vector4d N = objects[objId]->getUnitNormal(pointOfIntersection);
    Eigen::Vector4d V = -1 * ray.dir;

    auto mat = scene.getMaterial(objects[objId]->matId);

    for (unsigned int i = 0 ; i < lights.size(); ++i) {
        if (lights[i]->isAmbient()) {
            I += mat.Ka * lights[i]->getAmountOfLight(pointOfIntersection).cwiseProduct(mat.rgb);
            continue;
        }
        Eigen::Vector4d L = lights[i]->getVectorToLight(pointOfIntersection);
        Ray rayToLight(pointOfIntersection, L, objId);

        bool lightVisible = true;
        if (lights[i]->getShadowOn()) {
            double distToBlockingObject = getIntersection(rayToLight).dist;
            double distToLight = (pointOfIntersection - lights[i]->getPosition()).norm();

            lightVisible = distToBlockingObject <= EPSILON ||
                distToBlockingObject >= distToLight;
        }
        if (lightVisible) {
            /* Diffuse Reflection */
            Eigen::Vector4d Il = lights[i]->getAmountOfLight(pointOfIntersection);
            // Amount of light visible on surface determined by angle to light source
            double lambertCos = L.dot(N);
            if (lambertCos > 0) {
                I += mat.Kd * lambertCos * mat.rgb.cwiseProduct(Il);
            } else {
                continue;
            }

            /* Specular Reflection */
            Eigen::Vector4d reflection = 2 * N.dot(rayToLight.dir) * N - rayToLight.dir;
            double specCoeff = reflection.dot(V);
            if (specCoeff > 0) {
                specCoeff = std::max(0.0, pow(specCoeff, mat.ns));
                I += specCoeff * mat.Ks * mat.rgb.cwiseProduct(Il);
            }
        }
    }

    if (recursionLevel < MAX_DEPTH) {
        // Work out where in material stack we are
        int nextTransDepth;
        int nextObjId;
        if (objStack[transDepth] == objId) {
            nextTransDepth = transDepth - 1;
            nextObjId = objStack[transDepth - 1];
        } else {
            nextTransDepth = transDepth + 1;
            objStack[nextTransDepth] = objId;
            nextObjId = objId;
        }

        // Compute intensity of reflected ray, if necessary
        if (reflect && mat.Kr > 0)	{
            Ray reflectionRay(pointOfIntersection,  ray.dir - (2 * N.dot(ray.dir)) * N, nextObjId);
            I += mat.Kr * getColor(reflectionRay, recursionLevel + 1, nextTransDepth, objStack);
        }

        // Compute intensity of transmission ray, if necessary
        if (refract && mat.Kt > 0) {
            const double etaIncident = (objStack[transDepth] == ID_AIR) ? 1.0 :
                scene.getMaterial(objects[objStack[transDepth]]->matId).Irefract;
            double cosThetaI, etaRefract;
            if (objStack[transDepth] == objId) { // Exiting a material
                cosThetaI = ray.dir.dot(N);
                etaRefract = (objStack[transDepth - 1] == ID_AIR) ? 1.0 :
                    scene.getMaterial(objects[objStack[transDepth - 1]]->matId).Irefract;
            } else {
                cosThetaI = V.dot(N);
                etaRefract = scene.getMaterial(objects[objId]->matId).Irefract;
            }
            const double n = etaIncident/etaRefract;
            const double cosThetaR = sqrt(1 - (n * n) * (1 - cosThetaI * cosThetaI));
            Ray T(pointOfIntersection, (n * ray.dir - (cosThetaR - n * cosThetaI) * N).normalized(), nextObjId);
            I += mat.Kt * getColor(T, recursionLevel + 1, nextTransDepth, objStack);
        }
    }

    return I;

}