bool Scene::IsLightUnblocked(const Light& light, const Point<float>& point) const { Point<float> lightPosition = light.GetPosition(); Vector3<float> lightDirection = light.IsDirectional() ? Vector3<>(lightPosition.x, lightPosition.y, lightPosition.z) : lightPosition - point; // Create a ray to cast at the direction of the light: Ray ray(point, lightDirection); // Add a little bit of offset to handle the numeric errors: ray.origin = ray.origin + ray.direction * 0.00001f; // Calculate distance between the light and the intersection point: float lightDistance = lightDirection.length(); // Find if there is any object between the light and the object: if (!IsLightUnblocked<Sphere>(m_spheres, light, lightDistance, ray) || !IsLightUnblocked<GenericMesh>(m_genericMeshes, light, lightDistance, ray) ) return false; return true; }
void TerrainPatch::Illuminate(Color ambient, List<Light>& lights) { if (!model || model->NumVerts() < 1) return; Surface* s = model->GetSurfaces().first(); if (!s) return; illuminating = true; // clear the solid lights to ambient: VertexSet* vset = s->GetVertexSet(); int nverts = vset->nverts; DWORD aval = ambient.Value(); for (int i = 0; i < nverts; i++) { vset->diffuse[i] = aval; } TerrainRegion* trgn = terrain->GetRegion(); bool eclipsed = false; bool first = terrain->IsFirstPatch(this); if (trgn && !first) { eclipsed = trgn->IsEclipsed(); } // for sun and back lights: ListIter<Light> iter = lights; while (++iter) { Light* light = iter.value(); if (!light->IsDirectional()) // only do sun and continue; // back lights if (light->CastsShadow() && first) { eclipsed = light->Location().y < -100 || // has sun set, or scene->IsLightObscured(vset->loc[0], // is sun in eclipse light->Location(), // by orbital body radius); // such as a moon? } if (!light->CastsShadow() || !eclipsed) { Vec3 vl = light->Location(); vl.Normalize(); for (int i = 0; i < nverts; i++) { Vec3& nrm = vset->nrm[i]; double val = 0; double gain = vl * nrm; if (gain > 0) { val = light->Intensity() * (0.85 * gain); if (val > 1) val = 1; } if (val > 0.01) vset->diffuse[i] = ((light->GetColor().dim(val)) + vset->diffuse[i]).Value(); } } } // combine blend weights: if (ndetail >= 2) { for (int i = 0; i < nverts; i++) { vset->diffuse[i] = vset->specular[i] | (vset->diffuse[i] & 0x00ffffff); } } if (trgn && first) { trgn->SetEclipsed(eclipsed); } InvalidateSurfaceData(); illuminating = false; }