2013-03-25 1 views
9

Я читал многочисленные статьи о трассировке лучей и затенении, но изображение, прорисованное лучом, выглядит не очень хорошо. Я говорю о очень яркой зеленой зоне рядом с зеркальной подсветкой. Результат зеленого цвета здесь максимален, похоже. Как настроить расцветку и/или затенение расчетов, чтобы это выглядело правильно?Raytracing - как сочетать диффузный и зеркальный цвет?

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

Вот как это выглядит:

enter image description here

Вот диффузный компонент только:

enter image description here

Вот зеркальная составляющая только:

enter image description here

РЕДАКТИРОВАНИЕ: изменение диффузного цвета в цвете diffuseColor = ColorMake (0.0f, 0.6f, 0.0f); Затем изображение выглядит следующим образом:

enter image description here

Point lightPosition = PointMake(-100.0f, 100.0f, -100.0f); 
Color diffuseColor = ColorMake(0.0f, 1.0f, 0.0f); 
Color specularColor = ColorMake(1.0f, 1.0f, 1.0f); 
Color pixelColor = ColorMake(0.0f, 0.0f, 0.0f); 

// Trace... 

      // Diffuse 
      Point intersectionPosition = PointMake(x, y, z); 
      Vector intersectionNormal = VectorMake((x - xs)/rs, (y - ys)/rs, (z - zs)/rs); 
      Vector intersectionNormalN = VectorNormalize(intersectionNormal); 
      Vector lightVector   = VectorSubtract(lightPosition, intersectionPosition); 
      VectorlightVectorN   = VectorNormalize(lightVector); 
      float  cosTheta  = VectorDotProduct(intersectionNormalN, lightVectorN); 
      if (cosTheta < 0.0f) 
      { 
       cosTheta = 0.0f; 
      } 

      pixelColor = ColorMultScalar(diffuseColor, cosTheta); 

      // Specular 
      Vector incomVector = VectorSubtract(intersectionPosition, lightPosition); 
      Vector incomVectorN = VectorNormalize(incomVector); 

      float myDot = - VectorDotProduct(incomVectorN, intersectionNormalN); 
      float myLen = 2.0f * myDot; 

      Vector tempNormal  = VectorMultScalar(intersectionNormalN, myLen); 
      Vector reflectVector = VectorAdd(tempNormal, incomVectorN); 
      Vector reflectVectorN = VectorNormalize(reflectVector); 

      float mySpec = MAX(-VectorDotProduct(reflectVectorN, incomVectorN), 0); 
      mySpec  = powf(mySpec, 5); 

      specularColor = ColorMultScalar(specularColor, mySpec); 
      pixelColor = ColorAdd(pixelColor, specularColor); 
      pixelColor = ColorClamp(pixelColor); 

      [self putPixelatX:i andY:j andR:pixelColor.r andG:pixelColor.g andB:pixelColor.b]; 

ответ

6

Проблема, когда вы вычислить диффузный цвет сферы у вас уже есть небольшой участок пикселей, 1 или очень близких к 1 (в зеленый канал). Добавляя компонент «phong» (который имеет значение около одного во всех каналах) к этому, дает область пикселей, которая составляет> = 1. Когда вы затем зажимаете значение цвета до 1, эта область> = 1 стоит вне.

Вы можете протестировать это с помощью программы редактирования изображений и выполнить «добавление» наложения двух слоев (слой фогов над диффузным). Это дает результат, который вы видите - и что следует ожидать.

Вы можете избежать проблем с помощью ряда мер:

  1. Вы можете тусклый источнику света немного, то есть умножить диффузную силу вы вычисленная форму косинуса по яркости - скажем, 0,8 или 0,7 ,
  2. Вы можете ограничить насыщенность цвета (зеленые, что есть) сферы и сделать его менее греющим;)
  3. Используйте оператор отображения тонов для нормализации значений цвета пикселей в диапазоне [0..1] - эта тема, однако, обширна - википедия может дать хорошее представление. Вам даже не нужно заниматься этим, так как для не-физически основанного рендеринга более простые команды отображения тона вполне достаточны и дают результаты, которые приятны для глаз.

Мои эксперименты по отслеживанию лучей датируются несколькими годами, но вы можете попробовать эти вещи.


Update 1:

Одна вещь, которую я заметил, когда гамма-коррекции вашего выходного изображения - эффект менее выражен;) - Хорошо, что это своего рода неоднородный.

Конечным решением является переход на физически правильное или просто использование другой модели затенения: Wikipedia on Specular highlight.


Update 2:

Одно действительное решение было бы вычислить Фонг вклад в конечный цвет пикселя (то есть ваша переменная mySpec). Идея состоит в том, чтобы использовать только часть диффузного компонента, где зеркальное отображение фактически не равно 0, то есть, если у вас есть зеркальный компонент, вы фактически не видите диффузный компонент так много (или вообще), чтобы он мог с поправкой на:

float diffuseContrib = 1.f - mySpec; 

это должно выглядеть красиво, но я не совсем уверен, как правильно это на самом деле :).

Примечание: это предполагает, что ваши зеркальные и диффузные компоненты находятся в диапазоне [0..1].

Мой результат выглядит таким образом:

diffuse contribution calculated using the specular contribution

4

Это уже давно проблема с «зеркальными + диффузного + окружающей среды» модели освещения. А именно, это взлом и, следовательно, не имеет гарантии правильности.

Если вы так заинтересованы в цементировании своих основ, взгляните на отличную книгу «Физически основанная трассировка лучей» Мэтта Фарра и Грега Хамфриса.

+0

Неправильно, это точка. Не может быть «гарантии правильности»;) - это действительно просто способ раскрашивания пикселей с удобными математическими функциями (например, pow для phong и плюс некоторые произвольные значения для ambient). По крайней мере, так я это вижу. Самое главное; PBRT FTW !! 1 –

+0

Пока ваша точка на 100% действительна, многие люди, которые прыгают в raytracing, не понимают этого факта - их обычно качают красивые картинки, не зная, что существует целая куча настроек :) –

0

Вы должны прочитать на Blinn/Phong model. Здесь приведен пример фрагмента фрагмента кода шейдера. В основном вы масштабируете отдельные компоненты (окружающие, диффузные, зеркальные) с соответствующими углами и складываете их.

varying vec3 N; 
varying vec3 v;  
void main (void) 
{ 
    vec3 L = normalize(gl_LightSource[0].position.xyz - v); 
    vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0) 
    vec3 R = normalize(-reflect(L,N)); 

    //calculate Ambient Term: 
    vec4 Iamb = gl_FrontLightProduct[0].ambient;  

    //calculate Diffuse Term: 
    vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0); 
    Idiff = clamp(Idiff, 0.0, 1.0);  

    // calculate Specular Term: 
    vec4 Ispec = gl_FrontLightProduct[0].specular 
       * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess); 
    Ispec = clamp(Ispec, 0.0, 1.0); 
    // write Total Color: 
    gl_FragColor = gl_FrontLightModelProduct.sceneColor + Iamb + Idiff + Ispec;  
} 

взяты из: http://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/lighting.php

0

Почему бы не сделать (свет + эмбиент) * диффузный + зеркальную? т.е. добавление зеркального компонента после того, как вы умножили освещение и тени с диффузным? Это даст ясную подсветку.