|
|
|
灯光介绍
Contents of
this lesson:
常用的在 3D场景中实现灯光的方法有三种,第一种是利用DXGraphics提供的灯光对象简单地完成不太精确的光照效果,第二种方法是利用Lightmap技术,第三种办法是利用Pixel Shader。我们还是在一节中先看看最简单的第一种吧。 DXGraphics提供了三种光源:点光源POINT(例如灯泡)、平行光源DIRECTIONAL(例如太阳光)和聚光灯SPOT(DiabloII里面围绕着主角的一圈光就可以看作是这种光)。一个光源可以由一个D3DLIGHT9结构表示,这个结构的参数有:Type:表明光源种类。可以是D3DLIGHT_POINT、D3DLIGHT_SPOT或 D3DLIGHT_DIRECTIONAL。 Diffuse / Specular / Ambient :光源射出的三种光的颜色,每一个都是一个D3DCOLORVALUE结构,有a/r/g/b四个成员,取值范围都是0.0f到1.0f。Position:光源的位置,对于平行光源此值无意义。 Direction :光源照射的方向,对于点光源此值无意义。Range :光源能照射多远,最大允许值为sqrt(FLT_MAX),对于平行光源此值无意义,Attenuation0 / Attenuation1 / Attenuation2 :指定光线的衰减方式。一般来说Attenuation0与Attenuation2都设为0,Attenuation1设为一个常数。如果你将Attenuation0设为1并将其余两个值设为0,光线将不随距离而衰减。对于平行光源此值无意义。接下来的三个参数是聚光灯所特有的。 首先要定义顶点格式,Direct3D采用了一种被称之为“可变形顶点格式Flexible Vertex Format((FVF)”的技术,除顶点坐标外,还可以包括顶点的法线、颜色、纹理等数据。在本节中,用到了坐标和颜色。通常情况下,实体的外观由材质、光照和纹理决定,不需要再另外为顶点定义颜色,但目前还没有讲到这些内容,因此要给出顶点的颜色。Direct3D在渲染时,将使用顶点颜色,通过插值算法来填充三角形。 Before we go into any greater detail you'll need to know how to generate a normal for your triangle. Once you've learnt this it isn't particularly difficult - but if you do get it wrong it can lead to some weird and frustrating results. To generate a normal you need to follow these steps: 1.
Make sure the triangle is generated in a clockwise order
绿色长箭头表示法向方向,但顶点处你可设置顶点方向,这样交接可以平滑In the preceeding diagram we see two faces (in 2D) represented by black lines; the big green arrows represent the normal. At the joining vertex you can imagine a *fight* over which normal it uses - if it uses either of them the other face will look odd. So if we try adding the two vectors together - as shown by the 2 small green arrows at the top; we get to the point shown by the blue arrow; an average vector that doesn't really represent either face, but it's not biased to any one side in particular. We'll need to re-normalise the new vector, as it'll probably have a lengh of 2 (2 1 unit vectors added together). The final thing to mention on this is that you'll end up with slightly blurry lighting using this method - because Direct3D blends the colours across the vertices you'll find that you cant get a sharp difference between either triangle - which would be useful if they were the corners of two walls. The code for generating a normal goes like this:
创建三个点定义三角形不是很困难Not greatly complicated really, we can pass 3 vertices defining a triangle to this function and it'll return the normal for it - you then need to copy the normal to all 3 vertices. It's a good idea to remember this code, or at least how to write your own (I remember it as "Normalised Cross Product of the vectors from 0 to 1 and 0 to 2"). You could adapt this code slightly so that it fills the 3 passed vertices with the normal information, but I decided against this so that I left room for adding normals together (as explained above). This shouldn't take very long - hopefully you're already aware of how geometry works - so this is just a review of what has changed in order for lighting to work.
Not too difficult really. Next, the way we create the geometry has changed slightly. I've used the 3D cube that we generated in an earlier lesson as a basis, but altered it so that all the triangles are in the correct order (not all of them were CW in the other lesson); and I've added code to generate the normals.
That's only one triangle out of the 12 that make up the cube, but they're all pretty much the same. Note that in the initial creation I haven't specified a normal - it's left as [0,0,0] - we then calculate the normal and overwrite the old value with the new one. The "CreateVertex" function is a simple wrapper similar to ones we've used in previous lessons - it just saves us from having 8 lines of code to create each vertex. 5. Setting up lights设置灯光 相对的另一件事就是灯光There are a couple of things that you must do in order to get a light working in your scene; most of them can be done at the beginning and left alone for the remaining runtime. First you must apply a material to the device - if you forget to do this everything will appear black (this is the cause of many "newbie" problems).
You can change the values of the "Col" value if you want to alter the global lighting. At the moment it's set to white - it wont interfere with anything in the scene; if you set it to a slight tint of blue all subsequent lights would appear slightly blue... Secondly you must let the device know about your light:
Once this line is called you can use the light, but if you change the property in the D3DLight8 object you'll need to call this function again. The first argument is the index, being a long datatype means that theoretically you could have around 2 billion lights created - but it's unlikely to be needed. 第三,你要打开灯光,你可以设置很多灯光,并决定那些灯光当前打开Thirdly you need to turn the light on; in the theory section above I mentioned about keeping the number of lights down; well this is where it applies. You can register as many lights as you like with the device, but you need to keep a lid on how many of them are active. These values can be turned on and off as you please - enabling certain lights for certain parts of geometry is another way of keeping the processing overheads down...
最后你要告诉Direct3D是否允许灯光Lastly you need to tell Direct3D that you want it to do lighting for you - up till this point we've told it to disable the lighting engine; so here's how to enable it:
Nothing greatly challenging in here.... Onto learning how to set up each type of light. 这不是非常复杂你可以将红绿蓝混成白色This isn't a particularly complicated thing - one line of code is all it takes. Whilst a light can have an ambient property if it does Direct3D will just add them all together - for example, we could have 3 ambient values - red, green and blue, Direct3D would just add them together as being White.... you set the ambient light through a SetRenderState call, the ambient colour is a hexidecimal RRGGBB colour (as opposed to a AARRGGBB code).
对于环境,它是最好的,你可以用它来模拟日光These are best, after ambient lights, for lifting the overall lighting level of a scene. You can use these if you want to simulate the sun for example, and if you get it to change directions over time it'll appear to shade things like the sun would (only one side of a cube for example). A directional light has direction and colour but no position, no attenuation and no range. The direction specified is normally a normalised vector (we've done these, remember?) but it doesn't have to be - as long as it isn't [0,0,0] then it's okay. Here's how we set up our Directional light:
As you can tell, our light is pointing straight down and is white; you can mix and match the direction vector with anything you like - so long as it has length.
点光是最容易的,给它一个位置,颜色,强度,衰减,定义如下Point lights are one of the easiest to set up; give them a position, colour, range and attenuation and that's it (note that they dont have direction). Here's how we set up a point light:
Here we have created a blue point light. The range is quite short - so that you can see the basics of the attenuation factors coming in. You'll note that there are 3 attenuation variables - Attenuation0, Attenuation1 and Attenuation2 - these are the Constant, Linear and Quadratic values respectively. Play around with these values to get different effects - but remember, attenuation won't be very easy to notice if the light has a range of 100000 (or some-other suitably large number).
大家都会注意到,聚光灯的内圈的亮度不随距离而衰减,内圈与外圈之间则不然。下面三个参数就与这些有关: Theta :内圈的角度(单位为弧度)。Phi:外圈的角度(单位为弧度)。Falloff:内圈与外圈之间的亮度的衰减率,一般设为1.0f。填充完 D3DLIGHT9结构后,下一步就是设置灯光。假设你刚才填充的D3DLIGHT9结构的变量的名字是d3dLight,那么这样做即可:
You should also note that there are two radii for the cone - an inner (Theta) and outer (Phi); you can specify both of these. Note that they are both measured in radians, not degrees - to convert from degrees to radians multiply degrees by (Pi / 180). The following code is used by the example program to generate a spot light:
不是很难Not greatly complicated really; just remember that that the cone's inner and outer angles are specified in radians not degrees.
|