예제 #1
0
bool Storm3D_SpotlightShared::setScissorRect(Storm3D_Camera &camera, const VC2I &screenSize, Storm3D_Scene *scene)
{
	D3DXMATRIX light;
	D3DXVECTOR3 lightPosition(position.x, position.y, position.z);
	D3DXVECTOR3 up(0, 1.f, 0);
	D3DXVECTOR3 lookAt = lightPosition;
	lookAt += D3DXVECTOR3(direction.x, direction.y, direction.z);
	D3DXMatrixLookAtLH(&light, &lightPosition, &lookAt, &up);

	// Create frustum vertices

	D3DXVECTOR3 v[5];
	v[0] = D3DXVECTOR3(0, 0, 0);
	v[1] = D3DXVECTOR3(0, 0, 1.f);
	v[2] = D3DXVECTOR3(0, 0, 1.f);
	v[3] = D3DXVECTOR3(0, 0, 1.f);
	v[4] = D3DXVECTOR3(0, 0, 1.f);

	float det = D3DXMatrixDeterminant(&light);
	D3DXMatrixInverse(&light, &det, &light);
	float angle = D3DXToRadian(fov) * .5f;
	for(int i = 0; i <= 4; ++i)
	{
		if(i > 0)
		{
			float z = v[i].z;
			if(i == 1 || i == 2)
			{
				v[i].x = z * sinf(angle);
				v[i].z = z * cosf(angle);
			}
			else
			{
				v[i].x = z * sinf(-angle);
				v[i].z = z * cosf(-angle);
			}

			if(i == 1 || i == 3)
				v[i].y = z * sinf(angle);
			else
				v[i].y = z * sinf(-angle);

			float scale = range / cosf(angle);
			v[i] *= scale;
		}

		D3DXVec3TransformCoord(&v[i], &v[i], &light);
	}

	// Create area

	const Frustum &frustum = camera.getFrustum();
	int minX = screenSize.x;
	int minY = screenSize.y;
	int maxX = 0;
	int maxY = 0;

	for(int i = 0; i < 6; ++i)
	{
		VC3 v1;
		VC3 v2;
		VC3 v3;

		if(i == 0)
		{
			v1 = toVC3(v[0]);
			v2 = toVC3(v[1]);
			v3 = toVC3(v[2]);
		}
		else if(i == 1)
		{
			v1 = toVC3(v[0]);
			v2 = toVC3(v[2]);
			v3 = toVC3(v[4]);
		}
		else if(i == 2)
		{
			v1 = toVC3(v[0]);
			v2 = toVC3(v[3]);
			v3 = toVC3(v[4]);
		}
		else if(i == 3)
		{
			v1 = toVC3(v[0]);
			v2 = toVC3(v[1]);
			v3 = toVC3(v[3]);
		}
		else if(i == 4)
		{
			v1 = toVC3(v[1]);
			v2 = toVC3(v[2]);
			v3 = toVC3(v[3]);
		}
		else if(i == 5)
		{
			v1 = toVC3(v[4]);
			v2 = toVC3(v[2]);
			v3 = toVC3(v[3]);
		}

		const ClipPolygon &clipPolygon = clipTriangleToFrustum(v1, v2, v3, frustum);
		for(int j = 0; j < clipPolygon.vertexAmount; ++j)
		{
			VC3 result;
			float rhw = 0.f;
			float real_z = 0.f;
			camera.GetTransformedToScreen(clipPolygon.vertices[j], result, rhw, real_z);

			int x = int(result.x * screenSize.x);
			int y = int(result.y * screenSize.y);
			//if(x < -1 || x > screenSize.x)
			//	continue;
			//if(y < -1 || x > screenSize.y)
			//	continue;

			x = max(x, 0);
			y = max(y, 0);
			x = min(x, screenSize.x - 1);
			y = min(y, screenSize.y - 1);

			maxX = max(x, maxX);
			maxY = max(y, maxY);
			minX = min(x, minX);
			minY = min(y, minY);

			/*
			// Visualize clipped polygons
			if(scene)
			{
				VC3 p1 = clipPolygon.vertices[j];
				VC3 p2 = clipPolygon.vertices[(j + 1) % clipPolygon.vertexAmount];


				for(int k = 0; k < 5; ++k)
				{
					const VC3 &planeNormal = frustum.planeNormals[k];
					PLANE plane;

					if(k == 0)
						plane.MakeFromNormalAndPosition(planeNormal, frustum.position + planeNormal);
					else
						plane.MakeFromNormalAndPosition(planeNormal, frustum.position);
	
					float d1 = plane.GetPointRange(p1);
					float d2 = plane.GetPointRange(p2);

					if(d1 < .25f)
						p1 += planeNormal * (.25f - d1);
					if(d2 < .25f)
						p2 += planeNormal * (.25f - d2);
				}

				scene->AddLine(p1, p2, COL(1.f, 1.f, 1.f));
			}
			*/
		}
	}

	RECT rc;
	bool visible = false;

	if(maxX > minX && maxY > minY)
	{
		visible = true;
		rc.left = minX;
		rc.top = minY;
		rc.right = maxX;
		rc.bottom = maxY;
	}
	else
	{
		visible = false;
		rc.left = 0;
		rc.top = 0;
		rc.right = 1;
		rc.bottom = 1;
	}
/*
	// Visualize scissor area
	if(scene && visible)
	{
		static DWORD foo = GetTickCount();
		int dif = (GetTickCount() - foo) % 2000;
		if(dif < 1000)
			scene->Render2D_Picture(0, VC2(float(minX), float(minY)), VC2(float(maxX - minX), float(maxY - minY)), 0.5f, 0.f, 0, 0, 0, 0, false);
	}
*/
	device.SetScissorRect(&rc);
	device.SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);

	return visible;
}
bool Storm3D_SpotlightShared::setScissorRect(Storm3D_Camera &camera, const VC2I &screenSize)
{
	D3DXMATRIX light;
	D3DXVECTOR3 lightPosition(position.x, position.y, position.z);
	D3DXVECTOR3 up(0, 1.f, 0);
	D3DXVECTOR3 lookAt = lightPosition;
	lookAt += D3DXVECTOR3(direction.x, direction.y, direction.z);
	D3DXMatrixLookAtLH(&light, &lightPosition, &lookAt, &up);

	D3DXVECTOR3 v[5];
	v[0] = D3DXVECTOR3(0, 0, 0);
	v[1] = D3DXVECTOR3(0, 0, 1.f);
	v[2] = D3DXVECTOR3(0, 0, 1.f);
	v[3] = D3DXVECTOR3(0, 0, 1.f);
	v[4] = D3DXVECTOR3(0, 0, 1.f);

	int minX = screenSize.x;
	int minY = screenSize.y;
	int maxX = 0;
	int maxY = 0;

	float det = D3DXMatrixDeterminant(&light);
	D3DXMatrixInverse(&light, &det, &light);

	float angle = D3DXToRadian(fov) * .5f;
	for(int i = 0; i <= 4; ++i)
	{
		if(i > 0)
		{
			float z = v[i].z;
			if(i == 1 || i == 2)
			{
				v[i].x = z * sinf(angle);
				v[i].z = z * cosf(angle);
			}
			else
			{
				v[i].x = z * sinf(-angle);
				v[i].z = z * cosf(-angle);
			}

			if(i == 1 || i == 3)
				v[i].y = z * sinf(angle);
			else
				v[i].y = z * sinf(-angle);

			float scale = range / cosf(angle);
			v[i] *= scale;
		}

		D3DXVec3TransformCoord(&v[i], &v[i], &light);
	}

	const Frustum &frustum = camera.getFrustum();
	calculateLineToScissor(toVC3(v[0]), toVC3(v[1]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[0]), toVC3(v[2]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[0]), toVC3(v[3]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[0]), toVC3(v[4]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[1]), toVC3(v[2]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[2]), toVC3(v[3]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[3]), toVC3(v[4]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[4]), toVC3(v[1]), frustum, camera, screenSize, minX, minY, maxX, maxY);

	/*
	VC3 cameraPos = camera.GetPosition();
	VC3 cameraPosResult;
	float cameraRhw = 0, cameraRealZ = 0;
	bool cameraVisible = camera.GetTransformedToScreen(cameraPos, cameraPosResult, cameraRhw, cameraRealZ);

	for(i = 0; i <= 4; ++i)
	{
		VC3 source(v[i].x, v[i].y, v[i].z);
		VC3 result;
		float rhw = 0, realZ = 0;
		bool inFront = camera.GetTransformedToScreen(source, result, rhw, realZ);

		// HAX HAX!

		result.x = std::max(0.f, result.x);
		result.y = std::max(0.f, result.y);
		result.x = std::min(1.f, result.x);
		result.y = std::min(1.f, result.y);

		//if(fabsf(rhw) < 0.0001f)
		//	continue;

		bool flip = false;
		if(realZ < cameraRealZ)
			flip = true;

		if(flip)
		{
			result.x = 1.f - result.x;
			result.y = 1.f - result.y;

			//minX = 0;
			//minY = 0;
			//maxX = screenSize.x;
			//maxY = screenSize.y;
		}

		int x = int(result.x * screenSize.x);
		int y = int(result.y * screenSize.y);

		maxX = std::max(x, maxX);
		maxY = std::max(y, maxY);
		minX = std::min(x, minX);
		minY = std::min(y, minY);
	}
	*/

	if(maxX > screenSize.x)
		maxX = screenSize.x;
	if(maxY > screenSize.y)
		maxY = screenSize.y;
	if(minX < 0)
		minX = 0;
	if(minY < 0)
		minY = 0;

	RECT rc;
	rc.left = minX;
	rc.top = minY;
	rc.right = maxX;
	rc.bottom = maxY;

	if(rc.left < rc.right && rc.top < rc.bottom)
	{
		device.SetScissorRect(&rc);
		device.SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
	}
	else
	{
		RECT rc;
		rc.left = 0;
		rc.top = 0;
		rc.right = 1;
		rc.bottom = 1;

		device.SetScissorRect(&rc);
		device.SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);

		return false;
	}

	return true;
}