XML Exporter: 노멀값 적용

램버트 조명을 적용하기 맥스익스포트시 노멀값을 저장하고 뷰어에서 노멀값을 읽고 셰이더에서 램버트 조명을 이용해 면에 명암을 표시 한다.

< 맥스 플러그인 노멀값 추출 >

법선 벡터를 추출하기 위해 Mesh::BuildNormals()를 실행한다. 법선벡터는 "Normal"노드를 만들고 저장한다.
Point3 v = Normalize( pMesh->getNormal(i) ) 정점갯수만큼 노드를 구한다.

XmlExp* Export::WriteBaseMesh( INode* pNode, XmlExp* pParentXML )

{

    ............

    //노멀값

    pMesh->buildNormals();

    XmlNode* pXmlNormalNode = CreateXmlNode<XmlExp>( "Normal" );

    pXmlMeshNode->AttachChild( pXmlNormalNode );

    pXmlNormalNode->AddAttribute( "count", ToString( numVertex ).c_str() );

    for (int i=0; i < numVertex; ++i)

    {

        //노멀값 추출

        Point3 v = Normalize( pMesh->getNormal(i) );   

 

        if( GetLeftHand() )

        {

            float temp = v.y;

            v.y = v.z;

            v.z = temp;

        }

 

        base::Vector3 pos( v.x, v.y, v.z );

        pXmlNormalNode->AttachChild( CreateXmlNode<XmlExp>( "data" ) )->SetData( ToString(pos) );

    }

    ..........

}

< 뷰어에 노멀 추가 >

ConvertMeshInfo()에서 Normal 정보를 읽는다.

void XmlMesh::ConvertMeshInfo()

{

    ..........   

    //메쉬 노멀값 읽기

    XmlNode* pNormalXmlNode = FindFirstChild( "Normal" );

    if( pNormalXmlNode == NULL )

        return;

    pXmlMesh = (XmlMesh*)pNormalXmlNode;

    pXmlMesh->FetchNormal( GetParent()->m_vertexArr );

    ..........

}

 

void XmlMesh::FetchNormal( std::vector<VertexInfo>& vertexArr )

{

    //"Normal" 엘리먼트 - "count" 속성 구하기

    int number = GetIntAttribute( this, "count" );

    if( number < 3 )

        return;

 

    //"Normal" 엘리먼트 "data" 엘리먼트 구하기

    XmlNodeVector nodeArr;

    FindChild( "data", nodeArr );

    if( nodeArr.size() != number )

        return;

 

    XmlNodeVector::iterator iter = nodeArr.begin();

    XmlNodeVector::iterator endIter = nodeArr.end();

    for( int index = 0; iter != endIter; ++iter, ++index )

    {

        XmlNode* xmlNode = *iter;

        vertexArr[index].n = ToVector3( *xmlNode->GetData() );

    }

}

메시 정점 구조체 선언

struct ShaderBlendVertex

{

    D3DXVECTOR3    p;            //메시의 정점

 

    FLOAT        weight[3];        // BLEND WEIGHT

    BYTE        boneIndex[4];    // MATRIX Index

 

    D3DXVECTOR3        n;            //메시의 노멀값

 

    ShaderBlendVertex() : p(0,0,0), n(0, 0, 0)

    {

        boneIndex[0] = boneIndex[1] = boneIndex[2] = boneIndex[3] = 0;

        weight[0] = weight[1] = weight[2] = 0;

    }

 

    enum {    FVF = (D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4 | D3DFVF_NORMAL),    };

};

정점 버퍼 생성

int EShaderBoneMesh::CreateVertexBuffer( XmlNode* pXmlNode )

{

    ..............

    for( int i = 0; i < n; ++i )

    {

        ..............               

        m_pMeshVerts[i].n.x = xmlVx[i].n.x;

        m_pMeshVerts[i].n.y = xmlVx[i].n.y;

        m_pMeshVerts[i].n.z = xmlVx[i].n.z;

        ..............

    }

}

램버트 조명 공식으로 셰이더 계산

float    Ks = 0.1f;

float    Kd = 0.8f;

float    Ka = 1.0f;

float4    specular = { 1, 1, 1, 1};

float4  diffuse = { 0.7f, 0.7f, 0.7f, 1 };

float4  ambient = { 0.5f, 0.5f, 0.5f, 1 };

float4  lightDir = { 0.5f, -0.5f,0.5f, 1 };

float    n_specular = 1;

 

struct VsOut

{

    float4    Pos: POSITION;

    float4    Diff: COLOR0;   

    float4  Spec: COLOR1;

};

 

VsOut VtxBlend(float4 Pos: POSITION, float4 Wgt: BLENDWEIGHT, int4 Idx: BLENDINDICES, float3 Nor: NORMAL)

{

    .............

    Out.Pos = Pout;

    float3 vNormal = mul( Nor, m_mtViw);

    float4 vLight = -lightDir;

    Out.Diff = ambient*Ka + diffuse*Kd*max(0, dot(vNormal, vLight ) );

 

    float3 Pview = mul( Pout, mtW );

    float3 vView = -normalize( Pview );

    float3 vReflect = normalize(2*dot(vNormal, vLight ) * vNormal - vLight);

    Out.Spec = specular*Ks*pow( max(0, dot(vReflect, vView)), n_specular);

    return Out;

}

맥스 플러그인 프로젝트: maxProject_normal.zip
뷰어 프로젝트: viewer_normal.zip