??xml version="1.0" encoding="utf-8" standalone="yes"?>
注意图中的红U和l线Q红U是当前骨骼与目标骨骼的q线Q绿U是目标骨骼与最l位|的q线?br />从子骨骼到父骨骼的顺序P代计,旋{U线到绿Uѝ这样多q代几次׃得到较好的结果?br />
要注意的是需要对骨骼的旋转范围加以限Ӟ因ؓZ的关节不是以可以L方式旋{的?br />
[例如图中蓝色部分为可以旋转的范围]
]]>
N我的昑֍不支持BLENDINDICES和BLENDWEIGHT?
把BLENDINDICES和BLENDWEIGHT用TEXCOORD[n]表示才正常。?
不说废话Q直接上代码?nbsp; 阅读全文
]]>
效果比较单,只是模拟了下水面的反效果。折与FresnelpL没有考虑?br />
水面模拟大致需要分q么几步Q?br />1.剪裁掉水面以下的点[gpu里的clipplane要注意{换到Clip Space]Q?br />摄像机攑ֈ同原摄像机关于水面对U的位置Q比如原来摄像机?x,y,z)Q?br />此时p把摄像机攑֜(x,-y,z)Qup向量也要讄成向下的?br />再把场景渲染到Render Target的纹理上(我用的纹理大是256*256)Q不知道Z么Render Target的纹理大不能超q窗口大,过的话渲染会出错,知道的大大告诉我一下哈?br />
于是Q就得到了这样一个纹理:
2.上面得到的U理与水面的点对应.
把Vertex Shader中乘q变换矩阵后的坐标传到Pixel Shader,
在PS中计?br />
clipspace.x=((clipspace.x * 0.5f) + 0.5f);
clipspace.y = ((clipspace.y * -0.5f) + 0.5f);
clipspace.x=1-clipspace.x;
3.再渲染一ơ场景就可以了?br />
大家也可以参考下Azure的水面渲染源代码Q?a temp_href=" http://www.azure.com.cn/article.asp?id=186" href="%20http://www.azure.com.cn/article.asp?id=186">
http://www.azure.com.cn/article.asp?id=186
]]>
在过ȝ固定渲染道时代Q剪裁^面的实现较ؓ单,比如?/span> DirectX 9 中,可以先设定剪裁^面在世界坐标pM的方E?/span> (ax+by+cz+d=0) Q再调用 SetClipPlane(DWORD Index,CONST float * pPlane) q个 API 函数可以了?/span>
附上例子E序Q?/span>
vPosition=D3DXVECTOR3(0,0,0);
//
q面上一个点
vNormal=D3DXVECTOR3(0,1,0);
//
法向?span>
D3DXPlaneFromPointNormal( &clipplane, &vPosition, &vNormal );
//
生成剪裁q面
m_pDevice()->SetClipPlane( 0, (
float
*)clipplane);
然而,在现在的可编E管?/span> (programmable pipeline) 下,讄的剪裁^面会被在剪裁坐标pM处理Q而不是在世界坐标pM?/span>
解决q个问题的方法有Q?br />要将一个^面从世界坐标p{换到剪裁坐标p,必须求出q个变换矩阵?/span>
讑^面方E?/span>ax+by+cz+d=0Q用一?/span>4l向量来n表示(a,b,c,d)Q设q面上有个点p:(x,y,z,1)。根据^面方E的定义Q有Q?/span>
nTp = ax + by + cz + d = 0
讄?/span>R可以让点P从世界坐标系转换到剪裁坐标系Q矩?/span>Q可以让^?/span>n实现同样的变换。那么,有:
其中p'?/span>n'分别是{换后的点与^面?/span>
那么Q?/span>
nTQTRp = nTIp = nTp = 0
于是Q?/span>
?/span>DirectX 3D中,一个点从世界坐标系转换到剪裁坐标系Q所用的矩阵察矩阵与投媄矩阵的乘U,卻I
D3DXMATRIX TranMatrix = matView*matProj;
(TranMatrix为所求的变换矩阵Q?span>matView?span>matProj
分别?/span>观察矩阵与投q?/span>)
附上?/span>D3D中变换的完整代码Q?/span>
D3DXPLANE tempPlane = clipplane;
D3DXPlaneNormalize(&tempPlane, &tempPlane);
D3DXMATRIX TranMatrix = matView*matProj;
D3DXMatrixInverse(&TranMatrix, NULL, &TranMatrix);
D3DXMatrixTranspose(&TranMatrix, &TranMatrix);
D3DXPlaneTransform(&tempPlane, &tempPlane, &TranMatrix);
参考资料:
1.Back Face Culling Notes ,Jordan Smith (University of California, Berkeley)
http://www.cs.berkeley.edu/~ug/slide/pipeline/assignments/backfacecull.shtml
2.GameDev Forum
http://www.gamedev.net/community/forums/topic.asp?topic_id=402381
3.Oblique Near-Plane Clipping with Orthographic Camera ,Aras
http://aras-p.info/texts/obliqueortho.html
Ҏ一个简化的l计Qh脑由百亿条神l组?? 每条经q_q结到其它几千条经。通过q种q结方式Q神l可以收发不同数量的能量。神l的一个非帔R要的功能是它们对能量的接受ƈ不是立即作出响应Q? 是将它们累加hQ当q个累加的d辑ֈ某个临界阈值时Q它们将它们自己的那部分能量发送给其它的神l。大脑通过调节q些q结的数目和强度q行学习。尽? q是个生物行为的化描q。但同样可以充分有力地被看作是神l网l的模型?/p>
阈值逻辑单元QThreshold Logic UnitQTLUQ?/span>
理解经|络的第一步是从对抽象生物经开始,q把重点攑֜ 阈值逻辑单元QTLUQ?/em>q一特征上。一? TLU 是一个对象,它可以输入一l加权系数的量,对它们进行求和,如果q个和达到或者超q了某个阈|输出一个量? 让我们用W号标注q些功能Q首先,有输入g及它们的权系敎ͼX 1, X 2, ..., X n?W 1, W 2, ..., W n。接着是求和计出?X i*W i Q生了Ȁ发层 aQ换一U方法表C:
a = (X1 * W1)+(X2 * W2)+...+(Xi * Wi)+...+ (Xn * Wn)
阈值称?theta。最后,输出l果 y。当 a >=theta ?y=1Q反?
y=0。请注意输出可以是连l的Q因为它也可以由一?squash 函数 sQ或
sigmaQ判定,该函数的自变量是 aQ函数值在 0 ?1 之间Qy=s(a)?/p>
?1. 阈值逻辑单元Q带?sigma 函数Q顶部)?cutoff
函数Q底部)
TLU 会分c,假设一?TLU 有两个输入|它们的权pL{于 1Qtheta 值等?1.5。当q个 TLU 输入 <0,0>?lt;0,1>?lt;1,0> ?<1,1> Ӟ它的输出分别?0???。TLU 这些输入分Zl:0 l和 1 l。就像懂得逻辑q接Q布运? ANDQ的可以cM地将逻辑q接的句子分c那PTLU 也懂得一炚w辑q接之类的东ѝ?/p>
TLU 能够用几何学上的解释来阐明这U现象。它的四U可能输入对应于W卡图的四个点。从{式 X 1*W 1+ X 2*W 2 = thetaQ换句话_也即 TLU 转换其分c行为的点开始,它的炚w分布在曲U?X 2 = -X 1 + 1.5 上。这个方E的曲线?4 个可能的输入分成了两个对应于 TLU 分类的区域。这?TLU 原理中更为普通的实例。在 TLU 有Q意数目的 N 个输入的情况下,一l可能的输入对应?N l空间中的一个点集。如果这些点可以被超q面 ? 换句话说Q对应于上面CZ中的U的 N l的几何外Ş切割Q那么就有一l权pL和一个阈值来定义其分cd好与q个切割相匹配的 TLU?
既然 TLU 懂得分类Q它们就知道素材。神l网l也可假定ؓ可以学习。它们的学习机制是模仿大脑调节神l连l的原理。TLU 通过改变它的权系数和阈值来学习。实际上Q从数学的观点看Q权pL阈值的特征有点武断。让我们回想一下当 SUM(Xi * Wi) >= theta ?TLU 在界点时输出的?1 而不? 0Q这相当于说临界Ҏ出现?SUM(X i* W i)+ (-1 * theta) >= 0 的时候。所以,我们可以?-1 看成一个常量输入,它的权系?theta 在学习(或者用技术术语,UCؓ 培训Q的q程中进行调整。这P? SUM(X i* W i)+ (-1 * theta) >= 0 Ӟy=1Q反?y=0?
在培训过E中Q神l网l输入:
q样的输入可以看成一个向量:<X 1, X 2, ..., X n, theta, t>Q这?t 是一个目标或者正分cR神l网l用q些来调整权pLQ其目的使培训中的目标与其分cȝ匚w。更切地说Q这是有指导的培训,与之相反的是无指导的培训。前者是Z带目标的CZQ而后者却只是建立在统计分析的基础上。权pL的调整有一个学习规则,一个理惛_的学习算法如下所C:
fully_trained = FALSE |
您或许想知道Q?#8220;哪些培训规则Q?#8221;有很多,不过有一条似乎合理的规则是基于这样一U思想Q即权系数和阈值的调整应该由分? (t - y) 定。这个规则通过引入 alpha (0 < alpha < 1) 完成。我们把 alpha UCؓ 学习?/em>。W i 中的更改值等? (alpha * (t - y)* Xi)。当 alpha 向?0 Ӟ经|络的权pL的调整变得保守一点;?alpha 向?1 Ӟ权系数的调整变得Ȁq。一个用这个规则的经|络UCؓ 感知?/em>Qƈ且这个规则被UCؓ 感知器学习规?/em>。Rosenblatt ?1962 q下的结论是Q如?N l空间的炚w被超q面切割Q那么感知器的培训算法的应用会最l导致权pL的分配,从而定义了一? TLUQ它的超q面会进行需要的分割。当ӞZ记v KeynesQ最l我们都切断了与外界的联p,专心思考。但是在计算旉之外Q我们仍Ȓ危险Q因为我们需要自q经|络对可能输入的I间q行不止一ơ的切割?
文章开始的N举例说明了这个,假设l您 N 个字W的代码D,您知道是 C、C++、Java 或? Python。难的是构造一个程序来标识~写q段代码的语a。用 TLU 来实现需要对可能的输入空间进行不止一ơ的分割。它需要把I间分成四个区域。每U语a一个区域。把经|络培训成能实现两个切割可完成q种工作。第一个切割将 C/C++ ?Java/Python 分开来,另一个将 C/Java ?C++/Python 分开。一个能够完成这些切割的|络同样可以识别源代码样本中的语a。但是这需要网l有不同l构Q在描述q个不同之处之前Q先来简单地看一下实跉|面的考虑?/p>
考虑到排除取?N 个字W代码所需的计时_l计?ASCII 码的 32 ?127 的范围内可视 ASCII 码字W出现的频率Qƈ在这个统计以及关于代码语a的目标信息的基础上培训神l网l。我们的Ҏ是将字符l计限制? C、C++、Java ?Python 代码字符库中最常用?20 个非字母数字字符。由于关注Q点运的执行Q我们打用一U规格化因素这 20 字符l计分开来,q以此培训我们的|络。显Ӟ一个结构上的不同是我们的网l有 20 个输入节点,但这是很正常的,因ؓ我们的描q已l暗CZq种可能性。一个更有意思的区别是出C一对中间节点,N1 ?N2Q以及输Ҏ量从两个变成了四个(O1 ?O4Q?/p>
我们培?N1Q这样当它一看到 C ?C++Q设|?y1=1Q看?Java ? PythonQ它设|?y1=0。同理培?N2Q当它一看到 C ?JavaQ设|? y2=1Q看?C++ ?PythonQ设|?y2=0。此外,N1 ?N2 输?1 ?0 l?Oi。现在如?N1 看到 C ?C++Q而且 N2 看到 C 或? JavaQ那么难题中的代码是 C。而如?N1 看到 C ?C++QN2 看到 C++ ? PythonQ那么代码就?C++。这个模式很显而易见。所以假?Oi 已被培训q根据下面表格的情况输出 1 ?0?/p>
N1 | N2 | O1 (C) | O2 (C++) | O3 (Java) | O4 (Python) |
0 | 0 | 0 | 0 | 0 | 1 |
0 | 1 | 0 | 0 | 1 | 0 |
1 | 0 | 0 | 1 | 0 | 0 |
1 | 1 | 1 | 0 | 0 | 0 |
如果q样可行的话Q我们的|络可以从代码CZ中识别出语言了。这个想法很好。但是在实践上却有些难以|信。不q这U解x案预CZ C/C++ ?Java/Python 输入被一个超q面切割了,同样 C/Java ? C++/Python 输入被另一个切剌Ӏ这是一个网l培训的解决ҎQ迂回地解决了这个输入空间的设想?/p>
另一U培训的规则叫做 delta 规则。感知器培训规则是基于这样一U思\ ?权系数的调整是由目标和输出的差分方程表达式决定。? delta 规则是基于梯度降落这样一U思\。这个复杂的数学概念可以举个单的例子来表C。从l定的几Ҏ看,向南的那条\径比向东那条更陡些。向东就像从悬崖上掉 下来Q但是向南就是沿着一个略微倾斜的斜坡下来,向西像登一座陡峭的山,而北边则Cq_Q只要慢慢的闲逛就可以了。所以您要寻扄是到辑^地的所有\? 中将陡峭的d减少到最的路径。在权系数的调整中,经|络会扑ֈ一U将误差减少到最的权系数的分配方式?
我们的|络限制为没有隐藏节点,但是可能会有不止一个的输出节点Q设 p 是一l培训中的一个元素,t(p,n) 是相应的输出节点 n 的目标。但是,?y(p,n) ׃上提到的 squash 函数 s 军_Q这? a(p,n) 是与 p 相关?n 的激zd敎ͼ或者用 (p,n) = s( a(p,n) ) 表示Z p 相关的节?n ?squash q的Ȁzd数。ؓ|络讑֮权系敎ͼ每个 WiQ,也ؓ每个 p ?n 建立 t(p,n) ?y(p,n) 的差分,q就意味着为每?p 讑֮了网l全部的误差。因此对于每l权pL来说有一个^均误差。但? delta 规则取决于求q_值方法的_度以及误差。我们先不讨论细节问题,只是说一些与某些 p ?n 相关的误差:?* square( t(p,n) - y(p,n) )。现在,对于每个 WiQ^均误差定义如下:
sum = 0 |
delta 规则是依据q个误差的定义来定义的。因差是依据那些培训向量来说明的Qdelta 规则是一U获取一个特D的权系数集以及一个特D的向量的算法。而改变权pL会使神l网l的误差最化。我们不需要讨论支持这个算法的微积分学Q只要认ZQ? Wi 发生的变化都是如下所C就够了Q?/p>
alpha * s'(a(p,n)) * (t(p,n) - y(p,n)) * X(p,i,n). |
X(p,i,n) 是输入到节点 n ?p 中的W?i 个元素,alpha 是已知的学习率。最?s'( a(p,n) ) 是与 p 相关的第 n 个节Ҏzȝ squashing 函数的变化(zQ率Q这是 delta 规则Qƈ?Widrow ? Stearns 向我们展CZ? alpha 非常的时候,权系数向量接q某个将误差最化的向量。用于权pL调节的基? delta 规则的算法就是如此?
step 1: for each training vector, p, find a(p) |
q里有一些与感知器算法相区别的重要不同点。显Ӟ在权pL调整的公式下有着完全不同的分析。delta 规则法L在权pL上调_而且q是建立在相对输出的ȀzL式上。最后,q不一定适用于存在隐藏节点的|络?/p>
反向传播q一法把支?delta 规则的分析扩展到了带有隐藏节点的经|络。ؓ了理解这个问题,设想 Bob l?Alice 讲了一个故事,然后 Alice 又讲l了 TedQTed 查了q个事实真相Q发现这个故事是错误的。现?Ted 需要找出哪些错误是 Bob 造成的而哪些又归咎? Alice。当输出节点从隐藏节点获得输入,|络发现出现了误差,权系数的调整需要一个算法来扑և整个误差是由多少不同的节炚w成的,|络需要问Q?#8220;是谁让我误入歧途?到怎样的程度?如何弥补Q?#8221;q时Q网l该怎么做呢Q?
反向传播法同样来源于梯度降落原理,在权pL调整分析中的唯一不同是涉及到 t(p,n) ?y(p,n) 的差分。通常来说 W i的改变在于:
alpha * s'(a(p,n)) * d(n) * X(p,i,n) |
其中 d(n) 是隐藏节?n 的函敎ͼ让我们来看(1Qn 对Q何给出的输出节点有多大媄响;Q?Q输Ҏw对|络整体的误差有多少影响。一斚wQn 影响一个输点越多,n 造成|络整体的误差也多。另一斚wQ如果输点媄响网l整体的误差少Qn 对输点的影响也相应减。这?d(j) 是对|络的整体误差的基|W(n,j) ?n ?j 造成的媄响,d(j) * W(n,j) 是这两种影响的d。但?n 几乎L影响多个输出节点Q也怼影响每一个输出结点,q样Qd(n) 可以表示为:
SUM(d(j)*W(n,j)) |
q里 j 是一个从 n 获得输入的输点,联系hQ我们就得到了一个培训规则,W?1 部分Q在隐藏节点 n 和输?j 之间权系数改变,如下所C:
alpha * s'(a(p,n))*(t(p,n) - y(p,n)) * X(p,n,j) |
W?2 部分Q在输入节点 i 和输?n 之间权系数改变,如下所C:
alpha * s'(a(p,n)) * sum(d(j) * W(n,j)) * X(p,i,n) |
q里每个?n 接收输入的输?j 都不同。关于反向传播算法的基本情况大致如此?/p>
?Wi 初始化ؓ的随机倹{?/p>
W?1
步:输入培训向量?
W?2 步:隐藏节点计算它们的输? W?3 步:输出节点在第 2 步的基础上计它们的输出? W?4 步:计算W?3 步所得的l果和期望g间的差? W?5 步:把第 4 步的l果填入培训规则的第 1 部分? W?6 步:对于每个隐藏节点 nQ计?d(n)? W?7 步:把第 6 步的l果填入培训规则的第 2 部分? |
通常把第 1 步到W?3 步称?
正向传播Q把W?4 步到W?7
步称?
反向传播。反向传播的名字由此而来?
在掌握了反向传播法后,可以来看我们的识别源代码h语言的难题。ؓ了解册个问题,我们提供?
Neil Schemenauer ?Python 模型
bpnn。用它的模型解决问题真是难以|信的简单,在我们的c?
NN2
里定制了一个类
NN
Q不q我们的改变只是调整了表达方式和整个q程的输出,q没有涉及到法。基本的代码如下所C:
# Create the network (number of input, hidden, and training nodes) |
当然我们需要输入数据,实用E序 code2data.py 提供了这个功能。它的界面很直观Q只要将一堆扩展名各不相同的文件放C个子目录 ./code 中,然后q行q个实用E序Qƈ列D那些扩展名作为命令选项。例如:
python code2data.py py c java |
您得到的是一?STDOUT 上的向量Q可以把q些向量输入到另一个进E或者重定向C个文Ӟ它的输出如下所C:
0.15 0.01 0.01 0.04 0.07 0.00 0.00 0.03 0.01 0.00 0.00 0.00 0.05 0.00 > 1 0 0 |
让我们回忆一下输入值都是不同特D字W出现的规格化数目,目标|在大于号以后Q是 YES/NOQ它代表包含q些字符的源代码文g的类型,不过对于什么是什么来_q没有非常明昄东西。数字可以是输入或期望的 L?/em>Q这才是最重要的?
下一步是q行实际?code_recognizer.py E序。这需要(?
STDIN
中)像上面一L向量集。这个程序有一个包Q它能够Ҏ实际文g推断出需要多输入节点(计算在内的和期望的)Q选择隐藏节点的数目是一个诀H。对于源代码的识别,6
?8
个隐藏节点似乎工作得很好。如果打试验网l从而发现对于这些不同的选项它是如何做的Q您可以覆盖命o行中的所有参敎ͼ但每一ơ运行还是会耗费一些时间。值得注意的是Q?
code_recognizer.py 它的(大的Q测试结果文件发送到
STDOUTQ而将一些友好的消息攑֜ STDERR
里。这样在大部分时间里Qؓ了安全保,您将会把 STDOUT
定向C个文Ӟq监视针对进E和l果概要?STDERR?/p>
清单 5Q运?
code_recognizer.py
> code2data.py py c java | code_recognizer.py > test_results.txt |
不断减少误差是个很好的兆_q至在一D长旉里所获得的一U进步,且最后的l果必然是深入h心的。就我们的观点而言Q网l完成了一值得敬的工作,来识别代? ?我们会乐意們Q对于您的数字向量它是如何做的?