月食的成因和日食有着非常大的差别。日食是月亮实体对太阳的遮挡,在观察者和被观察物(太阳)之间,存在着视线的阻隔。而月食则不同,在观察者和被观察物(月亮)之间,实际没有对视线的阻挡,而是因为地球挡住了唯一的光源:太阳,导致月亮因为没有光照而看不到。
事实上,由于地球并不能完全挡住全部的太阳光,有一部分阳光通过大气层的折射仍然可以照在月亮上,所以月全食的时候,月亮并不是完全不可见,只是非常暗,而且带有红色。
地球在前两节课程中,地球一直只作为一个观察点而存在,现在它将一个真正的角色出现,虽然仍然是身处幕后,但它的存在已经是必不可少的了。
self.earth = loader.loadModel("sphere")
self.earth.reparentTo(render)
self.earth.setPos(0,0,3)
self.earth.setScale(1)
由于地球只是影子出境,它的本尊也就不必贴图了,简单地载入一个球体模型,设置它的位置和大小就可以了。
影子了解了月食的成因,我们就知道如果想编程实现月食现象,就必须引入下一个3D编程的基本概念:影子。熊猫引擎对影子功能的支持还算是不错的,但不能使用平行光了,必须使用聚光灯光源才能有最好的效果。
一个光源是否留下影子,被认为是光源的一个特征,打开影子模式只需一句话:
sunlight.setShadowCaster(True)
并且在世界节点上加一句:
render.setShaderAuto()
加上影子后,我们会发现,正如我们从天文常识中所了解的那样,月食发生在满月之时。由于地球投影挡住了光,月食就发生了。
聚光灯熊猫3D引擎声称对于平行光和聚光灯都支持影子,但实际使用效果来看,聚光灯的投影效果很好,但平行光的投影并不好用。所以我们把太阳光改为聚光灯。
聚光灯是4种光源中最复杂的一个,它不但有位置和方向,而且还有照射开角的问题。
由于聚光灯有投影角度,一个物体在聚光灯的照射下,投影大小与投影背景的位置是有关的。为了尽量接近太阳光,我们把这个角度(Field of View,简称FOV)设置得小一些。
self.light.node().getLens().setFov(5)
这行代码的意思是开角为5度,从我们的观感来说,基本就可以了。
红月亮上面的模拟月食,没有考虑红月亮的问题。地球的影子把所有光线都挡住了,月球被遮挡的部分呈与背景一样的黑色,完全看不到。
我们可以用两个光源来实现更加逼真的效果。一个代表正常的白色太阳光,另一个代表暗红色的地球折射光。
sunlight = panda3d.core.Spotlight('plight')
sunlight.setShadowCaster(True)
sunlight2 = panda3d.core.Spotlight('plight2')
sunlight2.setColor((0.1, 0.05, 0.05, 0.05))
第二个光源,设置一下颜色,整体非常暗,但红色部分略强(0.1, 0.05, 0.05, 0.05),这样的光线照在没有特别设置颜色的月球上,就会呈现暗红的效果。
这也证实了,观察者和月亮之间确实没有遮挡物,只是光线在改变而已。
,