PBRT_V2 总结记录 <21> CameraSample 和 Sample

CameraSample 类

struct CameraSample {
	float imageX, imageY;
	float lensU, lensV;
	float time;
};

类的作用:

(这个类代表的就是采样点,传入采样点给Camera ,会根据采样点生成 Ray,传入采样点给 Integrators,会执行光照计算

CameraSample 代表的只是作为生成射线的采样点)

The Sample structure is used by Samplers to store a single sample. After one or more
Samples is initialized by a call to the Sampler’s GetMoreSamples() method, the Sampler
RendererTask::Run() method passes each of the Samples to the camera and integrators,
which read values from it to construct the camera ray and perform lighting calculations

Sample inherits from the CameraSample structure; the CameraSample represents just the
sample values that are needed for generating camera rays
. This separation allows us to
just pass a CameraSample to the Camera::GenerateRay() method, not exposing all of the
details of the rest of the Sample structure to Cameras.

Sample 类


struct Sample : public CameraSample {
	// Sample Public Methods
	Sample(Sampler *sampler, SurfaceIntegrator *surf, VolumeIntegrator *vol,
		const Scene *scene);

	uint32_t Add1D(uint32_t num) {
		n1D.push_back(num);
		return n1D.size() - 1;
	}

	uint32_t Add2D(uint32_t num) {
		n2D.push_back(num);
		return n2D.size() - 1;
	}

	~Sample() {
		if (oneD != NULL) {
			FreeAligned(oneD[0]);
			FreeAligned(oneD);
		}
	}

	Sample *Duplicate(int count) const;

	vector<uint32_t> n1D, n2D;
	
	float **oneD, **twoD;
private:
	
	void AllocateSampleMemory();
	Sample() { oneD = twoD = NULL; }
};

类的作用:

(不同的integrators,需要的采样点的数据可能不一样,有些integrators需要的采样点的数据不止CameraSample 里面包含的,采样点里面还需要额外其他的采样点数据,所以,integrators 有一个机会去 请求额外的采样数据,请求的信息会保存到 Sample 里,当Sample 传入到 Sampler 中,Sampler就会根据请求数据,去生成对应的采样数据)

(Sample 和 CameraSample 的区别就是,Sample 里面还会保存一些另外的)

Depending on the details of the light transport algorithm being used, different integrators
may have different sampling needs beyond the camera sample values.
For example,
the WhittedIntegrator doesn’t do any random sampling, so it doesn’t need any additional
sample values beyond the ones to generate the camera ray. The DirectLighting

Integrator uses values from the Sampler to randomly choose a light source to sample
illumination from, as well as to randomly choose positions on area light sources. Therefore,
the integrators are given an opportunity to request additional sample values in
various quantities(不同数量)
. Information about these requirements is stored in the Sample object.
When it is later passed to the particular Sampler implementation, it is the Sampler’s responsibility
to generate all of the requested types of samples.

1. 构造函数

Sample::Sample(Sampler *sampler, SurfaceIntegrator *surf,
               VolumeIntegrator *vol, const Scene *scene) {

	// 
    if (surf) surf->RequestSamples(sampler, this, scene);
    if (vol)  vol->RequestSamples(sampler, this, scene);
    AllocateSampleMemory();
}

作用:

(Sample 构造函数 调用 Integrator:RequestSamples 方法去,  看看这个Integrator 额外需要有什么样的 采样点数据,Integrators 可以请求 额外的 多组 1D和2D 数据, 例如,一个场景有两个Area Light, Integrator 追踪 4条Ray 到第一个光源,追踪8条Ray到第二个光源,那么Integrator需要请求 2组 2D数据,一组有4个2D采样数据,另一组有8个2D采样数据,另外一个例子,如果Integrator 想要在多个光源中随机选择一个光源,那么就需要请求 1组1D 数据,这组数据只有一个采样数据,用来确定到底选择那一个光源

Integrator:RequestSamples 方法中,调用 Sample:AddID 和 Sample:Add2D 来请求 数据 )

The Sample constructor calls the Integrator::RequestSamples() methods of the surface
and volume integrators to find out what samples they will need.
The integrators can ask
for multiple one-dimensional and/or two-dimensional sampling patterns, each with an
arbitrary number of entries. For example, in a scene with two area light sources, where
the integrator traces four shadow rays to the first source and eight to the second, the
integrator would ask for two 2D sample patterns for each image sample, with four and
eight samples each. A 2D pattern is required because two dimensions are needed to
parameterize the surface of a light. Similarly, if the integrator wanted to randomly select
a single light source out of(由于) many, it could request a 1D sample with a single value for this
purpose and use its float value to randomly choose a light.

The integrators’ implementations of the Integrator::RequestSamples() method in turn
call the Sample::Add1D() and Sample::Add2D() methods, which request another sample
sequence with a given number of sample values. After they are done calling these methods,
the Sample constructor can continue, allocating storage for the requested sample
values.

2.  

uint32_t Add1D(uint32_t num) 和 uint32_t Add2D(uint32_t num)

作用:

(调用 Add1D(uint32_t num) 一次, 就是请求一组1D采样数据, 这组数据有num个)

The implementations of the Sample::Add1D() and Sample::Add2D() methods record the
number of samples asked for in an array and return an index that the integrator can later
use to access the desired sample values in the Sample.

3.  整理Sample思路

void Sample::AllocateSampleMemory()


void Sample::AllocateSampleMemory() {
    // Allocate storage for sample pointers
    int nPtrs = n1D.size() + n2D.size();
    if (!nPtrs) {
        oneD = twoD = NULL;
        return;
    }
    oneD = AllocAligned<float *>(nPtrs);
    twoD = oneD + n1D.size();

    // Compute total number of sample values needed
    int totSamples = 0;
    for (uint32_t i = 0; i < n1D.size(); ++i)
        totSamples += n1D[i];
    for (uint32_t i = 0; i < n2D.size(); ++i)
        totSamples += 2 * n2D[i];

    // Allocate storage for sample values
    float *mem = AllocAligned<float>(totSamples);
    for (uint32_t i = 0; i < n1D.size(); ++i) {
        oneD[i] = mem;
        mem += n1D[i];
    }
    for (uint32_t i = 0; i < n2D.size(); ++i) {
        twoD[i] = mem;
        mem += 2 * n2D[i];
    }
}
uint32_t Add1D(uint32_t num) {
		n1D.push_back(num);
		return n1D.size() - 1;
}
uint32_t Add2D(uint32_t num) {
		n2D.push_back(num);
		return n2D.size() - 1;
}
// n1D,n2D 记录个数
vector<uint32_t> n1D, n2D;
// oneD, twoD 记录值
float **oneD, **twoD;

细节:

a. n1D,n2D ,

n1D 表示有 n1D.size() 组一维数据,每一组有 n1D[index] 个float,n2D 表示有 n2D.size() 组二维数据,每一组有 n2D[index] 个2*float

b. Integrator:RequestSamples 方法中,调用 Sample:AddID 和 Sample:Add2D,  其实就是为 n1D,n2D 添加元素。

假如 调用了 AddID(10),那么就是 n1D.push_back(10), 那么意思就是,现在 额外需要 1组 10个 float ,

假如 调用了 Add2D( 10),那么就是 n2D.push_back(20), 那么意思就是,现在 额外需要  1组 10 *2 个 float。

(每一组数据,就是其实一个Float 数组)

AddID, Add2D 返回的 就是第几个 数组,就是数组的索引

c. oneD, twoD

分析 AllocateSampleMemory的代码, 其实不难理解 oneD, twoD ,

oneD: ,oneD[i] 第i个 float数组,oneD[i][j] 第i个 float数组的 第 j 个float 。

twoD : twoD[i] 第i个 float 数组,(twoD[i][0], twoD[i][1] ), 就是可以理解为 第 i 个 float 数组的 第0 个 2D数据,

d. 当分配好内存之后,Sample 会传入到Sampler中,Sampler就会填充 oneD,twoD 中的数据。

猜你喜欢

转载自blog.csdn.net/aa20274270/article/details/83180377
今日推荐