WMO/Rendering: Difference between revisions

From wowdev
Jump to navigation Jump to search
Line 92: Line 92:
bool CMapObjGroup::QueryLighting(CMapObjGroup *this, const C3Vector *point, uint16_t polyIdx, CImVector *color, bool *a5) {
bool CMapObjGroup::QueryLighting(CMapObjGroup *this, const C3Vector *point, uint16_t polyIdx, CImVector *color, bool *a5) {


   // Out of bounds
   // Poly is out of bounds


   if (polyIdx >= this->polyCount) {
   if (polyIdx >= this->polyCount) {
Line 122: Line 122:
   C3Vector* vert2 = &vertices[indices[1]];
   C3Vector* vert2 = &vertices[indices[1]];
   C3Vector* vert3 = &vertices[indices[2]];
   C3Vector* vert3 = &vertices[indices[2]];
  // Obtain normal for poly


   C4Plane plane;
   C4Plane plane;
   C4Plane::From3Pos(&plane, vert1, vert2, vert3);
   C4Plane::From3Pos(&plane, vert1, vert2, vert3);


   C3Vector::EAxis axis = C3Vector::MajorAxis(&plane.normal);
   C3Vector::EAxis majAxis = C3Vector::MajorAxis(&plane.normal);
 
  // Obtain 2d coordinates for point and poly
 
  C2iVector xy = xyAxisTable[majAxis];
 
  C2Vector pt = { ((float *)(&point))[xy.x], ((float *)(&point))[xy.y] };
  C2Vector v1 = { ((float *)(&vert1))[xy.x], ((float *)(&vert1))[xy.y] };
  C2Vector v2 = { ((float *)(&vert2))[xy.x], ((float *)(&vert2))[xy.y] };
  C2Vector v3 = { ((float *)(&vert3))[xy.x], ((float *)(&vert3))[xy.y] };
 
  // Calculate barycentric weights
  // https://stackoverflow.com/a/26567573/6770172
 
  C2Vector sv2 = { v2.x - v1.x, v2.y - v1.y };
  C2Vector sv3 = { v3.x - v1.x, v3.y - v1.y };
  C2Vector spt = { pt.x - v1.x, pt.y - v1.y };
 
  // total area = cross(sub(v2, v1), sub(v3, v1))
  float at = sv2.x * sv3.y - sv2.y * sv3.x;
 
  // a3 = cross(sub(v2, v1), sub(pt, v1)) / total area
  float a3 = (sv2.x * spt.y - sv2.y * spt.x) / at;
 
  // a2 = cross(sub(pt, v1), sub(v3, v1)) / total area
  float a2 = (spt.x * sv3.y - spt.y * sv3.x) / at;
 
  // Calculate color weights


   int v19 = xyAxisTable[axis].x;
   int w3 = (a3 * 256.0) - 0.5;
   int v20 = xyAxisTable[axis].y;
   int w2 = (a2 * 256.0) - 0.5;
  int w1 = 256 - w3 - w2;


   float v21 = ((float *)(&vert1))[v19];
   // Adjust weights in cases where point is outside poly
  float v22 = ((float *)(&vert1))[v20];
  float v23 = ((float *)(&vert2))[v19] - v21;
  float v27 = ((float *)(&vert2))[v20] - v22;
  float v24 = ((float *)(&vert3))[v19] - v21;
  float v25 = ((float *)(&vert3))[v20] - v22;
  float v26 = ((float *)(&point))[v19] - v21;
  float v30 = ((float *)(&point))[v20] - v22;


   v28 = v25;
   if (w3 < 0) {
  v29 = 1.0 / (v25 * v23 - v27 * v24);
  v54 = v29 * (v23 * v30 - v26 * v27);
  *(float *)&vert3 = (v28 * v26 - v24 * v30) * v29 * 256.0;
  v31 = (signed int)(*(float *)&vert3 - flt_AEEE50);
  *(float *)&pointb = v54 * 256.0;
  v32 = *(float *)&pointb - flt_AEEE50;
  vert3 = (C3Vector *)(signed int)v32;
  v33 = (signed int)v32;
  v34 = 256 - (signed int)v32 - v31;
  v58 = (signed int)v32;


  if (v31 < 0) {
    int o3 = (w3 * w2) / (w1 + w2);


     v35 = v31 * v33 / (v33 + v34);
     w2 += o3;
    v33 = (int)vert3 + v35;
     w1 += w3 - o3;
     v34 += v31 - v35;
 
    v58 = (int)vert3 + v35;
     w3 = 0;
     v31 = 0;


   }
   }


   if (v33 < 0) {
   if (w2 < 0) {


     v36 = v31 * v33 / (v34 + v31);
     int o2 = (w2 * w3) / (w1 + w3);
     v31 += v36;
 
     v34 += v58 - v36;
     w3 += o2;
    v33 = 0;
     w1 += w2 - o2;
     v58 = 0;
 
     w2 = 0;


   }
   }


   if (v34 < 0) {
   if (w1 < 0) {


     v37 = v31 * v34 / (v33 + v31);
     int o1 = (w1 * w2) / (w2 + w3);
     v58 += v34 - v37;
 
     v31 += v37;
     w2 += o1;
     v34 = 0;
     w3 += w1 - o1;
 
     w1 = 0;


   }
   }


   color->a = (unsigned __int16)(v58 * this->colorVertexList[indices[2]].a
   CImVector c1 = this->colorVertexList[indices[0]];
                              + v34 * this->colorVertexList[indices[0]].a
  CImVector c2 = this->colorVertexList[indices[1]];
                              + v31 * this->colorVertexList[indices[1]].a) >> 8;
  CImVector c3 = this->colorVertexList[indices[2]];


   color->r = (unsigned __int16)(v58 * this->colorVertexList[indices[2]].r
   // Interpolate color by weight
                              + v34 * this->colorVertexList[indices[0]].r
                              + v31 * this->colorVertexList[indices[1]].r) >> 8;


   color->g = (unsigned __int16)(v58 * this->colorVertexList[indices[2]].g
   color->a = (uint16_t)(w1 * c1.a + w2 * c2.a + w3 * c3.a) / 256;
                              + v34 * this->colorVertexList[indices[0]].g
  color->r = (uint16_t)(w1 * c1.r + w2 * c2.r + w3 * c3.r) / 256;
                              + v31 * this->colorVertexList[indices[1]].g) >> 8;
  color->g = (uint16_t)(w1 * c1.g + w2 * c2.g + w3 * c3.g) / 256;
  color->b = (uint16_t)(w1 * c1.b + w2 * c2.b + w3 * c3.b) / 256;


   color->b = (unsigned __int16)(v58 * this->colorVertexList[indices[2]].b
   // Double color RGB values -- not sure why?
                              + v34 * this->colorVertexList[indices[0]].b
                              + v31 * this->colorVertexList[indices[1]].b) >> 8;


   uint32_t v49 = 2 * color->r;
   uint32_t v49 = 2 * color->r;
   uint32_t v50 = 2 * color->g;
   uint32_t v50 = 2 * color->g;
   uint32_t v51 = 2 * color->b;
   uint32_t v51 = 2 * color->b;
  // If MOHD.flags & 0x02, add CMapObj ambient color


   if (this->parent->header->flags & 0x2) {
   if (this->parent->header->flags & 0x2) {
Line 208: Line 222:


   }
   }
  // Clamp final color to 255


   color->r = v49 >= 0xFF ? 0xFF : v49;
   color->r = v49 >= 0xFF ? 0xFF : v49;
   color->g = v50 >= 0xFF ? 0xFF : v50;
   color->g = v50 >= 0xFF ? 0xFF : v50;
   color->b = v51 >= 0xFF ? 0xFF : v51;
   color->b = v51 >= 0xFF ? 0xFF : v51;
  // MOPY.flags & 0x01 -- what is this used for?


   *a5 = this->polyList[polyIdx].flags & 0x1;
   *a5 = this->polyList[polyIdx].flags & 0x1;

Revision as of 05:56, 6 October 2017

Lighting

Lighting for interior WMO groups is prebaked into vertex colors.

CMapObj::QueryLighting

In order to light entities like units, game objects, etc that exist within interior WMO groups, the game does the following:

  1. Query for the closest MOPY.
  2. Obtain the 3 relevant MOCV values for the MOPY.
  3. Create a CImVector color by interpolating the values based on the position of the entity relative to the MOPY (ie barycentric interpolation).

This queried color value is then fed in to the standard lighting logic.

Query with C3Segment

The following function is used to query lighting when the exact poly is not yet known. It uses a C3Segment to perform a ranged query against the BSP tree for relevant tris.

bool CMapObj::QueryLighting(CMapObj *this, uint32_t groupIndex, const C3Segment *seg, CImVector *color, bool *a5) {

  CMapObjGroup group = this->groupList[groupIndex];

  if (!this->unk6[16] || !(group->unk14 & 1) || group->flags & (SMOGroup::EXTERIOR | SMOGroup::EXTERIOR_LIT)) {

    return 0;

  }

  World::TriData::resultFlags = 0;
  World::TriData::nBatches = 0;
  World::TriData::nTriIndices = 0;
  World::TriData::nVertexIndices = 0;
  World::TriData::nMatrices = 0;

  float hitT = 1.0;

  // Query the BSP tree for the group to find appropriate tris

  bool triRes = CMapObjGroup::GetTris(group, seg, &hitT, 0, 0x8, (int)&a2 + 3, 0);

  if (!triRes) {

    return 0;

  }

  // Obtain point matching intersection between segment and tri

  C3Vector point;

  point.x = seg->start.x + hitT * (seg->end.x - seg->start.x);
  point.y = seg->start.y + hitT * (seg->end.y - seg->start.y);
  point.z = seg->start.z + hitT * (seg->end.z - seg->start.z);

  unsigned __int16 hitPoly = word_CD8094;

  bool lightRes = CMapObjGroup::QueryLighting(group, &point, hitPoly, color, a5);

  return lightRes;

}

Query with C3Vector and poly index

The following function is used to query lighting when the relevant poly is already known.

bool CMapObj::QueryLighting(CMapObj *this, uint32_t groupIndex, const C3Vector *point, uint16_t polyIdx, CImVector *color, bool *a5) {

  CMapObjGroup group = this->groupList[groupIndex];

  if (!this->unk6[16] || !(group->unk14 & 1) || group->flags & (SMOGroup::EXTERIOR | SMOGroup::EXTERIOR_LIT)) {

    return 0;

  }

  // Since the point and poly are already known, there's no need to query the BSP tree

  bool lightRes = CMapObjGroup::QueryLighting(group, point, polyIdx, color, a5);

  return lightRes;

}

CMapObjGroup::QueryLighting

bool CMapObjGroup::QueryLighting(CMapObjGroup *this, const C3Vector *point, uint16_t polyIdx, CImVector *color, bool *a5) {

  // Poly is out of bounds

  if (polyIdx >= this->polyCount) {

    *color = this->parent->ambColor;
    *a5 = 0;

    return 1;

  }

  // Load xyAxisTable

  if (!(dword_D2DC18 & 1)) {

    dword_D2DC18 |= 1u;

    xyAxisTable[0] = { 1, 2 };
    xyAxisTable[1] = { 2, 0 };
    xyAxisTable[2] = { 0, 1 };

  }

  uint16_t* indices = &this->indexList[3 * polyIdx];

  C3Vector* vertices = this->vertexList;

  C3Vector* vert1 = &vertices[indices[0]];
  C3Vector* vert2 = &vertices[indices[1]];
  C3Vector* vert3 = &vertices[indices[2]];

  // Obtain normal for poly

  C4Plane plane;
  C4Plane::From3Pos(&plane, vert1, vert2, vert3);

  C3Vector::EAxis majAxis = C3Vector::MajorAxis(&plane.normal);

  // Obtain 2d coordinates for point and poly

  C2iVector xy = xyAxisTable[majAxis];

  C2Vector pt = { ((float *)(&point))[xy.x], ((float *)(&point))[xy.y] };
  C2Vector v1 = { ((float *)(&vert1))[xy.x], ((float *)(&vert1))[xy.y] };
  C2Vector v2 = { ((float *)(&vert2))[xy.x], ((float *)(&vert2))[xy.y] };
  C2Vector v3 = { ((float *)(&vert3))[xy.x], ((float *)(&vert3))[xy.y] };

  // Calculate barycentric weights
  // https://stackoverflow.com/a/26567573/6770172

  C2Vector sv2 = { v2.x - v1.x, v2.y - v1.y };
  C2Vector sv3 = { v3.x - v1.x, v3.y - v1.y };
  C2Vector spt = { pt.x - v1.x, pt.y - v1.y };

  // total area = cross(sub(v2, v1), sub(v3, v1))
  float at = sv2.x * sv3.y - sv2.y * sv3.x;

  // a3 = cross(sub(v2, v1), sub(pt, v1)) / total area
  float a3 = (sv2.x * spt.y - sv2.y * spt.x) / at;

  // a2 = cross(sub(pt, v1), sub(v3, v1)) / total area
  float a2 = (spt.x * sv3.y - spt.y * sv3.x) / at;

  // Calculate color weights

  int w3 = (a3 * 256.0) - 0.5;
  int w2 = (a2 * 256.0) - 0.5;
  int w1 = 256 - w3 - w2;

  // Adjust weights in cases where point is outside poly

  if (w3 < 0) {

    int o3 = (w3 * w2) / (w1 + w2);

    w2 += o3;
    w1 += w3 - o3;

    w3 = 0;

  }

  if (w2 < 0) {

    int o2 = (w2 * w3) / (w1 + w3);

    w3 += o2;
    w1 += w2 - o2;

    w2 = 0;

  }

  if (w1 < 0) {

    int o1 = (w1 * w2) / (w2 + w3);

    w2 += o1;
    w3 += w1 - o1;

    w1 = 0;

  }

  CImVector c1 = this->colorVertexList[indices[0]];
  CImVector c2 = this->colorVertexList[indices[1]];
  CImVector c3 = this->colorVertexList[indices[2]];

  // Interpolate color by weight

  color->a = (uint16_t)(w1 * c1.a + w2 * c2.a + w3 * c3.a) / 256;
  color->r = (uint16_t)(w1 * c1.r + w2 * c2.r + w3 * c3.r) / 256;
  color->g = (uint16_t)(w1 * c1.g + w2 * c2.g + w3 * c3.g) / 256;
  color->b = (uint16_t)(w1 * c1.b + w2 * c2.b + w3 * c3.b) / 256;

  // Double color RGB values -- not sure why?

  uint32_t v49 = 2 * color->r;
  uint32_t v50 = 2 * color->g;
  uint32_t v51 = 2 * color->b;

  // If MOHD.flags & 0x02, add CMapObj ambient color

  if (this->parent->header->flags & 0x2) {

    v49 += this->parent->ambColor.r;
    v50 += this->parent->ambColor.g;
    v51 += this->parent->ambColor.b;

  }

  // Clamp final color to 255

  color->r = v49 >= 0xFF ? 0xFF : v49;
  color->g = v50 >= 0xFF ? 0xFF : v50;
  color->b = v51 >= 0xFF ? 0xFF : v51;

  // MOPY.flags & 0x01 -- what is this used for?

  *a5 = this->polyList[polyIdx].flags & 0x1;

  return 1;

}