2008. 7. 21. 11:10

데칼에 범프맵 적용하는 작업을 하려다 보니

엔진에 데칼을 붙이이 작업을 저번에 한번 해서 이번에 그래픽파트 요구사항으로

데칼에 범프맵을 적용하게 되었습니다. 맥스에서 익스포트하는 유닛을은 탄젠트가 그냥 빠져서 편할것 같은데, 데칼은 직접 탄젠트를 구해줘야 할것 같아서, 책을 뒤적거라다가 인터넷에서 다음과 같은 페이지를 찻았습니다.

http://www.terathon.com/code/tangent.html

Computing Tangent Space Basis Vectors for an Arbitrary Mesh

흠... 위에부분만 보고 책에 나온거랑 완전 똑같다면서 욕하고 있었는데 아랬부분에 왠 쏘스가???

우왕ㅋ 굿ㅋ

Computing Tangent Space Basis Vectors for an Arbitrary Mesh

Modern bump mapping (also known as normal mapping) requires that tangent plane basis vectors be calculated for each vertex in a mesh. This article presents the theory behind the computation of per-vertex tangent spaces for an arbitrary triangle mesh and provides source code that implements the proper mathematics.

Mathematical Derivation

[This derivation also appears in Mathematics for 3D Game Programming and Computer Graphics, 2nd ed., Section 6.8.]

We want our tangent space to be aligned such that the x axis corresponds to the u direction in the bump map and the y axis corresponds to the v direction in the bump map. That is, if Q represents a point inside the triangle, we would like to be able to write

QP0 = (uu0)T + (vv0)B,

where T and B are tangent vectors aligned to the texture map, P0 is the position of one of the vertices of the triangle, and (u0, v0) are the texture coordinates at that vertex. The letter B stands for bitangent, but in many places it is stilled called binormal because of a mix-up in terms when tangent-space bump mapping first became widespread. (See “Bitangent versus Binormal” below.)

Suppose that we have a triangle whose vertex positions are given by the points P0, P1, and P2, and whose corresponding texture coordinates are given by (u0, v0), (u1, v1), and (u2, v2). Our calculations can be made much simpler by working relative to the vertex P0, so we let

Q1 = P1P0
Q2 = P2P0

and

(s1, t1) = (u1u0, v1v0)
(s2, t2) = (u2u0, v2v0).

We need to solve the following equations for T and B.

Q1 = s1T + t1B
Q2 = s2T + t2B

This is a linear system with six unknowns (three for each T and B) and six equations (the x, y, and z components of the two vector equations). We can write this in matrix form as follows.

  (Q1)x
(Q2)x
(Q1)y
(Q2)y
(Q1)z
(Q2)z
  =   s1
s2
t1
t2
      Tx
Bx
Ty
By
Tz
Bz
 

Multiplying both sides by the inverse of the (s, t) matrix, we have

  Tx
Bx
Ty
By
Tz
Bz
  = 1
s1t2s2t1
  t2
−s2
−t1
s1
      (Q1)x
(Q2)x
(Q1)y
(Q2)y
(Q1)z
(Q2)z
  .

This gives us the (unnormalized) T and B tangent vectors for the triangle whose vertices are P0, P1, and P2. To find the tangent vectors for a single vertex, we average the tangents for all triangles sharing that vertex in a manner similar to the way in which vertex normals are commonly calculated. In the case that neighboring triangles have discontinuous texture mapping, vertices along the border are generally already duplicated since they have different mapping coordinates anyway. We do not average tangents from such triangles because the result would not accurately represent the orientation of the bump map for either triangle.

Once we have the normal vector N and the tangent vectors T and B for a vertex, we can transform from tangent space into object space using the matrix

  Tx
Ty
Tz
Bx
By
Bz
Nx
Ny
Nz
  .

To transform in the opposite direction (from object space to tangent space—what we want to do to the light direction), we can simply use the inverse of this matrix. It is not necessarily true that the tangent vectors are perpendicular to each other or to the normal vector, so the inverse of this matrix is not generally equal to its transpose. It is safe to assume, however, that the three vectors will at least be close to orthogonal, so using the Gram-Schmidt algorithm to orthogonalize them should not cause any unacceptable distortions. Using this process, new (still unnormalized) tangent vectors T′ and B′ are given by

T′ = T − (N · T)N
B′ = B − (N · B)N − (T′ · B)T′

Normalizing these vectors and storing them as the tangent and bitangent for a vertex lets us use the matrix

  T′x
B′x
Nx
T′y
B′y
Ny
T′z
B′z
Nz
       (*)

to transform the direction to light from object space into tangent space. Taking the dot product of the transformed light direction with a sample from the bump map then produces the correct Lambertian diffuse lighting value.

It is not necessary to store an extra array containing the per-vertex bitangent since the cross product N × T′ can be used to obtain mB′, where m = ±1 represents the handedness of the tangent space. The handedness value must be stored per-vertex since the bitangent B′ obtained from N × T′ may point in the wrong direction. The value of m is equal to the determinant of the matrix in Equation (*). One may find it convenient to store the per-vertex tangent vector T′ as a four-dimensional entity whose w coordinate holds the value of m. Then the bitangent B′ can be computed using the formula

B′ = T′w(N × T′),

where the cross product ignores the w coordinate. This works nicely for vertex programs by avoiding the need to specify an additional array containing the per-vertex m values.

Bitangent versus Binormal

The term binormal is commonly used as the name of the second tangent direction (that is perpendicular to the surface normal and u-aligned tangent direction). This is a misnomer. The term binormal pops up in the study of curves and completes what is known as a Frenet frame about a particular point on a curve. Curves have a single tangent direction and two orthogonal normal directions, hence the terms normal and binormal. When discussing a coordinate frame at a point on a surface, there is one normal direction and two tangent directions, which should be called the tangent and bitangent.

Source Code

The code below generates a four-component tangent T in which the handedness of the local coordinate system is stored as ±1 in the w-coordinate. The bitangent vector B is then given by B = (N × T) · Tw.

#include "Vector4D.h"


struct Triangle
{
    unsigned short  index[3];
};


void CalculateTangentArray(long vertexCount, const Point3D *vertex, const Vector3D *normal,
        const Point2D *texcoord, long triangleCount, const Triangle *triangle, Vector4D *tangent)
{
    Vector3D *tan1 = new Vector3D[vertexCount * 2];
    Vector3D *tan2 = tan1 + vertexCount;
    ZeroMemory(tan1, vertexCount * sizeof(Vector3D) * 2);
    
    for (long a = 0; a < triangleCount; a++)
    {
        long i1 = triangle->index[0];
        long i2 = triangle->index[1];
        long i3 = triangle->index[2];
        
        const Point3D& v1 = vertex[i1];
        const Point3D& v2 = vertex[i2];
        const Point3D& v3 = vertex[i3];
        
        const Point2D& w1 = texcoord[i1];
        const Point2D& w2 = texcoord[i2];
        const Point2D& w3 = texcoord[i3];
        
        float x1 = v2.x - v1.x;
        float x2 = v3.x - v1.x;
        float y1 = v2.y - v1.y;
        float y2 = v3.y - v1.y;
        float z1 = v2.z - v1.z;
        float z2 = v3.z - v1.z;
        
        float s1 = w2.x - w1.x;
        float s2 = w3.x - w1.x;
        float t1 = w2.y - w1.y;
        float t2 = w3.y - w1.y;
        
        float r = 1.0F / (s1 * t2 - s2 * t1);
        Vector3D sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
                (t2 * z1 - t1 * z2) * r);
        Vector3D tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
                (s1 * z2 - s2 * z1) * r);
        
        tan1[i1] += sdir;
        tan1[i2] += sdir;
        tan1[i3] += sdir;
        
        tan2[i1] += tdir;
        tan2[i2] += tdir;
        tan2[i3] += tdir;
        
        triangle++;
    }
    
    for (long a = 0; a < vertexCount; a++)
    {
        const Vector3D& n = normal[a];
        const Vector3D& t = tan1[a];
        
        // Gram-Schmidt orthogonalize
        tangent[a] = (t - n * Dot(n, t)).Normalize();
        
        // Calculate handedness
        tangent[a].w = (Dot(Cross(n, t), tan2[a]) < 0.0F) ? -1.0F : 1.0F;
    }
    
    delete[] tan1;
}

How to cite this article

Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html

2008. 7. 19. 15:54

DXUT D3D 10 NVIDIA PerfHUD 6 Launcher 적용해보기

#if SHIPPING_VERSION
    // When building a shipping version, disable PerfHUD (opt-out)
    #else
    // Look for 'NVIDIA PerfHUD' adapter
    // If it is present, override default settings
   
    IDXGIFactory *pDXGIFactory;
    ID3D10Device *pDevice;
    HRESULT hRes;
    hRes = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pDXGIFactory);
   
    // Search for a PerfHUD adapter.
    UINT nAdapter = 0;
    IDXGIAdapter* adapter = NULL;
    IDXGIAdapter* selectedAdapter = NULL;
    D3D10_DRIVER_TYPE driverType = D3D10_DRIVER_TYPE_HARDWARE;

    while (pDXGIFactory->EnumAdapters(nAdapter, &adapter) != DXGI_ERROR_NOT_FOUND)
    {
     if (adapter)
     {
      DXGI_ADAPTER_DESC adaptDesc;
      if (SUCCEEDED(adapter->GetDesc(&adaptDesc)))
      { const bool isPerfHUD = wcscmp(adaptDesc.Description, L"NVIDIA PerfHUD") == 0;
     
      // Select the first adapter in normal circumstances or the PerfHUD one if it exists.
     
      if(nAdapter == 0 || isPerfHUD)
       selectedAdapter = adapter;
     
      if(isPerfHUD)
       driverType = D3D10_DRIVER_TYPE_REFERENCE;
      }
     }
     ++nAdapter;
    }
    #endif
   
    //if(FAILED(D3D10CreateDevice( selectedAdapter, driverType, NULL, 0, D3D10_SDK_VERSION, &pDevice))) return E_FAIL;

    // If D3D10.1 doesn't exist, then fallback to D3D10.0
                hr = DXUT_Dynamic_D3D10CreateDevice( selectedAdapter, driverType, NULL, 0, NULL, D3D10_SDK_VERSION, &pd3d10Device );

                //// If D3D10.1 doesn't exist, then fallback to D3D10.0
                //hr = DXUT_Dynamic_D3D10CreateDevice( pAdapter, pNewDeviceSettings->d3d10.DriverType, ( HMODULE )0,
                //                                     pNewDeviceSettings->d3d10.CreateFlags,
                //                                     NULL, D3D10_SDK_VERSION, &pd3d10Device );

일단 이렇게만 하니까 되긴 하던데 펌프후드 실행한뒤에 머가 재대로 안되는듯...
차후 수정해서 정보 갱신하겠습니다.

2008. 7. 19. 01:17

7월에 관악산에서 찍은 곤충

사용자 삽입 이미지



---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------
7월중 관악산 갔을때 찍었던 나비사진

이날 찍었던 사진중에 이 사진이 재일 맘에 든다. 색이 ^^;
---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------



사용자 삽입 이미지



---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------
풍댕이? 류같은데

검은 부분은 보정이 너무 힘든듯... 사실 사진 자체의 기본 상태가 좋지 못한점이 재일로 문제..ㅜ.ㅜ..
---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------



사용자 삽입 이미지