勾画轮廓边,描边总结的三角网格邻接信息
网格的绘制和拆分:可以先绘制网格,如果网格需要修饰那么需要拆分重组网格,那么需要深入了解网格的索引缓存,顶点缓存,邻接信息,属性子集材质和纹理,优化后的属性表等,这里主要讲邻接信息。
理解网格操作中重要的邻接信息:
邻接信息的是一个unsign int 数组就和顶点索引缓存一样,三个连续的下标确定一个 三角形如果当前传入一个三角形面片编号为i那么对应的邻接数组下标为(3*i, 3*i + 1, 3*i + 2), 邻接数组上面的值是当前边(当前顶点索引到下一个顶点索引)相邻的三角形面片的编号k1k2k3(没有则是-1或USHRT_MAX), 根据三角形面片编号k和顶点索引缓存下标(3*k, 3*k + 1, 3*k + 2)上的值得到三角形的三个顶点缓存的索引值,通过顶点缓存的索引值就可以得到顶点信息。(记住三角形面片编号总是和邻接数组,和顶点索引缓存数组对应的)。
例如:
for(int
i = 0; i < mesh->GetNumFaces(); i++)
{
WORD faceIndex0 = adj[i * 3];
WORD faceIndex1 = adj[i* 3 + 1];
WORD faceIndex2 = adj[i * 3 + 2];
// 得到了邻接三角形的编号,就可以得到邻接三角形的索引缓存值,从而得到顶点缓存值
if( faceIndex0 != USHRT_MAX ) // is there an adjacent triangle?
{
WORD i0 = indices[faceIndex0 * 3];
WORD i1 = indices[faceIndex0 * 3 + 1];
WORD i2 = indices[faceIndex0 * 3 + 2];
D3DXVECTOR3 v0 = vertices[i0].position;
D3DXVECTOR3 v1 = vertices[i1].position;
D3DXVECTOR3 v2 = vertices[i2].position;
}
// faceIndex1, faceIndex 2省略。
}
{
}
// faceIndex1, faceIndex 2省略。
}
/*需要知道当前操作的网格信息的类型,例如DX默认内置创建的物体的顶点结构,还需要取得或生产邻接信息用网格对象GenerateAdjacency得到,网格顶点结构如下:
struct
MeshVertex
{
D3DXVECTOR3
position;
D3DXVECTOR3
normal;
static
const DWORD FVF;
};
struct
EdgeVertex
{
D3DXVECTOR3
position;
D3DXVECTOR3
normal;
D3DXVECTOR3
faceNormal1;
D3DXVECTOR3
faceNormal2;
};
顶点声明:
IDirect3DVertexDeclaration9* _decl;
D3DVERTEXELEMENT9 decl[] =
{
// offsets in bytes
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
{0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 1},
{0, 36, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 2},
D3DDECL_END()
};
hr = _device->CreateVertexDeclaration(decl, &_decl);
if(FAILED(hr))
{
::MessageBox(0, "CreateVertexDeclaration() - FAILED", 0, 0);
return false;
}
void SilhouetteEdges::render()
{
// 顶点声明的使用,是和顶点着色器或像素着色器,输入相对应的,例如见EdgeVertex
_device->SetVertexDeclaration(_decl);
_device->SetStreamSource(0, _vb, 0, sizeof(EdgeVertex));
_device->SetIndices(_ib);
_device->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST, 0, 0, _numVerts, 0, _numFaces);
}
d3d::Release<IDirect3DVertexDeclaration9*>(_decl);
*///
(1).从边考虑(而不是顶点),每条边有4个顶点;非轮廓边因为是退化四边形得到的退化三角形不会被绘制,轮廓边是经过移动后的三角形
//
所以会绘制。
//
(2).轮廓边需要其中两个顶点产生偏移,另外两个顶点不动而生成三角形,渲染该三角形就得到描边。
//
(3).判断是否是轮廓边,通过物体顶点在摄像机空间中的位置向量(就是顶点到摄像机原点的向量)和边构造的4个顶点中的每个顶点的
//
当前三角形法向量和邻接边三角形法向量进行点乘,如果两个点乘后的值符号相反那么是轮廓边需要对顶点沿着顶点法向量方向平移并着色,
//
如果相同那么是非轮廓边,不需要平移当做退化三角形来处理。例如:
//extern
matrix WorldViewMatrix;
//extern
matrix ProjMatrix;
//
//static
vector Black = {0.9f, 0.0f, 0.0f, 0.0f};
//
////
////
Structures
////
//
//struct
VS_INPUT
//{
//
vector position : POSITION;
//
vector normal : NORMAL0;
//
vector faceNormal1 : NORMAL1;
//
vector faceNormal2 : NORMAL2;
//};
//
//struct
VS_OUTPUT
//{
//
vector position : POSITION;
//
vector diffuse : COLOR;
//};
//
////
////
Main
////
//
//VS_OUTPUT
Main(VS_INPUT input)
//{
//
// zero out each member in output
//
VS_OUTPUT output = (VS_OUTPUT)0;
//
//
// transform position to view space
//
input.position = mul(input.position, WorldViewMatrix);
//
//
// Compute a vector in the direction of the vertex
//
// from the eye. Recall the eye is at the origin
//
// in view space - eye is just camera position.
//
vector eyeToVertex = input.position;
//
//
// transform normals to view space. Set w
//
// components to zero since we're transforming vectors.
//
// Assume there are no scalings in the world
//
// matrix as well.
//
input.normal.w = 0.0f;
//
input.faceNormal1.w = 0.0f;
//
input.faceNormal2.w = 0.0f;
//
//
input.normal = mul(input.normal, WorldViewMatrix);
//
input.faceNormal1 = mul(input.faceNormal1, WorldViewMatrix);
//
input.faceNormal2 = mul(input.faceNormal2, WorldViewMatrix);
//
//
// compute the cosine of the angles between
//
// the eyeToVertex vector and the face normals.
//
float dot0 = dot(eyeToVertex, input.faceNormal1);
//
float dot1 = dot(eyeToVertex, input.faceNormal2);
//
//
// if cosines are different signs (positive/negative)
//
// than we are on a silhouette edge. Do the signs
//
// differ?
//
if( (dot0 * dot1) < 0.0f )
//
{
//
// yes, then this vertex is on a silhouette edge,
//
// offset the vertex position by some scalar in the
//
// direction of the vertex normal.
//
input.position += 0.05f * input.normal;
//
}
//
//
// transform to homogeneous clip space
//
output.position = mul(input.position, ProjMatrix);
//
//
// set outline color
//
output.diffuse = Black;
//
//
return output;
//}
//
(4).从网格信息和邻接信息对象中构建边的顶点缓存和索引缓存,邻接信息真正的有用关系,邻接信息和索引缓存大小一样,且和索引缓存对应,邻接信息缓存key是和索引缓存一样(概念为边),
//
value没有DX中是USHRT_MAX,有是和当前三角形相邻的三角形编号,该编号代表索引下标3*value, 3*value + 1, 3*value + 2代表的
//
三角形,而索引上的value代表的是顶点缓存的key,这样可以通过邻接信息是可以获取到相邻的三角形的顶点信息的。例如:
//
//
for(int i = 0; i < mesh->GetNumFaces(); i++)
//
{
//
// 根据当前的面片信息,获取当前的缓存信息,因为索引缓存和三角形的关系是,索引下标(3*i, 3*i + 1, 3*i + 2)确定当前编号为i的三角形
//
WORD index0 = indices[i * 3];
//
WORD index1 = indices[i * 3 + 1];
//
WORD index2 = indices[i* 3 + 2];
//
//
// Now extract the triangles vertices positions
//
// 索引缓存上的值是顶点缓存的下标,通过顶点缓存得到顶点信息
//
D3DXVECTOR3 v0 = vertices[index0].position;
//
D3DXVECTOR3 v1 = vertices[index1].position;
//
D3DXVECTOR3 v2 = vertices[index2].position;
//
//
// 根据当前的面片信息,得到当前的邻接信息,因为邻接信息和索引缓存对应的,邻接信息下标(3*i, 3*i + 1, 3*i + 2)确定当前编号为i的三角形
//
// 邻接信息上的值是代表当前三角形边,相邻的三角形的编号。
//
WORD faceIndex0 = adj[i * 3];
//
WORD faceIndex1 = adj[i* 3 + 1];
//
WORD faceIndex2 = adj[i * 3 + 2];
//
// 得到了邻接三角形的编号,就可以得到邻接三角形的索引缓存值,从而得到顶点缓存值
//
if( faceIndex0 != USHRT_MAX ) // is there an adjacent triangle?
//
{
//
WORD i0 = indices[faceIndex0 * 3];
//
WORD i1 = indices[faceIndex0 * 3 + 1];
//
WORD i2 = indices[faceIndex0 * 3 + 2];
//
//
D3DXVECTOR3 v0 = vertices[i0].position;
//
D3DXVECTOR3 v1 = vertices[i1].position;
//
D3DXVECTOR3 v2 = vertices[i2].position;
//
//
D3DXVECTOR3 edge0 = v1 - v0;
//
D3DXVECTOR3 edge1 = v2 - v0;
//
D3DXVec3Cross(&faceNormal0, &edge0, &edge1);
//
D3DXVec3Normalize(&faceNormal0, &faceNormal0);
//
}
//
}
//
(5). 索引缓存可以通过观察顶点缓存的规律,顶点缓存是四个顶点进行排序的,那么四个顶点的索引缓存就要6个索引,且他们之间是有相关
//
顺序的,例如:
//void
SilhouetteEdges::genEdgeIndices(ID3DXMesh* mesh)
//{
//
DWORD numEdges = mesh->GetNumFaces() * 3;
//
//
_numFaces = numEdges * 2;
//
//
_device->CreateIndexBuffer(
//
numEdges * 6 * sizeof(WORD), // 2 triangles per edge
//
D3DUSAGE_WRITEONLY,
//
D3DFMT_INDEX16,
//
D3DPOOL_MANAGED,
//
&_ib,
//
0);
//
//
WORD* indices = 0;
//
//
_ib->Lock(0, 0, (void**)&indices, 0);
//
//
// 0 1
//
// *--------*
//
// | edge |
//
// *--------*
//
// 2 3
//
//
for(UINT i = 0; i < numEdges; i++)
//
{
//
// Six indices to define the triangles of the edge,
//
// so every edge we skip six entries in the
//
// index buffer. Four vertices to define the edge,
//
// so every edge we skip four entries in the
//
// vertex buffer.
//
indices[i * 6] = i * 4 + 0;
//
indices[i * 6 + 1] = i * 4 + 1;
//
indices[i * 6 + 2] = i * 4 + 2;
//
indices[i * 6 + 3] = i * 4 + 1;
//
indices[i * 6 + 4] = i * 4 + 3;
//
indices[i * 6 + 5] = i * 4 + 2;
//
}
//
//
_ib->Unlock();
//}
//(7)启用顶点着色器和绘制轮廓边,之前的正常网格正常绘制,轮廓边后面绘制
//
Device->SetVertexShader(ToonShader);
//Device->SetTexture(0,
ShadeTex);
//Meshes[i]->DrawSubset(0);
//
//Device->SetVertexShader(OutlineShader);
//Device->SetTexture(0,
0);
//OutlineConstTable->SetMatrix(
//
Device,
//
OutlineWorldViewHandle,
//
&worldView);
//
//OutlineConstTable->SetMatrix(
//
Device,
//
OutlineProjHandle,
//
&ProjMatrix);
//
//MeshOutlines[i]->render();
671

被折叠的 条评论
为什么被折叠?



