PBRT_V2 总结记录 <7> Shape

Shape 类


// Shape Declarations
class Shape : public ReferenceCounted {
public:
	// Shape Interface
	Shape(const Transform *o2w, const Transform *w2o, bool ro);
	virtual ~Shape();
	virtual BBox ObjectBound() const = 0;
	virtual BBox WorldBound() const;
	virtual bool CanIntersect() const;
	virtual void Refine(vector<Reference<Shape> > &refined) const;
	virtual bool Intersect(const Ray &ray, float *tHit,
		float *rayEpsilon, DifferentialGeometry *dg) const;
	virtual bool IntersectP(const Ray &ray) const;
	virtual void GetShadingGeometry(const Transform &obj2world,
		const DifferentialGeometry &dg,
		DifferentialGeometry *dgShading) const {
		*dgShading = dg;
	}
	virtual float Area() const;
	virtual Point Sample(float u1, float u2, Normal *Ns) const {
		Severe("Unimplemented Shape::Sample() method called");
		return Point();
	}
	virtual float Pdf(const Point &Pshape) const {
		return 1.f / Area();
	}
	virtual Point Sample(const Point &P, float u1, float u2,
		Normal *Ns) const {
		return Sample(u1, u2, Ns);
	}
	virtual float Pdf(const Point &p, const Vector &wi) const;

	// Shape Public Data
	const Transform *ObjectToWorld, *WorldToObject;
	const bool ReverseOrientation, TransformSwapsHandedness;
	const uint32_t shapeId;
	static uint32_t nextshapeId;
};

类的作用:(Shape 类提供原生的几何有关的接口,例如几何物体的表面积,包围盒,和与Ray相交的方法,之后的Primitive 类提供的接口是几何无关的,例如材质)

pbrt hides details about its primitives behind a two-level abstraction. The Shape class
provides access to the raw geometric properties of the primitive, such as its surface
area and bounding box, and provides a ray intersection routine. The Primitive class
provides additional nongeometric information about the primitive, such as its material
properties.

1. 构造函数

Shape::Shape(const Transform *o2w, const Transform *w2o, bool ro)
: ObjectToWorld(o2w), WorldToObject(w2o), ReverseOrientation(ro),
TransformSwapsHandedness(o2w->SwapsHandedness()),
shapeId(nextshapeId++) {
}

注意:(shape 默认是 在 物体坐标系的,所以 ObjectToWorld 就是把 物体坐标变换到世界坐标)

All shapes are defined in object coordinate space; for example, all spheres are defined
in a coordinate system where the center of the sphere is at the origin. In order to place
a sphere at another position in the scene, a transformation that describes the mapping
from object space to world space must be provided. The Shape class stores both this transformation
and its inverse. Shapes also take a Boolean parameter, ReverseOrientation,
that indicates whether their surface normal directions should be reversed from the default.
This capability is useful because the orientation of the surface normal is used to
determine which side of a shape is “outside.” For example, shapes that emit illumination
are emissive only on the side the surface normal lies on. The value of this parameter is set
via the ReverseOrientation statement in pbrt input files.
Shapes also store the result of the Transform::SwapsHandedness() call for their objectto-
world transformation. This value is needed by the DifferentialGeometry constructor
that will be called each time a ray intersection is found, so the Shape constructor computes
it once and stores it.

2. 细化

(如果 CanIntersect 返回true,那么表示这个shape是可以直接与Ray进行相交的,不需要实现 Refine ,如果 CanIntersect 返回false,表示这个Shape不能直接与Ray进行相交,那么就需要实现 Refine ,用Refine  来细分可以与 Ray相交的 新的Shape出来)

bool Shape::CanIntersect() const {
return true;
}

作用:(并不是所有的shape 都可以直接与Ray进行相交的,例如一些复杂的模型,这些模型首先需要细化为一些三角形,这些三角形才可以与Ray进行相交操作,所以 CanIntersect 就是用来标记这个Shape是否可以与Ray进行相交)

Not every shape needs to be capable of determining whether a ray intersects it. For
example, a complex surface might first be tessellated(细化) into triangles, which can then be
intersected directly. Another possibility is a shape that is a placeholder for a large amount
of geometry stored on disk.We could store just the filename of the geometry file and the
bounding box of the geometry in memory, and read the geometry in from disk only if a
ray pierces the bounding box.
The default implementation of the Shape::CanIntersect() function indicates that a
shape can compute ray intersections, so only shapes that are nonintersectable need to
override this method.

void Shape::Refine(vector<Reference<Shape> > &refined) const {
Severe("Unimplemented Shape::Refine() method called");
}

作用:(如果这个Shape不可以直接与Ray进行相交的话,那么就必须提供 Refine 方法 来细分新的Shape出来和Ray相交。)

If the shape cannot be intersected directly, it must provide a Shape::Refine() method
that splits the shape into a group of new shapes, some of which may be intersectable
and some of which may need further refinement.
The default implementation of the
Shape::Refine() method issues an error message; thus, shapes that are intersectable
(which is the common case) do not have to provide an empty instance of this method.
pbrt will never call Shape::Refine() if Shape::CanIntersect() returns true.

3.相交

bool Shape::Intersect(const Ray &ray, float *tHit, float *rayEpsilon,
DifferentialGeometry *dg) const {
Severe("Unimplemented Shape::Intersect() method called");
return false;
}

bool Shape::IntersectP(const Ray &ray) const {
Severe("Unimplemented Shape::IntersectP() method called");
return false;
}

作用:

(Shape::Intersect() 主要的目的就是为了 计算一个 DifferentialGeometry ,这个DifferentialGeometry 包含了 相交点的很多几何信息,例如位置,UV,法线,偏导数dpdu... 

Shape::IntersectP() 主要的目的就是 为了判断是否与 Ray 相交,没有计算DifferentialGeometry )

The Shape class provides two intersection routines. The first, Shape::Intersect(), returns
geometric information about a single ray-shape intersection corresponding to the
first intersection, if any, in the [mint, maxt] parametric range along the ray. The other,
Shape::IntersectP(), is a predicate(判断) function that determines whether or not an intersection
occurs, without returning any details about the intersection itself.
Most shape
implementations can provide amore efficient implementation for IntersectP() that can
determine whether an intersection exists without computing all of its details.

There are a few important things to keep in mind when reading (and writing) intersection
routines:


a. The Ray structure contains Ray::mint and Ray::maxt variables that define a ray
segment. Intersection routinesmust ignore any intersections that do not occur along
this segment.

b. If an intersection is found, its parametric distance along the ray should be stored
in the pointer tHit that is passed into the intersection routine. If there are multiple
intersections along the ray, the closest one should be reported.


c. If an intersection is found, the value pointed to by the rayEpsilon parameter must
be initialized with a value that describes the maximum numeric error in the intersection
calculation. This parameter is discussed further in Section 3.1.4.

(如果Ray与 一个Suface A相交的话,正常情况下,这个相交点 应该会在 Surface A 上,但是由于 浮点数存在偏差,那么在计算的时候,这个相交点可能会有所偏差,可能在Surface A 的下面一点点,如果再次在这个相交点发出射线的话,那么新的射线就有可能与 Surface A 相交了,这个并不是我们想要的结果,所以就引入了 rayEpsilon ,假如新的Ray是从这个 相交点 作为 原点射出的话,那么这条Ray的Min 默认为 这个 rayEpsilon ,也就是默认假设偏移了 rayEpsilon ,这样可以防止这条新的Ray不与自己的Surface相交)


d. Information about an intersection is stored in the DifferentialGeometry structure,
which completely captures the local geometric properties of a surface. This
class is used heavily throughout pbrt, and it serves to cleanly isolate the geometric
portion of the ray tracer from the shading and illumination portions.

The DifferentialGeometry class was defined in Section 2.10.1


e.The rays passed into intersection routines are in world space, so shapes are responsible
for transforming them to object space if needed for intersection tests. The
differential geometry returned should be in
world space

(Ray传入 Intersect 或者 IntersectP 之前,都是世界坐标的,那么在传入之后,首先会把Ray 转换成 shape的局部空间中,再计算对应的相交点pHit,uv,dpdu等,计算完这些信息之后,会构造一个DifferentialGeometry,把这些信息传进去DifferentialGeometry中,但是,传进入之前,还要把这些信息变换到世界空间中, 如: const Transform &o2w = *ObjectToWorld;
*dg = DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv), o2w(dndu), o2w(dndv), u, v, this); 参考Spere的Intersect

所以 DifferentialGeometry 保存的信息是世界空间)

4. Shape::GetShadingGeometry()

作用:(对于某一些类型的shape,通过DifferentialGeometry 可以得到更加平滑,更加准确的数据, 例如Triangle,在Intersect中计算得到的DifferentialGeometry的dpdu,dpdv, 其实就是自动计算的,但是,有时候Triangle 有可能自身提供了法线(dpdu)和切线(dpdv)的数据, 那么GetShadingGeometry 就是 抛弃了自动计算的dpdu,dpdv,利用重心坐标插值提供的法线和切线数据,重新生成 更加合适的 法线(dpdu),切线(dpdv)数据,参考 Triangle:GetShadingGeometry )

Some shapes (notably triangle meshes) support the idea of having two types of differential
geometry at a point on the surface: the true geometry, which accurately reflects
the local properties of the surface, and the shading geometry, which may have normals
and tangents that are different than those in the true differential geometry. For triangle
meshes, the user can provide normal vectors and primary tangents at the vertices of the
mesh that are interpolated to give normals and tangents at points across the faces of triangles.
Shading geometry with interpolated normals can make otherwise faceted triangle
meshes appear to be more smooth than they geometrically are.


The Shape::GetShadingGeometry() method returns the shading geometry corresponding
to the DifferentialGeometry returned by the Shape::Intersect() routine. By default,
the shading geometry matches the true geometry, so the default implementation
just copies the true geometry. One subtlety is that an object-to-world transformation is
passed to this routine; if the routine needs to transform data from object space to world

space to compute the shading geometry, it must use this transformation rather than the
Shape::ObjectToWorld transformation.

猜你喜欢

转载自blog.csdn.net/aa20274270/article/details/82938841