Billboard矩阵

    这几天在研究Impostor,按照传统的方法可以做出来不错的效果,采用GamaStura的方法很快就可以做出来不错的效果,但是因为要扩展一下,在原先的质量上提高,而且用Instance来画,这样只需要一个quad mesh,别的信息都放在Instance Buffer上。因此需要有个Billboard矩阵,也就是说需要将一个quad mesh转换到世界坐标系。

    关于Billboard矩阵如何推导,NeHe和FlipCode都有相应的文章来讲解,NeHe讲解的更透彻一点。这虽然算是个很古老的技术,但是用到的时候还是要费一些脑细胞来挣扎一下,顺便就记录下来吧,正好可以理清思路。

http://www.flipcode.com/archives/Billboarding-Excerpt_From_iReal-Time_Renderingi_2E.shtml

http://nehe.gamedev.net/article/billboarding_how_to/18011/

    计算BillBoard矩阵之前我们需要知道CameraPos和BillBoard的中心位置CenterPos,然后可以计算出来LookAt向量look=normalize(CameraPos-CenterPos);然后我们需要计算Billboard矩阵的right向量,计算right需要Billboard矩阵的up向量,这时候我们还没有办法知道up向量,但是有一点事确定的Billboard的up位于look和主Camera的up构成平面上,而right是垂直于这个平面的,所以right=look x 主camera up;然后就可以计算出来Billboard矩阵的up。

Billboard矩阵_第1张图片

    有了look,up,right在加上Billboar的中心位置p就可以构建出Billboard矩阵了



    上面推导的方法适合于所有类型的Billboard,按x,y,z轴或者任意轴旋转的Billboard矩阵都可以按照上面的思路来推导。NeHe的教程中也给出了各种不同类型的Billboard矩阵的计算方法。


//*****************************************************************************
// This only needs to be done once for all the particles, because the view
// matrix does not change any between them.  If you were to modify the view
// matrix at all, you would need to recalculate the camera pos and up vector.
//*****************************************************************************
void GetCameraPosAndUp(Vertex3f &camPos, Vector3f &camUp)
{
	Matrix44f		view;
	glGetFloatv(GL_MODELVIEW_MATRIX, view.matrix);

	// The values in the view matrix for the camera are the negative values of
	// the camera. This is because of the way gluLookAt works; I'm don't fully
	// understand why gluLookAt does what it does, but I know doing this works:)
	// I know that gluLookAt creates a the look vector as (eye - center), the
	// resulting direction vector is a vector from center to eye (the oposite
	// of what are view direction really is).
	camPos	= Vertex3f(-view.matrix[12], -view.matrix[13], -view.matrix[14]);
	camUp	= Vector3f(view.matrix[1], view.matrix[5], view.matrix[9]);

	// zero the translation in the matrix, so we can use the matrix to transform
	// camera postion to world coordinates using the view matrix
	view.matrix[12] = view.matrix[13] = view.matrix[14] = 0;

	// the view matrix is how to get to the gluLookAt pos from what we gave as
	// input for the camera position, so to go the other way we need to reverse
	// the rotation.  Transposing the matrix will do this.
	view.TransposeRotation();

	// get the correct position of the camera in world space
	camPos	= view * camPos;
}

//*****************************************************************************
// Create the billboard matrix: a rotation matrix created from an arbitrary set
// of axis.  Store those axis values in the first 3 columns of the matrix.  Col
// 1 is the X axis, col 2 is the Y axis, and col 3 is the Z axis.  We are
// rotating right into X, up into Y, and look into Z.  The rotation matrix
// created from the rows will translate the arbitrary axis set to the global
// axis set.  Lastly, OpenGl stores the matrices by columns, so enter the data
// into the array columns first.
//*****************************************************************************
void CreateBillboardMatrix(Matrix44f &bbmat, const Vector3f &right, const Vector3f &up, const Vector3f &look, const Vertex3f &pos)
{
	bbmat.matrix[0] = right.x;
	bbmat.matrix[1] = right.y;
	bbmat.matrix[2] = right.z;
	bbmat.matrix[3] = 0;
	bbmat.matrix[4] = up.x;
	bbmat.matrix[5] = up.y;
	bbmat.matrix[6] = up.z;
	bbmat.matrix[7] = 0;
	bbmat.matrix[8] = look.x;
	bbmat.matrix[9] = look.y;
	bbmat.matrix[10] = look.z;
	bbmat.matrix[11] = 0;
	// Add the translation in as well.
	bbmat.matrix[12] = pos.x;
	bbmat.matrix[13] = pos.y;
	bbmat.matrix[14] = pos.z;
	bbmat.matrix[15] = 1;
}

//*****************************************************************************
//*****************************************************************************
void BillboardPoint(const Vertex3f &pos, const Vertex3f &camPos, const Vector3f &camUp)
{	// create the look vector: pos -> camPos
	Vector3f	look	= camPos - pos;
	look.Normalize();
	// right hand rule cross products
	Vector3f	right	= camUp.Cross(look);
	Vector3f	up		= look.Cross(right);

	Matrix44f	bbmat;
	CreateBillboardMatrix(bbmat, right, up, look, pos);

	// apply the billboard
	glMultMatrixf(bbmat.matrix);
};

//*****************************************************************************
//*****************************************************************************
void BillboardAxisX(const Vertex3f &pos, const Vertex3f &camPos)
{	// create the look vector: pos -> camPos
	Vector3f	look	= camPos - pos;
	// we are billboarding along the X axis - zero the look value for x
	look.x = 0;
	look.Normalize();
	// right hand rule cross products - the up vector is the +x Axis
	Vector3f	up		= Vector3f(1,0,0);
	Vector3f	right	= up.Cross(look);

	Matrix44f	bbmat;
	CreateBillboardMatrix(bbmat, right, up, look, pos);

	// apply the billboard
	glMultMatrixf(bbmat.matrix);
};

//*****************************************************************************
//*****************************************************************************
void BillboardAxisY(const Vertex3f &pos, const Vertex3f &camPos)
{	// create the look vector: pos -> camPos
	Vector3f	look	= camPos - pos;
	// we are billboarding along the Y axis - zero the look value for y
	look.y = 0;
	look.Normalize();
	// right hand rule cross products - the up vector is the +y Axis
	Vector3f	up		= Vector3f(0,1,0);
	Vector3f	right	= up.Cross(look);

	Matrix44f	bbmat;
	CreateBillboardMatrix(bbmat, right, up, look, pos);

	// apply the billboard
	glMultMatrixf(bbmat.matrix);
};

//*****************************************************************************
//*****************************************************************************
void BillboardAxisZ(const Vertex3f &pos, const Vertex3f &camPos)
{	// create the look vector: pos -> camPos
	Vector3f	look	= camPos - pos;
	// we are billboarding along the Z axis - zero the look value for z
	look.z = 0;
	look.Normalize();
	// right hand rule cross products - the up vector is the +z Axis
	Vector3f	up		= Vector3f(0,0,1);
	Vector3f	right	= up.Cross(look);

	Matrix44f	bbmat;
	CreateBillboardMatrix(bbmat, right, up, look, pos);

	// apply the billboard
	glMultMatrixf(bbmat.matrix);
};

//*****************************************************************************
//*****************************************************************************
void BillboardAxis(const Vertex3f &pos, const Vector3f &axis, const Vertex3f &camPos)
{	// create the look vector: pos -> camPos
	Vector3f	look	= camPos - pos;
	look.Normalize();

	// billboard about the direction vector
	Vector3f	up		= axis;
	Vector3f	right	= up.Cross(look);

	// watch out when the look vector is almost equal to the up vector the right
	// vector gets close to zeroed, normalize it
	right.Normalize();

	// the billboard won't actually face the direction of the look vector we
	// created earlier, that was just used as a tempory vector to create the
	// right vector so we could calculate the correct look vector from that.
	look = right.Cross(up);

	Matrix44f	bbmat;
	CreateBillboardMatrix(bbmat, right, up, look, pos);

	// apply the billboard
	glMultMatrixf(bbmat.matrix);
};


你可能感兴趣的:(General)