1,理论分析
这一章节要画的是鱼缸,其实和前面画的“一杯水”是差不多的。
只不过这里是用各种“基本图形”构建的是一个“鱼缸”。
示意图如下:
其中界面2和界面3、4的主要参数求解示意图如下:
2, 基本图形
略。
3,C++代码实现
----------------------FishBowlFlatBottom.h----------------------
#ifndef FISHBOWLFLATBOTTOM_H
#define FISHBOWLFLATBOTTOM_H
// Copyright (C) Kevin Suffern 2000-2007.
// This C++ code is for non-commercial purposes only.
// This C++ code is licensed under the GNU General Public License Version 2.
// See the file COPYING.txt for the full license.
// This file contains the declaration of the class FishBowlFlatBottom
// This is a spherical bowl with a specified glass thickness
// that contains water
// The bowl is centered on the world origin
#include "Compound.h"
class FishBowlFlatBottom: public Compound {
public:
FishBowlFlatBottom(void);
FishBowlFlatBottom( const double _inner_radius,
const double _glass_thickness,
const double _water_depth,
const double _meniscus_radius,
const double _opening_angle,
const double _bottom_angle);
FishBowlFlatBottom(const FishBowlFlatBottom& fb);
virtual FishBowlFlatBottom*
clone(void) const;
virtual FishBowlFlatBottom&
operator= (const FishBowlFlatBottom& rhs);
virtual
~FishBowlFlatBottom(void);
void
build_components(void);
void
set_glass_air_material(Material* m_ptr);
void
set_water_air_material(Material* m_ptr);
void
set_water_glass_material(Material* m_ptr);
protected:
double inner_radius; // radius of the inside glass surface
double glass_thickness;
double water_depth; // measured from the bottom of the water-glass boundary
double meniscus_radius;
double opening_angle; // specifies how wide the opening is at the top (alpha in Figure 28.40(a))
double bottom_angle; // specifies how wide the opening is at the bottom
};
#endif // FISHBOWLFLATBOTTOM_H
----------------------FishBowlFlatBottom.cpp----------------------
// Copyright (C) Kevin Suffern 2000-2007.
// This C++ code is for non-commercial purposes only.
// This C++ code is licensed under the GNU General Public License Version 2.
// See the file COPYING.txt for the full license.
#include "Constants.h"
#include "Disk.h"
#include "SpherePartConvex.h"
#include "SpherePartConcave.h"
#include "TorusPartConvex.h"
#include "TorusPartConcave.h"
#include "Instance.h"
#include "FishBowlFlatBottom.h"
// ------------------------------------------------------------------------------ default constructor
FishBowlFlatBottom::FishBowlFlatBottom(void)
: Compound(),
inner_radius(1.0),
glass_thickness(0.1),
water_depth(1.25),
meniscus_radius(0.05),
opening_angle(90),
bottom_angle(90)
{
build_components();
}
// ------------------------------------------------------------------------------ constructor
FishBowlFlatBottom::FishBowlFlatBottom( const double _inner_radius,
const double _glass_thickness,
const double _water_depth,
const double _meniscus_radius,
const double _opening_angle,
const double _bottom_angle)
: Compound(),
inner_radius(_inner_radius),
glass_thickness(_glass_thickness),
water_depth(_water_depth),
meniscus_radius(_meniscus_radius),
opening_angle(_opening_angle),
bottom_angle(_bottom_angle)
{
build_components();
}
// ------------------------------------------------------------------------------ copy constructor
FishBowlFlatBottom::FishBowlFlatBottom(const FishBowlFlatBottom& fb)
: Compound(fb),
inner_radius(fb.inner_radius),
glass_thickness(fb.glass_thickness),
water_depth(fb.water_depth),
meniscus_radius(fb.meniscus_radius),
opening_angle(fb.opening_angle),
bottom_angle(fb.bottom_angle)
{}
// ------------------------------------------------------------------------------ clone
FishBowlFlatBottom*
FishBowlFlatBottom::clone(void) const {
return(new FishBowlFlatBottom(*this));
}
// ------------------------------------------------------------------------------ assignment operator
FishBowlFlatBottom&
FishBowlFlatBottom::operator= (const FishBowlFlatBottom& rhs) {
if (this == &rhs)
return (*this);
Compound::operator=(rhs);
inner_radius = rhs.inner_radius;
glass_thickness = rhs.glass_thickness;
water_depth = rhs.water_depth;
meniscus_radius = rhs.meniscus_radius;
opening_angle = rhs.opening_angle;
bottom_angle = rhs.bottom_angle;
return (*this) ;
}
// ------------------------------------------------------------------------------ destructor
FishBowlFlatBottom::~FishBowlFlatBottom(void) {}
// ------------------------------------------------------------------------------ build_components
void
FishBowlFlatBottom::build_components(void) {
double angle_radians = (opening_angle / 2.0) * PI_ON_180; // half the opening angle in radians
double angle_radians_bottom = (bottom_angle / 2.0) * PI_ON_180; // half the bottom angle in radians
// meniscus calculations - required here because they affect the inner surface of the glass-air boundary
// torus tube center coordinates
double h = water_depth - inner_radius;
double yc = h + meniscus_radius;
double xc = sqrt(inner_radius * (inner_radius - 2.0 * meniscus_radius) - h * (h + 2.0 * meniscus_radius));
double beta = atan2(yc, xc) * 180.0 / PI; // in degrees
// outer glass-air boundary
objects.push_back(new SpherePartConvex( Point3D(0.0),
inner_radius + glass_thickness,
0, 360, // azimuth angle range - full circle
opening_angle / 2.0, // minimum polar angle measured from top
180 - (bottom_angle / 2.0))); // maximum polar angle measured from top
// inner glass-air boundary
// the inner surface of the glass only goes down to the top of the meniscus
objects.push_back(new SpherePartConcave(Point3D(0.0),
inner_radius,
0, 360, // azimuth angle - full circle
opening_angle / 2.0, // mimimum polar angle measured from top
90 - beta)); // maximum polar angle measured from top
// round rim - need an instance for this as it's a half torus
double theta_min = opening_angle / 2.0; // measured counter-clockwise from (x, z) plane
double theta_max = theta_min + 180; // measured counter-clockwise from (x, z) plane
Instance* rim_ptr = new Instance (new TorusPartConvex(
(inner_radius + glass_thickness / 2.0) * sin(angle_radians), // a
glass_thickness / 2.0, // b
0, 360,
theta_min,
theta_max));
rim_ptr->translate(0, (inner_radius + glass_thickness / 2.0) * cos(angle_radians), 0);
objects.push_back(rim_ptr);
// meniscus - if water_depth > 1, we need two part tori
Instance* torus_ptr1 = new Instance (new TorusPartConcave( xc,
meniscus_radius,
0, 360,
270, 360));
torus_ptr1->translate(0, yc, 0);
objects.push_back(torus_ptr1);
Instance* torus_ptr2 = new Instance (new TorusPartConcave( xc,
meniscus_radius,
0, 360,
0, beta));
torus_ptr2->translate(0, yc, 0);
objects.push_back(torus_ptr2);
// water-air boundary top
objects.push_back(new Disk( Point3D(0, h, 0),
xc,
Normal(0, 1, 0))); // the disk just touches the bottom of the meniscus
// water-glass boundary bottom
objects.push_back(new Disk( Point3D(0, -(cos(angle_radians_bottom)*inner_radius), 0),
(sin(angle_radians_bottom)*inner_radius),
Normal(0, -1, 0))); // the bottom disk between water and glass
// water-glass boundary
objects.push_back(new SpherePartConvex( Point3D(0),
inner_radius,
0, 360,
90 - beta, // mimimum polar angle measured from top
180 - (bottom_angle / 2.0)));// maximum polar angle measured from top
// glass-air boundary bottom
objects.push_back(new Disk( Point3D(0, -(cos(angle_radians_bottom)*(inner_radius+glass_thickness)), 0),
(sin(angle_radians_bottom)*(inner_radius+glass_thickness)),
Normal(0, -1, 0))); // the bottom disk between glass and air
}
// ------------------------------------------------------------------------------ set_glass_air_material
// [0]: outer glass-air boundary
// [1]: inner glass-air boundary
// [2]: rim
// [8]: bottom
void
FishBowlFlatBottom::set_glass_air_material(Material* m_ptr) {
for (int j = 0; j < 3; j++)
objects[j]->set_material(m_ptr);
objects[8]->set_material(m_ptr);
}
// ------------------------------------------------------------------------------ set_water_air_material
// [3]: meniscus torus 1
// [4]: meniscus torus 2
// [5]: water-air boundary
void
FishBowlFlatBottom::set_water_air_material(Material* m_ptr) {
objects[3]->set_material(m_ptr);
objects[4]->set_material(m_ptr);
objects[5]->set_material(m_ptr);
}
// ------------------------------------------------------------------------------ set_water_glass_material
// [6]: water-glass boundary
// [6]: water-glass boundary bottom
void
FishBowlFlatBottom::set_water_glass_material(Material* m_ptr) {
objects[6]->set_material(m_ptr);
objects[7]->set_material(m_ptr);
}
4,测试图形
4.1,平底鱼缸
相关测试代码:
#include "World.h"
#include "Ambient.h"
#include "Pinhole.h"
#include "Directional.h"
#include "RayCast.h"
#include "Matte.h"
#include "Phong.h"
#include "Plane.h"
#include "OpenCylinder.h"
#include "MultiJittered.h"
#include "AmbientOccluder.h"
#include "Emissive.h"
#include "AreaLight.h"
#include "AreaLighting.h"
#include "Instance.h"
#include "Grid.h"
#include "PointLight.h"
#include "Reflective.h"
#include "GlossyReflector.h"
#include "Whitted.h"
#include "PathTrace.h"
#include "GlobalTrace.h"
#include "Rectangle.h"
#include "Transparent.h"
#include "Dielectric.h"
#include "FishBowlFlatBottom.h"
#include "OpenCylinderConvex.h"
void
World::build(void) {
int num_samples = 9;
vp.set_hres(600);
vp.set_vres(600);
vp.set_samples(num_samples);
vp.set_max_depth(10);
tracer_ptr = new Whitted(this);
background_color = RGBColor(0.9);
Pinhole* pinhole_ptr = new Pinhole;
pinhole_ptr->set_eye(-0.5, -1.0, 4);
pinhole_ptr->set_lookat(0.0);
pinhole_ptr->set_view_distance(900.0);
pinhole_ptr->compute_uvw();
set_camera(pinhole_ptr);
PointLight* light_ptr1 = new PointLight;
light_ptr1->set_location(40, 25, 10);
light_ptr1->scale_radiance(2.5);
light_ptr1->set_cast_shadow(false);
add_light(light_ptr1);
Directional* light_ptr2 = new Directional;
light_ptr2->set_direction(-1, 0, 0);
light_ptr2->scale_radiance(2.5);
light_ptr2->set_cast_shadow(false);
add_light(light_ptr2);
// fishbowl
// glass-air interface
float c = 2;
RGBColor glass_color(0.27*c, 0.49*c, 0.42*c);
RGBColor water_color(0.75, 1, 0.75);
Dielectric* glass_ptr = new Dielectric;
glass_ptr->set_ks(0.5);
glass_ptr->set_exp(8000.0);
glass_ptr->set_eta_in(1.50); // glass
glass_ptr->set_eta_out(1.0); // air
glass_ptr->set_cf_in(glass_color);
glass_ptr->set_cf_out(white);
// water-air interface
Dielectric* water_ptr = new Dielectric;
water_ptr->set_ks(0.5);
water_ptr->set_exp(8000);
water_ptr->set_eta_in(1.33); // water
water_ptr->set_eta_out(1.0); // air
water_ptr->set_cf_in(water_color);
water_ptr->set_cf_out(white);
// water-glass interface
Dielectric* dielectric_ptr1 = new Dielectric;
dielectric_ptr1->set_ks(0.5);
dielectric_ptr1->set_exp(8000);
dielectric_ptr1->set_eta_in(1.33); // water
dielectric_ptr1->set_eta_out(1.5); // glass
dielectric_ptr1->set_cf_in(water_color);
dielectric_ptr1->set_cf_out(glass_color);
// physical bowl parameters (also the defaults)
double inner_radius = 1.0;
double glass_thickness = 0.1;
double water_depth = 1.25;
double meniscus_radius = 0.05;
double opening_angle = 90.0;
double bottom_angle = 90.0;
FishBowlFlatBottom* fishbowl_ptr = new FishBowlFlatBottom( inner_radius,
glass_thickness,
water_depth,
meniscus_radius,
opening_angle,
bottom_angle);
fishbowl_ptr->set_glass_air_material(glass_ptr);
fishbowl_ptr->set_water_air_material(water_ptr);
fishbowl_ptr->set_water_glass_material(dielectric_ptr1);
add_object(fishbowl_ptr);
// goldfish
Phong* phong_ptr1 = new Phong;
phong_ptr1->set_ka(0.4);
phong_ptr1->set_kd(0.8);
phong_ptr1->set_cd(1.0, 0.15, 0.0); // orange
phong_ptr1->set_ks(0.5);
// phong_ptr1->set_cs(1.0, 0.35, 0.0); // orange
phong_ptr1->set_exp(50.0);
// phong_ptr1->set_shadows(false);
// we read the fish file once, and instance it
// const char* file_name = "goldfish_low_res.ply"; // for scene design
char* file_name = ".\\PLYFiles\\goldfish_high_res.ply"; // for production
Grid* grid_ptr = new Grid(new Mesh);
// grid_ptr->read_flat_triangles(file_name);
grid_ptr->read_smooth_triangles(file_name);
grid_ptr->set_material(phong_ptr1);
grid_ptr->setup_cells();
Instance* gold_fish_ptr1 = new Instance(grid_ptr);
gold_fish_ptr1->scale(0.03);
gold_fish_ptr1->rotate_y(-45);
gold_fish_ptr1->translate(0.5, 0.0, 0.0);
add_object(gold_fish_ptr1);
Instance* goldfish_ptr2 = new Instance(grid_ptr);
goldfish_ptr2->scale(0.02);
goldfish_ptr2->rotate_y(90);
goldfish_ptr2->translate(-0.75, 0.0, 0.0);
goldfish_ptr2->rotate_y(-60);
add_object(goldfish_ptr2);
Instance* goldfish_ptr3 = new Instance(grid_ptr);
goldfish_ptr3->scale(0.02);
goldfish_ptr3->rotate_x(20);
goldfish_ptr3->rotate_y(-45);
goldfish_ptr3->translate(-0.1, -0.4, 0.0);
add_object(goldfish_ptr3);
// cylinder under the bowl
Phong* phong_ptr2 = new Phong;
phong_ptr2->set_ka(0.4);
phong_ptr2->set_kd(0.8);
phong_ptr2->set_cd(0.05);
phong_ptr2->set_ks(0.2);
phong_ptr2->set_exp(100.0);
double bottom = -1.2;
double radius = 0.5;
double top = -sqrt(1.1 * 1.1 - radius * radius);
OpenCylinderConvex* cylinder_ptr = new OpenCylinderConvex(bottom, top, radius);
cylinder_ptr->set_material(phong_ptr2);
add_object(cylinder_ptr);
// single air bubble
Dielectric* dielectric_ptr2 = new Dielectric;
dielectric_ptr2->set_eta_in(1.0); // air
dielectric_ptr2->set_eta_out(1.33); // water
dielectric_ptr2->set_cf_in(white);
dielectric_ptr2->set_cf_out(water_color);
Sphere* bubble_ptr = new Sphere(Point3D(0.2, 0.2, 0.2), 0.05);
bubble_ptr->set_material(dielectric_ptr2);
add_object(bubble_ptr);
// streams of air bubbles
set_rand_seed(1000);
double bubble_radius = 0.045;
double yc_bottom = -0.9; // height of bottom bubble center
double yc_top = 0.2; // height of top bubble center
double num_bubbles = 8; // number of bubbles in stream
double spacing = (yc_top - yc_bottom) / num_bubbles; // vertical spacing between bubble centers
double translation_factor = bubble_radius / 2.0;
double min = 0.9; // minimum bubble scaling
double max = 1.1; // maximum bubble scaling
double xc = -0.1; // center x
double zc = 0.3; // center y
// bubble stream 1
Grid* bubble_stream_ptr_1 = new Grid;
for (int j = 0; j <= num_bubbles; j++) {
Instance* bubble_ptr = new Instance(new Sphere);
bubble_ptr->scale( min + rand_float() * (max - min),
min + rand_float() * (max - min),
min + rand_float() * (max - min));
bubble_ptr->scale(bubble_radius);
bubble_ptr->rotate_x(360.0 * rand_float());
bubble_ptr->rotate_y(360.0 * rand_float());
bubble_ptr->rotate_z(360.0 * rand_float());
bubble_ptr->translate( xc + (2.0 * rand_float() - 1.0) * translation_factor,
yc_bottom + j * spacing + (2.0 * rand_float() - 1.0) * translation_factor,
zc + (2.0 * rand_float() - 1.0) * translation_factor);
bubble_ptr->set_material(dielectric_ptr2);
bubble_stream_ptr_1->add_object(bubble_ptr);
}
bubble_stream_ptr_1->setup_cells();
add_object(bubble_stream_ptr_1);
// bubble stream 2
num_bubbles = 7;
xc = 0.075;
zc = 0.1;
Grid* bubble_stream_ptr_2 = new Grid;
for (int j = 0; j <= num_bubbles; j++) {
Instance* bubble_ptr = new Instance(new Sphere);
bubble_ptr->scale( min + rand_float() * (max - min),
min + rand_float() * (max - min),
min + rand_float() * (max - min));
bubble_ptr->scale(bubble_radius);
bubble_ptr->rotate_x(360.0 * rand_float());
bubble_ptr->rotate_y(360.0 * rand_float());
bubble_ptr->rotate_z(360.0 * rand_float());
bubble_ptr->translate( xc + (2.0 * rand_float() - 1.0) * translation_factor,
yc_bottom + j * spacing + (2.0 * rand_float() - 1.0) * translation_factor,
zc + (2.0 * rand_float() - 1.0) * translation_factor);
bubble_ptr->set_material(dielectric_ptr2);
bubble_stream_ptr_2->add_object(bubble_ptr);
}
bubble_stream_ptr_2->setup_cells();
add_object(bubble_stream_ptr_2);
// bubble stream 3
num_bubbles = 9;
xc = -0.15;
zc = -0.3;
Grid* bubble_stream_ptr_3 = new Grid;
for (int j = 0; j <= num_bubbles; j++) {
Instance* bubble_ptr = new Instance(new Sphere);
bubble_ptr->scale( min + rand_float() * (max - min),
min + rand_float() * (max - min),
min + rand_float() * (max - min));
bubble_ptr->scale(bubble_radius);
bubble_ptr->rotate_x(360.0 * rand_float());
bubble_ptr->rotate_y(360.0 * rand_float());
bubble_ptr->rotate_z(360.0 * rand_float());
bubble_ptr->translate( xc + (2.0 * rand_float() - 1.0) * translation_factor,
yc_bottom + j * spacing + (2.0 * rand_float() - 1.0) * translation_factor,
zc + (2.0 * rand_float() - 1.0) * translation_factor);
bubble_ptr->set_material(dielectric_ptr2);
bubble_stream_ptr_3->add_object(bubble_ptr);
}
bubble_stream_ptr_3->setup_cells();
add_object(bubble_stream_ptr_3);
// plane
Phong* phong_ptr3 = new Phong;
phong_ptr3->set_ka(0.4);
phong_ptr3->set_kd(0.8);
phong_ptr3->set_cd(1.0, 0.5, 0.5);
phong_ptr3->set_ks(0.5);
// phong_ptr3->set_cs(1.0, 1.0, 0.0);
phong_ptr3->set_exp(50.0);
Plane* plane_ptr = new Plane(Point3D(0, -1.2, 0), Normal(0, 1, 0));
plane_ptr->set_material(phong_ptr3);
Instance* plane_ptr2 = new Instance(plane_ptr); // to adjust the reflection of the grid lines off the top of the water
plane_ptr2->rotate_y(30);
plane_ptr2->translate(0.25, 0, 0.15);
add_object(plane_ptr2);
}
特别指出“鱼缸中各种金鱼”的相关代码:
输出图形:(耗时1325min,太TM费时啦!!!)
(图中的bottom_angle是90度,明显和下方的圆柱底座不匹配。当时疏忽了这一点。bottom_angle应该设置为50~60之间,会比较合适。)
4.1,圆底鱼缸
其实本人最开始生成的图形是圆底鱼缸。“圆底鱼缸”则不需要考虑bottom_angle了,或者说bottom_angle为0。
下面直接贴出相关代码:FishBowl.h、FishBowl.cpp、BuildShadedObjects.cpp
#ifndef __FISH_BOWL__
#define __FISH_BOWL__
// Copyright (C) Kevin Suffern 2000-2007.
// This C++ code is for non-commercial purposes only.
// This C++ code is licensed under the GNU General Public License Version 2.
// See the file COPYING.txt for the full license.
// This file contains the declaration of the class FishBowl
// This is a spherical bowl with a specified glass thickness
// that contains water
// The bowl is centered on the world origin
#include "Compound.h"
class FishBowl: public Compound {
public:
FishBowl(void);
FishBowl( const double _inner_radius,
const double _glass_thickness,
const double _water_depth,
const double _meniscus_radius,
const double _opening_angle);
FishBowl(const FishBowl& fb);
virtual FishBowl*
clone(void) const;
virtual FishBowl&
operator= (const FishBowl& rhs);
virtual
~FishBowl(void);
void
build_components(void);
void
set_glass_air_material(Material* m_ptr);
void
set_water_air_material(Material* m_ptr);
void
set_water_glass_material(Material* m_ptr);
protected:
double inner_radius; // radius of the inside glass surface
double glass_thickness;
double water_depth; // measured from the bottom of the water-glass boundary
double meniscus_radius;
double opening_angle; // specifies how wide the opening is at the top (alpha in Figure 28.40(a))
};
#endif
----------------------FishBowl.cpp----------------------
// Copyright (C) Kevin Suffern 2000-2007.
// This C++ code is for non-commercial purposes only.
// This C++ code is licensed under the GNU General Public License Version 2.
// See the file COPYING.txt for the full license.
#include "Constants.h"
#include "Disk.h"
#include "SpherePartConvex.h"
#include "SpherePartConcave.h"
#include "TorusPartConvex.h"
#include "TorusPartConcave.h"
#include "Instance.h"
#include "FishBowl.h"
// ------------------------------------------------------------------------------ default constructor
FishBowl::FishBowl(void)
: Compound(),
inner_radius(1.0),
glass_thickness(0.1),
water_depth(1.25),
meniscus_radius(0.05),
opening_angle(90)
{
build_components();
}
// ------------------------------------------------------------------------------ constructor
FishBowl::FishBowl( const double _inner_radius,
const double _glass_thickness,
const double _water_depth,
const double _meniscus_radius,
const double _opening_angle)
: Compound(),
inner_radius(_inner_radius),
glass_thickness(_glass_thickness),
water_depth(_water_depth),
meniscus_radius(_meniscus_radius),
opening_angle(_opening_angle)
{
build_components();
}
// ------------------------------------------------------------------------------ copy constructor
FishBowl::FishBowl(const FishBowl& fb)
: Compound(fb),
inner_radius(fb.inner_radius),
glass_thickness(fb.glass_thickness),
water_depth(fb.water_depth),
meniscus_radius(fb.meniscus_radius),
opening_angle(fb.opening_angle)
{}
// ------------------------------------------------------------------------------ clone
FishBowl*
FishBowl::clone(void) const {
return(new FishBowl(*this));
}
// ------------------------------------------------------------------------------ assignment operator
FishBowl&
FishBowl::operator= (const FishBowl& rhs) {
if (this == &rhs)
return (*this);
Compound::operator=(rhs);
inner_radius = rhs.inner_radius;
glass_thickness = rhs.glass_thickness;
water_depth = rhs.water_depth;
meniscus_radius = rhs.meniscus_radius;
opening_angle = rhs.opening_angle;
return (*this) ;
}
// ------------------------------------------------------------------------------ destructor
FishBowl::~FishBowl(void) {}
// ------------------------------------------------------------------------------ build_components
void
FishBowl::build_components(void) {
double angle_radians = (opening_angle / 2.0) * PI_ON_180; // half the opening angle in radians
// meniscus calculations - required here because they affect the inner surface of the glass-air boundary
// torus tube center coordinates
double h = water_depth - inner_radius;
double yc = h + meniscus_radius;
double xc = sqrt(inner_radius * (inner_radius - 2.0 * meniscus_radius) - h * (h + 2.0 * meniscus_radius));
double beta = atan2(yc, xc) * 180.0 / PI; // in degrees
// outer glass-air boundary
objects.push_back(new SpherePartConvex( Point3D(0.0),
inner_radius + glass_thickness,
0, 360, // azimuth angle range - full circle
opening_angle / 2.0, // minimum polar angle measured from top
180)); // maximum polar angle measured from top
// inner glass-air boundary
// the inner surface of the glass only goes down to the top of the meniscus
objects.push_back(new SpherePartConcave(Point3D(0.0),
inner_radius,
0, 360, // azimuth angle - full circle
opening_angle / 2.0, // mimimum polar angle measured from top
90 - beta)); // maximum polar angle measured from top
// round rim - need an instance for this as it's a half torus
double theta_min = opening_angle / 2.0; // measured counter-clockwise from (x, z) plane
double theta_max = theta_min + 180; // measured counter-clockwise from (x, z) plane
Instance* rim_ptr = new Instance (new TorusPartConvex(
(inner_radius + glass_thickness / 2.0) * sin(angle_radians), // a
glass_thickness / 2.0, // b
0, 360,
theta_min,
theta_max));
rim_ptr->translate(0, (inner_radius + glass_thickness / 2.0) * cos(angle_radians), 0);
objects.push_back(rim_ptr);
// meniscus - if water_depth > 1, we need two part tori
Instance* torus_ptr1 = new Instance (new TorusPartConcave( xc,
meniscus_radius,
0, 360,
270, 360));
torus_ptr1->translate(0, yc, 0);
objects.push_back(torus_ptr1);
Instance* torus_ptr2 = new Instance (new TorusPartConcave( xc,
meniscus_radius,
0, 360,
0, beta));
torus_ptr2->translate(0, yc, 0);
objects.push_back(torus_ptr2);
// water-air boundary
objects.push_back(new Disk( Point3D(0, h, 0),
xc,
Normal(0, 1, 0))); // the disk just touches the bottom of the meniscus
// water-glass boundary
objects.push_back(new SpherePartConvex( Point3D(0),
inner_radius,
0, 360,
90 - beta, // mimimum polar angle measured from top
180)); // maximum polar angle measured from top
}
// ------------------------------------------------------------------------------ set_glass_air_material
// [0]: outer glass-air boundary
// [1]: inner glass-air boundary
// [2]: rim
void
FishBowl::set_glass_air_material(Material* m_ptr) {
for (int j = 0; j < 3; j++)
objects[j]->set_material(m_ptr);
}
// ------------------------------------------------------------------------------ set_water_air_material
// [3]: meniscus torus 1
// [4]: meniscus torus 2
// [5]: water-air boundary
void
FishBowl::set_water_air_material(Material* m_ptr) {
objects[3]->set_material(m_ptr);
objects[4]->set_material(m_ptr);
objects[5]->set_material(m_ptr);
}
// ------------------------------------------------------------------------------ set_water_glass_material
// [6]: water-glass boundary
void
FishBowl::set_water_glass_material(Material* m_ptr) {
objects[6]->set_material(m_ptr);
}
----------------------BuildShadedObjects.cpp----------------------
#include "World.h"
#include "Ambient.h"
#include "Pinhole.h"
#include "Directional.h"
#include "RayCast.h"
#include "Matte.h"
#include "Phong.h"
#include "Plane.h"
#include "OpenCylinder.h"
#include "MultiJittered.h"
#include "AmbientOccluder.h"
#include "Emissive.h"
#include "AreaLight.h"
#include "AreaLighting.h"
#include "Instance.h"
#include "Grid.h"
#include "PointLight.h"
#include "Reflective.h"
#include "GlossyReflector.h"
#include "Whitted.h"
#include "PathTrace.h"
#include "GlobalTrace.h"
#include "Rectangle.h"
#include "Transparent.h"
#include "Dielectric.h"
#include "FishBowl.h"
void
World::build(void) {
int num_samples = 9;
vp.set_hres(600);
vp.set_vres(600);
vp.set_samples(num_samples);
vp.set_max_depth(10);
tracer_ptr = new Whitted(this);
background_color = RGBColor(0.75);
Pinhole* pinhole_ptr = new Pinhole;
pinhole_ptr->set_eye(4.5, 6, 4);
pinhole_ptr->set_lookat(0.0);
pinhole_ptr->set_view_distance(1800.0);
pinhole_ptr->compute_uvw();
set_camera(pinhole_ptr);
PointLight* light_ptr1 = new PointLight;
light_ptr1->set_location(40, 25, -10);
light_ptr1->scale_radiance(5.0);
light_ptr1->set_cast_shadow(false);
add_light(light_ptr1);
// fishbowl
// glass-air interface
float c = 2;
RGBColor glass_color(0.27*c, 0.49*c, 0.42*c);
RGBColor water_color(0.75, 1, 0.75);
Dielectric* glass_ptr = new Dielectric;
glass_ptr->set_ks(0.5);
glass_ptr->set_exp(8000.0);
glass_ptr->set_eta_in(1.50); // glass
glass_ptr->set_eta_out(1.0); // air
glass_ptr->set_cf_in(glass_color);
glass_ptr->set_cf_out(white);
// water-air interface
Dielectric* water_ptr = new Dielectric;
water_ptr->set_ks(0.5);
water_ptr->set_exp(8000);
water_ptr->set_eta_in(1.33); // water
water_ptr->set_eta_out(1.0); // air
water_ptr->set_cf_in(water_color);
water_ptr->set_cf_out(white);
// water-glass interface
Dielectric* dielectric_ptr = new Dielectric;
dielectric_ptr->set_ks(0.5);
dielectric_ptr->set_exp(8000);
dielectric_ptr->set_eta_in(1.33); // water
dielectric_ptr->set_eta_out(1.5); // glass
dielectric_ptr->set_cf_in(water_color);
dielectric_ptr->set_cf_out(glass_color);
// physical bowl parameters (also the defaults)
double inner_radius = 1.0;
double glass_thickness = 0.1;
double water_depth = 1.25;
double meniscus_radius = 0.05;
double opening_angle = 90.0;
FishBowl* fishbowl_ptr = new FishBowl( inner_radius,
glass_thickness,
water_depth,
meniscus_radius,
opening_angle);
fishbowl_ptr->set_glass_air_material(glass_ptr);
fishbowl_ptr->set_water_air_material(water_ptr);
fishbowl_ptr->set_water_glass_material(dielectric_ptr);
add_object(fishbowl_ptr);
// goldfish
Phong* phong_ptr = new Phong;
phong_ptr->set_ka(0.4);
phong_ptr->set_kd(0.8);
phong_ptr->set_cd(1.0, 0.15, 0.0); // orange
phong_ptr->set_ks(0.5);
// phong_ptr->set_cs(1.0, 0.35, 0.0); // orange
phong_ptr->set_exp(50.0);
// phong_ptr->set_shadows(false);
// const char* file_name = "goldfish_low_res.ply"; // for scene design
char* file_name = ".\\PLYFiles\\goldfish_high_res.ply"; // for production
Grid* grid_ptr = new Grid(new Mesh);
// grid_ptr->read_flat_triangles(file_name);
grid_ptr->read_smooth_triangles(file_name);
grid_ptr->set_material(phong_ptr);
grid_ptr->setup_cells();
Instance* gold_fish_ptr = new Instance(grid_ptr);
gold_fish_ptr->scale(0.03);
gold_fish_ptr->translate(0.5, 0.0, 0.0);
add_object(gold_fish_ptr);
// plane
Phong* phong_ptr2 = new Phong;
phong_ptr2->set_ka(0.4);
phong_ptr2->set_kd(0.8);
phong_ptr2->set_cd(0.8, 0.8, 0.8);
phong_ptr2->set_ks(0.5);
// phong_ptr2->set_cs(1.0, 1.0, 0.0);
phong_ptr2->set_exp(50.0);
Plane* plane_ptr = new Plane(Point3D(0, -1.51, 0), Normal(0, 1, 0));
plane_ptr->set_material(phong_ptr2);
add_object(plane_ptr);
}
输出图形:(耗时38554s。也非常费时,但相比“平底鱼缸”那个图形已经快很多了)
5,其他说明
完整代码下载链接:(参考下方评论)
参考书籍:
[1]. Kevin Suffern, Ray Tracing from theGround Up, A K PetersLtd, 2007.