FBX网格,材质和纹理
FBX网格,材质和纹理
本节介绍FBX SDK中的网格,纹理和材质。
一.网格
网格由FbxMesh类抽象。 FbxMesh定义了一个控制点列表,在普通文献中也称为顶点。 FbxMesh的单个实例可以绑定到FbxNode的多个实例,以减少内存消耗。这称为实例化。场景几何使用图层和图层元素(FbxLayerElement)的概念来定义法线贴图,材质贴图,纹理贴图等。
1.实例化-共享网格
为了减少内存需求,可以将FbxMesh的单个实例绑定到FbxNode的多个实例。 想象一下,您需要一个程序,其中所有多维数据集看起来都一样,但是您需要成千上万个多维数据集。 您可以在程序启动时通过创建一个FbxMesh对象来节省内存。 然后,每次需要一个新的多维数据集时,都将创建一个新的FbxNode对象,然后将该节点指向一个网格。 这称为实例化。
通常,可以通过让许多节点对象共享一个节点属性对象(即,FbxNodeAttribute的任何子类的一个对象)来节省内存。 以下功能说明了如何将FbxMesh绑定到新创建的节点。
// Create a cube instance with the given mesh as node attribute, and add it to the scene.
FbxNode* CreateCubeInstance(FbxScene* pScene, const char* pName, FbxMesh* pFirstCube)
{
// create a FbxNode
FbxNode* lNode = FbxNode::Create(pScene,pName);
// set the node attribute
lNode->SetNodeAttribute(pFirstCube);
// rescale the cube
lNode->LclScaling.Set(FbxVector4(0.3, 0.3, 0.3));
// Add node to the scene
pScene->GetRootNode()->AddChild(lNode);
// return the FbxNode
return lNode;
}
每个节点都是网格,NURBS或其他场景元素的一个实例。 如果将场景导出到FBX文件,则实例化还可以减小文件大小。 您还可以通过让多个节点共享纹理,材质,动画曲线等来节省内存。
二.材质
材质(FbxSurfaceLambert,FbxSurfacePhong)通过FbxNode :: AddMaterial()绑定到FbxNode的实例。材质定义了场景中几何图形的基本渲染特性,例如其漫反射,环境和发光颜色属性。每种材质在FbxNode中占据特定的索引,FbxMesh :: BeginPolygon()可以引用该索引来定义新创建的多边形的材质。
1.使用硬件着色器创建材质
从2010版开始,FBX SDK支持CGFX和DirectX硬件着色器。您可以使用FbxImplementation类和FbxBindingTable类使用CGFX或DirectX实现来设置材质。
三.贴图
纹理(FbxFileTexture,FbxLayeredTexture,FbxProceduralTexture)连接到材质通道,以定义如何渲染几何图形。 FbxFileTexture类使用文件中包含的数据(例如.jpg)来定义纹理的值。
1.分层纹理
在本教程主题中,我们介绍如何使用FbxLayeredTexture来分层FbxFileTexture的四个实例。 我们还扩展了FbxLayerElement的概念,以定义网格的法线和UV坐标。 本主题中的代码是用Python编写的,它直接适用于C ++。
示例:对四个纹理进行分层
所需资源:从左到右:“ one.jpg”,“ two.jpg”,“ three.jpg”,“ four.jpg”。 请注意,这些文件的宽度和高度是2的倍数(128x128),建议用于纹理尺寸。
示例输出:该屏幕快照是在运行Python程序并将导入的.fbx文件导入Autodesk MotionBuilder之后获得的。
程序摘要:下面的Python程序创建一个场景并将其导出到.fbx文件。 该场景包含使用FbxLayeredTexture实例进行纹理处理的平面网格。 FbxLayeredTexture的此实例由FbxFileTexture的四个累加混合实例组成。 FbxLayeredTexture连接到FbxSurfaceLambert实例的diffuse属性。 如下图所示,此FbxSurfaceLambert实例已添加到FbxNode的材料列表中。
平面FbxMesh设置为FbxNode的属性。 使用FbxLayerElementNormal和FbxLayerElementUV在该网格的第0个FbxLayer中设置其法线值和UV坐标。 当以“ 0”作为参数调用FbxMesh.BeginPolygon()时,材料将绑定到平面多边形。 此0表示父FbxNode的材料列表中包含的(唯一)材料,即前面提到的FbxSurfaceLambert。
注意:要成功运行此Python程序,请确保上面的四个.jpg图像在执行时与此Python程序位于同一文件夹中。
'''
layeredTextures.py
> creates a plane in the scene whose four textures are layered
one on top of another.
> requires texture files: one.jpg, two.jpg, three.jpg, four.jpg
'''
import fbx
import FbxCommon
vertices = [fbx.FbxVector4( -5, -5, 0 ), # 0 - vertex index.
fbx.FbxVector4( 5, -5, 0 ), # 1
fbx.FbxVector4( 5, 5, 0 ), # 2
fbx.FbxVector4( -5, 5, 0 )] # 3
normalPosZ = fbx.FbxVector4( 0, 0, 1 ) # positive-Z normal vector.
# Define the filename and alpha transparency of each texture.
textureFilenames = [ ( 'one.jpg', 0.2 ),
( 'two.jpg', 0.5 ),
( 'three.jpg', 0.4 ),
( 'four.jpg', 1.0 ) ]
saveFilename = 'layeredTextures.fbx'
###############################################################
# Helper Function(s). #
###############################################################
def createPlane(pScene):
''' Create a planar polygon as a child to the root node. '''
rootNode = pScene.GetRootNode()
#======================================================
# Node definition and mesh object creation.
#======================================================
# Create the node.
newNode = fbx.FbxNode.Create( pScene, 'planeNode' )
rootNode.AddChild( newNode )
# Create the mesh node attribute.
newMesh = fbx.FbxMesh.Create( pScene, 'planeMesh' )
newNode.SetNodeAttribute( newMesh )
# Create a Lambertian material and assign it to the mesh's node.
applyLambertMaterial( pScene, newNode )
# Create and apply the layered texture.
applyLayeredTexture( pScene, newNode )
# Set the node's shading mode to view textures.
newNode.SetShadingMode( fbx.FbxNode.eTextureShading )
#======================================================
# Control points.
#======================================================
# Define the vertices of the polygon.
global vertices
newMesh.InitControlPoints( 4 )
newMesh.SetControlPointAt( vertices[0], 0 )
newMesh.SetControlPointAt( vertices[1], 1 )
newMesh.SetControlPointAt( vertices[2], 2 )
newMesh.SetControlPointAt( vertices[3], 3 )
#======================================================
# Normals.
#======================================================
# For normals and UV coordinates, we will be using the
# Layer indexed at 0. If it doesn't exist, we will create it.
layer = newMesh.GetLayer( 0 )
if( not layer ):
newMesh.CreateLayer()
layer = newMesh.GetLayer( 0 )
# Create a normal layer element.
normalLayerElement = fbx.FbxLayerElementNormal.Create( newMesh, 'normals' )
# We want to have one normal for each vertex (or control point), # so we set the mapping mode to eByControlPoint
normalLayerElement.SetMappingMode( fbx.FbxLayerElement.eByControlPoint )
# Set the normal values for every control point.
normalLayerElement.SetReferenceMode( fbx.FbxLayerElement.eDirect )
global normalPosZ # positive-Z normals.
normalLayerElement.GetDirectArray().Add( normalPosZ )
normalLayerElement.GetDirectArray().Add( normalPosZ )
normalLayerElement.GetDirectArray().Add( normalPosZ )
normalLayerElement.GetDirectArray().Add( normalPosZ )
# Assign the normal layer element to the mesh's layer 0.
layer.SetNormals( normalLayerElement )
#======================================================
# Diffuse Channel UV Coordinates.
#======================================================
# Given that we are only dealing with one polygon (a square plane),
# we can simplify the code and map the uv coordinates directly to the
# four polygon control points.
uvDiffuseLayerElement = fbx.FbxLayerElementUV.Create( newMesh, 'diffuseUV' )
uvDiffuseLayerElement.SetMappingMode( fbx.FbxLayerElement.eByPolygonVertex )
uvDiffuseLayerElement.SetReferenceMode( fbx.FbxLayerElement.eDirect )
# Populate the direct array.
uv0 = fbx.FbxVector2( 0, 0 )
uv1 = fbx.FbxVector2( 1, 0 )
uv2 = fbx.FbxVector2( 1, 1 )
uv3 = fbx.FbxVector2( 0, 1 )
uvDiffuseLayerElement.GetDirectArray().Add( uv0 )
uvDiffuseLayerElement.GetDirectArray().Add( uv1 )
uvDiffuseLayerElement.GetDirectArray().Add( uv2 )
uvDiffuseLayerElement.GetDirectArray().Add( uv3 )
# Assign the uv layer element to the mesh's layer 0.
layer.SetUVs( uvDiffuseLayerElement, fbx.FbxLayerElement.eTextureDiffuse )
#======================================================
# Polygon Definition.
#======================================================
# Create one planar polygon.
# > The 0 in FbxMesh.BeginPolygon() refers to the index of the material to be
# applied to the polygon. Since we only have one material applied to our FbxNode,
# we use index 0.
newMesh.BeginPolygon( 0 )
for i in range( 0, 4 ):
newMesh.AddPolygon( i )
newMesh.EndPolygon()
return newNode
def applyLambertMaterial( pScene, pNode ):
''' Apply a Lambertian material to the node. '''
black = fbx.FbxDouble3( 0, 0, 0 )
white = fbx.FbxDouble3( 1, 1, 1 )
material = fbx.FbxSurfaceLambert.Create( pScene, 'myMaterial' )
material.ShadingModel.Set( 'Lambert' ) # could also use 'Phong' if we were using an instance of FbxSurfacePhong
material.Emissive.Set( black )
material.Ambient.Set( white )
material.Diffuse.Set( white )
material.TransparencyFactor.Set( 0 )
pNode.AddMaterial( material )
def applyLayeredTexture( pScene, pNode ):
''' Apply a layered texture on the node using the given texture filenames. '''
global textureFilenames
textures = []
# Create the individual texture objects to be layered afterwards.
for i in range( 0, len( textureFilenames ) ):
textureFilename = textureFilenames[i][0]
textureAlpha = textureFilenames[i][1]
newTexture = fbx.FbxFileTexture.Create( pScene, 'myFileTexture_' + str( i ) )
newTexture.SetFileName( textureFilename )
newTexture.SetTextureUse( fbx.FbxTexture.eStandard )
newTexture.SetMappingType( fbx.FbxTexture.eUV )
newTexture.SetMaterialUse( fbx.FbxFileTexture.eModelMaterial )
newTexture.SetSwapUV( False )
newTexture.SetTranslation( 0.0, 0.0 )
newTexture.SetScale( 1.0, 1.0 )
newTexture.SetRotation( 0.0, 0.0 )
newTexture.Alpha.Set( textureAlpha )
textures.append( newTexture )
# Create the layered texture object, and layer the textures within it.
layeredTexture = fbx.FbxLayeredTexture.Create( pScene, 'myLayeredTexture' )
for i in range( 0, len( textures ) ):
texture = textures[ i ]
layeredTexture.ConnectSrcObject( texture )
layeredTexture.SetTextureBlendMode( i, fbx.FbxLayeredTexture.eAdditive )
# Connect the layered texture to the node's material indexed at 0.
# The layered texture is connected on the material's diffuse channel.
material = pNode.GetMaterial( 0 )
material.Diffuse.ConnectSrcObject( layeredTexture )
###############################################################
# Main. #
###############################################################
def main():
''' Main Program. '''
fbxManager = fbx.FbxManager.Create()
fbxScene = fbx.FbxScene.Create( fbxManager, '' )
# Create the textured planar mesh.
newNode = createPlane( fbxScene )
# Save the file.
global saveFilename
FbxCommon.SaveScene( fbxManager, fbxScene, saveFilename, pEmbedMedia=True )
# Clean up.
fbxManager.Destroy()
del fbxManager, fbxScene, newNode
if __name__ == '__main__':
main()
本节中的主题
网格
材质
贴图