void Light::SetIntensitySortValue(const BoundingBox& box) { // When sorting lights for object's maximum light cap, give priority based on attenuation and intensity switch (lightType_) { case LIGHT_DIRECTIONAL: sortValue_ = 1.0f / GetIntensityDivisor(); break; case LIGHT_SPOT: { Vector3 centerPos = box.Center(); Vector3 lightPos = node_->GetWorldPosition(); Vector3 lightDir = node_->GetWorldDirection(); Ray lightRay(lightPos, lightDir); Vector3 centerProj = lightRay.Project(centerPos); float centerDistance = (centerProj - lightPos).Length(); Ray centerRay(centerProj, centerPos - centerProj); float centerAngle = centerRay.HitDistance(box) / centerDistance; // Check if a corner of the bounding box is closer to the light ray than the center, use its angle in that case Vector3 cornerPos = centerPos + box.HalfSize() * Vector3(centerPos.x_ < centerProj.x_ ? 1.0f : -1.0f, centerPos.y_ < centerProj.y_ ? 1.0f : -1.0f, centerPos.z_ < centerProj.z_ ? 1.0f : -1.0f); Vector3 cornerProj = lightRay.Project(cornerPos); float cornerDistance = (cornerProj - lightPos).Length(); float cornerAngle = (cornerPos - cornerProj).Length() / cornerDistance; float spotAngle = Min(centerAngle, cornerAngle); float maxAngle = tanf(fov_ * M_DEGTORAD * 0.5f); float spotFactor = Min(spotAngle / maxAngle, 1.0f); // We do not know the actual range attenuation ramp, so take only spot attenuation into account float att = Max(1.0f - spotFactor * spotFactor, M_EPSILON); sortValue_ = 1.0f / GetIntensityDivisor(att); } break; case LIGHT_POINT: { Vector3 centerPos = box.Center(); Vector3 lightPos = node_->GetWorldPosition(); Vector3 lightDir = (centerPos - lightPos).Normalized(); Ray lightRay(lightPos, lightDir); float distance = lightRay.HitDistance(box); float normDistance = distance / range_; float att = Max(1.0f - normDistance * normDistance, M_EPSILON); sortValue_ = 1.0f / (Max(color_.SumRGB(), 0.0f) * att + M_EPSILON); } break; } }
bool ShadowTracer::hasOcclusion(const Vector light, const Vector* point) { Vector origin = light; Vector direction = (origin - *point); Vector normalized = direction.normalize(); Ray lightRay(*point, normalized); IntersectionPtr intersection = _scene->intersect(lightRay); if (intersection != nullptr) { return fabs((*point - intersection->getPoint()).length()) > 0.001; } else { return false; } }
int createLightPath(const RTScene& scene, Rand& rand, int maxVerts, PathVertex vertices[]) { const auto & light = *scene.light(0); ShadingCS lightPosShadingCS(light.normal); const float3 lightPos = light.samplePoint(rand); const float3 woWorldLight = lightPosShadingCS.world(sampleHemisphere(rand)); Ray lightRay(lightPos, woWorldLight); vertices[0] = PathVertex(light.normal, float3(0), lightPos, &light.material, light.material.emission * light.area()); float3 lightPdf = float3(1.f / (2 * PI * light.area())); float3 alpha = light.material.emission * dot(woWorldLight, light.normal) / lightPdf; //HACK: changed to intersect lights return 1 + createPath(scene, rand, maxVerts - 1, alpha, lightRay, false, &vertices[1]); }
void PointLight::shade( Ray3D& ray, Ray3D::intersection_func intersectCheck ) const { Material* mat = ray.intersection.mat; // compute direction towards light Vector3D lightDir = pos_ - ray.intersection.point; double distance = lightDir.normalize(); ray.col += col_ambient_ * mat->ambient.at(ray.intersection.uv); // cos of angle from normal to lightDir double cosAngle = lightDir.dot(ray.intersection.normal); if (cosAngle < 0) { return; } // shadow check else { Ray3D lightRay(ray.intersection.point, lightDir); intersectCheck(lightRay); // if we intersect an object between the light and point // we are considering, then it is in shadow if (!lightRay.intersection.none && lightRay.intersection.t_value < distance ) { return; } } // diffuse ray.col += col_diffuse_ * mat->diffuse.at(ray.intersection.uv) * cosAngle; // direction of reflection of light ray Vector3D reflectDir = 2*cosAngle*ray.intersection.normal - lightDir; reflectDir.normalize(); // cos of angle from reflection to ray back to viewer double rv = -reflectDir.dot(ray.dir); // specular if (rv > 0) { ray.col += col_specular_ * mat->specular.at(ray.intersection.uv) * pow(rv, mat->specular_exp); } }
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; }
void GeometryTerrain::computeLightmap(Vector3 _vlightSource, bool update) { bool bIntegrateNormals = false; std::vector<GLubyte> shadowMapTexture(GetWidth()*GetWidth()*4); float maxHeight = -99999.0f; for(int z =0; z <= GetLength(); ++z) for(int x = 0; x <= GetWidth(); ++x) maxHeight = max(getHeight(x,z), maxHeight); for(int z =0; z <= GetLength(); ++z) { for(int x = 0; x <= GetWidth(); ++x) { float ambientLight = 255; Ray lightRay(Vector3(x, getHeight(x, z), z), _vlightSource ); Vector3 current_ray_pos(Vector3(x, getHeight(x, z), z)); Vector3 direction_to_sun = lightRay.m_v3Direction.normalize(); int numRayHits = 0; while(!(current_ray_pos.x <= 0 || current_ray_pos.x >= GetWidth() || current_ray_pos.z <= 0 || current_ray_pos.z >= GetWidth() )) { if(current_ray_pos.y > maxHeight) break; // Is the terrain blocking the ray at this point? if(getHeight((int)floor(current_ray_pos.x), (int)floor(current_ray_pos.z)) > current_ray_pos.y) { numRayHits++; break; } //light still traveling... current_ray_pos += direction_to_sun; } float ambientLightNormals = 0; if(bIntegrateNormals) { Vector3 n( m_pNormals[x+z * (GetWidth()+1)].x, m_pNormals[x+z * (GetWidth()+1)].y, m_pNormals[x+z * (GetWidth()+1)].z ); ambientLightNormals = 0.5*( 1.0f + dot(n.normalize(), direction_to_sun) ); if(ambientLightNormals > 1.0f) ambientLightNormals = 1.0f; if(ambientLightNormals < 0.0f) ambientLightNormals = 0.0f; } if(numRayHits > 0) { //ambientLight = (current_ray_pos - Vector3(x,getHeight(x,z),z)).magnitude() - ambientLightNormals * 255; ambientLight = 170; if(ambientLight > 255) ambientLight = 255; if(ambientLight < 170) ambientLight = 170; } int index = (x + z * GetWidth()) * 3; for (int i = 0; i < 3; ++i) { shadowMapTexture[index + i] = (GLubyte)ambientLight; } } } for(int z =0; z <= GetLength(); ++z) { for(int x = 0; x <= GetWidth(); ++x) { int factor = 2; ColorOGL colCurrent; colCurrent.m_fRed = shadowMapTexture[(x + z * GetWidth()) * 3 + 0]; colCurrent.m_fGreen = shadowMapTexture[(x + z * GetWidth()) * 3 + 1]; colCurrent.m_fBlue = shadowMapTexture[(x + z * GetWidth()) * 3 + 2]; ColorOGL colT; ColorOGL colD; ColorOGL colL; ColorOGL colR; if(shadowMapTexture.size() > ((x + (z+factor) * GetWidth()) * 3 + 0) && shadowMapTexture.size() > ((x + (z+factor) * GetWidth()) * 3 + 1) && shadowMapTexture.size() > ((x + (z+factor) * GetWidth()) * 3 + 2) ) { colT.m_fRed = shadowMapTexture[(x + (z+factor) * GetWidth()) * 3 + 0]; colT.m_fGreen = shadowMapTexture[(x + (z+factor) * GetWidth()) * 3 + 1]; colT.m_fBlue = shadowMapTexture[(x + (z+factor) * GetWidth()) * 3 + 2]; } if(shadowMapTexture.size() > ((x + (z-factor) * GetWidth()) * 3 + 0) && shadowMapTexture.size() > ((x + (z-factor) * GetWidth()) * 3 + 1) && shadowMapTexture.size() > ((x + (z-factor) * GetWidth()) * 3 + 2) ) { colD.m_fRed = shadowMapTexture[(x + (z-factor) * GetWidth()) * 3 + 0]; colD.m_fGreen = shadowMapTexture[(x + (z-factor) * GetWidth()) * 3 + 1]; colD.m_fBlue = shadowMapTexture[(x + (z-factor) * GetWidth()) * 3 + 2]; } if(shadowMapTexture.size() > ( (x+factor + z * GetWidth()) * 3 + 0) && shadowMapTexture.size() > ((x+factor + z * GetWidth()) * 3 + 1) && shadowMapTexture.size() > ((x+factor + z * GetWidth()) * 3 + 2) ) { colL.m_fRed = shadowMapTexture[(x+factor + z * GetWidth()) * 3 + 0]; colL.m_fGreen = shadowMapTexture[(x+factor + z * GetWidth()) * 3 + 1]; colL.m_fBlue = shadowMapTexture[(x+factor + z * GetWidth()) * 3 + 2]; } if(shadowMapTexture.size() > (( x-factor + z * GetWidth()) * 3 + 0) && shadowMapTexture.size() > ((x-factor + z * GetWidth()) * 3 + 1) && shadowMapTexture.size() > ((x-factor + z * GetWidth()) * 3 + 2) ) { colR.m_fRed = shadowMapTexture[(x-factor + z * GetWidth()) * 3 + 0]; colR.m_fGreen = shadowMapTexture[(x-factor + z * GetWidth()) * 3 + 1]; colR.m_fBlue = shadowMapTexture[(x-factor + z * GetWidth()) * 3 + 2]; } shadowMapTexture[(x + z * GetWidth()) * 3 + 0] = (colT.m_fRed+colD.m_fRed+colR.m_fRed+colL.m_fRed+colCurrent.m_fRed)/5; shadowMapTexture[(x + z * GetWidth()) * 3 + 1] = (colT.m_fGreen+colD.m_fGreen+colR.m_fGreen+colL.m_fGreen+colCurrent.m_fGreen)/5; shadowMapTexture[(x + z * GetWidth()) * 3 + 2] = (colT.m_fBlue+colD.m_fBlue+colR.m_fBlue+colL.m_fBlue+colCurrent.m_fBlue)/5; } } if(update) { ResourceManager::getInstance()->getTexture2D("resources/textures/lightmap.tga")->bind(2); glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, GetWidth(), GetWidth(), GL_RGBA, GL_UNSIGNED_BYTE, &shadowMapTexture[0]); } else { ilTexImage(GetWidth(),GetWidth(), 1, 3, IL_RGB, IL_UNSIGNED_BYTE, &shadowMapTexture[0]); ilSetData(&shadowMapTexture[0]); ilSetInteger(IL_IMAGE_BITS_PER_PIXEL,32); ilEnable(IL_FILE_OVERWRITE); ilSave(IL_TGA, "resources/textures/lightmap.tga"); } }
D3DXCOLOR PhongMaterial::shade(vector<Light*>* lightList, vector<Mesh*>* objectList, Mesh* object, Camera* cam) { float Idiff, Ispec; Idiff = 0.0f; Ispec = 0.0f; D3DXCOLOR returnColor = color; D3DXCOLOR specularColor = D3DXCOLOR(255.0f, 255.0f, 255.0f, 255.0f); D3DXVECTOR3 L, Lnorm, R, Rnorm, V, Vnorm; V = cam->position - object->info.intersectionPoint; D3DXVec3Normalize(&Vnorm, &V); bool inShadow = false; vector<Mesh*> objs = *objectList; vector<Light*> lights = *lightList; for(int l = 0; l < lights.size(); l++) { L = lights[l]->position - object->info.intersectionPoint; D3DXVec3Normalize(&Lnorm, &L); Ray lightRay(object->info.intersectionPoint, Lnorm); for(int i = 0; i < objs.size(); i++) if(objs[i]->testIntersection(&lightRay).hasIntersected) inShadow = true; if(!inShadow) { R = 2 * D3DXVec3Dot(&object->info.intersectionNormal, &Lnorm) * object->info.intersectionNormal- Lnorm; D3DXVec3Normalize(&Rnorm, &R); float dDot = D3DXVec3Dot(&object->info.intersectionNormal, &Lnorm); if(dDot < 0.0f) dDot = 0.0f; if(dDot > 1.0f) dDot = 1.0f; float sDot = D3DXVec3Dot(&Vnorm, &Rnorm); if(sDot < 0.0f) sDot = 0.0f; if(sDot > 1.0f) sDot = 1.0f; Ispec += ks * pow(sDot, kse); if(Ispec > 1.0f) Ispec = 1.0f; if(Ispec < 0.0f) Ispec = 0.0f; Idiff += kd * dDot; //I += ks * pow(sDot, kse); } } if(inShadow) Idiff = lights[0]->ambientIntensity.x; else Idiff += lights[0]->ambientIntensity.x; returnColor *= Idiff; specularColor *= Ispec; D3DXCOLOR addedColor; D3DXColorAdd(&addedColor, &returnColor, &specularColor); if(addedColor.r > 255.0f) addedColor.r = 255.0f; if(addedColor.g > 255.0f) addedColor.g = 255.0f; if(addedColor.b > 255.0f) addedColor.b = 255.0f; return addedColor; }