球状マップをキューブマップに変換するコード

ためしにコードを貼ってみる。


球状マップをCubeMapに変換するプログラム。
変数とか標準のものから名前が変わっているが予想はつくかと思う。
バイリニアフィルタとかかけとくといい感じ。
キューブマップを直接描くよりか、
球状マップを描いて変換するほうが扱いやすいように感じた。

	void ConvertToCubeMapFromSphere_inner(
			PBitmap sbmp, Long width,
			PBitmap dbmp,
			TVec3F v00, TVec3F v01, TVec3F v10)
	{
		dbmp->SetBitmapStatus(width, width, 32);

		Byte * sbt = (Byte *)sbmp->Lock();
		Long slsz = sbmp->GetScanlineSize();
		DWord * slp;
		Float sw = (Float)sbmp->GetWidth() - 1.0f;
		Float sh = (Float)sbmp->GetHeight() - 1.0f;
		Long swi = sbmp->GetWidth();
		Long shi = sbmp->GetHeight();

		Byte * dbt = (Byte *)dbmp->Lock();
		Long dlsz = dbmp->GetScanlineSize();
		DWord * dlp;

		Float u, v;
		Float du, dv;
		TVec3F p;

		Float theta, phi;
		Float iwidth = 1.0f / width;

		/*
		du = 1.0f / (width + 1);
		dv = 1.0f / (width + 1);
		u = du * 0.5f;
		v = dv * 0.5f;
		*/

		du = 1.0f / width;
		dv = 1.0f / width;
		u = 0.0f;
		v = 0.0f;

		Long i, j;

		Long px00, py00;
		Long tx, ty;
		Float whx, why, whx1, why1;
		Float sr, sg, sb, sa;

		for(i = 0 ; i < width ; i++)
		{
			for(j = 0 ; j < width ; j++)
			{
				p = v00 + (v01 - v00) * (u + j * du)
					+ (v10 - v00) * (v + i * dv);

				p.Normalize();

				if(p.x != 0.0f || p.z != 0.0f)
				{
					theta = DycAtan2(p.z, p.x);
				}
				else
				{
					theta = 0.0f;
				}
					
				if(p.y >= 1.0f) p.y = 1.0f;
				if(p.y <= -1.0f) p.y = -1.0f;
				phi = DycAsin(p.y);

				theta += FloatPI;
				phi += FloatPI * 0.5f;

				theta = theta * sw / (2.0f * FloatPI);
				phi = phi * sh / (1.0f * FloatPI);

				px00 = (Long)theta;
				py00 = (Long)phi;

				why = phi - py00;
				whx = theta - px00;

				why1 = 1.0f - why;
				whx1 = 1.0f - whx;

				sa = 0.0f;
				sr = 0.0f;
				sg = 0.0f;
				sb = 0.0f;

				//
				slp = (DWord *)(sbt + slsz * (Long)(phi) + (Long)(theta) * 4);

				sa += (((*slp) >> 24) & 0x000000ff) * whx1 * why1;
				sr += (((*slp) >> 16) & 0x000000ff) * whx1 * why1;
				sg += (((*slp) >> 8) & 0x000000ff) * whx1 * why1;
				sb += (((*slp)) & 0x000000ff) * whx1 * why1;

				//
				tx = (Long)(theta + 1);
				tx %= swi;
				slp = (DWord *)(sbt + slsz * (Long)(phi) + tx * 4);

				sa += (((*slp) >> 24) & 0x000000ff) * whx * why1;
				sr += (((*slp) >> 16) & 0x000000ff) * whx * why1;
				sg += (((*slp) >> 8) & 0x000000ff) * whx * why1;
				sb += (((*slp)) & 0x000000ff) * whx * why1;

				//
				ty = (Long)(phi + 1);
				ty %= shi;
				slp = (DWord *)(sbt + slsz * ty + (Long)(theta) * 4);

				sa += (((*slp) >> 24) & 0x000000ff) * whx1 * why;
				sr += (((*slp) >> 16) & 0x000000ff) * whx1 * why;
				sg += (((*slp) >> 8) & 0x000000ff) * whx1 * why;
				sb += (((*slp)) & 0x000000ff) * whx1 * why;

				//
				tx = (Long)(theta + 1);
				tx %= swi;
				ty = (Long)(phi + 1);
				ty %= shi;
				slp = (DWord *)(sbt + slsz * ty + tx * 4);

				sa += (((*slp) >> 24) & 0x000000ff) * whx * why;
				sr += (((*slp) >> 16) & 0x000000ff) * whx * why;
				sg += (((*slp) >> 8) & 0x000000ff) * whx * why;
				sb += (((*slp)) & 0x000000ff) * whx * why;



				dlp = (DWord *)(dbt + dlsz * i + j * 4);

				*dlp = ((DWord)(sa + 0.5f)) << 24 |
					((DWord)(sr + 0.5f)) << 16 |
					((DWord)(sg + 0.5f)) << 8 |
					((DWord)(sb + 0.5f)) ;

			}
		}

		sbmp->UnLock();
		dbmp->UnLock();
	}

	Bool ConvertToCubeMapFromSphere(PBitmap sbmp, 
				Long width,
				PBitmap bmpXP, PBitmap bmpXM, 
				PBitmap bmpYP, PBitmap bmpYM, 
				PBitmap bmpZP, PBitmap bmpZM)
	{
		ConvertToCubeMapFromSphere_inner(
			sbmp, width,
			bmpXP,
			TVec3F(1.0f, 1.0f, 1.0f), 
			TVec3F(1.0f, 1.0f, -1.0f), 
			TVec3F(1.0f, -1.0f, 1.0f));

		ConvertToCubeMapFromSphere_inner(
			sbmp, width,
			bmpXM,
			TVec3F(-1.0f, 1.0f, -1.0f), 
			TVec3F(-1.0f, 1.0f, 1.0f), 
			TVec3F(-1.0f, -1.0f, -1.0f));


		ConvertToCubeMapFromSphere_inner(
			sbmp, width,
			bmpYP,
			TVec3F(-1.0f, 1.0f, -1.0f), 
			TVec3F(1.0f, 1.0f, -1.0f), 
			TVec3F(-1.0f, 1.0f, 1.0f));

		ConvertToCubeMapFromSphere_inner(
			sbmp, width,
			bmpYM,
			TVec3F(-1.0f, -1.0f, 1.0f), 
			TVec3F(1.0f, -1.0f, 1.0f), 
			TVec3F(-1.0f, -1.0f, -1.0f));


		ConvertToCubeMapFromSphere_inner(
			sbmp, width,
			bmpZP,
			TVec3F(-1.0f, 1.0f, 1.0f), 
			TVec3F(1.0f, 1.0f, 1.0f), 
			TVec3F(-1.0f, -1.0f, 1.0f));

		ConvertToCubeMapFromSphere_inner(
			sbmp, width,
			bmpZM,
			TVec3F(1.0f, 1.0f, -1.0f), 
			TVec3F(-1.0f, 1.0f, -1.0f), 
			TVec3F(1.0f, -1.0f, -1.0f));


		//bmpXP->SaveWBitmap("../../Media/Test/ToCubeMapFromSphereXP.bmp");
		//bmpXM->SaveWBitmap("../../Media/Test/ToCubeMapFromSphereXM.bmp");
		//bmpYP->SaveWBitmap("../../Media/Test/ToCubeMapFromSphereYP.bmp");
		//bmpYM->SaveWBitmap("../../Media/Test/ToCubeMapFromSphereYM.bmp");
		//bmpZP->SaveWBitmap("../../Media/Test/ToCubeMapFromSphereZP.bmp");
		//bmpZM->SaveWBitmap("../../Media/Test/ToCubeMapFromSphereZM.bmp");

		return True;
	}