光线追踪算法—图像纹理

1. 纹理的概念

由于一个物体表面的不同位置上通常有含有不同的颜色或者其他属性(如发射率、法线等),所以需要一种方法来表示物体每个位置上的不同的属性。在CG中,通常通过使用纹理映射技术来表示物体不同位置上不同的属性。

由于物体可以是一维、二维或者三维的,所有纹理技术可以适用于1D、2D与3D空间。通常来说,纹理映射技术可以通过两种方法来实现,一种是将物体的属性存储在一个二维数组中,该数组一般称为纹理图,然后使用物体的某个位置信息或者其他信息在纹理图中查找属性值,或者也可以使用一个程序来计算物体每个位置上的属性,该实现方法通常称为过程纹理。

2. 纹理分类

纹理可以根据多种方法来进行分类:

根据纹理函数的维度:1D纹理,2D纹理,3D纹理
根据纹理的实现方法:过程纹理或者使用存储然后查找实现
根据纹理改变物体的属性:凹凸贴图、漫反射贴图、光泽贴图、环境贴图、置换贴图、深度纹理

3. 纹理映射方法

纹理映射技术一般可以看做一个函数,通过给定物体表面的一个位置来获取物体表面该位置上的某个属性。在过程纹理中,过程纹理函数通常以位置作为参数返回物体该位置上的属性。对于将物体属性存储在数组中的情况,通常将物体的表面位置映射到一个[0,1]X[0,1]的范围,该范围即为2D正规化纹理坐标(u,v)的范围,然后使用纹理坐标在数组中取出属性的值。

在光线追踪中,通常在碰撞时返回与光线碰撞物体的表面位置的世界坐标,并将碰撞点的坐标转换到局部坐标系中,即将该物体变换为通用的几何对象,如球体变换为通用球体,通用球体的中心在坐标原点,半径为1。然后,将获得的通用球体上位置坐标映射到正规化纹理坐标中。

通用球体位置坐标映射到2D正规化纹理坐标:

Point2f SphericalMapping::GetTextureCoordinates(const Point3f& local_hit_point) const
{
  Float theta = acos(local_hit_point.y_);
  Float phi = atan2(local_hit_point.x_, local_hit_point.z_);
  if (phi < 0)
    phi += 2 * M_PI;
  Float u = phi / (2 * M_PI);
  Float v = theta * INV_PI;
  return Point2f(u, v);
}

通用矩形位置坐标映射到2D正规化纹理坐标:

Point2f RectanglelMapping::GetTextureCoordinates(const Point3f& local_hit_point) const
{
  Float u = (local_hit_point.x_ + 1) / 2.0f;
  Float v = (-local_hit_point.z_ + 1) / 2.0f;
  return Point2f(u, v);
}

4. 一个光线追踪中的纹理映射图

场景中球体背后存在一个矩形,该矩形映射到一个纹理图。最左边的球体映射到一个地球的纹理图中。图像采用抖动采样,每个像素使用16个采样点。

场景创建代码

std::shared_ptr<World> BuildTexture( )
{
  std::shared_ptr<World> world = std::make_shared<World>( );
  world->AddLight(std::make_shared<PointLight>(Point3f(400, 400, -200), 3.0));
  
  world->AddSurface(std::make_shared<Sphere>(Point3f(50, 0, -500), 50,
         std::make_shared<Transparent>(Color(120.0 / 256.0, 20.0 / 256.0, 120.0 / 256.0), 1.4 / 1.0)));
  world->AddSurface(std::make_shared<Sphere>(Point3f(0, -20, -400), 30,
         std::make_shared<Transparent>(Color(25.0 / 256.0, 25.0 / 256.0, 112.0 / 256.0), 1.2 / 1.0)));

  MappingPtr mapper = std::make_shared<SphericalMapping>( );
  TexturePtr earth_texture = std::make_shared<ImageTexture>("earthmap.jpg", mapper);
  world->AddSurface(std::make_shared<Sphere>(Point3f(-60, 0, -400), 30,
                                             std::make_shared<VARMatte>(earth_texture)));
  
  MappingPtr rect_mapper = std::make_shared<RectanglelMapping>( );
  TexturePtr texture = std::make_shared<ProcessTexture>(Checker3D);
  TexturePtr plane_texture = std::make_shared<ImageTexture>("background1.jpg", rect_mapper);
  world->AddSurface(std::make_shared<Plane>(Point3f(0, -50, 0), Normal3f(0, 1, 0),
                                            std::make_shared<VARMatte>(plane_texture)));
  TexturePtr image_texture = std::make_shared<ImageTexture>("background2.jpg", rect_mapper);
  world->AddSurface(std::make_shared<leptus::Rectangle>(Point3f(-300, -50, -600), Vector3f(0, 250, 0), Vector3f(800, 0, 0),
                                                        std::make_shared<VARMatte>(image_texture)));
  return world;
}

实际的纹理映射渲染图


本文转自:博客园 - Leptus
原文链接:https://www.cnblogs.com/tallisHe/p/5532385.html
转载此文目的在于传递更多信息,版权归原作者所有。

最新文章