Глава 33. Пересечение полигонов

На всякий случай: мы все еще пытаемся “нарисовать” стык (щель) между пачкой и крышкой, как небольшую normal map приложенную к части существующей текстурированной поверхности. Как-то так:

В предыдущей главе мы смогли пометить и переместить “marked vertices/triangles group“. Теперь нам надо выбрать одну (в этом примере – “box_right”), клонировать ее, развернуть и сдвинуть лицом к нам:

Затем – вырезать из этой поверхности белый прямоугольник.

Мы просканируем треугольники меша (поверхности) и построим пересечения этих треугольников с нашим белым прямоугольником. И треугольник, и прямоугольник – это полигоны. То есть мы говорим о пересечении полигонов.

  • Пересечение красного треугольника с белым прямоугольником – 4-х-вершинный полигон (2 треугольника).
  • Пересечение левого синего треугольника – 5-и-вершинный полигон (3 треугольника).

Новые концепции здесь: Полигоны и Пересечение полигонов. Полигон – это вобщем массив Ребер полигона (Polygon Ribs).

Теперь – реализация:

Windows

1. Запускаем VS, открываем C:\CPP\a997modeler\p_windows\p_windows.sln.


2. Под modeler добавим новый header file PolygonRib.h

Location: C:\CPP\engine\modeler

Код:

#pragma once
#include "Vertex01.h"
#include <vector>

class PolygonRib
{
public:
	int i0;
	int i1;
	float* p0; //rib p0
	float* p1; //rib p1
	//line equation
	float a_slope = 0; //a
	float b_intercept = 0; //b
	bool isVertical = false;
	float x_vertical = 0;
	bool isHorizontal = false;
	//direction to "inner" side
	float xDirIn = 0;
	float yDirIn = 0;
public:
	PolygonRib(std::vector<Vertex01*>* pVxSrc, int idx0);
	static bool matchingLines(PolygonRib* pRibFrame, PolygonRib* pRibSrc);
	static bool parallelLines(PolygonRib* pRibFrame, PolygonRib* pRibSrc);
};


3. Под modeler добавим новый C++ file PolygonRib.cpp

Location: C:\CPP\engine\modeler

Код:

#include "PolygonRib.h"

PolygonRib::PolygonRib(std::vector<Vertex01*>* pVxSrc, int idx0) {
	//2 points
	i0 = idx0;
	p0 = pVxSrc->at(idx0)->aPos;
	int ribsN = pVxSrc->size();
	int idx1 = (idx0 + 1) % ribsN;
	i1 = idx1;
	p1 = pVxSrc->at(idx1)->aPos;
	//3-rd "inner" ref point
	float* p2;
	int idx2 = (idx0 + 2) % ribsN;
	p2 = pVxSrc->at(idx2)->aPos;
	//find line equation
	if (p0[0] == p1[0]) {
		isVertical = true;
		x_vertical = p0[0];
		//"inner" side
		if (p2[0] < x_vertical)
			xDirIn = -1;
		else
			xDirIn = 1;
	}
	else if (p0[1] == p1[1]) {
		isHorizontal = true;
		a_slope = 0;
		b_intercept = p0[1];
		//"inner" side
		if (p2[1] < b_intercept)
			yDirIn = -1;
		else
			yDirIn = 1;
	}
	else {
		a_slope = (p1[1]-p0[1]) / (p1[0] - p0[0]);
		b_intercept = p0[1] - a_slope * p0[0];
		//"inner" side
		float y = a_slope * p2[0] + b_intercept;
		if(p2[1] < y)
			yDirIn = -1;
		else
			yDirIn = 1;
		float x = (p2[1] - b_intercept) / a_slope;
		if (p2[0] < x)
			xDirIn = -1;
		else
			xDirIn = 1;
	}
}
bool PolygonRib::matchingLines(PolygonRib* pRibFrame, PolygonRib* pRibSrc) {
	if (!parallelLines(pRibFrame, pRibSrc))
		return false;
	if (pRibFrame->b_intercept != pRibSrc->b_intercept)
		return false;
	if (pRibFrame->x_vertical != pRibSrc->x_vertical)
		return false;
	return true;
}
bool PolygonRib::parallelLines(PolygonRib* pRibFrame, PolygonRib* pRibSrc) {
	if (pRibFrame->isVertical != pRibSrc->isVertical)
		return false;
	if (pRibFrame->a_slope != pRibSrc->a_slope)
		return false;
	return true;
}


4. Под modeler добавим новый header file Polygon.h

Location: C:\CPP\engine\modeler

Код:

#pragma once
#include "Vertex01.h"
#include "Triangle01.h"
#include "PolygonRib.h"
#include <vector>

class Polygon
{
public:
	std::vector<Vertex01*> vertices;
	std::vector<PolygonRib*> ribs;
	std::vector<Triangle01*> triangles;
	float normal[3] = {0,0,0};
	int ribsN = 0;
	//bounding box
	float bbMin[3] = { 0,0,0 };
	float bbMax[3] = { 0,0,0 };
public:
	virtual ~Polygon() { clearAll(this); };
	static void clearAll(Polygon* pPL);
	static int addVertex(Polygon* pPL, Vertex01* pV);
	static int addVertex(Polygon* pPL, float x, float y, float z);
	static int finalizePolygon(Polygon* pPL);
	static int setTriangle(Polygon* pPL, Triangle01* pT, std::vector<Vertex01*>* pVxSrc);
	static int setRectangle(Polygon* pPL, float w, float h);
	static int xyIntersection(Polygon* pDst, Polygon* pFrame, Polygon* pSrc);
	static int addLinesIntersection(Polygon* pDst, Polygon* pFrame, int ribNframe, Polygon* pSrc, int ribNsrc);

	static bool dotFits(float* p0, PolygonRib* pPR);
	static bool dotFits(float* p0, Polygon* pPL);
	static bool correctSide(float* p0, PolygonRib* pPR);
	static int addVert(Polygon* pDst, float* p0, Vertex01* pV0, Vertex01* pV1);
	static int addVert(Polygon * pDst, float* p0, Polygon * pSrc);
	static int buildTriangles(Polygon* pPL);
};


5. Под modeler добавим новый C++ file Polygon.cpp

Location: C:\CPP\engine\modeler

Код:

#include "Polygon.h"
#include "linmath.h"
#include "utils.h"
#include "platform.h"
#include <algorithm>

extern float radians2degrees;

void Polygon::clearAll(Polygon* pPL) {
	for (int i = pPL->vertices.size() - 1; i >= 0; i--)
		delete pPL->vertices.at(i);
	pPL->vertices.clear();

	for (int i = pPL->ribs.size() - 1; i >= 0; i--)
		delete pPL->ribs.at(i);
	pPL->ribs.clear();

	for (int i = pPL->triangles.size() - 1; i >= 0; i--)
		delete pPL->triangles.at(i);
	pPL->triangles.clear();
}
int Polygon::addVertex(Polygon* pPL, float x, float y, float z) {
	Vertex01* pV = new Vertex01();
	pV->aPos[0] = x;
	pV->aPos[1] = y;
	pV->aPos[2] = z;
	pPL->vertices.push_back(pV);
	return 1;
}
int Polygon::addVertex(Polygon* pPL, Vertex01* pV0) {
	Vertex01* pV = new Vertex01(*pV0);
	pPL->vertices.push_back(pV);
//mylog("====Adding vertexs %f x %f\n",pV->aPos[0], pV->aPos[1]);
	return 1;
}
int Polygon::setTriangle(Polygon* pPL, Triangle01* pT, std::vector<Vertex01*>* pVxSrc) {
	clearAll(pPL);
	for (int i = 0; i < 3; i++) {
		int vN = pT->idx[i];
		Vertex01* pV = pVxSrc->at(vN);
		addVertex(pPL, pV);
	}
	finalizePolygon(pPL);
	return 1;
}
int Polygon::setRectangle(Polygon* pPL, float w, float h) {
	clearAll(pPL);
	w /= 2;
	h /= 2;
	//CCW
	addVertex(pPL, -w,  h, 0); //NW
	addVertex(pPL, -w, -h, 0); //SW
	addVertex(pPL,  w, -h, 0); //SE
	addVertex(pPL,  w,  h, 0); //NE
	finalizePolygon(pPL);
	return 1;
}
int Polygon::finalizePolygon(Polygon* pPL) {
	pPL->ribsN = pPL->vertices.size();
	for (int i = 0; i < pPL->ribsN; i++) {
		PolygonRib* pPR = new PolygonRib(&pPL->vertices,i);
		pPL->ribs.push_back(pPR);
	}
	//calculate polygon's normal
	float v0[3];
	float v2[3];
	for (int i = 0; i < 3; i++) {
		v0[i] = pPL->vertices.at(1)->aPos[i] - pPL->vertices.at(0)->aPos[i];
		v2[i] = pPL->vertices.at(2)->aPos[i] - pPL->vertices.at(0)->aPos[i];
	}
	vec3_mul_cross(pPL->normal, v0, v2);
	vec3_norm(pPL->normal, pPL->normal);
	//bounding box
	Vertex01* pV = pPL->vertices.at(0);
	v3copy(pPL->bbMin, pV->aPos);
	v3copy(pPL->bbMax, pV->aPos);
	for (int vN = pPL->vertices.size() - 1; vN >= 1; vN--) {
		pV = pPL->vertices.at(vN);
		for (int i = 0; i < 3; i++) {
			if (pPL->bbMin[i] > pV->aPos[i])
				pPL->bbMin[i] = pV->aPos[i];
			if (pPL->bbMax[i] < pV->aPos[i])
				pPL->bbMax[i] = pV->aPos[i];
		}
	}
	return 1;
}
int Polygon::addLinesIntersection(Polygon* pDst, Polygon* pFrame, int ribNframe, Polygon* pSrc, int ribNsrc) {
	PolygonRib* pRibFrame = pFrame->ribs.at(ribNframe);
	PolygonRib* pRibSrc = pSrc->ribs.at(ribNsrc);
	/*
mylog("==addLinesIntersection\n");
mylog("  fr %f x %f to %f x %f v=%d h=%d\n", pRibFrame->p0[0], pRibFrame->p0[1], pRibFrame->p1[0], pRibFrame->p1[1], pRibFrame->isVertical, pRibFrame->isHorizontal);
mylog("  tr %f x %f to %f x %f v=%d h=%d\n", pRibSrc->p0[0], pRibSrc->p0[1], pRibSrc->p1[0], pRibSrc->p1[1], pRibSrc->isVertical, pRibSrc->isHorizontal);
*/
	if (PolygonRib::matchingLines(pRibFrame, pRibSrc)) {
		Vertex01* pV0 = pSrc->vertices.at(pRibSrc->i0);
		Vertex01* pV1 = pSrc->vertices.at(pRibSrc->i1);
		int dstVertsN0 = pDst->vertices.size();
		if (dotFits(pRibFrame->p0, pRibSrc))
			addVert(pDst, pRibFrame->p0, pV0,pV1);
		if (dotFits(pRibFrame->p1, pRibSrc))
			addVert(pDst, pRibFrame->p1, pV0, pV1);
		if (dotFits(pRibSrc->p0, pRibFrame))
			addVertex(pDst, pV0);
		if (dotFits(pRibSrc->p1, pRibFrame))
			addVertex(pDst, pV1);
//mylog("  lines are identical\n");
		return pDst->vertices.size()- dstVertsN0;
	}
	if (PolygonRib::parallelLines(pRibFrame, pRibSrc)) {
//mylog("  lines are parallel\n");
		return 0;
	}
	//find lines intersection, assuming lines are not parallel
	float x,y;
	if (pRibFrame->isVertical) {
		x = pRibFrame->p0[0];
		y = pRibSrc->a_slope * x + pRibSrc->b_intercept;
	}
	else { //pRibFrame not vertical
		if (pRibSrc->isVertical) {
			x = pRibSrc->p0[0];
			y = pRibFrame->a_slope * x + pRibFrame->b_intercept;
		}
		else { //both lines are "normal"
			x = (pRibSrc->b_intercept - pRibFrame->b_intercept) / (pRibFrame->a_slope - pRibSrc->a_slope);
			y = pRibFrame->a_slope * x + pRibFrame->b_intercept;
		}
	}
	//check if belongs to both PolygonRibs
	float xy[2];
	xy[0] = x;
	xy[1] = y;
	if (!dotFits(xy, pRibFrame))
		return 0;
	if (!dotFits(xy, pRibSrc))
		return 0;
	addVert(pDst, xy, pSrc->vertices.at(pRibSrc->i0), pSrc->vertices.at(pRibSrc->i1));
	return 1;
}
bool Polygon::correctSide(float* p0, PolygonRib* pPR) {
	if (pPR->isVertical)
		if ((p0[0] - pPR->x_vertical) * pPR->xDirIn < 0)
			return false;
	if (pPR->isHorizontal)
		if ((p0[1] - pPR->b_intercept) * pPR->yDirIn < 0)
			return false;
	float y = pPR->a_slope * p0[0] + pPR->b_intercept;
	if ((p0[1] - y) * pPR->yDirIn < 0)
		return false;
	return true;
}
int Polygon::addVert(Polygon* pDst, float* p0, Vertex01* pV0, Vertex01* pV1) {
	float d[2];
	for (int i = 0; i < 2; i++)
		d[i] = pV0->aPos[i] - p0[i];
	float dist2v0 = v3lengthXY(d);
	if (dist2v0 == 0)
		return addVertex(pDst, pV0);
	for (int i = 0; i < 2; i++)
		d[i] = pV1->aPos[i] - p0[i];
	float dist2v1 = v3lengthXY(d);
	if (dist2v1 == 0)
		return addVertex(pDst, pV1);
	//if here - find mid values
	float k0 = dist2v1 / (dist2v0 + dist2v1);
	float k1 = dist2v0 / (dist2v0 + dist2v1);
	Vertex01* pVx = new Vertex01(*pV0);
	pVx->aPos[0] = p0[0];
	pVx->aPos[1] = p0[1];
	pVx->aPos[2] = k0 * pV0->aPos[2] + k1 * pV1->aPos[2];
	for (int i = 0; i < 3; i++)
		pVx->aNormal[i] = k0 * pV0->aNormal[i] + k1 * pV1->aNormal[i];
	for (int i = 0; i < 2; i++)
		pVx->aTuv[i] = k0 * pV0->aTuv[i] + k1 * pV1->aTuv[i];
	for (int i = 0; i < 2; i++)
		pVx->aTuv2[i] = k0 * pV0->aTuv2[i] + k1 * pV1->aTuv2[i];
	addVertex(pDst, pVx);
	delete pVx;
	return 0;
}
int Polygon::xyIntersection(Polygon* pDst, Polygon* pFrame, Polygon* pSrc) {
	//check bounding boxes, XY only
	for (int i = 0; i < 2; i++) {
		if (pFrame->bbMin[i] > pSrc->bbMax[i])
			return 0;
		if (pFrame->bbMax[i] < pSrc->bbMin[i])
			return 0;
	}
	//compare normals
	if (v3dotProduct(pFrame->normal, pSrc->normal) <= 0)
		return 0;
/*
mylog(">>>pFrame %fx%f to %fx%f to %fx%f \n",
	pFrame->vertices.at(0)->aPos[0], pFrame->vertices.at(0)->aPos[1],
	pFrame->vertices.at(1)->aPos[0], pFrame->vertices.at(1)->aPos[1],
	pFrame->vertices.at(2)->aPos[0], pFrame->vertices.at(2)->aPos[1]
);
mylog("   pSrc   %fx%f to %fx%f to %fx%f \n",
	pSrc->vertices.at(0)->aPos[0], pSrc->vertices.at(0)->aPos[1],
	pSrc->vertices.at(1)->aPos[0], pSrc->vertices.at(1)->aPos[1],
	pSrc->vertices.at(2)->aPos[0], pSrc->vertices.at(2)->aPos[1]
);
mylog("---SrcVerts\n");
*/
	//if here - have overlap
	int addedSrcVerts = 0;
	for (int vN = 0; vN < pSrc->ribsN; vN++) {
		Vertex01* pV = pSrc->vertices.at(vN);
		if (dotFits(pV->aPos, pFrame))
			addedSrcVerts += addVertex(pDst, pV);
	}
	if (addedSrcVerts == pSrc->ribsN)
		return addedSrcVerts;

//mylog("---FrameVerts\n");
	int addedFrameVerts = 0;
	for (int vN = 0; vN < pFrame->ribsN; vN++) {
		Vertex01* pV = pFrame->vertices.at(vN);
		if (dotFits(pV->aPos, pSrc)) {
			int frameVerts = addVert(pDst, pV->aPos, pSrc);
			addedFrameVerts += frameVerts;
		}
	}
	if (addedFrameVerts == pFrame->ribsN)
		return addedFrameVerts;

//mylog("---CrossVerts\n");
	//check ribs intersections
	int addedCrossVerts = 0;
	for (int ribNframe = 0; ribNframe < pFrame->ribsN; ribNframe++) {
		for (int ribNsrc = 0; ribNsrc < pSrc->ribsN; ribNsrc++) {
			int crossVerts = addLinesIntersection(pDst, pFrame, ribNframe, pSrc, ribNsrc);
			addedCrossVerts += crossVerts;
		}
	}
	return (addedSrcVerts + addedFrameVerts + addedCrossVerts);
}
bool Polygon::dotFits(float* p0, PolygonRib* pPR) {
//mylog("dotFits Rib %f x %f vs %f x %f to %f x %f\n", p0[0], p0[1], pPR->p0[0], pPR->p0[1], pPR->p1[0], pPR->p1[1]);
	//assuming that p0 is on the line
	int dir0;
	int dir1;
	if (pPR->isVertical) {
		if (pPR->p0[1] == p0[1])
			return true;
		else if (pPR->p0[1] < p0[1])
			dir0 = -1;
		else
			dir0 = 1;

		if (pPR->p1[1] == p0[1])
			return true;
		else if (pPR->p1[1] < p0[1])
			dir1 = -1;
		else
			dir1 = 1;
	}
	else{ //"normal" line
		if (pPR->p0[0] == p0[0])
			return true;
		else if (pPR->p0[0] < p0[0])
			dir0 = -1;
		else
			dir0 = 1;

		if (pPR->p1[0] == p0[0])
			return true;
		else if (pPR->p1[0] < p0[0])
			dir1 = -1;
		else
			dir1 = 1;
	}
//mylog("  fits?=%d\n", !(dir0 == dir1));
	if (dir0 == dir1)
		return false;
	return true;
}
bool Polygon::dotFits(float* p0, Polygon* pPL) {
//mylog("dotFits Polygon %f x %f\n",p0[0],p0[1]);

	for (int i = 0; i < pPL->ribsN; i++)
		if (!correctSide(p0, pPL->ribs.at(i))) {
//mylog("  don't Fit side %f x %f to %f x %f\n", pPL->ribs.at(i)->p0[0], pPL->ribs.at(i)->p0[1], pPL->ribs.at(i)->p1[0], pPL->ribs.at(i)->p1[1]);
			return false;
		}
//mylog("  dotFits!\n");
	return true;
}
int Polygon::buildTriangles(Polygon* pPL) {
	int vertsN = pPL->vertices.size();
	//mid point coords
	float p0[2] = { 0,0 };
	for (int vN = 0; vN < vertsN; vN++) {
		float* p1 = pPL->vertices.at(vN)->aPos;
		p0[0] += p1[0];
		p0[1] += p1[1];
	}
	p0[0] /= vertsN;
	p0[1] /= vertsN;
	for (int vN = 0; vN < vertsN; vN++) {
		float* p1 = pPL->vertices.at(vN)->aPos;
		float v1[3] ={0,0,0};
		v1[0] = p1[0] - p0[0];
		v1[1] = p1[1] - p0[1];
		float az = -atan2f(v1[0], v1[1]) * radians2degrees;
		//aTangent is not used at this point, ok to use it to store az
		pPL->vertices.at(vN)->aTangent[0] = az;
	}
	//sort vertices
	std::sort(pPL->vertices.begin(), pPL->vertices.end(), 
		[](Vertex01* pV0, Vertex01* pV1) {
		return pV0->aTangent[0] > pV1->aTangent[0]; });
	//check for redundancy
	for (int vN = pPL->vertices.size() - 1; vN > 0; vN--) {
		Vertex01* pV = pPL->vertices.at(vN);
		Vertex01* pVprev = pPL->vertices.at(vN-1);
		if (pV->aTangent[0] == pVprev->aTangent[0]) {
			delete pV;
			pPL->vertices.erase(pPL->vertices.begin() + vN);
		}
	}
	pPL->ribsN = pPL->vertices.size();
	//build triangles
	Vertex01* pV = pPL->vertices.at(0);
	for (int vN = 2; vN < pPL->ribsN; vN++) {
		Triangle01* pTR = new Triangle01();
		pPL->triangles.push_back(pTR);
		pTR->idx[0] = 0;
		pTR->idx[1] = vN;
		pTR->idx[2] = vN - 1;
		pTR->subjN = pV->subjN;
		pTR->materialN = pV->materialN;
		//mark
		myStrcpy_s(pTR->marks, 124, pV->marks);
	}
	return 1;
}
int Polygon::addVert(Polygon* pDst, float* p0, Polygon* pSrc) {
	//check where horizontal line drawn through p0 crosses polygon's ribs
	Vertex01 vx0;
	Vertex01 vx1;
	int vxN = 0;
	for (int ribN = 0; ribN < pSrc->ribsN; ribN++) {
		PolygonRib* pPR = pSrc->ribs.at(ribN);
		if (pPR->isHorizontal)
			continue;
		float p1[2];
		p1[1] = p0[1];
		if (pPR->isVertical)
			p1[0] = pPR->x_vertical;
		else
			p1[0] = (p1[1] - pPR->b_intercept) / pPR->a_slope;
		if (!dotFits(p1, pPR))
			continue;
		//if here - 1 intersection found
		Vertex01* pVdst = &vx0;
		if(vxN > 0)
			pVdst = &vx1;
		Vertex01* pV0src = pSrc->vertices.at(pPR->i0);
		Vertex01* pV1src = pSrc->vertices.at(pPR->i1);
		memcpy(pVdst, pV0src, sizeof(Vertex01));
		float d[2];
		for (int i = 0; i < 2; i++)
			d[i] = pV0src->aPos[i] - p1[i];
		float dist2v0 = v3lengthXY(d);
		if (dist2v0 == 0)
			memcpy(pVdst, pV0src, sizeof(Vertex01));
		else {
			for (int i = 0; i < 2; i++)
				d[i] = pV1src->aPos[i] - p1[i];
			float dist2v1 = v3lengthXY(d);
			if (dist2v1 == 0)
				memcpy(pVdst, pV1src, sizeof(Vertex01));
			else {
				//if here - find mid values
				float k0 = dist2v1 / (dist2v0 + dist2v1);
				float k1 = dist2v0 / (dist2v0 + dist2v1);
				pVdst->aPos[0] = p1[0];
				pVdst->aPos[1] = p1[1];
				pVdst->aPos[2] = k0 * pV0src->aPos[2] + k1 * pV1src->aPos[2];
				for (int i = 0; i < 3; i++)
					pVdst->aNormal[i] = k0 * pV0src->aNormal[i] + k1 * pV1src->aNormal[i];
				for (int i = 0; i < 2; i++)
					pVdst->aTuv[i] = k0 * pV0src->aTuv[i] + k1 * pV1src->aTuv[i];
				for (int i = 0; i < 2; i++)
					pVdst->aTuv2[i] = k0 * pV0src->aTuv2[i] + k1 * pV1src->aTuv2[i];
			}
		}
		vxN++;
		if (vxN > 1)
			break;
	}
	addVert(pDst, p0, &vx0, &vx1);
	return 1;
}


Теперь – model description.

6. Копируем нижеследующий код в Текстовый редактор и сохраняем (overwrite) его to/as

C:\CPP\a997modeler\dt\models\misc\marlboro01\root01.txt

<texture_as="tx0" src="marlboro03small.png" ckey="#00ff00"/>
<mt_type="phong" uTex0_use="tx0" />
<vs="box_tank" whl="53,83,21" ext=1 sectR=1 />
<a="front v" xywh="2,1,323,495" mark="box_front"/>
<a="back v"  xywh="2,1,323,495" mark="box_back"/>
<a="right all" xywh="327,1,128,495" mark="box_right"/>
<a="left all" xywh="457,1,128,495" mark="box_left"/>
<a="top" xywh="588,1,323,133"/>
<a="bottom" xywh="587,136,324,134"/>
//golden prints
<vs="box" whl="55.1,85.1,23.1" />
<texture_as="whitenoise" src="/dt/common/img/whitenoise/wn64_blur3.bmp"/>
<texture_as="gold" src="/dt/common/img/materials/gold02roman.bmp" />
<mt_type="mirror" uAlphaBlending uTex1mask_use="tx0" uTex1alphaChannelN=1 uTex0_use="whitenoise" uTex0translateChannelN=0 uTex3_use="gold" />
//side golden prints
<a="right" xywh="342,12,101,10" whl="x,1.8,18.1" pxyz="x,39.8, -0.3" /> //Please do not litter
<a="right" xywh="339,144,105,89" whl="x,15.35,18.9" pxyz="x,10.3,-0.12" /> //For special offers...
<a="left" xywh="475,15,95,48" whl="x,8.4,17" pxyz="x,36, 0.3" /> //Underage sale...
//front prints
<group>
	//bottom golden print "20 class a..."
	<a="front" xywh="20,498,289,13" whl="47.5,2,x" pxyz="1,-36,x" />
	//blazon/emblem
	<mt_type="mirror" uAlphaBlending uTex2nm_use="tx0" uTex0_use="whitenoise" uTex0translateChannelN=0 uTex3_use="gold" />
	<a="front" xywh2nm="589,415,128,94" whl="20.7,16,x" pxyz="0.3,6.1,x" /> //emblem
	//"Marlboro
	<mt_type="phong" uAlphaBlending uTex2nm_use="tx0" uColor="#1E211E" />
	<a="front" xywh2nm="590,275,301,136" whl="49.2,23.3,x" pxyz="0.21,-18,x" /> //marlboro
</group> 
<clone ay=180 />
//joint (slit) between the pack and the lid
<group> 
	<a2mesh wh="50,2" all markedAs="box_right" onThe="right" py=24.6 az=31 />
	<a2mesh wh="50,2" all markedAs="box_left" onThe="left" py=24.6 az=-31 />
	<a2mesh wh="53,2" all markedAs="box_front" py=17.8 />
	<a2mesh wh="6 ,2" all markedAs="box_back" onThe="back" py=31.5 px=23.5 />
	<a2mesh wh="6 ,2" all markedAs="box_back" onThe="back" py=31.5 px=-23.5 />
</group sizeD="0.1,0,0.1"> 

  • Новый код – со строки 32.
  • У нас новые таги “a2mesh“. Это как “a” (apply), только “apply to mesh”.

Чтобы их читать и отрабатывать, в ModelLoader-е – новый функционал.

7. Заменим ModelLoader.h код на:

#pragma once
#include "XMLparser.h"
#include "ModelBuilder.h"
#include "GroupTransform.h"

class ModelLoader : public XMLparser
{
public:
	ModelBuilder* pModelBuilder = NULL;
	bool ownModelBuilder = false;
	std::vector<GameSubj*>* pSubjsVector = NULL;
public:
	ModelLoader(std::vector<GameSubj*>* pSubjsVector0, int subjN, ModelBuilder* pMB, std::string filePath) : XMLparser(filePath) {
		pSubjsVector = pSubjsVector0;
		if (pMB != NULL) {
			ownModelBuilder = false;
			pModelBuilder = pMB;
		}
		else {
			ownModelBuilder = true;
			pModelBuilder = new ModelBuilder();
			pModelBuilder->lockGroup(pModelBuilder);
		}
		pModelBuilder->useSubjN(subjN);
	};
	virtual ~ModelLoader() {
		if (!ownModelBuilder)
			return;
		pModelBuilder->buildDrawJobs(*pSubjsVector);
		delete pModelBuilder;
	};
	static int processTag_a(ModelLoader* pML); //apply
	static int setValueFromIntHashMap(int* pInt, std::map<std::string, int> intHashMap, std::string varName, std::string tagStr);
	static int setTexture(ModelLoader* pML, int* pInt, std::string txName);
	static int setMaterialTextures(ModelLoader* pML, Material* pMT);
	static int fillProps_vs(VirtualShape* pVS, std::string tagStr); //virtual shape
	static int fillProps_mt(Material* pMT, std::string tagStr, ModelLoader* pML); //Material
	static int fillProps_gt(GroupTransform* pGS, ModelBuilder* pMB, std::string tagStr);
	int processTag() { return processTag(this); };
	static int processTag(ModelLoader* pML);
	static int loadModel(std::vector<GameSubj*>* pSubjsVector0, std::string sourceFile, std::string subjClass);
	static int processTag_clone(ModelLoader* pML);
	static int addMark(char* marks, std::string newMark);
	static int processTag_do(ModelLoader* pML);
	static int processTag_a2mesh(ModelLoader* pML);
};

  • Новая функция здесь – processTag_a2mesh(..)

Реализация:

8. Заменим ModelLoader.cpp код на:

#include "ModelLoader.h"
#include "platform.h"
#include "TheGame.h"
#include "DrawJob.h"
#include "Texture.h"
#include "utils.h"
#include "Polygon.h"

extern TheGame theGame;

int ModelLoader::loadModel(std::vector<GameSubj*>* pSubjsVector0, std::string sourceFile, std::string subjClass) {
	//returns element's (Subj) number or -1
	int subjN = pSubjsVector0->size();
	GameSubj* pGS = theGame.newGameSubj(subjClass);
	pSubjsVector0->push_back(pGS);
	//pGS->djStartN = DrawJob::drawJobs.size();
	ModelLoader* pML = new ModelLoader(pSubjsVector0, subjN, NULL, sourceFile);
	processSource(pML);
	delete pML;
	//pGS->djTotalN = DrawJob::drawJobs.size() - pGS->djStartN;
	return subjN;
}
int ModelLoader::setValueFromIntHashMap(int* pInt, std::map<std::string, int> intHashMap, std::string varName, std::string tagStr) {
	if (!varExists(varName, tagStr))
		return 0;
	std::string str0 = getStringValue(varName, tagStr);
	if (intHashMap.find(str0) == intHashMap.end()) {
		mylog("ERROR in ModelLoader::setValueFromIntMap, %s not found, %s\n", varName.c_str(), tagStr.c_str());
		return -1;
	}
	*pInt = intHashMap[getStringValue(varName, tagStr)];
	return 1;
}
int ModelLoader::setTexture(ModelLoader* pML, int* pInt, std::string txName) {
	ModelBuilder* pMB = pML->pModelBuilder;
	std::string varName = txName + "_use";
	if (setValueFromIntHashMap(pInt, pMB->texturesHashMap, varName, pML->currentTag) == 0) {
		//the texture is not in hash table
		varName = txName + "_src";
		if (varExists(varName, pML->currentTag)) {
			std::string txFile = getStringValue(varName, pML->currentTag);
			varName = txName + "_ckey";
			unsigned int intCkey = 0;
			setUintColorValue(&intCkey, varName, pML->currentTag);
			*pInt = Texture::loadTexture(buildFullPath(pML, txFile), intCkey);
		}
	}
	return 1;
}
int ModelLoader::setMaterialTextures(ModelLoader* pML, Material* pMT) {
	setTexture(pML, &pMT->uTex0, "uTex0");
	setTexture(pML, &pMT->uTex1mask, "uTex1mask");
	setTexture(pML, &pMT->uTex2nm, "uTex2nm");
	setTexture(pML, &pMT->uTex3, "uTex3");
	return 1;
}
int ModelLoader::fillProps_mt(Material* pMT, std::string tagStr, ModelLoader* pML) {
	setCharsValue(pMT->shaderType, 20, "mt_type", tagStr);
	setMaterialTextures(pML, pMT);
	//color
	if (varExists("uColor", tagStr)) {
		unsigned int uintColor = 0;
		setUintColorValue(&uintColor, "uColor", tagStr);
		pMT->uColor.setUint32(uintColor);
	}
	//mylog("mt.uTex0=%d, mt.uTex1mask=%d\n", mt.uTex0, mt.uTex1mask);
	if (varExists("primitiveType", tagStr)) {
		std::string str0 = getStringValue("primitiveType", tagStr);
		if (str0.compare("GL_POINTS") == 0) pMT->primitiveType = GL_POINTS;
		else if (str0.compare("GL_LINES") == 0) pMT->primitiveType = GL_LINES;
		else if (str0.compare("GL_LINE_STRIP") == 0) pMT->primitiveType = GL_LINE_STRIP;
		else if (str0.compare("GL_LINE_LOOP") == 0) pMT->primitiveType = GL_LINE_LOOP;
		else if (str0.compare("GL_TRIANGLE_STRIP") == 0) pMT->primitiveType = GL_TRIANGLE_STRIP;
		else if (str0.compare("GL_TRIANGLE_FAN") == 0) pMT->primitiveType = GL_TRIANGLE_FAN;
		else pMT->primitiveType = GL_TRIANGLES;
	}
	setIntValue(&pMT->uTex1alphaChannelN, "uTex1alphaChannelN", tagStr);
	setIntValue(&pMT->uTex0translateChannelN, "uTex0translateChannelN", tagStr);
	setIntBoolValue(&pMT->uAlphaBlending, "uAlphaBlending", tagStr);
	setFloatValue(&pMT->uAlphaFactor, "uAlphaFactor", tagStr);
	setFloatValue(&pMT->uAmbient, "uAmbient", tagStr);
	setFloatValue(&pMT->uSpecularIntencity, "uSpecularIntencity", tagStr);
	setFloatValue(&pMT->uSpecularMinDot, "uSpecularMinDot", tagStr);
	setFloatValue(&pMT->uSpecularPowerOf, "uSpecularPowerOf", tagStr);

	pML->pModelBuilder->useMaterial(pMT);
	return 1;
}
int ModelLoader::processTag(ModelLoader* pML) {
	ModelBuilder* pMB = pML->pModelBuilder;
	if (pML->tagName.compare("texture_as") == 0) {
		//saves texture N in texturesMap under given name
		std::string keyName = getStringValue("texture_as", pML->currentTag);
		if (pMB->texturesHashMap.find(keyName) != pMB->texturesHashMap.end())
			return pMB->texturesHashMap[keyName];
		else { //add new
			std::string txFile = getStringValue("src", pML->currentTag);
			unsigned int intCkey = 0;
			setUintColorValue(&intCkey, "ckey", pML->currentTag);
			int txN = Texture::loadTexture(buildFullPath(pML, txFile), intCkey);
			pMB->texturesHashMap[keyName] = txN;
			//mylog("%s=%d\n", keyName.c_str(), pMB->texturesMap[keyName]);
			return txN;
		}
	}
	if (pML->tagName.find("mt_") == 0) {
		//sets current material
		ModelBuilder* pMB = pML->pModelBuilder;
		if (!pML->closedTag) {
			//save previous material in stack
			if (pMB->usingMaterialN >= 0)
				pMB->materialsStack.push_back(pMB->usingMaterialN);
		}
		Material mt;
		return fillProps_mt(&mt, pML->currentTag, pML);
	}
	if (pML->tagName.find("/mt_") == 0) {
		//restore previous material
		if (pMB->materialsStack.size() > 0) {
			pMB->usingMaterialN = pMB->materialsStack.back();
			pMB->materialsStack.pop_back();
		}
		return 1;
	}
	if (pML->tagName.compare("vs") == 0) {
		//sets virtual shape
		ModelBuilder* pMB = pML->pModelBuilder;
		if (pML->closedTag) {
			if (pMB->pCurrentVShape != NULL)
				delete pMB->pCurrentVShape;
		}
		else { //open tag
			//save previous vshape in stack
			if (pMB->pCurrentVShape != NULL)
				pMB->vShapesStack.push_back(pMB->pCurrentVShape);
		}
		pMB->pCurrentVShape = new VirtualShape();
		fillProps_vs(pMB->pCurrentVShape, pML->currentTag);
		return 1;
	}
	if (pML->tagName.compare("/vs") == 0) {
		//restore previous virtual shape
		if (pMB->vShapesStack.size() > 0) {
			if (pMB->pCurrentVShape != NULL)
				delete(pMB->pCurrentVShape);
			pMB->pCurrentVShape = pMB->vShapesStack.back();
			pMB->vShapesStack.pop_back();
		}
		return 1;
	}
	if (pML->tagName.compare("group") == 0) {
		std::string notAllowed[] = { "pxyz","axyz","align","headTo" };
		int notAllowedLn = sizeof(notAllowed) / sizeof(notAllowed[0]);
		for (int i = 0; i < notAllowedLn; i++)
			if (varExists(notAllowed[i], pML->currentTag)) {
				mylog("ERROR in ModelLoader::processTag: use %s in </group>: %s\n", notAllowed[i].c_str(), pML->currentTag.c_str());
				return -1;
			}
		pMB->lockGroup(pMB);
		//mark
		if (varExists("mark", pML->currentTag))
			addMark(pMB->pCurrentGroup->marks, getStringValue("mark", pML->currentTag));
		return 1;
	}
	if (pML->tagName.compare("/group") == 0) {
		GroupTransform gt;
		fillProps_gt(&gt, pMB, pML->currentTag);
		gt.executeGroupTransform(pMB);

		pMB->releaseGroup(pMB);
		return 1;
	}
	if (pML->tagName.compare("a") == 0)
		return processTag_a(pML); //apply 
	if (pML->tagName.compare("clone") == 0)
		return processTag_clone(pML);
	if (pML->tagName.compare("/clone") == 0)
		return processTag_clone(pML);
	if (pML->tagName.compare("do") == 0)
		return processTag_do(pML);
	if (pML->tagName.compare("a2mesh") == 0)
		return processTag_a2mesh(pML);

	//mylog("%s, %s /group?=%d\n",pML->currentTag.c_str(), pML->tagName.c_str(), (pML->tagName.compare("/group") == 0));
	mylog("ERROR in ModelLoader::processTag, unhandled tag %s, file %s\n", pML->currentTag.c_str(), pML->fullPath.c_str());
	return -1;
}
int ModelLoader::fillProps_vs(VirtualShape* pVS, std::string tagStr) {
	//sets virtual shape
	setCharsValue(pVS->shapeType, 20, "vs", tagStr);
	setFloatArray(pVS->whl, 3, "whl", tagStr);
	//extensions
	float ext;
	if (varExists("ext", tagStr)) {
		setFloatValue(&ext, "ext", tagStr);
		pVS->setExt(ext);
	}
	if (varExists("extX", tagStr)) {
		setFloatValue(&ext, "extX", tagStr);
		pVS->setExtX(ext);
	}
	if (varExists("extY", tagStr)) {
		setFloatValue(&ext, "extY", tagStr);
		pVS->setExtY(ext);
	}
	if (varExists("extZ", tagStr)) {
		setFloatValue(&ext, "extZ", tagStr);
		pVS->setExtZ(ext);
	}
	setFloatValue(&pVS->extU, "extU", tagStr);
	setFloatValue(&pVS->extD, "extD", tagStr);
	setFloatValue(&pVS->extL, "extL", tagStr);
	setFloatValue(&pVS->extR, "extR", tagStr);
	setFloatValue(&pVS->extF, "extF", tagStr);
	setFloatValue(&pVS->extB, "extB", tagStr);
	//sections
	setIntValue(&pVS->sectionsR, "sectR", tagStr);
	setIntValue(&pVS->sections[0], "sectX", tagStr);
	setIntValue(&pVS->sections[1], "sectY", tagStr);
	setIntValue(&pVS->sections[2], "sectZ", tagStr);

	//mylog("pVS->shapeType=%s whl=%fx%fx%f\n", pVS->shapeType, pVS->whl[0], pVS->whl[1], pVS->whl[2]);
	return 1;
}
int ModelLoader::processTag_a(ModelLoader* pML) {
	//apply
	ModelBuilder* pMB = pML->pModelBuilder;
	std::string tagStr = pML->currentTag;
	pMB->lockGroup(pMB);
	//mark
	if (varExists("mark", tagStr))
		addMark(pMB->pCurrentGroup->marks, getStringValue("mark", tagStr));

	std::vector<std::string> applyTosVector = splitString(pML->getStringValue("a", tagStr), ",");
	Material* pMT = pMB->materialsList.at(pMB->usingMaterialN);
	int texN = pMT->uTex1mask;
	if (texN < 0)
		texN = pMT->uTex0;
	float xywh[4] = { 0,0,1,1 };
	setFloatArray(xywh, 4, "xywh", tagStr);
	std::string flipStr = getStringValue("flip", tagStr);
	TexCoords tc;
	tc.set(texN, xywh[0], xywh[1], xywh[2], xywh[3], flipStr);

	setFloatArray(xywh, 4, "xywh2nm", tagStr);
	flipStr = getStringValue("flip2nm", tagStr);
	TexCoords tc2nm;
	tc2nm.set(pMT->uTex2nm, xywh[0], xywh[1], xywh[2], xywh[3], flipStr);

	//adjusted VirtualShape
	VirtualShape* pVS_a = new VirtualShape(*pMB->pCurrentVShape);
	fillProps_vs(pVS_a, tagStr);

	for (int aN = 0; aN < (int)applyTosVector.size(); aN++) {
		//pMB->buildFace(pMB, applyTosVector.at(aN), pMB->pCurrentVShape, &tc, &tc2nm);
		pMB->buildFace(pMB, applyTosVector.at(aN), pVS_a, &tc, &tc2nm);
	}
	delete pVS_a;
	//mylog("vertsN=%d\n",pMB->vertices.size());

	GroupTransform GT_a;
	fillProps_gt(&GT_a, pMB, tagStr);
	GT_a.executeGroupTransform(pMB);

	pMB->releaseGroup(pMB);
	return 1;
}
int ModelLoader::processTag_clone(ModelLoader* pML) {
	ModelBuilder* pMB = pML->pModelBuilder;
	if (pML->tagName.compare("clone") == 0) {
		//mark what to clone
		GroupTransform gt;
		gt.pGroup = pMB->pLastClosedGroup;
		gt.flagSelection(&gt, &pMB->vertices, &pMB->triangles);

		//cloning
		pMB->lockGroup(pMB);
		gt.cloneFlagged(pMB, &pMB->vertices, &pMB->triangles, &pMB->vertices, &pMB->triangles);
	}
	GroupTransform gt;
	fillProps_gt(&gt, pMB, pML->currentTag);
	gt.executeGroupTransform(pMB);

	if (pML->tagName.compare("/clone") == 0 || pML->closedTag) {
		pMB->releaseGroup(pMB);
	}
	return 1;
}
int ModelLoader::addMark(char* marks, std::string newMark) {
	if (newMark.empty())
		return 0;
	std::string allMarks;
	allMarks.assign(marks);
	allMarks.append("<"+ newMark+">");
	myStrcpy_s(marks,124, allMarks.c_str());
	return 1;
}

int ModelLoader::fillProps_gt(GroupTransform* pGT, ModelBuilder* pMB, std::string tagStr) {
	pGT->pGroup = pMB->pCurrentGroup;
	//position
	setFloatArray(pGT->shift, 3, "pxyz", tagStr);
	setFloatValue(&pGT->shift[0], "px", tagStr);
	setFloatValue(&pGT->shift[1], "py", tagStr);
	setFloatValue(&pGT->shift[2], "pz", tagStr);
	//angles
	setFloatArray(pGT->spin, 3, "axyz", tagStr);
	setFloatValue(&pGT->spin[0], "ax", tagStr);
	setFloatValue(&pGT->spin[1], "ay", tagStr);
	setFloatValue(&pGT->spin[2], "az", tagStr);
	//scale
	setFloatArray(pGT->scale, 3, "scale", tagStr);

	pGT->onThe = getStringValue("onThe", tagStr);
	pGT->allign = getStringValue("allign", tagStr);
	pGT->headZto = getStringValue("headZto", tagStr);
	//limit to
	if(varExists("all",tagStr))
		pGT->pGroup = NULL;
	if (varExists("lastClosedGroup", tagStr))
		pGT->pGroup = pMB->pLastClosedGroup;
	if (varExists("markedAs", tagStr))
		pGT->limit2mark(pGT, getStringValue("markedAs", tagStr));
	setFloatArray(pGT->pMin, 3, "xyzMin", tagStr);
	setFloatArray(pGT->pMax, 3, "xyzMax", tagStr);

	if (varExists("sizeD", tagStr)) { //re-size
		float sizeD[3];
		setFloatArray(sizeD, 3, "sizeD", tagStr);
		//bounding box
		pGT->flagSelection(pGT, &pMB->vertices, NULL);
		float bbMin[3];
		float bbMax[3];
		pGT->buildBoundingBoxFlagged(bbMin, bbMax, &pMB->vertices);
		for (int i = 0; i < 3; i++) {
			float size = bbMax[i] - bbMin[i];
			pGT->scale[i] = (size + sizeD[i]) / size;
		}
	}

	return 1;
}
int ModelLoader::processTag_do(ModelLoader* pML) {
	ModelBuilder* pMB = pML->pModelBuilder;
	GroupTransform gt;
	fillProps_gt(&gt, pMB, pML->currentTag);
	gt.flagSelection(&gt, &pMB->vertices, &pMB->triangles);
	gt.transformFlagged(&gt, &pMB->vertices);
	return 1;
}
int ModelLoader::processTag_a2mesh(ModelLoader* pML) {
	ModelBuilder* pMB = pML->pModelBuilder;
	std::string tagStr = pML->currentTag;
	GroupTransform gt;
	fillProps_gt(&gt, pMB, pML->currentTag);
	gt.flagSelection(&gt, &pMB->vertices, &pMB->triangles);
	//clone a copy
	std::vector<Vertex01*> vx1;
	std::vector<Triangle01*> tr1;
	gt.cloneFlagged(NULL, &vx1, &tr1, &pMB->vertices, &pMB->triangles);
	// build transform and inverted martrices
	mat4x4 transformMatrix;
	gt.buildTransformMatrix(&gt, &transformMatrix);
	mat4x4 transformMatrixInverted;
	mat4x4_invert(transformMatrixInverted, transformMatrix);
	//move/rotate cloned
	gt.flagAll(&vx1, &tr1);
	//gt.transformFlagged(&pMB->vertices, &transformMatrixInverted);
	gt.transformFlaggedMx(&vx1, &transformMatrixInverted);

//gt.cloneFlagged(pMB, &pMB->vertices, &pMB->triangles, &vx1, &tr1);

	float wh[2];
	setFloatArray(wh, 2, "wh", tagStr);
	Polygon frame;
	frame.setRectangle(&frame, wh[0],wh[1]);
	//destination arrays
	std::vector<Vertex01*> vx2;
	std::vector<Triangle01*> tr2;
	Polygon triangle;
	for (int i = tr1.size() - 1; i >= 0; i--) {
		triangle.setTriangle(&triangle, tr1.at(i), &vx1);
		Polygon intersection;
		int pointsN = Polygon::xyIntersection(&intersection, &frame, &triangle);
		if (pointsN > 2) {
			Polygon::buildTriangles(&intersection);
			GroupTransform::flagAll (&intersection.vertices, &intersection.triangles);
			GroupTransform::cloneFlagged(NULL, &vx2, &tr2, &intersection.vertices, &intersection.triangles);
		}
	}
	gt.flagAll(&vx2, &tr2);
	//------------
	//replace material
	Material mt;
	mt.setShaderType("phong");
	mt.uColor.setRGBA(0,255,0,255);
	int mtN = pMB->useMaterial(pMB, &mt);
	for (int i = vx2.size() - 1; i >= 0; i--)
		vx2.at(i)->materialN = mtN;
	for (int i = tr2.size() - 1; i >= 0; i--)
		tr2.at(i)->materialN = mtN;
	//------------
 	//move/rotate
	gt.transformFlaggedMx(&vx2, &transformMatrix);
	//clone back to modelBuilder arrays
	gt.cloneFlagged(pMB, &pMB->vertices, &pMB->triangles, &vx2, &tr2);

	//clear memory
	for (int i = vx1.size() - 1; i >= 0; i--)
		delete vx1.at(i);
	vx1.clear();
	for (int i = tr1.size() - 1; i >= 0; i--)
		delete tr1.at(i);
	tr1.clear();
	for (int i = vx2.size() - 1; i >= 0; i--)
		delete vx2.at(i);
	vx2.clear();
	for (int i = tr2.size() - 1; i >= 0; i--)
		delete tr2.at(i);
	tr2.clear();

	return 1;
}

Как это работает:

Все происходит в функции processTag_a2mesh(..) (строка 351).

Строка 355. Чтение позиции “куда” мы собираемся “apply”.

Строка 360. Клонируем выбранный (помеченный) меш.

Строка 369. Разворачиваем скопированный меш лицом к нам:

Строка 374. Читаем размеры что мы хотим “вырезать”.

Строки 381-390. Сканируем треугольники меша и строим пересечения (строка 384). Полученное пересечение сохраняем в отдельном Polygon-е под названием intersection (строка 383).

Если пересечение существует, то строим треугольники (строка 486) и сохраняем результат в массивы (vectors) vx2 (vertices) и tr2 (triangles) (строка 388).

Когда все треугольники обработаны, в массивах vx2 / tr2 у нас – желаемый фрагмент, вырезанный из скопированной поверхности (меша):

Чтобы он не слился с фоном после перемещения назад, поменяем его material (строки 394-401).

Мы уберем этот код чуть позже.

Строка 404. Перемещение вырезанного фрагмента на его окончательную (или изначальную?) позицию.

Строка 406. Клонирование полученных вертексов/треугольников обратно в основные массивы ModelBuilder-а. Однако, у них точно такие же координаты как и у исходного меша, поэтому они перекрывают друг друга:

Чтобы их сдвинуть чуток от исходного меша, у нас дополнительная команда в root01.txt:

</group sizeD="0.1,0,0.1">

Это последняя строка 38.

ModelLoader переведет sizeD в scale (масштаб), это строки 327-339 в ModelLoader.cpp, функция fillProps_gt(..).


9. Компиляция и запуск. Результат:

Поставленная цель достигнута.


Android

10. Пере-запускаем VS. Открываем C:\CPP\a997modeler\p_android\p_android.sln.


11. Под modeler добавим Existing Item

из C:\CPP\engine\modeler

  • Polygon.cpp
  • Polygon.h
  • PolygonRib.cpp
  • PolygonRib. h

Add


12. Включаем, разблокируем, подключаем, разрешаем.

Компиляция и запуск.

Ok.

VS top menu -> Debug -> Stop Debugging.


Следующая задача – наложить normal map на вырезанные фрагменты, при этом не нарушив их “родные” материалы и текстуры.


Leave a Reply

Your email address will not be published. Required fields are marked *