Q91:真实地模拟透明材质(Realistic Transparency)(4)——Fish Bowl

198 篇文章 12 订阅
195 篇文章 27 订阅


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,平底鱼缸

相关测试代码:

----------------------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 "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

----------------------FishBowl.h----------------------

#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.

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值