]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
reworked collision cache to only be used by bouncegrid and only in
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 17 Oct 2011 17:00:10 +0000 (17:00 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 17 Oct 2011 17:00:10 +0000 (17:00 +0000)
dynamic mode (static mode no longer causes several heart attacks in the
collision cache as it executes many times the regular amount of traces)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11436 d7cf8633-e32d-0410-b094-e92efae38249

cl_collision.c
cl_collision.h
collision.c
collision.h
r_shadow.c

index 8c9540669c9ba6518bcb472962286efa79b71446..6829863048decabbc2bb1045d0eb7d74aac0460b 100644 (file)
@@ -938,3 +938,123 @@ finished:
 #endif
        return cliptrace;
 }
+
+/*
+==================
+CL_Cache_TraceLine
+==================
+*/
+#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
+trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t pEnd, int type, int hitsupercontentsmask)
+#else
+trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int type, int hitsupercontentsmask)
+#endif
+{
+       int i;
+       prvm_edict_t *touch;
+       trace_t trace;
+       // bounding box of entire move area
+       vec3_t clipboxmins, clipboxmaxs;
+       // start and end origin of move
+       vec3_t clipstart, clipend;
+       // trace results
+       trace_t cliptrace;
+       // matrices to transform into/out of other entity's space
+       matrix4x4_t matrix, imatrix;
+       // model of other entity
+       dp_model_t *model;
+       // list of entities to test for collisions
+       int numtouchedicts;
+       static prvm_edict_t *touchedicts[MAX_EDICTS];
+#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
+       vec3_t end;
+       vec_t len = 0;
+
+       if(collision_endposnudge.value > 0 && !VectorCompare(start, pEnd))
+       {
+               // TRICK: make the trace 1 qu longer!
+               VectorSubtract(pEnd, start, end);
+               len = VectorNormalizeLength(end);
+               VectorMA(pEnd, collision_endposnudge.value, end, end);
+       }
+       else
+               VectorCopy(pEnd, end);
+#endif
+
+       VectorCopy(start, clipstart);
+       VectorCopy(end, clipend);
+#if COLLISIONPARANOID >= 3
+       Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]);
+#endif
+
+       // clip to world
+       Collision_Cache_ClipLineToWorldSurfaces(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
+       cliptrace.bmodelstartsolid = cliptrace.startsolid;
+       if (cliptrace.startsolid || cliptrace.fraction < 1)
+               cliptrace.ent = prog ? prog->edicts : NULL;
+       if (type == MOVE_WORLDONLY)
+               goto finished;
+
+       // create the bounding box of the entire move
+       for (i = 0;i < 3;i++)
+       {
+               clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) - 1;
+               clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + 1;
+       }
+
+       // if the passedict is world, make it NULL (to avoid two checks each time)
+       // this checks prog because this function is often called without a CSQC
+       // VM context
+
+       // collide against network entities
+       for (i = 0;i < cl.num_brushmodel_entities;i++)
+       {
+               entity_render_t *ent = &cl.entities[cl.brushmodel_entities[i]].render;
+               if (!BoxesOverlap(clipboxmins, clipboxmaxs, ent->mins, ent->maxs))
+                       continue;
+               Collision_Cache_ClipLineToGenericEntitySurfaces(&trace, ent->model, &ent->matrix, &ent->inversematrix, start, end, hitsupercontentsmask);
+               Collision_CombineTraces(&cliptrace, &trace, NULL, true);
+       }
+
+       // clip to entities
+       // because this uses World_EntitiestoBox, we know all entity boxes overlap
+       // the clip region, so we can skip culling checks in the loop below
+       // note: if prog is NULL then there won't be any linked entities
+       numtouchedicts = 0;
+       if (prog != NULL)
+       {
+               numtouchedicts = World_EntitiesInBox(&cl.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
+               if (numtouchedicts > MAX_EDICTS)
+               {
+                       // this never happens
+                       Con_Printf("CL_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
+                       numtouchedicts = MAX_EDICTS;
+               }
+       }
+       for (i = 0;i < numtouchedicts;i++)
+       {
+               touch = touchedicts[i];
+               // might interact, so do an exact clip
+               // only hit entity models, not collision shapes
+               model = CL_GetModelFromEdict(touch);
+               if (!model)
+                       continue;
+               // animated models are too slow to collide against and can't be cached
+               if (touch->priv.server->frameblend || touch->priv.server->skeleton.relativetransforms)
+                       continue;
+               if (type == MOVE_NOMONSTERS && PRVM_clientedictfloat(touch, solid) != SOLID_BSP)
+                       continue;
+               Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2], PRVM_clientedictvector(touch, angles)[0], PRVM_clientedictvector(touch, angles)[1], PRVM_clientedictvector(touch, angles)[2], 1);
+               Matrix4x4_Invert_Simple(&imatrix, &matrix);
+               Collision_Cache_ClipLineToGenericEntitySurfaces(&trace, model, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask);
+               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_clientedictfloat(touch, solid) == SOLID_BSP);
+       }
+
+finished:
+#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
+       if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
+               Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
+#endif
+       return cliptrace;
+}
+
index 27ce51be26db7bdd7f3ebb48f2072efe9a668572..851502cfa349537789da8f9f65683a3edeb56290 100644 (file)
@@ -13,6 +13,7 @@ int CL_GenericHitSuperContentsMask(const prvm_edict_t *edict);
 trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities);
 trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities, qboolean hitsurfaces);
 trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities);
+trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int type, int hitsupercontentsmask);
 #define CL_PointSuperContents(point) (CL_TracePoint((point), sv_gameplayfix_swiminbmodels.integer ? MOVE_NOMONSTERS : MOVE_WORLDONLY, NULL, 0, true, false, NULL, false).startsupercontents)
 
 #endif
index cf0d527f360a424e6d7707382fe12400ee25b081..e0cc37dd817c1644a0dbac94750ed75ab328fcf2 100644 (file)
@@ -1671,17 +1671,8 @@ typedef struct collision_cachedtrace_parameters_s
        dp_model_t *model;
        vec3_t end;
        vec3_t start;
-       vec3_t mins;
-       vec3_t maxs;
-//     const frameblend_t *frameblend;
-//     const skeleton_t *skeleton;
-//     matrix4x4_t inversematrix;
        int hitsupercontentsmask;
-       int type; // which type of query produced this cache entry
        matrix4x4_t matrix;
-       vec3_t bodymins;
-       vec3_t bodymaxs;
-       int bodysupercontents;
 }
 collision_cachedtrace_parameters_t;
 
@@ -1810,7 +1801,7 @@ static unsigned int Collision_Cache_HashIndexForArray(unsigned int *array, unsig
        return hashindex;
 }
 
-static collision_cachedtrace_t *Collision_Cache_Lookup(int type, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask)
+static collision_cachedtrace_t *Collision_Cache_Lookup(dp_model_t *model, const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask)
 {
        int hashindex = 0;
        unsigned int fullhashindex;
@@ -1823,28 +1814,18 @@ static collision_cachedtrace_t *Collision_Cache_Lookup(int type, dp_model_t *mod
        collision_cachedtrace_t *cached = collision_cachedtrace_array + index;
        collision_cachedtrace_parameters_t params;
        // all non-cached traces use the same index
-       if ((frameblend && frameblend[0].lerp != 1) || (skeleton && skeleton->relativetransforms))
-               r_refdef.stats.collisioncache_animated++;
-       else if (!collision_cache.integer)
+       if (!collision_cache.integer)
                r_refdef.stats.collisioncache_traced++;
        else
        {
                // cached trace lookup
                memset(&params, 0, sizeof(params));
-               params.type = type;
                params.model = model;
-               VectorCopy(bodymins, params.bodymins);
-               VectorCopy(bodymaxs, params.bodymaxs);
-               params.bodysupercontents = bodysupercontents;
                VectorCopy(start, params.start);
-               VectorCopy(mins,  params.mins);
-               VectorCopy(maxs,  params.maxs);
                VectorCopy(end,   params.end);
                params.hitsupercontentsmask = hitsupercontentsmask;
                params.matrix = *matrix;
-               //params.inversematrix = *inversematrix;
                fullhashindex = Collision_Cache_HashIndexForArray((unsigned int *)&params, sizeof(params) / sizeof(unsigned int));
-               //fullhashindex = Collision_Cache_HashIndexForArray((unsigned int *)&params, 10);
                hashindex = (int)(fullhashindex % (unsigned int)collision_cachedtrace_hashsize);
                for (index = hash[hashindex];index;index = arraynext[index])
                {
@@ -1859,20 +1840,6 @@ static collision_cachedtrace_t *Collision_Cache_Lookup(int type, dp_model_t *mod
                         || cached->p.start[0] != params.start[0]
                         || cached->p.start[1] != params.start[1]
                         || cached->p.start[2] != params.start[2]
-                        || cached->p.mins[0] != params.mins[0]
-                        || cached->p.mins[1] != params.mins[1]
-                        || cached->p.mins[2] != params.mins[2]
-                        || cached->p.maxs[0] != params.maxs[0]
-                        || cached->p.maxs[1] != params.maxs[1]
-                        || cached->p.maxs[2] != params.maxs[2]
-                        || cached->p.type != params.type
-                        || cached->p.bodysupercontents != params.bodysupercontents
-                        || cached->p.bodymins[0] != params.bodymins[0]
-                        || cached->p.bodymins[1] != params.bodymins[1]
-                        || cached->p.bodymins[2] != params.bodymins[2]
-                        || cached->p.bodymaxs[0] != params.bodymaxs[0]
-                        || cached->p.bodymaxs[1] != params.bodymaxs[1]
-                        || cached->p.bodymaxs[2] != params.bodymaxs[2]
                         || cached->p.hitsupercontentsmask != params.hitsupercontentsmask
                         || cached->p.matrix.m[0][0] != params.matrix.m[0][0]
                         || cached->p.matrix.m[0][1] != params.matrix.m[0][1]
@@ -1938,16 +1905,38 @@ static collision_cachedtrace_t *Collision_Cache_Lookup(int type, dp_model_t *mod
        return cached;
 }
 
-void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask)
+void Collision_Cache_ClipLineToGenericEntitySurfaces(trace_t *trace, dp_model_t *model, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask)
 {
-       float starttransformed[3], endtransformed[3];
-       collision_cachedtrace_t *cached = Collision_Cache_Lookup(3, model, frameblend, skeleton, bodymins, bodymaxs, bodysupercontents, matrix, inversematrix, start, mins, maxs, end, hitsupercontentsmask);
+       collision_cachedtrace_t *cached = Collision_Cache_Lookup(model, matrix, inversematrix, start, end, hitsupercontentsmask);
+       if (cached->valid)
+       {
+               *trace = cached->result;
+               return;
+       }
+
+       Collision_ClipLineToGenericEntity(trace, model, NULL, NULL, vec3_origin, vec3_origin, 0, matrix, inversematrix, start, end, hitsupercontentsmask, true);
+
+       cached->result = *trace;
+}
+
+void Collision_Cache_ClipLineToWorldSurfaces(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents)
+{
+       collision_cachedtrace_t *cached = Collision_Cache_Lookup(model, &identitymatrix, &identitymatrix, start, end, hitsupercontents);
        if (cached->valid)
        {
                *trace = cached->result;
                return;
        }
 
+       Collision_ClipLineToWorld(trace, model, start, end, hitsupercontents, true);
+
+       cached->result = *trace;
+}
+
+void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask)
+{
+       float starttransformed[3], endtransformed[3];
+
        memset(trace, 0, sizeof(*trace));
        trace->fraction = trace->realfraction = 1;
 
@@ -1987,19 +1976,10 @@ void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const fram
        // transform plane
        // NOTE: this relies on plane.dist being directly after plane.normal
        Matrix4x4_TransformPositivePlane(matrix, trace->plane.normal[0], trace->plane.normal[1], trace->plane.normal[2], trace->plane.dist, trace->plane.normal);
-
-       cached->result = *trace;
 }
 
 void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontents)
 {
-       collision_cachedtrace_t *cached = Collision_Cache_Lookup(3, model, NULL, NULL, vec3_origin, vec3_origin, 0, &identitymatrix, &identitymatrix, start, mins, maxs, end, hitsupercontents);
-       if (cached->valid)
-       {
-               *trace = cached->result;
-               return;
-       }
-
        memset(trace, 0, sizeof(*trace));
        trace->fraction = trace->realfraction = 1;
        // ->TraceBox: TraceBrush not needed here, as worldmodel is never rotated
@@ -2008,20 +1988,11 @@ void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start
        trace->fraction = bound(0, trace->fraction, 1);
        trace->realfraction = bound(0, trace->realfraction, 1);
        VectorLerp(start, trace->fraction, end, trace->endpos);
-
-       cached->result = *trace;
 }
 
 void Collision_ClipLineToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask, qboolean hitsurfaces)
 {
        float starttransformed[3], endtransformed[3];
-       collision_cachedtrace_t *cached = Collision_Cache_Lookup(2, model, frameblend, skeleton, bodymins, bodymaxs, bodysupercontents, matrix, inversematrix, start, vec3_origin, vec3_origin, end, hitsupercontentsmask);
-       if (cached->valid)
-       {
-               *trace = cached->result;
-               return;
-       }
-
        memset(trace, 0, sizeof(*trace));
        trace->fraction = trace->realfraction = 1;
 
@@ -2044,19 +2015,10 @@ void Collision_ClipLineToGenericEntity(trace_t *trace, dp_model_t *model, const
        // transform plane
        // NOTE: this relies on plane.dist being directly after plane.normal
        Matrix4x4_TransformPositivePlane(matrix, trace->plane.normal[0], trace->plane.normal[1], trace->plane.normal[2], trace->plane.dist, trace->plane.normal);
-
-       cached->result = *trace;
 }
 
 void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents, qboolean hitsurfaces)
 {
-       collision_cachedtrace_t *cached = Collision_Cache_Lookup(2, model, NULL, NULL, vec3_origin, vec3_origin, 0, &identitymatrix, &identitymatrix, start, vec3_origin, vec3_origin, end, hitsupercontents);
-       if (cached->valid)
-       {
-               *trace = cached->result;
-               return;
-       }
-
        memset(trace, 0, sizeof(*trace));
        trace->fraction = trace->realfraction = 1;
        if (model && model->TraceLineAgainstSurfaces && hitsurfaces)
@@ -2066,20 +2028,11 @@ void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t s
        trace->fraction = bound(0, trace->fraction, 1);
        trace->realfraction = bound(0, trace->realfraction, 1);
        VectorLerp(start, trace->fraction, end, trace->endpos);
-
-       cached->result = *trace;
 }
 
 void Collision_ClipPointToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, int hitsupercontentsmask)
 {
        float starttransformed[3];
-       collision_cachedtrace_t *cached = Collision_Cache_Lookup(1, model, frameblend, skeleton, bodymins, bodymaxs, bodysupercontents, matrix, inversematrix, start, vec3_origin, vec3_origin, start, hitsupercontentsmask);
-       if (cached->valid)
-       {
-               *trace = cached->result;
-               return;
-       }
-
        memset(trace, 0, sizeof(*trace));
        trace->fraction = trace->realfraction = 1;
 
@@ -2097,26 +2050,15 @@ void Collision_ClipPointToGenericEntity(trace_t *trace, dp_model_t *model, const
        // transform plane
        // NOTE: this relies on plane.dist being directly after plane.normal
        Matrix4x4_TransformPositivePlane(matrix, trace->plane.normal[0], trace->plane.normal[1], trace->plane.normal[2], trace->plane.dist, trace->plane.normal);
-
-       cached->result = *trace;
 }
 
 void Collision_ClipPointToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, int hitsupercontents)
 {
-       collision_cachedtrace_t *cached = Collision_Cache_Lookup(1, model, NULL, NULL, vec3_origin, vec3_origin, 0, &identitymatrix, &identitymatrix, start, vec3_origin, vec3_origin, start, hitsupercontents);
-       if (cached->valid)
-       {
-               *trace = cached->result;
-               return;
-       }
-
        memset(trace, 0, sizeof(*trace));
        trace->fraction = trace->realfraction = 1;
        if (model && model->TracePoint)
                model->TracePoint(model, NULL, NULL, trace, start, hitsupercontents);
        VectorCopy(start, trace->endpos);
-
-       cached->result = *trace;
 }
 
 void Collision_CombineTraces(trace_t *cliptrace, const trace_t *trace, void *touch, qboolean isbmodel)
index 919e9dcd9084ec597ef552cc6806935f7cbaff9b..5e0a4ba02367bf030266fcdf267df4bd79786457 100644 (file)
@@ -160,6 +160,9 @@ void Collision_ClipPointToGenericEntity(trace_t *trace, dp_model_t *model, const
 void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontents);
 void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents, qboolean hitsurfaces);
 void Collision_ClipPointToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, int hitsupercontents);
+// caching surface trace for renderer (NOT THREAD SAFE)
+void Collision_Cache_ClipLineToGenericEntitySurfaces(trace_t *trace, dp_model_t *model, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask);
+void Collision_Cache_ClipLineToWorldSurfaces(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents);
 // combines data from two traces:
 // merges contents flags, startsolid, allsolid, inwater
 // updates fraction, endpos, plane and surface info if new fraction is shorter
index 020a35b4ac40496568a2ba1aa1e5c4f3d9960c89..f48621e52d1cc7a707729f48c4a7a8640f6cb3cc 100644 (file)
@@ -2702,10 +2702,16 @@ void R_Shadow_UpdateBounceGridTexture(void)
                                r_refdef.stats.bouncegrid_traces++;
                                //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
                                //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
-                               //if (settings.staticmode)
-                               //      Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask, true);
-                               //else
+                               if (settings.staticmode)
+                               {
+                                       // static mode fires a LOT of rays but none of them are identical, so they are not cached
                                        cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, true, false, NULL, true, true);
+                               }
+                               else
+                               {
+                                       // dynamic mode fires many rays and most will match the cache from the previous frame
+                                       cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask);
+                               }
                                if (bouncecount > 0 || settings.includedirectlighting)
                                {
                                        // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)