Странное прямое освещение в нестандартной задаче

В настоящее время я реализую пользовательский рендерер с трассировкой лучей, и я столкнулся с проблемой прямого освещения. Вот мой результат:

normalOnLight

sphereNormal

max(normalOnLight.dot(globeNormal), 0,0)

Я не понимаю, последний результат, я думаю, что первый и второй являются правильными, но не последний (точка..) свет является точечным светом.

    const Vec4<double> LambertianSampler::radiance(const Ray& ray, const Scene& scene) const
  {
     Context ctx;
     ctx.setCamtoWorld(scene.getCamera()->getLookAt());
     Vec4<double> maxColor(1.0, 1.0, 1.0, 1.0);
     Vec4<double> ambient(0.4, 0.4, 0.4, 1.0);

     Vec4<double> finaleRadiance = ambient;
     for(const auto & light : scene.getLights())
     {
       for(const auto & shape : scene.getShapes())
       {
          shape->intersect(ray, ctx);
       }

      if(ctx.intersectionFound())
      {
      Vec3<double> lightPosition = light->getPos();
      Vec4<double> lightColor    = light->getRadiance();
      Vec3<double> lightNormal   = ctx.getPoint() - lightPosition;
      lightNormal = Vec3<double>(std::fabs(lightNormal.x()), std::fabs(lightNormal.y()), std::fabs(lightNormal.z()));
      lightNormal.normalize();

      Vec3<double> sphereNormal = ctx.getNormal();
      sphereNormal   = Vec3<double>(std::fabs(sphereNormal.x()), std::fabs(sphereNormal.y()), std::fabs(sphereNormal.z())) ;
      sphereNormal.normalize();

      double dot     = lightNormal.dot(sphereNormal);
      finaleRadiance = maxColor*std::max(0.0,dot);
      finaleRadiance = Vec4<double>(finaleRadiance.x(), finaleRadiance.y(), finaleRadiance.z(), 1.0);

      //finaleRadiance = Vec4<double>(sphereNormal.x(), sphereNormal.y(), sphereNormal.z(), 1.0);
      //finaleRadiance = Vec4<double>(lightNormal.x(), lightNormal.y(), lightNormal.z(), 1.0);

    }
  }
  return finaleRadiance;
}

Правильный ли мой точечный результат? потому что я думаю, что мои lightNormalOnSphere и phereNormal правы, я думаю..

2 ответа

Решение

Я исправляю свою проблему, заменяя:

lightNormal = Vec3<double>(std::fabs(lightNormal.x()), std::fabs(lightNormal.y()), std::fabs(lightNormal.z()));

по

lightNormal = Vec3<double>((lightNormal.x()+1)*0.5, (lightNormal.y()+1)*0.5, (lightNormal.z()+1)*0.5);

Основная проблема здесь:

  Vec3<double> sphereNormal = ctx.getNormal();
  sphereNormal   = Vec3<double>(std::fabs(sphereNormal.x()), std::fabs(sphereNormal.y()), std::fabs(sphereNormal.z())) ;
  sphereNormal.normalize();

Но приведенное выше решение кажется не совсем правильным. Прежде всего, вам не нужно заново нормализовать сферу в нормальном состоянии. fabs звонки изменят некоторые знаки, но не величины, поэтому дополнительная нормализация - это просто потеря времени.

Но почему fabs звонки. Полагаю, вы добавили это, потому что нормали сферы, казалось, указывали неправильное направление. Таким образом, когда вы взяли точечное произведение, вы получили отрицательные значения на светлой стороне. Вы добавили потрясающие материалы, которые, как оказалось, повернули все нормальные сферы к свету, даже те, что на темной стороне. Вот почему вы видите начало затенения, но затем свет снова нарастает, а не гаснет совсем.

Это также объясняет, почему предложенное вами решение работает. Вы смещаете нормали туда, где (я думаю) вы поместили свет.

Если моя теория верна, то вам нужно перевернуть сферные нормали так, чтобы они указывали, а не в сферу. Быстрый способ проверки состоит в том, чтобы вычесть центр сферы из точки пересечения, что должно дать вам указательный вектор, и вы можете затем его нормализовать. Если это не соответствует сферным нормам, которые вы сейчас вычисляете (в частности, если все знаки перевернуты), моя теория будет подтверждена.

В этом случае решение состоит в том, чтобы просто перевернуть сферу в норме перед вычислением точечного произведения.

Наконец, вы перебираете источники света, но используете только вклад последнего источника в списке. (Трудно сказать точно, потому что у вас есть несколько несоответствующих скобок в вопросе.)

Другие вопросы по тегам