Example #1
0
bool Primitive::Intersect( Ray& ray, Intersection& isect )
{
	Ray localRay(ray);

	localRay.o = Vec3d(worldToLocal * Vec4d(ray.o, 1.0));
	localRay.d = Vec3d(worldToLocal * Vec4d(ray.d, 0.0));

	if (!shape->Intersect(localRay, isect))
	{
		return false;
	}

	ray.minT = localRay.minT;
	ray.maxT = localRay.maxT;

	if (localToWorld != Mat4d(1.0))
	{
		isect.p = Vec3d(localToWorld * Vec4d(isect.p, 1.0));
		isect.sn = Math::Normalize(normalLocalToWorld * isect.sn);
		isect.gn = Math::Normalize(normalLocalToWorld * isect.gn);
		isect.ss = Math::Normalize(Vec3d(localToWorld * Vec4d(isect.ss, 0.0)));
		isect.st = Math::Normalize(Vec3d(localToWorld * Vec4d(isect.st, 0.0)));
	}

	return true;
}
void BSplineCurveEvaluator::evaluateCurve(
	const std::vector<Point>& controlPoints,
	std::vector<Point>& evaluatedPoints,
	const float& animationLength,
	const bool& beWrap) const
{
	evaluatedPoints.clear();

	if (!beWrap) 
	{
		evaluatedPoints.push_back(Point(0, controlPoints.front().y));
		evaluatedPoints.push_back(Point(animationLength, controlPoints.back().y));
	}
	
	// a hack to make the endpoints controllable
	vector<Point> controlPointsCopy;
	if (beWrap) 
	{
		Point start_p1 = Point((controlPoints.end() - 2)->x - animationLength,
			(controlPoints.end() - 2)->y);
		Point start_p2 = Point((controlPoints.end() - 1)->x - animationLength,
			(controlPoints.end() - 1)->y);
		Point end_p1 = Point((controlPoints.begin())->x + animationLength,
			(controlPoints.begin())->y);
		Point end_p2 = Point((controlPoints.begin() + 1)->x + animationLength,
			(controlPoints.begin() + 1)->y);
		controlPointsCopy.push_back(start_p1);
		controlPointsCopy.push_back(start_p2);
		controlPointsCopy.insert(controlPointsCopy.end(), controlPoints.begin(), controlPoints.end());
		controlPointsCopy.push_back(end_p1);
		controlPointsCopy.push_back(end_p2);
	}
	else
	{
		controlPointsCopy.push_back(controlPoints.front());
		controlPointsCopy.push_back(controlPoints.front());
		controlPointsCopy.insert(controlPointsCopy.end(), controlPoints.begin(), controlPoints.end());
		controlPointsCopy.push_back(controlPoints.back());
		controlPointsCopy.push_back(controlPoints.back());
	}
	const Mat4d basis = Mat4d(
		1, 4, 1, 0,
		0, 4, 2, 0,
		0, 2, 4, 0,
		0, 1, 4, 1) / 6.0;

	BezierCurveEvaluator bezierCurveEvaluator;
	for (size_t cnt = 0; cnt + 3 < controlPointsCopy.size(); ++cnt)
	{
		Vec4d param_x(controlPointsCopy[cnt].x, controlPointsCopy[cnt + 1].x,
			controlPointsCopy[cnt + 2].x, controlPointsCopy[cnt + 3].x);
		Vec4d param_y(controlPointsCopy[cnt].y, controlPointsCopy[cnt + 1].y,
			controlPointsCopy[cnt + 2].y, controlPointsCopy[cnt + 3].y);
		param_x = basis * param_x;
		param_y = basis * param_y;
		vector<Point> param_control;
		for (int i = 0; i < 4; ++i)
		{
			param_control.push_back(Point(param_x[i], param_y[i]));
		}
		vector<Point> param_evaluated;
		bezierCurveEvaluator.evaluateCurve(param_control, param_evaluated, animationLength, false);
		evaluatedPoints.insert(evaluatedPoints.end(), param_evaluated.begin(), param_evaluated.end()-2);
	}

}
HINATA_NAMESPACE_BEGIN

CornellBoxScene::CornellBoxScene( double aspect )
{
    // Fixed scene definition (Cornell Box)

    // Right
    primitives.push_back(
        std::make_shared<Primitive>(
            Mat4d::Identity(),
            std::make_shared<Sphere>(1e5, Vec3d(1e5+1, 0, 0)),
            std::make_shared<DiffuseBSDF>(Vec3d(0.75, 0.25, 0.25))));

    // Left
    primitives.push_back(
        std::make_shared<Primitive>(
            Mat4d::Identity(),
            std::make_shared<Sphere>(1e5, Vec3d(-1e5-1, 0, 0)),
            std::make_shared<DiffuseBSDF>(Vec3d(0.25, 0.25, 0.75))));

    // Top
    primitives.push_back(
        std::make_shared<Primitive>(
            Mat4d::Identity(),
            std::make_shared<Sphere>(1e5, Vec3d(0, 1e5+1, 0)),
            std::make_shared<DiffuseBSDF>(Vec3d(0.75))));

    // Bottom
    primitives.push_back(
        std::make_shared<Primitive>(
            Mat4d::Identity(),
            std::make_shared<Sphere>(1e5, Vec3d(0, -1e5-1, 0)),
            std::make_shared<DiffuseBSDF>(Vec3d(0.75))));

    // Back
    primitives.push_back(
        std::make_shared<Primitive>(
            Mat4d::Identity(),
            std::make_shared<Sphere>(1e5, Vec3d(0, 0, 1e5+7)),
            std::make_shared<DiffuseBSDF>(Vec3d())));

    // Front
    primitives.push_back(
        std::make_shared<Primitive>(
            Mat4d::Identity(),
            std::make_shared<Sphere>(1e5, Vec3d(0, 0, -1e5-1)),
            std::make_shared<DiffuseBSDF>(Vec3d(0.75))));
    //std::make_shared<GlossyConductorBSDF>(Vec3d(1), Vec3d(0.1), Vec3d(1.67), 0.08)));

    // Light
    auto light = std::make_shared<AreaLight>(Vec3d(30));

    //auto lp =
    //	std::make_shared<Primitive>(
    //		Mat4d(1.0),
    //		std::make_shared<Sphere>(0.15, Vec3d(0.5, 0.7, 0)),
    //		//std::make_shared<Sphere>(0.15, Vec3d(0, 0.85, 0)),
    //		std::make_shared<DiffuseBSDF>(Vec3d(0.75)),
    //		light);

    auto mesh = std::make_shared<TriangleMesh>();
    mesh->positions.push_back(Vec3d( 0.2, 0.9,  0.2));
    mesh->positions.push_back(Vec3d(-0.2, 0.9,  0.2));
    mesh->positions.push_back(Vec3d(-0.2, 0.9, -0.2));
    mesh->positions.push_back(Vec3d( 0.2, 0.9, -0.2));
    mesh->normals.push_back(Vec3d(0, -1, 0));
    mesh->normals.push_back(Vec3d(0, -1, 0));
    mesh->normals.push_back(Vec3d(0, -1, 0));
    mesh->normals.push_back(Vec3d(0, -1, 0));

    auto lp1 =
        std::make_shared<Primitive>(
            Math::Rotate(30.0, Vec3d(0, 0, 1)),
            std::make_shared<Triangle>(mesh, 0, 1, 3),
            std::make_shared<DiffuseBSDF>(Vec3d(0.75)),
            //std::make_shared<DiffuseBSDF>(Vec3d()),
            light);

    primitives.push_back(lp1);
    light->AddPrimitive(lp1);

    auto lp2 =
        std::make_shared<Primitive>(
            Math::Rotate(30.0, Vec3d(0, 0, 1)),
            std::make_shared<Triangle>(mesh, 1, 2, 3),
            std::make_shared<DiffuseBSDF>(Vec3d(0.75)),
            //std::make_shared<DiffuseBSDF>(Vec3d()),
            light);

    primitives.push_back(lp2);
    light->AddPrimitive(lp2);

    light->Initialize();
    lights.push_back(light);

    // Ball 1
    primitives.push_back(
        std::make_shared<Primitive>(
            Mat4d(1.0),
            std::make_shared<Sphere>(0.35, Vec3d(0.45, -0.65, 0.5)),
            //std::make_shared<DiffuseBSDF>(Vec3d(0.75))));
            std::make_shared<DielecticBSDF>(Vec3d(1), Vec3d(1), 1, 1.544)));

    // Ball 2
    primitives.push_back(
        std::make_shared<Primitive>(
            Mat4d(1.0),
            std::make_shared<Sphere>(0.35, Vec3d(-0.45, -0.65, -0.3)),
            std::make_shared<DiffuseBSDF>(Vec3d(0.75))));
    //std::make_shared<GlossyConductorBSDF>(Vec3d(1), Vec3d(0.1), Vec3d(1.67), 0.05)));

    // Camera
    camera = std::make_shared<PerspectiveCamera>(
                 Math::LookAt(Vec3d(0, 0, 6.99), Vec3d(0, 0, 0), Vec3d(0, 1, 0)),
                 Math::Perspective(20.0, aspect, 0.1, 1000.0));
}
Example #4
0
	PoolTilesExample(void)
	 : make_plane(
		Vec3f(),
		Vec3f(7.0f, 0.0f, 0.0f),
		Vec3f(0.0f, 0.0f,-7.0f),
		48,
		48
	), plane_instr(make_plane.Instructions())
	 , plane_indices(make_plane.Indices())
	 , make_shape()
	 , shape_instr(make_shape.Instructions())
	 , shape_indices(make_shape.Indices())
	 , plane_vs(ObjectDesc("Plane vertex"))
	 , shape_vs(ObjectDesc("Shape vertex"))
	 , plane_fs(ObjectDesc("Plane fragment"))
	 , shape_fs(ObjectDesc("Shape fragment"))
	 , plane_camera_matrix(plane_prog, "CameraMatrix")
	 , shape_camera_matrix(shape_prog, "CameraMatrix")
	 , plane_camera_position(plane_prog, "CameraPosition")
	 , width(800)
	 , height(600)
	 , refl_tex_side(width > height ? height : width)
	 , tile_tex_side(64)
	{
		gl.RequireAtLeast(LimitQuery::MaxCombinedTextureImageUnits, 5);

		plane_vs.Source(
			"#version 140\n"
			"uniform vec3 LightPosition;"
			"uniform vec3 CameraPosition;"
			"uniform mat4 ProjectionMatrix, CameraMatrix, ModelMatrix;"
			"in vec4 Position;"
			"in vec2 TexCoord;"
			"out vec3 vertLightDir;"
			"out vec3 vertViewDir;"
			"out vec4 vertReflTexCoord;"
			"out vec2 vertTileTexCoord;"
			"void main(void)"
			"{"
			"	gl_Position = ModelMatrix* Position;"
			"	vertLightDir = normalize(LightPosition - gl_Position.xyz);"
			"	vertViewDir = normalize(CameraPosition - gl_Position.xyz);"
			"	gl_Position = ProjectionMatrix * CameraMatrix * gl_Position;"
			"	vertReflTexCoord = gl_Position;"
			"	vertTileTexCoord = TexCoord;"
			"}"
		);
		plane_vs.Compile();

		plane_fs.Source(
			"#version 140\n"
			"uniform sampler2D RandTex, PictTex, TileTex, NormTex;"
			"uniform sampler2D ReflectTex;"
			"uniform uint TileCount;"
			"uniform float Aspect;"
			"in vec3 vertLightDir;"
			"in vec3 vertViewDir;"
			"in vec4 vertReflTexCoord;"
			"in vec2 vertTileTexCoord;"
			"out vec4 fragColor;"
			"void main(void)"
			"{"
			"	vec3 Normal = texture("
			"		NormTex, "
			"		vertTileTexCoord * TileCount"
			"	).rgb;"
			"	vec3 LightRefl = reflect("
			"		-normalize(vertLightDir),"
			"		normalize(Normal)"
			"	);"
			"	float Diffuse = max(dot("
			"		Normal, "
			"		vertLightDir"
			"	), 0.0);"
			"	float Specular = max(dot("
			"		LightRefl,"
			"		vertViewDir"
			"	), 0.0);"
			"	float PlasterLight = 0.3 + max(Diffuse, 0.0);"
			"	float TileLight = 0.3 + pow(Diffuse, 2.0)*0.9 + pow(Specular, 4.0)*2.5;"
			"	vec2 ReflCoord = vertReflTexCoord.xy;"
			"	ReflCoord /= vertReflTexCoord.w;"
			"	ReflCoord *= 0.5;"
			"	ReflCoord += vec2(Aspect*0.5, 0.5);"
			"	ReflCoord += vec2(Normal.x, Normal.z)*0.5;"
			"	vec3 ReflColor = texture("
			"		ReflectTex, "
			"		ReflCoord"
			"	).rgb;"
			"	vec3 TileProps = texture("
			"		TileTex, "
			"		vertTileTexCoord * TileCount"
			"	).rgb;"
			"	float Pict = texture(PictTex, vertTileTexCoord).r;"
			"	float Rand = texture(RandTex, vertTileTexCoord).r;"
			"	float LightVsDark = "
			"		mix( 0.1, 0.9, Pict)+"
			"		mix(-0.1, 0.1, Rand);"
			"	vec3 TileColor = mix("
			"		vec3(0.1, 0.1, 0.5),"
			"		vec3(0.4, 0.4, 0.9),"
			"		LightVsDark "
			"	);"
			"	vec3 PlasterColor = vec3(0.9, 0.9, 0.9);"
			"	fragColor = vec4("
			"		mix("
			"			PlasterColor * PlasterLight,"
			"			TileColor * TileLight, "
			"			TileProps.b"
			"		) +"
			"		ReflColor * TileProps.g * 0.6,"
			"		1.0"
			"	);"
			"}"
		);
		plane_fs.Compile();

		plane_prog.AttachShader(plane_vs);
		plane_prog.AttachShader(plane_fs);
		plane_prog.Link();
		plane_prog.Use();

		Vec3f lightPos(3.0f, 2.5f, 2.0f);
		Uniform<Vec3f>(plane_prog, "LightPosition").Set(lightPos);
		Uniform<GLuint>(plane_prog, "TileCount").Set(tile_tex_side);
		Uniform<Mat4f>(plane_prog, "ModelMatrix").Set(
			ModelMatrixf::Translation(0.0f, -0.5f, 0.0f)
		);

		std::vector<GLfloat> data;
		GLuint n_per_vertex;

		n_per_vertex = make_plane.Positions(data);
		plane_verts.Data(data);
		DSAVertexArrayAttribEXT(plane, plane_prog, "Position")
			.Setup<GLfloat>(plane_verts, n_per_vertex)
			.Enable();

		n_per_vertex = make_plane.TexCoordinates(data);
		plane_texcoords.Data(data);
		DSAVertexArrayAttribEXT(plane, plane_prog, "TexCoord")
			.Setup<GLfloat>(plane_texcoords, n_per_vertex)
			.Enable();

		//
		rand_tex.target = Texture::Target::_2D;
		rand_tex.Image2D(
			images::RandomRedUByte(
				tile_tex_side,
				tile_tex_side
			)
		);
		rand_tex.Filter(TextureFilter::Nearest);
		rand_tex.Wrap(TextureWrap::Repeat);
		Texture::Active(0);
		UniformSampler(plane_prog, "RandTex").Set(0);
		rand_tex.Bind();

		//
		pict_tex.target = Texture::Target::_2D;
		pict_tex.Image2D(images::LoadTexture("pool_pictogram"));
		pict_tex.Filter(TextureFilter::Linear);
		pict_tex.Wrap(TextureWrap::Repeat);
		Texture::Active(1);
		UniformSampler(plane_prog, "PictTex").Set(1);
		pict_tex.Bind();
		//
		auto tile_image = images::LoadTexture("small_tile");
		//
		tile_tex.target = Texture::Target::_2D;
		tile_tex.Image2D(tile_image);
		tile_tex.MinFilter(TextureMinFilter::LinearMipmapLinear);
		tile_tex.MagFilter(TextureMagFilter::Linear);
		tile_tex.Wrap(TextureWrap::Repeat);
		tile_tex.GenerateMipmap();
		Texture::Active(2);
		UniformSampler(plane_prog, "TileTex").Set(2);
		tile_tex.Bind();
		//
		norm_tex.target =  Texture::Target::_2D;
		norm_tex.Image2D(
			images::TransformComponents<GLfloat, 3>(
				images::NormalMap(tile_image),
				Mat4d(
					Vec4d(1.0, 0.0, 0.0, 0.0),
					Vec4d(0.0, 0.0, 1.0, 0.0),
					Vec4d(0.0,-1.0, 0.0, 0.0),
					Vec4d(0.0, 0.0, 0.0, 1.0)
				)
			)
		);
		norm_tex.MinFilter(TextureMinFilter::LinearMipmapLinear);
		norm_tex.MagFilter(TextureMagFilter::Linear);
		norm_tex.Wrap(TextureWrap::Repeat);
		norm_tex.GenerateMipmap();
		Texture::Active(3);
		UniformSampler(plane_prog, "NormTex").Set(3);
		norm_tex.Bind();
		//
		reflect_tex.target = Texture::Target::_2D;
		reflect_tex.Image2D(
			0,
			PixelDataInternalFormat::RGB,
			refl_tex_side, refl_tex_side,
			0,
			PixelDataFormat::RGB,
			PixelDataType::UnsignedByte,
			nullptr
		);
		reflect_tex.Filter(TextureFilter::Linear);
		reflect_tex.Wrap(TextureWrap::ClampToEdge);
		Texture::Active(4);
		UniformSampler(plane_prog, "ReflectTex").Set(4);
		reflect_tex.Bind();

		rbo.Storage(
			PixelDataInternalFormat::DepthComponent,
			refl_tex_side,
			refl_tex_side
		);
		fbo.target = Framebuffer::Target::Draw;
		fbo.AttachTexture(
			FramebufferAttachment::Color,
			reflect_tex,
			0
		);
		fbo.AttachRenderbuffer(
			FramebufferAttachment::Depth,
			rbo
		);

		shape_vs.Source(
			"#version 140\n"
			"uniform vec3 LightPosition;"
			"uniform mat4 ProjectionMatrix, ModelMatrix, CameraMatrix;"
			"in vec4 Position;"
			"in vec3 Normal;"
			"out vec3 vertNormal;"
			"out vec3 vertLightDir;"
			"out vec3 vertLightRefl;"
			"out vec3 vertViewDir;"
			"out vec3 vertViewRefl;"
			"out vec3 vertColor;"
			"void main(void)"
			"{"
			"	gl_Position = "
			"		ModelMatrix *"
			"		Position;"
			"	vertLightDir = LightPosition - gl_Position.xyz;"
			"	vertNormal = mat3(ModelMatrix)*Normal;"
			"	vertLightRefl = reflect("
			"		-normalize(vertLightDir),"
			"		normalize(vertNormal)"
			"	);"
			"	vertViewDir = ("
			"		vec4(0.0, 0.0, 1.0, 1.0)*"
			"		CameraMatrix"
			"	).xyz;"
			"	vertViewRefl = reflect("
			"		-normalize(vertViewDir),"
			"		normalize(vertNormal)"
			"	);"
			"	vertColor = vec3(0.3, 0.3, 0.7);"
			"	gl_Position = "
			"		ProjectionMatrix *"
			"		CameraMatrix *"
			"		gl_Position;"
			"}"
		);
		shape_vs.Compile();

		shape_fs.Source(
			"#version 140\n"
			"uniform sampler2D PictTex, TileTex;"
			"uniform uint TileCount;"
			"in vec3 vertNormal;"
			"in vec3 vertLightDir;"
			"in vec3 vertLightRefl;"
			"in vec3 vertViewDir;"
			"in vec3 vertViewRefl;"
			"in vec3 vertColor;"
			"out vec4 fragColor;"

			"void main(void)"
			"{"
			"	float LtDist = length(vertLightDir);"
			"	float Diffuse = dot("
			"		normalize(vertNormal), "
			"		normalize(vertLightDir)"
			"	) / LtDist;"
			"	float Specular = dot("
			"		normalize(vertLightRefl),"
			"		normalize(vertViewDir)"
			"	);"
			"	vec3 LightColor = vec3(1.0, 1.0, 1.0);"
			"	vec2 ReflTexCoord = -vec2("
			"		vertViewRefl.x,"
			"		vertViewRefl.z "
			"	);"
			"	ReflTexCoord *= 0.25;"
			"	ReflTexCoord += vec2(0.5, 0.5);"
			"	float Pict = texture(PictTex, ReflTexCoord).r;"
			"	float LightVsDark = mix( 0.1, 0.9, Pict);"
			"	vec3 TileColor = mix("
			"		vec3(0.2, 0.2, 0.6),"
			"		vec3(0.5, 0.5, 0.9),"
			"		LightVsDark"
			"	);"
			"	vec3 PlasterColor = vec3(0.7, 0.7, 0.7);"
			"	vec3 FloorColor = mix("
			"		PlasterColor, "
			"		TileColor, "
			"		texture(TileTex, ReflTexCoord*TileCount).b"
			"	);"
			"	vec3 ReflColor = mix("
			"		vec3(0.5, 0.5, 0.4), "
			"		FloorColor, "
			"		pow(max((-vertViewRefl.y-0.5)*2.0, 0.0), 2.0)"
			"	);"
			"	fragColor = vec4("
			"		vertColor * 0.4 + "
			"		ReflColor * 0.3 + "
			"		(LightColor + vertColor)*pow(max(2.5*Diffuse, 0.0), 3) + "
			"		LightColor * pow(max(Specular, 0.0), 64), "
			"		1.0"
			"	);"
			"}"
		);
		shape_fs.Compile();

		shape_prog.AttachShader(shape_vs);
		shape_prog.AttachShader(shape_fs);
		shape_prog.Link();
		shape_prog.Use();

		Uniform<Vec3f>(shape_prog, "LightPosition").Set(lightPos);
		Uniform<Mat4f>(shape_prog, "ModelMatrix").Set(
			ModelMatrixf::Translation(0.0f, 0.6f, 0.0f)
		);
		UniformSampler(shape_prog, "PictTex").Set(0);
		UniformSampler(shape_prog, "TileTex").Set(1);
		Uniform<GLuint>(shape_prog, "TileCount").Set(tile_tex_side);


		n_per_vertex = make_shape.Positions(data);
		shape_verts.Data(data);
		DSAVertexArrayAttribEXT(shape, shape_prog, "Position")
			.Setup<GLfloat>(shape_verts, n_per_vertex)
			.Enable();

		n_per_vertex = make_shape.Normals(data);
		shape_normals.Data(data);
		DSAVertexArrayAttribEXT(shape, shape_prog, "Normal")
			.Setup<GLfloat>(shape_normals, n_per_vertex)
			.Enable();
		//
		gl.ClearColor(0.5f, 0.5f, 0.4f, 0.0f);
		gl.ClearDepth(1.0f);
		gl.Enable(Capability::DepthTest);
	}
void CatmullRomCurveEvaluator::evaluateCurve(const std::vector<Point>& controlPoints,
	std::vector<Point>& evaluatedPoints,
	const float& animationLength,
	const bool& beWrap) const
{
	evaluatedPoints.clear();

	vector<Point> controlPointsCopy;
	if (beWrap)
	{
		Point start_p1 = Point((controlPoints.end() - 2)->x - animationLength,
			(controlPoints.end() - 2)->y);
		Point start_p2 = Point((controlPoints.end() - 1)->x - animationLength,
			(controlPoints.end() - 1)->y);
		Point end_p1 = Point((controlPoints.begin())->x + animationLength,
			(controlPoints.begin())->y);
		Point end_p2 = Point((controlPoints.begin() + 1)->x + animationLength,
			(controlPoints.begin() + 1)->y);
		controlPointsCopy.push_back(start_p1);
		controlPointsCopy.push_back(start_p2);
		controlPointsCopy.insert(controlPointsCopy.end(), controlPoints.begin(), controlPoints.end());
		controlPointsCopy.push_back(end_p1);
		controlPointsCopy.push_back(end_p2);
	}
	else
	{
		controlPointsCopy.push_back(Point(0, controlPoints.front().y));
		controlPointsCopy.insert(controlPointsCopy.end(), controlPoints.begin(), controlPoints.end());
		controlPointsCopy.push_back(Point(animationLength, controlPoints.back().y));
	}

	const Mat4d basis = Mat4d(
		-1, 3, -3, 1,
		2, -5, 4, -1,
		-1, 0, 1, 0,
		0, 2, 0, 0) / 2.0;

	for (size_t cnt = 0; cnt + 3 < controlPointsCopy.size(); ++cnt)
	{
		const Vec4d param_x(controlPointsCopy[cnt].x, controlPointsCopy[cnt + 1].x,
			controlPointsCopy[cnt + 2].x, controlPointsCopy[cnt + 3].x);
		const Vec4d param_y(controlPointsCopy[cnt].y, controlPointsCopy[cnt + 1].y,
			controlPointsCopy[cnt + 2].y, controlPointsCopy[cnt + 3].y);
		
		for (int i = 0; i < SEGMENT; ++i)
		{
			const double t = i / (double) SEGMENT;
			const Vec4d param_time(t*t*t, t*t, t, 1); 
			Point eval_point(param_time * basis * param_x, param_time*basis*param_y);
			// avoid wave curve occurs
			if (evaluatedPoints.empty() || eval_point.x > evaluatedPoints.back().x)
			{
				evaluatedPoints.push_back(eval_point);
			}
		}
	}

	if (!beWrap)
	{
		// avoid slope interpolate at the end
		if (controlPoints.back().x > evaluatedPoints.back().x)
		{
			evaluatedPoints.push_back(controlPoints.back());
		}
		evaluatedPoints.push_back(Point(0, controlPoints.front().y));
		evaluatedPoints.push_back(Point(animationLength, controlPoints.back().y));
	}
}