From 9c48cfce0b8f7b0256346ece4ecf5ee968be7c52 Mon Sep 17 00:00:00 2001 From: AaronRobert Date: Tue, 19 Jun 2018 21:45:58 +0800 Subject: [PATCH 1/3] =?UTF-8?q?Update,=E4=B8=80=E7=82=B9=E5=BE=AE=E5=B0=8F?= =?UTF-8?q?=E7=9A=84=E8=B4=A1=E7=8C=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/10-let-there-be-light.md | 86 ++++++++++++++++++ source/_static/10/polished_surface.png | Bin 0 -> 3992 bytes source/_static/10/specular_lightining.png | Bin 0 -> 20283 bytes .../_static/10/specular_lightining_calc.png | Bin 0 -> 11148 bytes 4 files changed, 86 insertions(+) create mode 100644 source/_static/10/polished_surface.png create mode 100644 source/_static/10/specular_lightining.png create mode 100644 source/_static/10/specular_lightining_calc.png diff --git a/source/10-let-there-be-light.md b/source/10-let-there-be-light.md index c45099b..7e2a704 100644 --- a/source/10-let-there-be-light.md +++ b/source/10-let-there-be-light.md @@ -104,3 +104,89 @@ $$ color = diffuseColour * lColour * diffuseFactor * intensity$$ ![平面](_static/10/surface.png) +但是,当光线照射抛光平面时,例如金属,光线会受到较低扩散的影响,并且大部分光线会反射到相反的方向。 + +![抛光平面](_static/10/polished_surface.png) + +这就是高光分量模型,它取决于材质特性。关于镜面反射,要注意的一点是,只有当摄像机处于适当的位置时,即反射光的发射区域内,反射光才可见。 + +![高光](_static/10/specular_lightining.png) + +解释了反射的机制,我们接下来准备计算这个分量。首先,我们需要一个从光源指向顶点的向量。当我们计算漫反射分量时,我们使用的是方向与之相反的向量,它指向的是光源。 $toLightDirection$,所以让我们将其计算为$fromLightDirection = -(toLightDirection)$。 + +然后我们需要计算正常情况下由$fromLightDirection$到平面所产生的反射光。有一个名为reflect的GLSL函数。所以,$reflectLight = reflect(fromLightSource, normal)$。 + +我们还需要一个指向相机的向量,并将其命名为$cameraDirection$,然后计算出相机位置和顶点位置之间的差值:$cameraDirection = cameraPos - vPos$。相机位置向量和顶点位置需要处于相同的坐标系中,并且生成的向量需要进行归一化。下图概述了我们目前计算的主要分量: + +![高光运算](_static/10/specular_lightining_calc.png) + +现在我们需要计算光强,即$specularFactor$。如果$cameraDirection$和$reflectLight$向量指向相同的方向,该值就越高,如果它们方向相反其值则越低。为了计算这个值我们将再次使用点积。$specularFactor = cameraDirection \cdot reflectLight$。我们只希望这个值在$0$和$1$之间,所以如果它低于$0$,就设置它为0。 + +我们还需要考虑到,如果相机指向反射光锥,则该光更强烈。这可以通过计算$specularFactor$的$specularPower$幂来实现,其中$specularPower$为给定的参数: + +$$ specularFactor = specularFactor ^ {specularPower} $$。 + +最后,我们需要对材质的反射率进行建模,反射率将影响反射光的强度,这将使用一个名为reflectance的参数。所以镜面反射分量的颜色分量为:$$ specularColour * lColour * reflectance * specularFactor * intensity $$。 + +## 衰减 + +我们现在知道如何计算这三个分量了,这些分量可以帮助我们用环境光模拟点光源。 但是我们的光照模型还不完整,物体反射的光与光的距离无关,我们需要模拟光线衰减。 + +衰减是一个有关距离和光的函数。光的强度与距离的平方成反比。这很容易理解,随着光线的传播,其能量沿着球体表面分布,其半径等于光线行进的距离,而球的表面与其半径的平方成正比。我们可以用下式来计算衰减因子:$1.0 /(atConstant + atLineardist + atExponentdist ^ {2})$。 + +为了模拟衰减,我们只需要将衰减因子乘以最终的颜色即可。 + +## 实现 + +现在我们可以开始编程实现上面描述的所有概念,我们将从着色器开始。大部分工作将在片段着色器中完成,但我们还需要将顶点着色器中的一些数据传递给它。在前一章中,片段着色器只是接收纹理坐标,现在我们还将传递两个参数: + +* 已转换为模型视图空间坐标系并已归一化的顶点法线。 +* 已转换为模型视图空间坐标系的顶点位置。 + +这是顶点着色器的代码: + +```glsl +#version 330 + +layout (location=0) in vec3 position; +layout (location=1) in vec2 texCoord; +layout (location=2) in vec3 vertexNormal; + +out vec2 outTexCoord; +out vec3 mvVertexNormal; +out vec3 mvVertexPos; + +uniform mat4 modelViewMatrix; +uniform mat4 projectionMatrix; + +void main() +{ + vec4 mvPos = modelViewMatrix * vec4(position, 1.0); + gl_Position = projectionMatrix * mvPos; + outTexCoord = texCoord; + mvVertexNormal = normalize(modelViewMatrix * vec4(vertexNormal, 0.0)).xyz; + mvVertexPos = mvPos.xyz; +} +``` + +在我们继续讲解片段着色器之前,必须强调一个非常重要的概念。从上面的代码可以看到,`mvVertexNormal`,该变量包含已转换为模型视图空间坐标的顶点法线。这是通过将`vertexNormal`乘上`modelViewMatrix`来实现的,就像顶点位置一样。但有一个细微的差别,该顶点法线的w分量在乘以矩阵之前被设置为0:`vec4(vertexNormal,0.0)`。我们为什么要这样做呢 ?因为我们希望法线可以旋转和缩放,但我们不希望它被变换,所以我们只对它的方向感兴趣,而不是它的位置。而这是通过将w分量设置为0来实现的,这也是是使用齐次坐标的优点之一,通过设置w分量,我们可以控制应用了哪些变换。你可以用手做矩阵乘法,看看为什么是这样。 + +现在我们可以开始在片段着色器中干点事情了,除了将来自顶点着色器的值声明为输入参数之外,我们将定义一些有用的结构体来模拟光照和材质特性。首先,我们将定义用于模拟光的结构。 + +```glsl +struct Attenuation +{ + float constant; + float linear; + float exponent; +}; + +struct PointLight +{ + vec3 colour; + // 光源位置是在视图坐标系中的 + vec3 position; + float intensity; + Attenuation att; +}; +``` diff --git a/source/_static/10/polished_surface.png b/source/_static/10/polished_surface.png new file mode 100644 index 0000000000000000000000000000000000000000..473b22c91fe529c6007bae58024d08684d02c22d GIT binary patch literal 3992 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 UW=M{+)ij6sRZHWyhAxr+0hOxd+W-In literal 0 HcmV?d00001 diff --git a/source/_static/10/specular_lightining.png b/source/_static/10/specular_lightining.png new file mode 100644 index 0000000000000000000000000000000000000000..a574b9951ef0c5456a5c0b436f0a16b71fb45158 GIT binary patch literal 20283 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 ONmyGQwk)N2{QO^^r#tQd literal 0 HcmV?d00001 diff --git a/source/_static/10/specular_lightining_calc.png b/source/_static/10/specular_lightining_calc.png new file mode 100644 index 0000000000000000000000000000000000000000..08e03ffc2a474cd39a11e5997801fb73245d6345 GIT binary patch literal 11148 zcmb_?bzGD0-|vv_P)b@s8vG*NhzJZMMmM5>Nqym9Jw7NPEARrJ?Gw_k8 zxCT5aW%E@Aeu!WY?fanWLC#g+4~eVBBMlI!Hj(=5F)8q$(nrS%1_IH2z4{RKLCcU{z>^EkqO_?V<)O=#flfU!(UH;?l1c@nI89ys5XO^xilOclGv^1uTO_!~n zyspj?ZT^XA*m>(FDtE!0+(2QspVXK7z-D`j`i?AB;E&n~YBTBw!W%W_{yw>bVVr%6d77`SI&>A_M|8CV3z|xLRtL5bw(^0fmqs5$ zxn7#7(Dw)=fhG&FIRfYU)CErfrv zv`&7E91RHxepc9d7YUZoXVX-gO7jekwL2bBG|V;if^mFL;#E@wvAw6DK{krYJ-*c! zhgQACp8DKGJeZ2Vw*F)E;ofkCk@Fuy3QBsn|Zc`rb~$0RM3*J;;hVCK{X&^emwA6^K4VlN6+_ol;XJ-;yfUO=bdAkukW(S*FDq@i z;>R@xmd5%)!tybs0B4&pG>cK)Q#idGmPmA-_D8k%nfz7DfHW%4O!1ww8dHElw^4yn zqLyYYgtE+l5rtd#wLj4oF>Z#0sAhPW;3T%AUxta*Lc3u_Cn8fbO+0mu2{32rGX}t{ z517TGt5YHsTdZ~ez^@*zKuJCXNhy0^E6r|6WKx}3~ zK|y+Yv6enbSy?BqdCqv%)bgpEm`SKKC>?bg8yf=y15MdfL*%vj#&69o-C?>H08FA; z1TXni5;^Yv2n?Q2Eh#LFm?ubvA5+VGDfg0?K-JaNrHR|fx(;&I(x_?zYNQwV14vQ! zAvf2~Vaqp-0)>*p1{Alpwsv(ne0m?Nr>9rkY}@QpXi3IXaF6^;01Az6F|xG$L5dW5 zh=k&>)6;sFkQd1okWko2kyd|y|BZrnGU>vHl#X{zRZ237!T9aDujRA3A3pHPJ}Wd= z5D=65#g1^*(ju+4bH5+Y^u-Y#n>ZG7pdvuo>-6Z+BO9A+%x38dr=0gp{g7&ViNmSVlVy?c_9r3l3MSX@l-B0ko=8QoxPQN=&KceO7k@9Q zmIfG+Ej2aO*0Md|AJ+T$DkOIPn%viJ$}BAC`!E)(>OCVbVlpKYiAX9SZoU_o3TjSo-WeYsR~EPVk?48zDx_aw;;$!w9b8;Wd!2N3bP8@i z5klBpy#Se=^o+!7T3cHO{0jU)d~bjjkN`BZSqgUe;d)N#5R26x-Xj}Us@Ow({Aj|* zIV=C}-Mc-gySqD}UQ22TqhgZbwp=BDKMnQ`HW8(le+%Fx*D6x5fY}N>P``40Oizxg zl~%rwytygxs@fPKssF@Z=oTe2VRttv`M+9Kv5aCcQ9te&=H(;;GhqW7Qu+v$L~%t+zpsprG@4_E6XLt$VK!9OwclMHiwI{Dm>C8*QMd<)8H{FQSpL+{AVgwB+q*RQm%#R?iJYvBCf#y zhU?m#(hV5kf==1DE62e$sborpT*8{YF6l@gO(b zQMnrHM(`~65DMk);jvI<)8sjq%FN6R1PPG%Xo@>KRfUD$JxMUS!NSZOSYZc=t59+; zW9c_TkBynyKkt~Q%mbh+?hVFkW2$lOyG*JuLn>8qN@?kxeIY$OHkE&-K!xzuBxAGM&!2}kmKi6jY>;8+LAAUd-rjVM89_hq13}M>SWMtj0_*7o z8aQaZe0lIBQRRF7G-Kr=<5Db(_`K9%9*jLCqJZRX)5XQb)YMc*@FAwFT63Vju1<)B zoc87e{8f_Z=*Xp-MnWwdI!PV@#!e}qDoxICN>v)Wi?ps@(%9jIZKzE zWEj+{!%|j(L;ysxnnHMeBP(zxT=kau8)JSR^ws1VijzTB@cWg!U!8=n(_d7ZeBzx8 z659guK0`@=Dz2(U*TErM?7!N}u@X~!>`LwB@w$OOHGhXZ#N!^R98EnA%=NUM^^f%{ zxz;F}&SGaEl3jaiQ;2yn-v12N7q^A@m8fZh6l>FzVA|i|k`<0dK~vqC6%f)S)i+ro;a$8jmoeR!tZ;6GTK|jR zhsSmTnUB}DB&}G5b;YZ#b{mQb$7_!pYu$u#1!=XuUle1I=#tIK%0E~bHs2W->`Rwr zPFHHscZdQ5sfuFPx4IZNA}M? zrCzh(>~c(&H`R7ezCp#KhP%?0*59Puy^h7vBt4r}ARiy-biIB@1 z{mu3fhmCMQ^d{o}Z=4FRhkeE;1-pBWc(^vwY)*lJFNl(X86(U50{ zIpJyjskiDnd;^|s4NdHNAiACV;I+qROu6lzHAx~v{CKQ($i?&@kOt+jm8wjhzPN>; z{;))T>XQ}GC#DJlN|0uYaVDA!fZtpTeU_*eJJhZ={VH+Gr7vlLI4n622<{#fftuz}Vy)cQ=n;ji`c?V&5j_RhFcl=B$_pj_n#_kM?se7+b8G*L61 zdR@dccKo=pweKsvL|^)eJ6#1&&-F{5spDEt3$oDV^WQgEFC4q+` zlm423tPFQj@)_;OIgTrGR=zWDZG5-gN3^QT^QhT-n;SNNg{hNV45ut_8}~j@c$I^=}Db!u6NaN?Yy4M}?bcf3|=d(j)>8XdI|=0G?Y-3C^jeu4vMsN<~K1K|>4M zwXj3GM7{ouaw?KJ+H4jHSa&~N)graum9U=c2Mo5HnQV&{^x!-|5hk( zgxd4LNmILRh+G5Cf~H-~=CEd*3pZVEznU=pH7ZR0C!klpQ zY30FU-@w5bg2p!~HFZ=5C754STP;wegljhHMTwDg^lZqn&&Vji<`~>eP%r&Z2xZlw zJoDU-i$uOAs6586?@iKF`V>CW-E(%3adsZ$#1e1$v11yKQT6x8rbAMP#1Xi?Ab@VwmzditQu=-e!Xs}JTf|ZJ8fYe098>DktiDWTWLhR zvb;jGmDSay@Eg=3?Ck8(bX;H^9R@Urf!HS=6Au8v{Jc}`pC3-OpB%dE#X#zw>PD@` zHa3;szDmEl!n=fs{(Uln#Y%uT8yXs7m_XmiNDv&&B$Oa`3b34%l+=TMt}Pp)FCh$Y z@2Aerfx2H)MJ?Vlt-MaBMnw(7stn=kH4N}g0Ov%7`v(RTStRY1uZSv0aTtfo&&+h2 z`4rN$(I|LvcG-Jvg*g(V0`4y@Ed>}HKFAq>m48{KWTXKgUuR_{delckrTG2RrQk~0 zyc4_0@Ng0H2>Zuh6xi6b7Mpz+${@PVCtqC((0!+BUZwA!;`S@s19sbFY(b#_Ev1PQ zNzO@r+Mg_7JFMpJy)2z7B&=&xJ_g_io0+Djrk7Wh<%d3`_iU?~*h(s9h6OE40nP=? zZQNp?Zrc?W>X086{Gq%>WiuC%c6nkXR>>>$0)Uw)Q*-mB6UOqqJnq>rCR}4nRaC*h zgVLLE09?B_^0s^E`u4rjQ8mjdX=Jn@fA!5>6$w$*lT%V-sW$2ki@{tuY_l;S1<)bz zPf3u7GdFGuhr9e+KSa2hTehJJ5Fh^Z`pvvy*#!Z_e(nzalNQI#oA|~ds5JMwPW>Z0~@X!i7zm$%-=+QpH8PIa=Lu} zUBd`>ysMy~pghW@#YgHC5~5u5@m@=FbMvQ9aVT9~U3m6M&dk&P9aNS1@o{2??e4zW zPO#Q+_7frJ^-OQ{js*IhM8$oG7UYvzVN6NE4eIXzCAq!2zOJXQUvllOBMf#=rej<~ zcf5ab@u_#}I_ykgTtd5j-}Le_!~kCkO>^N-&{Z}1vEf}|4C#PeNE8=+-*1|_Q~RfT z#%eYDeJ_rTxLXE%HcgPoy~XUC#_^DR|H$c`9Swv2hPGs3f%1Yk z#gwJreZaaE%Gkg*7$R)S!sJ1}5kRG%m`n<_6u2(Xsm_KSb25uuY|Z!TCK^W+!HjqH zZlrtNb1-Pe>k<6fnMv`}X)mez+~_|()z|m-R%>&L-Q9n)&=$Uym3I|I;5Me%F>XV)yTdEOt4|#k-hI^bhXoFQu{jRHACYU1 zb$DhNW>plfay^8~HLBD-+g*R5-7EF2Dc6w`tMey;WSQS{I-{0Ly`(AJ;-p90nBOekE1EhqXY?cod&5?ilf;>AHZZtnFj?>zJbutQy!0Y2ATMbAyI zAp=I3UHb=7w=OP`vAgMgS0>~IUv)tv|`Jsq5eE|jKf6h3699OdR7 z;F-2I`S2PZCj)Fed&phBIf9w2p(}9yGUJDIG99U-q{JhdTFWx1Jde)4w zqnlFh$Qqk5oh+-PTZfP!ur5qJUdj&+UyN8ey=l08E8~~>dYD0fTsWHtVAq z7`Xh0xJYr?cGcagjbK>4?JNHl5%j3&MIA`9643)o??HH1SAH}HD3*8Fi zEF}TTNGZ%1@rb0|#>aYE;*kOH>UZHYRB`FCG!hf6nTo=2kq01F`GksJU7T%-1tu%O zO1e`$>BIp8oCr=VyA7y35;wxSNXOWwe9NXkSsq?tzl6lW{H{o<#y` z7$J*8(m_$DVd(gu46AR3BrCj-@|>kYQuUopUoiw!3%37v%yF5k}L9zqkkCDi93iQt?;~tb%=H+}UV! zCt~i`O-X?Yyq4cz}zLjISX!l zq%iNF7n3}sBd#Q{*^74_;9BT}5X*`>ZHoZG6 z&hsJp;=a+%C@HjLZO-SSC)$EE{^)3A_SAo#_XGZ;w-ox?z@x&BpaSJ<9YcoP1y>)xjrp#DnqV#3SQHN`Kn_?sd+mOqYFlY2gQ(aIr5BPp>{mHyy7L{-FUrp^yPD z7$?{M-PcSMo0scCeR8NnZFTGKt{_^t3m#`CX^r1JE-gC=EC2Dmjn6lT^})*IfH^+WbjQr{74!=w^0M zngbAP)|N?+V{BA;1vDu%+ya!*lIb{acg;Qn61Mp?`soAf=2vhU?nn$x+RxMPfEarQ zW!UBzEVGmNn|MC&WA!;5L1Ks$|J^?`%1$uephfZ=n;=8y&bDMKAQ@P@nyqa-i5;u> z0eEPNF}sW~G~!F)LpN@)RGR7dkXQ&K4;g(5CIJV#g0#J~P;uL)`8u6G#GTL@C-F{{pcNdn<82Z=b1t&AXImvGR0_%JNs}}F90&Y`ku#2u# zX+iG-i(*4?2(H0M%TJs6oEYG>PW`s42l1v~#JVmZI09emtUMd#4RH#TWrS52acRnx zRf{P!*fsB>p`fXnkfP{+pHOSC+l)?_9A`{z-W7B*^EOw&@Mb7)kY%5-_ePLM zze5v*?>_{RfYRv^YgddYh%+u_kKvvu(1%)L37OKDJ86`L%<)Y5xruC@67Q@_xC>Uf ziUEj%XBeh$4%(e~gs{!%e(g=kNd}x}De*>rRw5hXkgR@tjVMxT!WayQtkJ0Vld%4P z{b^n}?l$9v57LB34zQ0RiSsAXto*lDVRq%vV}?0}pnsTjq5%~pVBcrpC(RnX0lSY0 zk_b4aIk=9r;)y$sbaX@S8$~`)L2m)nN)#KCh^`g3Muq?&svq7^2DIiN5umt=2jqs= zd%V>>xOYxWXmhqCE&a^^4}kyVWu?6Px6v;zkwJ8TP$0m2COsu$e#=#yq|qn2`EMx< zE7xyp<(($f`2o%efk5y6;pCJLJ=44d*n#SwkSnS@ac)}h(0^dkVh6Qt90Xl?QH?!< z_b=tk(T)jq6KU~(1-KlU_(1diG(N1!FwpyckI z`uFA6PJcr`B4M{16yWWLDrjhL_Ev|zKODVuz28RFv?|PL>T7XQ^3|BMY7UCoY7+NF zUUs=o#HKPfdz}oF-1~JLC@bl{Sx?lHMCa{Y0Rg81(8_gECqwiYRWjEIIvB5r2?(R zNEwX!^Lqn?%I6Djo_uIA;W;eDJBbmoQA9GGec_p`{4nKR<6iiYNP7NVt-G==sqtH z8flyIpKEqV(&M#MM1vldzzZUq1x<-Llh)?~>B}89#LBA#B`pgg>)4R;c+$Iqq ziSf`c-t1CR*$=Cb9x3|e$jJww@FCU+EJBR#<^(Js=~sA2HJ%|aP!3@~j#we0mxmtz z%))-oLC^l4e!aEzkO%n=DA;QhS}wv%Vt(3Oa8&5-xCZPQmK#8dIfN;(d_sIAWfGal z_KJOdq_NBKM$3f7dH<;`T_*>*uv-uXn1ZOnl;zw=pVB+VDoir~pa)OI)Q#>xWAjME zF<`Hj{QVk7<2NSB zBq0FQWxSR9e#8S$o7HXcSge`diZL7UD|9d4)9*ZABCYMQAlh2Fwy;%bx^d^jzD`WU39 z5^4b7(`XOT&9?5P>WKMyeRL#IP1@IIVChLv(y6a8Xc0Ct;~9@$<07SO*vx?%Gx-+s$qw(7X{S>q4x zvx&m=J}%1>jN~BAsoVIT3F&z7{QMoUkQ4gdD6mbrmeIEMKVRa0{y?5@o3<_4E%kbp zM7A3!j>)Bnx1~I|9ock3Kqk>6l*>ko&N(=BhMtxYa(j8Y_``(4=&IF9_mC&2_q2X< zj3-0}M z7bYm2auM}@s{>2RYG`ojD8tM|M$<4@vA6ytHf>?z%xt=avk7h*Cfu3Fk%vo8_!yCH z5_|Og%*9ms)?f zdtcVwjiQs|p)+4av($|)(A3QkxtO-}UnBioO%|EMFp7B;#rT0)SKf7k)%@FC(K|9M zoG%NZM`o!Z9sPl$-D}J&#$ya$pnNowQG55$(7Qld2NLw=r{^MXx+GTnTIQ&?+D>1* z3{=xQSGWu<*-b)*zhYfLOGrTS#W~AZ zjrxyOfcLzD9v3{<1Q13vOHJjLxHr!b?G{vb$;)4DNCGzmaTpBe2?(K1Orc6P>IiRq zyL1!(=I!p^)MFUyG~zPqT-xCQgwVcv*3%g7xix6~_y-|tIEIN-C8wgXW}HMRL_iu z2yIuJ_@^zLS2Pr}2|hUgPnxgufdQo+`;vmVFE4Z*hG+vj$o`{f1^BLS!_ei2m|ws3 zdWJJ^x6W;{BhKm;q7nj);I~{Co40i6gXa4x9M)#Ezfm$ed51j>kC~mNJo=${EdGn8 zZh)YN2R3A7zrAXx(DhkJ8!o^FHc1-3-gMv!}yP`i8Lf zBR{8Y?*~i8= z(X?|BE6U%boQOyCl){Ecc>r4%C#l;H(mDj-W^3xv=)xSihHbWdXF%H^}X}GkZPkX)24z0e=W$iKld$oZIrXQBO z$Rj%6o`+w$Q|pZ?1!4_7bA2PnOjzbLO3s#l0MRIUEZyX?DCaN_>v6qjQP#SJ*p$6g zyqM{9Iy+2}eP^#Md)tBLpV6S?)+6x%b!J_#E(%2f@V7~Ep66-FOp?n{lI>fYlfUtJ zBaOVvP0}-#gUjZK)$V`FDlJ{7 z!(+5rDVZi(BaUFy7`P?(P&gD$!Mf7+c`a&*A zTff-Hv~(XaY+8CsTZl0jNjL~YlUHbo5WkXTUgi_nSGRyZ9+mCrW~kOhLeFTU#{dd4 z;dv20wuFDAN`Mr9+E7hC{1|Vl!*=(x+@Xx&`D}109z!mF-_G} zW#}LjBU?Vpul}|TG%3(c zJtm~V3Ws~DjOHTSMSfU?0Y#B}pln@`Mnk)!>^=_JFFv9& zytjH_yI#4W+T*-$t1%O-DT8`8*h3xlwtz&XsFiz&pyv!mdIe_(sEGbs4KJKwF@98T zPyqzf=E6j`Si7S#a0FAH^fl_L3RPj(id~%WYuCG&Tr-t3#St{h4V?HHNUn}>v|0`f z@LfW}fdEk(B6#pT4{VL5)(7@KXGs_pzocXaCSV|$ef7OeQc1rxL?ZL`9}U)Ak(kvq zdL3N~W}t}wWwoAlH|=r>Gky^oF9`PMWK(mOuYr0aaf2v;nWm*csB?J*_;e`1cV7Xu z9hE~H41+IZXDJx0T2W)%iX}WY@x=ngY+yKUvYgk|RtYxIcd*@>Z&^Ntjlb~2C9cWo zTngObZzphF{F)yk8@QayD2FFvg8DR;KoJ1@4ii2cFD%G8A9$DOQd<4Xc71GAJksx= zteHoT=Z|iy^U=WjLU^2MtZ5w+ug4Vuwd5P%Ky%LnUu0GP@sX*aKA@iWLgkOR8Recbobz0&A!kMo!pqcO=>F`X z=6h2rw=xSHPPEUC9W)_wFYvx_cgSe)2E2JMxGZG(UE6i~MD;D&H=L17G+(`(!k!n2 zZQ?U+xoZUlHmb=19s5zB*y@0DnEmz1Skl|EUHAz}dXC`f&$WA7eYY=p_ZPqQ&c57C z;A`_%y8LL-*^C{+k$D1VOna5A)C>%^#Uu+Y$G!2Dv*8`T2&eVr_RZsdnVs|A-vl^2 zNQEgM13MVv;&1Iclhqs?xR%P2t@`j_;;ZMSa-dgaz}2Mxm#c;Uv#-YFe_u2NB>~eG zm;cvAL(nb2#~=kwMeESQT$GzpFnNJM4C_T<<8RM6X?~gxPZ5;@HfS=C0pjdIF=g3kzjj41=|LY zF=fPkqx*0LLBwRvC&?SX`HHtHj^>6s~MFlRGr&M@3T~}8JCihCvT~!sNXN^ze z7`}CfdQAid7s`Pg(1`2INdNSb`3ZOC3Hhww7De@k1rTD8Pgu!XW@;9~Z2Vq#8tI3J zu&LOW%R{6md_CX8dq3ZzU;|nWrNK=ZKh>nJ#Yrf*t?%FAOctqFD;8IJn*(+ux2bGf z3$!hH1L70XAb$Yi4uf^?dc!asISPL9BdX?Q^}uzB!y3sO9g5&_f{#b^9?vTrka5VH zN|Zm1Y`%o=(pa!m`r)ZFn&`G8m%okcOs78bb*sO+;CJJT91yFdHtX3(IVpb5JEhGG z!oO-9mrNBs3uz_dUxIjgfm@{}H;6!Axc(oE-u^!J)Ir`t5f_o$Aqw1}1?g%TJgC0! H82P^dP1#~L literal 0 HcmV?d00001 From 9d5aa751430bfd311b074009ed3c6358641c1603 Mon Sep 17 00:00:00 2001 From: AaronRobert Date: Sat, 23 Jun 2018 22:51:08 +0800 Subject: [PATCH 2/3] Update --- source/10-let-there-be-light.md | 156 +++++++++++++++++++++++++++++--- 1 file changed, 144 insertions(+), 12 deletions(-) diff --git a/source/10-let-there-be-light.md b/source/10-let-there-be-light.md index 7e2a704..c3dfafe 100644 --- a/source/10-let-there-be-light.md +++ b/source/10-let-there-be-light.md @@ -22,19 +22,19 @@ Phong算法提供了三种光照分量: * 环境光:模拟来自任何地方的光,这将为我们提供(需要对应强度值)未被任何光线照射的区域,就像背景光。 -* 漫反射:考虑到面对光源的表面更亮。 +* 漫射:考虑到面对光源的表面更亮。 * 高光:模拟光线如何在抛光或金属表面上反射。 -最后,我们还要知道的规律是,乘以分配给片段的颜色,将根据接收的光线将该颜色变得更亮或更暗。我们令$A$为环境组光、$D$为漫反射、$S$为高光。 以上规律对于分量的加法表示如下: +最后,我们还要知道的规律是,乘以分配给片段的颜色,将根据接收的光线将该颜色变得更亮或更暗。我们令$A$为环境组光、$D$为漫射、$S$为高光。 以上规律对于分量的加法表示如下: $$L = A + D + S$$ 这些分量其实就是颜色,也就是每个光分量所贡献的颜色分量。 这是因为光分量不仅会提供一定程度的强度,还会改变模型的颜色。在我们的片段着色器中,我们只需将该光的颜色与原始片段颜色(从纹理或基色获得)相乘即可。 -我们也可以为相同的材质分配不同的颜色,这些颜色将用于环境,漫反射和高光分量。 因此,这些分量将由材质相关的颜色而受到调整。 如果材质具有纹理,我们将简单地为每个分量使用单个纹理。 +我们也可以为相同的材质分配不同的颜色,这些颜色将用于环境,漫射和高光分量。 因此,这些分量将由材质相关的颜色而受到调整。 如果材质具有纹理,我们将简单地为每个分量使用单个纹理。 -所以对于非纹理材质的最终颜色将是:$L = A * 环境光色 + D * 漫反射的颜色 + S * 高光颜色$ +所以对于非纹理材质的最终颜色将是:$L = A * 环境光色 + D * 漫射的颜色 + S * 高光颜色$ 对于有纹理材质的最终颜色将是: @@ -46,11 +46,11 @@ $$L = A * 材质颜色 + D * 材质颜色 + S * 材质颜色$$ 环境光是运算最简单的分量,我们只需要传递一种颜色,并乘以基本颜色,以调整该基本颜色。 假如我们已经确定片段的颜色是$(1.0,0.0,0.0)$,即红色。 如果没有环境光时,它将显示为完全红色的片段。 如果我们将环境光设置为$(0.5,0.5,0.5)$,则最终颜色将为$(0.5,0,0)$,其实就是变暗的红色。 这种光会以同样的方式使所有片段变暗(说光照暗了物体似乎有点奇怪,实际上这就是我们得到的效果)。除此之外,如果光色的RGB分量不相同,它还可以为片段添加一些颜色,所以我们只需要一个向量来调节环境光强度和颜色。 -## 漫反射 +## 漫射 -现在我们来谈谈漫反射。 它模拟了这样的规律,即与光源垂直的面看起来比以更接近光的角度接收光的面更亮。 一个物体接收的光线越多,其光密度(让我这样称呼)就越高。 +现在我们来谈谈漫射。 它模拟了这样的规律,即与光源垂直的面看起来比以更接近光的角度接收光的面更亮。 一个物体接收的光线越多,其光密度(让我这样称呼)就越高。 -![漫反射光](_static/10/diffuse_light.png) +![漫射光](_static/10/diffuse_light.png) 但是,我们该如何计算它? 你还记得上一章我们介绍过的法线概念吗? 法线是垂直于平面并且长度为1的向量。 因此,让我们在上图中绘制三个点的法线,如你所见,每个点的法线将是垂直于每个点的切平面的向量。 我们不去绘制来自光源的光线,而是绘制从每个点到光源(即相反的方向)的向量。 @@ -68,11 +68,11 @@ $P2$点的法线$N2$,与指向光源的向量的夹角约为30度,所以它 ![点积](_static/10/dot_product.png) -如果两个向量都归一化,即它们的长度,它们的模块将等于1,它们的点积即为夹角的余弦值。 我们同样使用该运算来计算漫反射分量。 +如果两个向量都归一化,即它们的长度,它们的模块将等于1,它们的点积即为夹角的余弦值。 我们同样使用该运算来计算漫射分量。 所以我们需要计算指向光源的向量。 我们如何做到这一点? 假如我们有每个点的位置(即顶点位置),我们有光源的位置。首先,这两个坐标必须位于相同的坐标系中。 为了简化,让我们假设它们都处于世界坐标系中,那么这些位置是指向顶点位置($VP$)和光源($VS$)的矢量的坐标,如下图所示: -![漫反射光照运算](_static/10/diffuse_calc_i.png) +![漫射光照运算](_static/10/diffuse_calc_i.png) 如果我们从$VP$中减去$VS$,我们就得到了$L$向量。 @@ -88,7 +88,7 @@ $P2$点的法线$N2$,与指向光源的向量的夹角约为30度,所以它 首先,我们需要计算从当前位置指向光源的向量:$toLightDirection = lPos - vPos$。该操作的结果需要进行归一化。 -然后我们需要计算漫反射因子(标量):$diffuseFactor = normal \cdot toLightDirection$。计算两个向量之间的点积,我们希望它在$-1$和$1$之间,所以两个向量都需要进行归一化。颜色需要在$0$到$1$之间,所以如果值低于$0$,我们将它设置为$0$。 +然后我们需要计算漫射因子(标量):$diffuseFactor = normal \cdot toLightDirection$。计算两个向量之间的点积,我们希望它在$-1$和$1$之间,所以两个向量都需要进行归一化。颜色需要在$0$到$1$之间,所以如果值低于$0$,我们将它设置为$0$。 最后,我们只需要通过漫射因子和光强来调制光色: @@ -112,7 +112,7 @@ $$ color = diffuseColour * lColour * diffuseFactor * intensity$$ ![高光](_static/10/specular_lightining.png) -解释了反射的机制,我们接下来准备计算这个分量。首先,我们需要一个从光源指向顶点的向量。当我们计算漫反射分量时,我们使用的是方向与之相反的向量,它指向的是光源。 $toLightDirection$,所以让我们将其计算为$fromLightDirection = -(toLightDirection)$。 +解释了反射的机制,我们接下来准备计算这个分量。首先,我们需要一个从光源指向顶点的向量。当我们计算漫射分量时,我们使用的是方向与之相反的向量,它指向的是光源。 $toLightDirection$,所以让我们将其计算为$fromLightDirection = -(toLightDirection)$。 然后我们需要计算正常情况下由$fromLightDirection$到平面所产生的反射光。有一个名为reflect的GLSL函数。所以,$reflectLight = reflect(fromLightSource, normal)$。 @@ -169,7 +169,7 @@ void main() } ``` -在我们继续讲解片段着色器之前,必须强调一个非常重要的概念。从上面的代码可以看到,`mvVertexNormal`,该变量包含已转换为模型视图空间坐标的顶点法线。这是通过将`vertexNormal`乘上`modelViewMatrix`来实现的,就像顶点位置一样。但有一个细微的差别,该顶点法线的w分量在乘以矩阵之前被设置为0:`vec4(vertexNormal,0.0)`。我们为什么要这样做呢 ?因为我们希望法线可以旋转和缩放,但我们不希望它被变换,所以我们只对它的方向感兴趣,而不是它的位置。而这是通过将w分量设置为0来实现的,这也是是使用齐次坐标的优点之一,通过设置w分量,我们可以控制应用了哪些变换。你可以用手做矩阵乘法,看看为什么是这样。 +在我们继续讲解片段着色器之前,必须强调一个非常重要的概念。从上面的代码可以看到,`mvVertexNormal`,该变量包含已转换为模型视图空间坐标的顶点法线。这是通过将`vertexNormal`乘上`modelViewMatrix`来实现的,就像顶点位置一样。但有一个细微的差别,该顶点法线的w分量在乘以矩阵之前被设置为0:`vec4(vertexNormal,0.0)`。我们为什么要这样做呢 ?因为我们希望法线可以旋转和缩放,但我们不希望它被平移,所以我们只对它的方向感兴趣,而不是它的位置。而这是通过将w分量设置为0来实现的,这也是是使用齐次坐标的优点之一,通过设置w分量,我们可以控制应用了哪些变换。你可以用手做矩阵乘法,看看为什么是这样。 现在我们可以开始在片段着色器中干点事情了,除了将来自顶点着色器的值声明为输入参数之外,我们将定义一些有用的结构体来模拟光照和材质特性。首先,我们将定义用于模拟光的结构。 @@ -190,3 +190,135 @@ struct PointLight Attenuation att; }; ``` + +点光源由一个颜色,一个位置,以及一个介于$0$和$1$之间的数字来定义,这个数字模拟光的强度以及一组衰减方程的参数。 + +模拟材质特性的结构体是: + +```glsl +struct Material +{ + vec4 ambient; + vec4 diffuse; + vec4 specular; + int hasTexture; + float reflectance; +}; +``` + +材质由一组颜色定义(假如我们不使用纹理为片段着色): + +* 用于环境分量的颜色。 +* 用于漫射分量的颜色。 +* 用于高光分量的颜色。 + +材质也由一个标志来定义,该标志控制它是否具有相关的纹理以及反射率指数。我们将在片段着色器中使用以下uniform。 + +```glsl +uniform sampler2D texture_sampler; +uniform vec3 ambientLight; +uniform float specularPower; +uniform Material material; +uniform PointLight pointLight; +uniform vec3 camera_pos; +``` + +我们用新建的uniform设置下面的几个变量: + +* 环境光:包含会以同样方式影响每个片段的颜色。 +* 高光反射功率(在讨论高光反射光时提供的公式中使用的指数)。 +* 一个点光源。 +* 材质特性。 +* 相机在视图空间坐标系中的位置。 + +我们还将定义一些全局变量,它们将保存要在环境、漫射和高光分量中使用的材质颜色分量。我们使用这些变量是因为如果分量具有纹理,我们将对所有分量使用相同的颜色,并且我们不希望进行冗余的纹理查找。这些变量是这样定义的: + +```glsl +vec4 ambientC; +vec4 diffuseC; +vec4 speculrC; +``` + +我们现在可以定义一个函数,来根据材质特性设置这些变量: + +```glsl +void setupColours(Material material, vec2 textCoord) +{ + if (material.hasTexture == 1) + { + ambientC = texture(texture_sampler, textCoord); + diffuseC = ambientC; + speculrC = ambientC; + } + else + { + ambientC = material.ambient; + diffuseC = material.diffuse; + speculrC = material.specular; + } +} +``` + +现在我们要定义一个函数,以点光源、顶点位置及其法线为输入并返回前面描述的漫射和高光分量计算的颜色。 + +```glsl +vec4 calcPointLight(PointLight light, vec3 position, vec3 normal) +{ + vec4 diffuseColour = vec4(0, 0, 0, 0); + vec4 specColour = vec4(0, 0, 0, 0); + + // 漫射 + vec3 light_direction = light.position - position; + vec3 to_light_source = normalize(light_direction); + float diffuseFactor = max(dot(normal, to_light_source ), 0.0); + diffuseColour = diffuseC * vec4(light.colour, 1.0) * light.intensity * diffuseFactor; + + // 高光 + vec3 camera_direction = normalize(-position); + vec3 from_light_source = -to_light_source; + vec3 reflected_light = normalize(reflect(from_light_source, normal)); + float specularFactor = max( dot(camera_direction, reflected_light), 0.0); + specularFactor = pow(specularFactor, specularPower); + specColour = speculrC * specularFactor * material.reflectance * vec4(light.colour, 1.0); + + // 衰减 + float distance = length(light_direction); + float attenuationInv = light.att.constant + light.att.linear * distance + + light.att.exponent * distance * distance; + return (diffuseColour + specColour) / attenuationInv; +} +``` + +前面的代码相对比较直白简单,它只是计算了漫射分量的颜色,另一个是计算高光分量的颜色,并通过光线在行进到我们正在处理的顶点时受到的衰减来调制它们。 + +请注意,顶点坐标是位于视图空间中的。在计算高光分量时,我们必须指出视角,即相机。这可以这样做: + +```glsl + vec3 camera_direction = normalize(camera_pos - position); +``` + +但是,由于`位置`在视图空间中,相机位置始终位于原点,即$(0,0,0)$,所以我们如下计算它: + +```glsl + vec3 camera_direction = normalize(vec3(0, 0, 0) - position); +``` + +可以如此简化: + +```glsl + vec3 camera_direction = normalize(-position); +``` + +有了前面的函数,定点着色器的主函数就变得非常简单了。 + +```glsl +void main() +{ + setupColours(material, outTexCoord); + + vec4 diffuseSpecularComp = calcPointLight(pointLight, mvVertexPos, mvVertexNormal); + + fragColor = ambientC * vec4(ambientLight, 1) + diffuseSpecularComp; +} +``` + From 716a12a751d99690ee8f31c86b66f3e6a006f793 Mon Sep 17 00:00:00 2001 From: AaronRobert Date: Sun, 24 Jun 2018 10:28:04 +0800 Subject: [PATCH 3/3] finish chapter 10 --- source/10-let-there-be-light.md | 65 +++++++++++++++++++++++++ source/_static/10/lightning_result.png | Bin 0 -> 90832 bytes 2 files changed, 65 insertions(+) create mode 100644 source/_static/10/lightning_result.png diff --git a/source/10-let-there-be-light.md b/source/10-let-there-be-light.md index c3dfafe..2025dfc 100644 --- a/source/10-let-there-be-light.md +++ b/source/10-let-there-be-light.md @@ -322,3 +322,68 @@ void main() } ``` +调用setupColours函数将使用适当的颜色来设置变量ambientC、diffuseC和speculrC。然后,我们计算漫射和高光分量,并考虑衰减。为了方便,我们使用单个函数调用来完成此操作,如上所述。最终的颜色是通过添加环境光分量来计算的(将ambientC乘以环境光)。正如你所看到的,环境光不受衰减的影响。 + +在着色器中我们引入了一些需要进一步解释的新概念,定义结构体并将它们用作uniform。但我们要怎么传递这些结构体?首先,我们将定义两个新类,它们模拟点点光源和材质的特性,名为`PointLight`和`Material`。它们只是普通的POJO,所以你可以在本书附带的源代码中查看它们。然后,我们需要在ShaderProgram类中创建新方法,首先要能够为点光源和材质结构创建uniform。 + +```java +public void createPointLightUniform(String uniformName) throws Exception { + createUniform(uniformName + ".colour"); + createUniform(uniformName + ".position"); + createUniform(uniformName + ".intensity"); + createUniform(uniformName + ".att.constant"); + createUniform(uniformName + ".att.linear"); + createUniform(uniformName + ".att.exponent"); +} + +public void createMaterialUniform(String uniformName) throws Exception { + createUniform(uniformName + ".ambient"); + createUniform(uniformName + ".diffuse"); + createUniform(uniformName + ".specular"); + createUniform(uniformName + ".hasTexture"); + createUniform(uniformName + ".reflectance"); +} +``` + +正如你所看到的,它非常简单,我们只为构成结构体的所有属性创建一个单独的uniform。现在我们需要创建另外两个方法来设置这些uniform的值,并且将使用参数`PointLight`和材质的实例。 + +```java +public void setUniform(String uniformName, PointLight pointLight) { + setUniform(uniformName + ".colour", pointLight.getColor() ); + setUniform(uniformName + ".position", pointLight.getPosition()); + setUniform(uniformName + ".intensity", pointLight.getIntensity()); + PointLight.Attenuation att = pointLight.getAttenuation(); + setUniform(uniformName + ".att.constant", att.getConstant()); + setUniform(uniformName + ".att.linear", att.getLinear()); + setUniform(uniformName + ".att.exponent", att.getExponent()); +} + +public void setUniform(String uniformName, Material material) { + setUniform(uniformName + ".ambient", material.getAmbientColour()); + setUniform(uniformName + ".diffuse", material.getDiffuseColour()); + setUniform(uniformName + ".specular", material.getSpecularColour()); + setUniform(uniformName + ".hasTexture", material.isTextured() ? 1 : 0); + setUniform(uniformName + ".reflectance", material.getReflectance()); +} +``` + +在本章源代码中,你还将看到我们还修改了`Mesh`类来存放材质实例,并且我们创建了一个简单的示例,并在其中创建了一个可用“N”和“M”键控制移动的点光源,以显示点光源聚焦在反射率值高于0的网格上时是怎样的。 + +让我们回到片段着色器,正如我们所说的,我们需要另一种包含相机位置camera_pos的uniform。这些坐标必须位于视图空间中。通常我们将在世界空间坐标中设置光坐标,因此我们需要将它们乘以视图矩阵以便能够在着色器中使用它们,所以我们需要在`Transformation`类中创建一个新方法,该方法返回视图矩阵让我们转换光照坐标。 + +```java +// 获得光源对象的副本并将它的坐标转换为视图坐标 +PointLight currPointLight = new PointLight(pointLight); +Vector3f lightPos = currPointLight.getPosition(); +Vector4f aux = new Vector4f(lightPos, 1); +aux.mul(viewMatrix); +lightPos.x = aux.x; +lightPos.y = aux.y; +lightPos.z = aux.z; +shaderProgram.setUniform("pointLight", currPointLight); +``` + +我们不会在这里引用整个源代码,因为如果这样这一章就太长了,对于解释概念并没有太多的作用。您可以在本书附带的源代码中查看它。 + +![Lightning results](_static/10/lightning_result.png) + diff --git a/source/_static/10/lightning_result.png b/source/_static/10/lightning_result.png new file mode 100644 index 0000000000000000000000000000000000000000..3c1300358df05a262017c643bb659f16d2d86bec GIT binary patch literal 90832 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