Войти
ПрограммированиеФорумГрафика

Max SDK. Render Normals

#0
10:49, 30 июля 2004

Кто-нибудь, знает как вытащить нормаль("сглаженную") из Mesh'a (в TriObject), для определенного треугольника и его вертекса, если в Mesh'e используются Smooth группы?
Я доставал только общие нормали, используя mesh.getRVert(n_vertex);


#1
11:13, 30 июля 2004

не знаю можно ли ее вытащить, но посчитать самому можно. Алгоритм простой.

Делаеш обход по фейсам, и в каждую вершину записываешь нормаль. Если в вершине нормаль уже есть, тогда смотришь группу сглаживания вершины. Если группа сглаживания совпадает с новой но складываешь нормали, получаешь сглаженную. Если группы сглаживания разные, вершину необходимо продублировать с новой нормалью.

#2
11:30, 30 июля 2004

Сумму нормалей нормализовывать надо?(Если надо то не отвечайте)

#3
11:48, 30 июля 2004

Так я понял этот алгоритм:
1. Для каждого треугольника определяю, и записываю в каждую нормаль вершины: "Нормаль к плоскости треугольника". Тоесть вначале все 3 нормали каждого треугольника одинаковые.
2 цикл по всем вершинам:

2.1. Начиниаю обход по всем вершинам. Например беру 1 вершину первого face'а.
2.2. Определяю её SmGroup (SG).
2.3. Ищу все соседние треугольники.
2.4. Нашел их. Оставляю те, что имеют ту же SG.
2.5  Далее. В этих оставшихся треугольниках ищу общие вершины, совпадающие с исходной.
2.6  Нашел. Допустим их 3.
                  ??? Сложить надо все три или попарно? И Записывать результат только в исходную вершину или во все найденные.

#4
12:18, 30 июля 2004

Frankinshtein
http://siv-games.leosam.com/cgi-bin/pages.pl?page=article&aname=a… ed_max_export

#5
12:29, 30 июля 2004

Чего-то сложный у тебя алгоритм получился :)

но вроде результат будет правильный. Сложить надо все три нормали, записать во все вершины. Но тогда в вертекс буфере у тебя будет три совершенно одинаковые вершины. Из них надо оставить одну, изменив соответствующим образом индекс буффер.

я использую как мне кажется более простой алгоритм:

цикл по фейсам
  1.все вершины фейса записываю в массив вершин,
    если такая вершина уже существует, запоминаю где она находится
  2. записываю значения в массив индексов, в соответсвии с тем, где лежат вершины в массиве вершин


При этом, при проверке существования вершины в массиве вершин, проверяется на равенство, и SG. Если позиции вершин одинаковые но разные SG добавляю новую вершину. Если SG совпадают, тогда к имеющеся в вершине нормали прибавляю нормаль из новой вершины.

Где нибудь потом нормализация.

#6
10:43, 31 июля 2004

Alexded
>>но вроде результат будет правильный. Сложить надо все три нормали, записать во все вершины. Но тогда в вертекс буфере у тебя будет три совершенно одинаковые вершины. Из них надо оставить одну, изменив соответствующим образом индекс буффер.
Я же не работаю сразу с вертекс буффером, я создаю массив вспомогательных эл-тов класса VNormal, в которых если получится три вершини, которые должны быть сглажены, то они ссумируются перед нормализацией.

Скажу частно, я не понял твой способ, вот, например, как ты считаешь нормали для каждой вершины каждого треугольника? Не мог бы ты куда-нибудь запостить код, если он проще и в нём нет ошибок, то с твоего разрешения я его включу в статью с указанием авторства.

#7
12:16, 31 июля 2004

Alexded
Вот что я нашел в Cal3D:

Point3 CMaxMesh::GetVertexNormal(int faceId, int vertexId)
{
	RVertex *pRVertex = mesh.getRVertPtr(vertexId);
	Face *pFace = &mesh.faces[faceId];
	DWORD smGroup = pFace->smGroup;
	int normalCount = pRVertex->rFlags & NORCT_MASK;

	if(pRVertex->rFlags & SPECIFIED_NORMAL)
	{
		return pRVertex->rn.getNormal();
	}
	else if((normalCount > 0) && (smGroup != 0))
	{
		if(normalCount == 1)
		{
			return pRVertex->rn.getNormal();
		}
		else{
			for(int normalId = 0; normalId < normalCount; normalId++)
			{
				if(pRVertex->ern[normalId].getSmGroup() & smGroup)
				{
					return pRVertex->ern[normalId].getNormal();
				}
			}
		}
	}
	return mesh.getFaceNormal(faceId);
};
#8
21:23, 31 июля 2004

Вот такой не хитрый алгоритм у нас используется для расчета нормалей максовского меша:

struct VNormalEl
{
  ::Point3 normal;
  float    angle;

  VNormalEl()
  : normal(0, 0, 0),
    angle(0)
  {
  }
  VNormalEl& operator +=(const VNormalEl& vnormal_el)
  {
    normal += vnormal_el.normal/* * angle*/;
    angle += vnormal_el.angle;
    return *this;
  }
};

typedef std::map<UInt, VNormalEl> VNormal;

class MeshNormals
{
public:
  MeshNormals()
  {
    m_n_normals_used = 0;
  }
  void calc_normals(::Mesh& mesh);
  ::Point3 normal(UInt vertex_n, UInt smooth_group);
  void clear()
  {
    for(UInt n = 0; n < m_n_normals_used; n++)
    {
      m_temp_normals[n].clear();
    }
    m_n_normals_used = 0;
  }

protected:
  UInt                 m_n_normals_used;
  std::vector<VNormal> m_normals;
  std::vector<VNormal> m_temp_normals;
};

float FindVertexAngle(Mesh *mesh, int face, int corner)
{

  int cnext = (corner+1)%3;
  int cprev = (corner+2)%3;
  DWORD* vv = mesh->faces[face].v;

  // Get edge vectors:
  ::Point3 A = mesh->verts[vv[cnext]] - mesh->verts[vv[corner]];
  ::Point3 B = mesh->verts[vv[cprev]] - mesh->verts[vv[corner]];

  // Normalize the edge-vectors, but return 0 if either has 0 length.
  float len = Length(A);

  if(!len)
    return len;
  A = A/len;
  len = Length(B);
  if(!len)
    return len;
  B = B/len;

   // The dot product gives the cosine of the angle:
  float dp = DotProd (A,B);
  if(dp>1)
    dp=1.0f;	// shouldn't happen, but might
  if(dp<-1)
    dp=-1.0f;	// shouldn't happen, but might
  return acosf(dp);
}

void MeshNormals::calc_normals(Mesh& mesh)
{
  if((int)m_normals.size() < mesh.numVerts)
  {
    m_temp_normals.resize(mesh.numVerts);
    m_normals.resize(mesh.numVerts);
  }
  m_n_normals_used = mesh.numVerts;

  for(int face_n = 0; face_n < mesh.getNumFaces(); face_n++)
  {
    Face face = mesh.faces[face_n];

    ::Point3 face_normal = mesh.FaceNormal(face_n, TRUE);
    for(int j = 0; j < 3; ++j)
    {
      float angle = FindVertexAngle(&mesh, face_n, j);
      m_temp_normals[face.v[j]][face.smGroup].normal += face_normal * angle;
      m_temp_normals[face.v[j]][face.smGroup].angle += angle;
    }
  }


  for(int n = 0; n < mesh.numVerts; n++)
  {
    for(VNormal::iterator
        it = m_temp_normals[n].begin(); it != m_temp_normals[n].end(); ++it)
    {
      int sm1 = (*it).first;
      if(sm1 == 0)
        continue;
      VNormalEl& normal = m_normals[n][(*it).first];
      // Посчитать среднюю нормаль по smoothing группам
      normal = (*it).second;
      // Посчитать свою smoothing group
      // Если в точке собранны группы [1], [2], [1, 2]
      // То это все "одна" группа
      int smooth_group = sm1;
      for(VNormal::iterator
          sub_it = m_temp_normals[n].begin();
          sub_it != m_temp_normals[n].end();
          ++sub_it)
      {
        int sm2 = (*sub_it).first;
        if(smooth_group & sm2)
          smooth_group |= sm2;
      }
      for(VNormal::iterator
          sub_it = m_temp_normals[n].begin();
          sub_it != m_temp_normals[n].end();
          ++sub_it)
      {
        int sm2 = (*sub_it).first;

        if((sm1 != sm2) && (smooth_group & sm2))
          normal += (*sub_it).second;
      }
    }
  }
}


::Point3 MeshNormals::normal(UInt vertex_n, UInt smooth_group)
{
  return m_normals[vertex_n][smooth_group].normal;
}

#9
7:20, 2 авг. 2004

А зачем считать ?
в классе RVertex уже они просчитанны. И хранятся в массиве RNormal *ern (extra render normals). Единаственная сложность в том как узнать какой элемент массива нужен мне для данного вертекса, данного треугольника?

#10
7:34, 3 авг. 2004

Иннокентий
Вот это то что надо.
Спасибо вам

Прошло более 15 лет
#11
2:20, 17 авг. 2019

Иннокентий Спасибо !

ПрограммированиеФорумГрафика