Пример #1
0
// add extra methods here
void MyScene::rayTrace(Point3 point, Vector3 ray){
	HitRecord* hits = new HitRecord();
	transformStack.clear();
	transformStack.push_back(Matrix4::identity());

	castRayAgainstSubgraph(point, ray, root, hits);

	bool gotHit;
	double tH, uH, vH;
	Point3 pH;
	Vector3 nH;
	gotHit = hits->getFirstHit(tH, uH, vH, pH, nH);
	delete hits;

	int col, row;
	getScreenCoord(point+ray, col, row);
	int idx = pxIdx(col, row);

	if (gotHit){
		for (Light& l : lights){
			Point3 lPos = l.getPos();

			castLight(lPos, pH, l, 0, 0, NULL);
		}
	}
	else{
		pixelArray[idx] = (unsigned char)(background[0] * 255);
		pixelArray[idx + 1] = (unsigned char)(background[1] * 255);
		pixelArray[idx + 2] = (unsigned char)(background[2] * 255);
	}
}
Пример #2
0
void map::castLight( int row, float start, float end, int xx, int xy, int yx, int yy,
                     const int offsetX, const int offsetY, const int offsetDistance )
{
    float newStart = 0.0f;
    float radius = 60.0f - offsetDistance;
    if( start < end ) {
        return;
    }
    bool blocked = false;
    for( int distance = row; distance <= radius && !blocked; distance++ ) {
        int deltaY = -distance;
        for( int deltaX = -distance; deltaX <= 0; deltaX++ ) {
            int currentX = offsetX + deltaX * xx + deltaY * xy;
            int currentY = offsetY + deltaX * yx + deltaY * yy;
            float leftSlope = (deltaX - 0.5f) / (deltaY + 0.5f);
            float rightSlope = (deltaX + 0.5f) / (deltaY - 0.5f);

            if( !(currentX >= 0 && currentY >= 0 && currentX < SEEX * my_MAPSIZE &&
                  currentY < SEEY * my_MAPSIZE) || start < rightSlope ) {
                continue;
            } else if( end > leftSlope ) {
                break;
            }

            //check if it's within the visible area and mark visible if so
            if( rl_dist(0, 0, deltaX, deltaY) <= radius ) {
                /*
                float bright = (float) (1 - (rStrat.radius(deltaX, deltaY) / radius));
                lightMap[currentX][currentY] = bright;
                */
                seen_cache[currentX][currentY] = true;
            }

            if( blocked ) {
                //previous cell was a blocking one
                if( light_transparency(currentX, currentY) == LIGHT_TRANSPARENCY_SOLID ) {
                    //hit a wall
                    newStart = rightSlope;
                    continue;
                } else {
                    blocked = false;
                    start = newStart;
                }
            } else {
                if( light_transparency(currentX, currentY) == LIGHT_TRANSPARENCY_SOLID &&
                    distance < radius ) {
                    //hit a wall within sight line
                    blocked = true;
                    castLight(distance + 1, start, leftSlope, xx, xy, yx, yy,
                              offsetX, offsetY, offsetDistance);
                    newStart = rightSlope;
                }
            }
        }
    }
}
Пример #3
0
/**
 * Calculates the Field Of View for the provided map from the given x, y
 * coordinates. Returns a lightmap for a result where the values represent a
 * percentage of fully lit.
 *
 * A value equal to or below 0 means that cell is not in the
 * field of view, whereas a value equal to or above 1 means that cell is
 * in the field of view.
 *
 * @param startx the horizontal component of the starting location
 * @param starty the vertical component of the starting location
 * @param radius the maximum distance to draw the FOV
 */
void map::build_seen_cache( game *g ) {
    memset(seen_cache, false, sizeof(seen_cache));
    seen_cache[g->u.posx][g->u.posy] = true;

    castLight( g, 1, 1.0f, 0.0f, 0, 1, 1, 0 );
    castLight( g, 1, 1.0f, 0.0f, 1, 0, 0, 1 );

    castLight( g, 1, 1.0f, 0.0f, 0, -1, 1, 0 );
    castLight( g, 1, 1.0f, 0.0f, -1, 0, 0, 1 );

    castLight( g, 1, 1.0f, 0.0f, 0, 1, -1, 0 );
    castLight( g, 1, 1.0f, 0.0f, 1, 0, 0, -1 );

    castLight( g, 1, 1.0f, 0.0f, 0, -1, -1, 0 );
    castLight( g, 1, 1.0f, 0.0f, -1, 0, 0, -1 );
}
Пример #4
0
/**
 * Calculates the Field Of View for the provided map from the given x, y
 * coordinates. Returns a lightmap for a result where the values represent a
 * percentage of fully lit.
 *
 * A value equal to or below 0 means that cell is not in the
 * field of view, whereas a value equal to or above 1 means that cell is
 * in the field of view.
 *
 * @param startx the horizontal component of the starting location
 * @param starty the vertical component of the starting location
 * @param radius the maximum distance to draw the FOV
 */
void map::build_seen_cache()
{
    memset(seen_cache, false, sizeof(seen_cache));
    seen_cache[g->u.posx][g->u.posy] = true;

    const int offsetX = g->u.posx;
    const int offsetY = g->u.posy;

    castLight( 1, 1.0f, 0.0f, 0, 1, 1, 0, offsetX, offsetY, 0 );
    castLight( 1, 1.0f, 0.0f, 1, 0, 0, 1, offsetX, offsetY, 0 );

    castLight( 1, 1.0f, 0.0f, 0, -1, 1, 0, offsetX, offsetY, 0 );
    castLight( 1, 1.0f, 0.0f, -1, 0, 0, 1, offsetX, offsetY, 0 );

    castLight( 1, 1.0f, 0.0f, 0, 1, -1, 0, offsetX, offsetY, 0 );
    castLight( 1, 1.0f, 0.0f, 1, 0, 0, -1, offsetX, offsetY, 0 );

    castLight( 1, 1.0f, 0.0f, 0, -1, -1, 0, offsetX, offsetY, 0 );
    castLight( 1, 1.0f, 0.0f, -1, 0, 0, -1, offsetX, offsetY, 0 );

    if (vehicle *veh = veh_at(offsetX, offsetY)) {
        // We're inside a vehicle. Do mirror calcs.
        std::vector<int> mirrors = veh->all_parts_with_feature(VPFLAG_MIRROR, true);
        // Do all the sight checks first to prevent fake multiple reflection
        // from happening due to mirrors becoming visible due to processing order.
        for (std::vector<int>::iterator m_it = mirrors.begin(); m_it != mirrors.end(); /* noop */) {
            const int mirrorX = veh->global_x() + veh->parts[*m_it].precalc_dx[0];
            const int mirrorY = veh->global_y() + veh->parts[*m_it].precalc_dy[0];
            // We can utilize the current state of the seen cache to determine
            // if the player can see the mirror from their position.
            if (!g->u.sees(mirrorX, mirrorY)) {
                m_it = mirrors.erase(m_it);
            } else {
                ++m_it;
            }
        }

        for (std::vector<int>::iterator m_it = mirrors.begin(); m_it != mirrors.end(); ++m_it) {
            const int mirrorX = veh->global_x() + veh->parts[*m_it].precalc_dx[0];
            const int mirrorY = veh->global_y() + veh->parts[*m_it].precalc_dy[0];

            // Determine how far the light has already traveled so mirrors
            // don't cheat the light distance falloff.
            int offsetDistance = rl_dist(offsetX, offsetY, mirrorX, mirrorY);

            // @todo: Factor in the mirror facing and only cast in the
            // directions the player's line of sight reflects to.
            //
            // The naive solution of making the mirrors act like a second player
            // at an offset appears to give reasonable results though.

            castLight( 1, 1.0f, 0.0f, 0, 1, 1, 0, mirrorX, mirrorY, offsetDistance );
            castLight( 1, 1.0f, 0.0f, 1, 0, 0, 1, mirrorX, mirrorY, offsetDistance );

            castLight( 1, 1.0f, 0.0f, 0, -1, 1, 0, mirrorX, mirrorY, offsetDistance );
            castLight( 1, 1.0f, 0.0f, -1, 0, 0, 1, mirrorX, mirrorY, offsetDistance );

            castLight( 1, 1.0f, 0.0f, 0, 1, -1, 0, mirrorX, mirrorY, offsetDistance );
            castLight( 1, 1.0f, 0.0f, 1, 0, 0, -1, mirrorX, mirrorY, offsetDistance );

            castLight( 1, 1.0f, 0.0f, 0, -1, -1, 0, mirrorX, mirrorY, offsetDistance );
            castLight( 1, 1.0f, 0.0f, -1, 0, 0, -1, mirrorX, mirrorY, offsetDistance );
        }
    }
}
Пример #5
0
void MyScene::castLight(const Point3& src, const Point3& dst, Light& l, int depth, double distance, Color* reflectedColor){
	Vector3 ray = dst - src;
	ray.normalize();

	HitRecord* hits = new HitRecord();
	castRayAgainstSubgraph(src, ray, root, hits);

	double t, u, v;
	Point3 p;
	Vector3 n;
	hits->getFirstHit(t, u, v, p, n);
	Object* o = (Object*)hits->getFirstHitObj();
	delete hits;

	int col, row;
	getScreenCoord(dst, col, row);
	int idx = pxIdx(col, row);

	Color screenColor = Color(pixelArray[idx] / (float)255, pixelArray[idx+1] / (float)255, pixelArray[idx+2] / (float)255);

	//ambient
	screenColor[0] += o->ambient[0];
	screenColor[1] += o->ambient[1];
	screenColor[2] += o->ambient[2];

	//not in shadow
	double diff = (dst - p).length();
	if (diff < EPSILON){
		Color lightColor = l.getColor();
		distance += (dst-src).length();
		Point3 falloff = l.getFalloff();
		double attenuation = 1 / (double)(falloff[0] + falloff[1] * distance + falloff[2] * distance*distance);

		//diffuse
		double dot = n*(-ray);
		if (dot > 0){
			screenColor[0] += (GLfloat)(o->diffuse[0] * lightColor[0] * attenuation*dot);
			screenColor[1] += (GLfloat)(o->diffuse[1] * lightColor[1] * attenuation*dot);
			screenColor[2] += (GLfloat)(o->diffuse[2] * lightColor[2] * attenuation*dot);
		}
		
		//reflect
		++depth;
		if ((depth < MAX_RECURSION_DEPTH) && (attenuation  > EPSILON)){
			Vector3 reflectedRay = 2 * (ray * n) * n - ray;
			reflectedRay.normalize();

			Point3 newSrc = p + EPSILON*reflectedRay;
			Point3 newDst = p + reflectedRay;
			
			double r = o->reflect[0] * lightColor[0] * attenuation*dot;
			double g = o->reflect[1] * lightColor[1] * attenuation*dot;
			double b = o->reflect[2] * lightColor[2] * attenuation*dot;

			if (r > INVISIBLE || g > INVISIBLE || b > INVISIBLE){
				Color* reflect = new Color((GLfloat)r, (GLfloat)g, (GLfloat)b);
				castLight(newSrc, newDst, l, depth, distance, reflect);
				delete reflect;
			}
		}

		//specular
		Vector3 reflection = ray - 2 * n*(ray*n);
		reflection.normalize();
		Vector3 look = camera.getLook();
		look.normalize();
		dot = reflection*(-look);
		if (dot > 0){
			screenColor[0] += (GLfloat)(o->specular[0] * lightColor[0] * attenuation * pow(dot, o->shine));
			screenColor[1] += (GLfloat)(o->specular[1] * lightColor[1] * attenuation * pow(dot, o->shine));
			screenColor[2] += (GLfloat)(o->specular[2] * lightColor[2] * attenuation * pow(dot, o->shine));
		}
	}

	if (screenColor[0] > 1){
		screenColor[0] = 1;
	}
	if (screenColor[1] > 1){
		screenColor[1] = 1;
	}
	if (screenColor[2] > 1){
		screenColor[2] = 1;
	}

	pixelArray[idx] = (unsigned char)roundToNearest(screenColor[0]*255);
	pixelArray[idx + 1] = (unsigned char)roundToNearest(screenColor[1] * 255);
	pixelArray[idx + 2] = (unsigned char)roundToNearest(screenColor[2] * 255);
}
Пример #6
0
/**
 * Calculates the Field Of View for the provided map from the given x, y
 * coordinates. Returns a lightmap for a result where the values represent a
 * percentage of fully lit.
 *
 * A value equal to or below 0 means that cell is not in the
 * field of view, whereas a value equal to or above 1 means that cell is
 * in the field of view.
 *
 * @param startx the horizontal component of the starting location
 * @param starty the vertical component of the starting location
 * @param radius the maximum distance to draw the FOV
 */
void map::build_seen_cache()
{
    memset(seen_cache, false, sizeof(seen_cache));
    seen_cache[g->u.posx][g->u.posy] = true;

    const int offsetX = g->u.posx;
    const int offsetY = g->u.posy;

    castLight( 1, 1.0f, 0.0f, 0, 1, 1, 0, offsetX, offsetY, 0 );
    castLight( 1, 1.0f, 0.0f, 1, 0, 0, 1, offsetX, offsetY, 0 );

    castLight( 1, 1.0f, 0.0f, 0, -1, 1, 0, offsetX, offsetY, 0 );
    castLight( 1, 1.0f, 0.0f, -1, 0, 0, 1, offsetX, offsetY, 0 );

    castLight( 1, 1.0f, 0.0f, 0, 1, -1, 0, offsetX, offsetY, 0 );
    castLight( 1, 1.0f, 0.0f, 1, 0, 0, -1, offsetX, offsetY, 0 );

    castLight( 1, 1.0f, 0.0f, 0, -1, -1, 0, offsetX, offsetY, 0 );
    castLight( 1, 1.0f, 0.0f, -1, 0, 0, -1, offsetX, offsetY, 0 );

    int part;
    if ( vehicle *veh = veh_at( offsetX, offsetY, part ) ) {
        // We're inside a vehicle. Do mirror calcs.
        std::vector<int> mirrors = veh->all_parts_with_feature(VPFLAG_EXTENDS_VISION, true);
        // Do all the sight checks first to prevent fake multiple reflection
        // from happening due to mirrors becoming visible due to processing order.
        // Cameras are also handled here, so that we only need to get through all veh parts once
        int cam_control = -1;
        for (std::vector<int>::iterator m_it = mirrors.begin(); m_it != mirrors.end(); /* noop */) {
            const int mirrorX = veh->global_x() + veh->parts[*m_it].precalc_dx[0];
            const int mirrorY = veh->global_y() + veh->parts[*m_it].precalc_dy[0];
            // We can utilize the current state of the seen cache to determine
            // if the player can see the mirror from their position.
            if( !veh->part_info( *m_it ).has_flag( "CAMERA" ) && !g->u.sees(mirrorX, mirrorY)) {
                m_it = mirrors.erase(m_it);
            } else if( !veh->part_info( *m_it ).has_flag( "CAMERA_CONTROL" ) ) {
                ++m_it;
            } else {
                if( offsetX == mirrorX && offsetY == mirrorY && veh->camera_on ) {
                    cam_control = *m_it;
                }
                m_it = mirrors.erase( m_it );
            }
        }

        for( size_t i = 0; i < mirrors.size(); i++ ) {
            const int &mirror = mirrors[i];
            bool is_camera = veh->part_info( mirror ).has_flag( "CAMERA" );
            if( is_camera && cam_control < 0 ) {
                continue; // Player not at camera control, so cameras don't work
            }

            const int mirrorX = veh->global_x() + veh->parts[mirror].precalc_dx[0];
            const int mirrorY = veh->global_y() + veh->parts[mirror].precalc_dy[0];

            // Determine how far the light has already traveled so mirrors
            // don't cheat the light distance falloff.
            int offsetDistance;
            if( !is_camera ) {
                offsetDistance = rl_dist(offsetX, offsetY, mirrorX, mirrorY);
            } else {
                offsetDistance = 60 - veh->part_info( mirror ).bonus *  
                                      veh->parts[mirror].hp / veh->part_info( mirror ).durability;
                seen_cache[mirrorX][mirrorY] = true;
            }

            // @todo: Factor in the mirror facing and only cast in the
            // directions the player's line of sight reflects to.
            //
            // The naive solution of making the mirrors act like a second player
            // at an offset appears to give reasonable results though.
            castLight( 1, 1.0f, 0.0f, 0, 1, 1, 0, mirrorX, mirrorY, offsetDistance );
            castLight( 1, 1.0f, 0.0f, 1, 0, 0, 1, mirrorX, mirrorY, offsetDistance );

            castLight( 1, 1.0f, 0.0f, 0, -1, 1, 0, mirrorX, mirrorY, offsetDistance );
            castLight( 1, 1.0f, 0.0f, -1, 0, 0, 1, mirrorX, mirrorY, offsetDistance );

            castLight( 1, 1.0f, 0.0f, 0, 1, -1, 0, mirrorX, mirrorY, offsetDistance );
            castLight( 1, 1.0f, 0.0f, 1, 0, 0, -1, mirrorX, mirrorY, offsetDistance );

            castLight( 1, 1.0f, 0.0f, 0, -1, -1, 0, mirrorX, mirrorY, offsetDistance );
            castLight( 1, 1.0f, 0.0f, -1, 0, 0, -1, mirrorX, mirrorY, offsetDistance );
        }
    }
}