MQPoint GetPoint(MQDocument doc)
	{
		MQPoint p(0,0,0);
		if(IsEmpty()) return p;
		MQObject obj = doc->GetObject(index_o);
		int indices[5];
		int pcount;
		if(obj == NULL) return p;
		switch(type)
		{
		case SELEL_FACE:
			obj->GetFacePointArray(index_1,indices);
			pcount = obj->GetFacePointCount(index_1);
			for(int i=0;i<pcount;i++) p += obj->GetVertex(indices[i]);
			p /= (float)pcount;
			break;
		case SELEL_LINE:
			obj->GetFacePointArray(index_1,indices);
			pcount = obj->GetFacePointCount(index_1);
			p += obj->GetVertex(indices[index_2]);
			p += obj->GetVertex(indices[(index_2+1)%pcount]);
			p /= 2.0f;
			break;
		case SELEL_VERTEX:
			p = obj->GetVertex(index_1);
			break;
		}
		return p;
	}
예제 #2
0
//---------------------------------------------------------------------------
//  IsFrontFace()
//     Check whether a direction of the face is front side in the scene.
//     面の向きが表かどうか調べる
//---------------------------------------------------------------------------
bool IsFrontFace(MQScene scene, MQObject obj, int face_index)
{
	int num = obj->GetFacePointCount(face_index);
	int vert_index[4];
	obj->GetFacePointArray(face_index, vert_index);

	MQPoint sp[4];
	for (int i=0; i<num; i++){
		sp[i] = scene->Convert3DToScreen(obj->GetVertex(vert_index[i]));

		// 視野より手前にあれば表とみなさない
		if (sp[i].z <= 0) return false;
	}

	// 法線の向きで調べる
	if(num >= 3){
		if((sp[1].x-sp[0].x) * (sp[2].y-sp[1].y) - (sp[1].y-sp[0].y) * (sp[2].x-sp[1].x) < 0) {
			return true;
		}else if(num >= 4){
			if((sp[2].x-sp[0].x) * (sp[3].y-sp[2].y) - (sp[2].y-sp[0].y) * (sp[3].x-sp[2].x) < 0) {
				return true;
			}
		}
	}
	else if (num > 0){
		return true;
	}

	return false;
}
예제 #3
0
MQObjNormal::MQObjNormal(MQObject obj)
{
	int i,j;
	int face_count, vert_count;
	int vi[4];

	face_count = obj->GetFaceCount();
	vert_count = obj->GetVertexCount();

	MQPoint *face_n = new MQPoint[face_count];
	normal = new MQPoint[face_count * 4];

	// 面ごとに法線を計算
	for(i=0; i<face_count; i++)
	{
		int count = obj->GetFacePointCount(i);

		// 三角形と四角形では面に対する法線の計算法は異なる
		switch(count) {
		case 3:
			obj->GetFacePointArray(i, vi);
			face_n[i] = GetNormal(
				obj->GetVertex(vi[0]), obj->GetVertex(vi[1]), obj->GetVertex(vi[2]));
			break;
		case 4:
			obj->GetFacePointArray(i, vi);
			face_n[i] = GetQuadNormal(
				obj->GetVertex(vi[0]), obj->GetVertex(vi[1]), 
				obj->GetVertex(vi[2]), obj->GetVertex(vi[3]));
			break;
		default:
			face_n[i].zero();
			break;
		}
	}

	switch(obj->GetShading()) {
	case MQOBJECT_SHADE_FLAT:
		for(i=0; i<face_count; i++)
		{
			int count = obj->GetFacePointCount(i);
			for(j=0; j<count; j++)
				normal[i*4+j] = face_n[i];
			for(; j<4; j++)
				normal[i*4+j].zero();
		}
		break;

	case MQOBJECT_SHADE_GOURAUD:
		{
			MQGouraudHashTable *vtbl, *cvt;
			MQGouraudHash *hash, *chs;

			// スムージング角度の取得
			float facet = cosf( RAD(obj->GetSmoothAngle()) );

			// ハッシュの初期化
			vtbl = new MQGouraudHashTable[face_count];
			hash = new MQGouraudHash[vert_count + face_count*4];
			int hash_count = vert_count;

			// 面ごとにハッシュに法線ベクトルをセット
			for(i=0,cvt=vtbl; i<face_count; i++,cvt++)
			{
				int count = obj->GetFacePointCount(i);
				if(count < 3) continue;

				obj->GetFacePointArray(i, vi);

				// 面中の各頂点ごとに法線ベクトルをハッシュへ格納してやる
				for(j=0; j<count; j++)
				{
					// 注目する頂点に対してのハッシュを得る
					chs = &hash[vi[j]];

					// ハッシュがまだ空ならそこに情報を格納
					if(chs->count == 0) {
						chs->nv = face_n[i];
						chs->count++;
						(*cvt)[j] = chs;
						continue;
					}

					// ハッシュが空でないなら、既に格納されている法線とのスムージング
					// 角度をチェックする必要がある。
					// アルゴリズムとしては不完全かもしれないが、とりあえず実用程度に
					// はなると思う。

					const MQPoint& pa = face_n[i];
					float da = pa.norm();
					for(; ; chs=chs->next)
					{
						// 2面の角度をチェック
						float c = 0.0f;
						if(da > 0.0f) {
							MQPoint& pb = chs->nv;
							float db = pb.norm();
							if(db > 0.0f)
								c = GetInnerProduct(pa, pb) / sqrtf(da*db);
						}
							
						// スムージング角度以内か?
						if(c >= facet)
						{
							// 注目する頂点に対して面の法線ベクトルをそのまま加算する。
							// 本来なら、注目する頂点に属する面内の2辺の角度によって
							// ベクトルの加算量を変えるべきだが、とりあえずパス。
							chs->nv += pa;
							chs->count++;
							(*cvt)[j] = chs;
							break;
						}

						// スムージングは行われないので、次のハッシュをチェック。
						// 次のハッシュデータがない場合は新規作成。
						if(chs->next == NULL) {
							(*cvt)[j] = chs->next = &hash[hash_count++];
							chs = chs->next;
							chs->nv = pa;
							chs->count = 1;
							chs->next = NULL;
							break;
						}
					}
				}
			}

			// ハッシュ中の法線ベクトルの正規化
			for(i=0,chs=hash; i<hash_count; i++,chs++) {
				if(chs->count > 1)
					chs->nv.normalize();
			}

			// 法線をバッファにセット
			for(i=0,cvt=vtbl; i<face_count; i++,cvt++)
			{
				int count = obj->GetFacePointCount(i);
				if(count < 3) continue;
				for(j=0; j<count; j++)
					normal[i*4+j] = (*cvt)[j]->nv;
				for(; j<4; j++)
					normal[i*4+j].zero();
			}

			// ハッシュを解放
			delete[] vtbl;
			delete[] hash;
		}
		break;
	}

	delete[] face_n;
}