광선이 공간을 통과하면서 일부는 사물에 부딪치면서 상호 작용하여 색상이 나타납니다. 사실 색상의 일부는 직사광 때문이 아니라 다른 물체에서 반사되거나 산란되는 주변광에 영향을 받습니다.
- Ambient light (주변광/환경광): 광원이 아닌 다른 물체에서 반사되거나 산란되는 빛 (간접조명)
- Diffuse light (산란광/난반사광/분산광): 물체에 빛이 닿을 때, 여러방향으로 반사되는 것(난반사)을 나타내는 빛
- Specular light(정반사광): 물체에 빛이 닿을 때 특정 방향으로만 반사되는 빛. 즉, 광원이 직접 반사되는 하이라이트 지점을 나타내는 빛
실행 결과
- Ambient light 변화 확인: Red sphere
- Diffuse light 변화 확인: Blue sphere
- Specular light 변화 확인: Green sphere
- Specular power (=shininess factor) 변화 확인: 왼쪽 → 오른쪽
예제 코드
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkLight.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSphereSource.h>
#include <array>
int main(int, char*[])
{
vtkNew<vtkNamedColors> colors;
std::array<unsigned char, 4> bkg{{26, 51, 102, 255}};
colors->SetColor("bkg", bkg.data());
vtkNew<vtkSphereSource> sphere;
sphere->SetThetaResolution(100);
sphere->SetPhiResolution(50);
vtkNew<vtkPolyDataMapper> sphereMapper;
sphereMapper->SetInputConnection(sphere->GetOutputPort());
auto const numberOfSpheres = 12;
std::array<vtkNew<vtkActor>, numberOfSpheres> spheres;
auto ambient = 0.4;
auto diffuse = 0.4;
auto specular = 0.4;
auto spBase = 5.0;
auto spScale = 1.0;
std::array<double, 3> position{{0, 0, 0}};
// Ambient light
for (auto i = 0; i < 4; ++i)
{
auto specularPower = spBase * spScale;
spheres[i]->SetMapper(sphereMapper);
spheres[i]->GetProperty()->SetColor(colors->GetColor3d("Red").GetData());
spheres[i]->GetProperty()->SetAmbient(ambient);
spheres[i]->GetProperty()->SetDiffuse(diffuse);
spheres[i]->GetProperty()->SetSpecular(specular);
spheres[i]->GetProperty()->SetSpecularPower(specularPower);
spheres[i]->GetProperty()->SetSpecularColor(
colors->GetColor3d("White").GetData());
spheres[i]->AddPosition(position.data());
spScale = spScale * 2.0;
position[0] += 1.25;
ambient += 0.2;
}
ambient = 0.4;
spScale = 1.0;
position[0] = 0;
position[1] = 1.25;
// Diffuse light
for (auto i = 4; i < 8; i++)
{
auto specularPower = spBase * spScale;
spheres[i]->SetMapper(sphereMapper);
spheres[i]->GetProperty()->SetColor(colors->GetColor3d("Blue").GetData());
spheres[i]->GetProperty()->SetAmbient(ambient);
spheres[i]->GetProperty()->SetDiffuse(diffuse);
spheres[i]->GetProperty()->SetSpecular(specular);
spheres[i]->GetProperty()->SetSpecularPower(specularPower);
spheres[i]->GetProperty()->SetSpecularColor(
colors->GetColor3d("White").GetData());
spheres[i]->AddPosition(position.data());
spScale = spScale * 2.0;
position[0] += 1.25;
diffuse += 0.2;
}
diffuse = 0.4;
spScale = 1.0;
position[0] = 0;
position[1] = 2.5;
// Specular light
for (auto i = 8; i < 12; i++)
{
auto specularPower = spBase * spScale;
spheres[i]->SetMapper(sphereMapper);
spheres[i]->GetProperty()->SetColor(colors->GetColor3d("Green").GetData());
spheres[i]->GetProperty()->SetAmbient(ambient);
spheres[i]->GetProperty()->SetDiffuse(diffuse);
spheres[i]->GetProperty()->SetSpecular(specular);
spheres[i]->GetProperty()->SetSpecularPower(specularPower);
spheres[i]->GetProperty()->SetSpecularColor(
colors->GetColor3d("White").GetData());
spheres[i]->AddPosition(position.data());
spScale = spScale * 2.0;
position[0] += 1.25;
specular += 0.2;
}
vtkNew<vtkRenderer> ren;
vtkNew<vtkRenderWindow> renWin;
renWin->AddRenderer(ren);
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renWin);
for (auto i = 0; i < numberOfSpheres; ++i)
{
ren->AddActor(spheres[i]);
}
ren->SetBackground(colors->GetColor3d("bkg").GetData());
renWin->SetSize(640, 640);
renWin->SetWindowName("Specular Spheres");
vtkNew<vtkLight> light;
light->SetFocalPoint(1.875, 0.6125, 0);
light->SetPosition(0.875, 1.6125, 1);
ren->AddLight(light);
ren->GetActiveCamera()->SetFocalPoint(0, 0, 0);
ren->GetActiveCamera()->SetPosition(0, 0, 1);
ren->GetActiveCamera()->SetViewUp(0, 1, 0);
ren->GetActiveCamera()->ParallelProjectionOn();
ren->ResetCamera();
ren->GetActiveCamera()->SetParallelScale(3.0);
iren->Initialize();
renWin->Render();
iren->Start();
return EXIT_SUCCESS;
}