Panda3D/Manual/Iluminação
Básico de iluminação
No mundo real, se você coloca uma lâmpada em uma sala, objetos naquela sala serão iluminados. Por exemplo, se você colocar uma lâmpada de mesa em sua sala, aquela lâmpada vai automaticamente iluminar o seu sofá e sua cadeira. Em um motor 3d como o panda3d, luzes não iluminam coisas automaticamente. Ao invés disso, você precisa dizer ao sofá e à cadeira para serem iluminados pela lâmpada.
Resumindo, iluminar uma cena no panda3d consiste de dois passos: 1. Criar as luzes e posicioná-las dentro da cena 2. Falar aos outros objetos para serem iluminados pelas luzes
Panda3D define quatro diferentes tipo de objeto de luz: ponto, direcional, ambiente e luz de área. Cada uma dessas é um nodo que deve ser ligado em algum lugar do grafo de cena. Como qualquer coisa que você coloca na cena, luzes tem posição e orientação, que são determinadas por operações básicas do grafo de cena como setPos(), setHpr(), etc. O método lookAt() é particularmente útil para apontar luzes de área e direcionais para um objeto particular. O código a seguir insere uma luz direcional na cena:
luz_d = DirectionalLight( 'minha luz direcional' ) ldnp = render.attachNewNode( luz_d )
Note que ao contrário de um bulbo de luz real, objetos luz não são visiveis. Apesar de você não poder ver a luz do panda3d, você pode ver o efeito que ela tem na geometria ao seu redor. Se você quiser fazer as luzes visíveis, um truque simples é simplesmente carregar um modelo simples (como uma esfera) e parentá-la diretamente à própria luz.
Criar a luz e a colocar no grafo de cena não vai, por si só, ter qualquer efeito visível. Seu próximo passo está em falar para os objetos para serem iluminados pela luz. Para fazer isso, use o método nodePath.setLight(), que liga a luz para o nodepath indicado e qualquer coisa abaixo dele no grafo de cena.
In the simplest case, you want all of your lights to illuminate everything they can, so you turn them on at render, the top of the scene graph:
render.setLight(plnp)
You can remove the light setting from render:
render.clearLight(plnp)
You could also apply the setLight() call to a sub-node in the scene graph, so that a given light only affects a particular object or group of objects:
sofa.setLight(plnp)
Note that there are two (or more) different NodePaths involved here: the NodePath of the light itself, which defines the position and/or orientation of the light, and the NodePath(s) on which you call setLight(), which determines what subset of the scene graph the light illuminates. There's no requirement for these two NodePaths to be related in any way.
Lots of Lights: Performance Implications
Each light slows down rendering a little. Using a half-dozen lights to illuminate an object is no problem at all. However, if you were to use a hundred lights to illuminate an object, that object would render slowly.
Because of this, when you create a big virtual world, you need to pick and choose which lights affect which objects. For example, if you had a dungeon containing a hundred torches, it would not be practical to tell every object to be illuminated by every torch. Instead, for each object in the dungeon, you would want to search for the three or four nearest torches, and tell the object to be illuminated only by those three or four torches.
When per-pixel lighting is enabled, lights are considerably more costly. Colored Lights
All lights have a color, which is specified by light.setColor(VBase4(r, g, b, a)). The default color is full white: setColor(VBase4(1, 1, 1, 1)). The alpha component is largely irrelevant.
Note: The R, G, B values can be larger than 1, if you want brighter lights! However, you can't use lighting to make a model brighter than its texture color. Point Lights
Point lights are the easiest kind of light to understand: a point light simulates a light originating from a single point in space and shining in all directions, like a very tiny light bulb. A point light's position is important, but its orientation doesn't matter.
plight = PointLight('plight') plight.setColor(VBase4(0.2, 0.2, 0.2, 1)) plnp = render.attachNewNode(plight) plnp.setPos(10, 20, 0) render.setLight(plnp)
Attenuation
You can set the attenuation coefficients, which causes the light to drop off gradually with distance. There are three attenuation coefficients: A, B, C.
plight.setAttenuation(Point3(A, B, C))
Setting coefficients A and B to 0 and C between 0 and 1 works well.
plight.setAttenuation(Point3(0, 0, 0.5))
Directional Lights
A directional light is an infinite wave of light, always in the same direction, like sunlight. A directional light's position doesn't matter, but its orientation is important. The default directional light is shining down the forward (+Y) axis; you can use nodePath.setHpr() or nodePath.lookAt() to rotate it to face in a different direction.
dlight = DirectionalLight('dlight') dlight.setColor(VBase4(0.8, 0.8, 0.5, 1)) dlnp = render.attachNewNode(dlight) dlnp.setHpr(0, -60, 0) render.setLight(dlnp)
Ambient Lights
An ambient light is used to fill in the shadows on the dark side of an object, so it doesn't look completely black. The light from an ambient light is uniformly distributed everywhere in the world, so the ambient light's position and orientation are irrelevant.
Usually you don't want to create an ambient light without also creating one of the other kinds of lights, since an object illuminated solely by ambient light will be completely flat shaded and you won't be able to see any of its details. Typically, ambient lights are given a fairly dark gray color, so they don't overpower the other lights in the scene.
alight = AmbientLight('alight') alight.setColor(VBase4(0.2, 0.2, 0.2, 1)) alnp = render.attachNewNode(alight) render.setLight(alnp)
Spotlights
Spotlights represent the most sophisticated kind of light. A spotlight has both a point and a direction, and a field-of-view. In fact, a spotlight contains a lens, just like a camera does; the lens should be a PerspectiveLens and is used to define the area of effect of the light (the light illuminates everything within the field of view of the lens).
Note that the English word "spotlight" is one word, as opposed to the other kinds of lights, which are two words. Thus, the class name is correctly spelled "Spotlight", not "SpotLight".
slight = Spotlight('slight') slight.setColor(VBase4(1, 1, 1, 1)) lens = PerspectiveLens() slight.setLens(lens) slnp = render.attachNewNode(slight) slnp.setPos(10, 20, 0) slnp.lookAt(myObject) render.setLight(slnp)
Putting it all Together
Here is an example of lighting. There are an ambient light and two directional lights lighting the scene, and a green ambient light that only affects one of the pandas.
import direct.directbase.DirectStart from pandac.PandaModules import *
- Put two pandas in the scene, panda x and panda y.
x = loader.loadModel("panda") x.reparentTo(render) x.setPos(10,0,-6)
y = loader.loadModel("panda") y.reparentTo(render) y.setPos(-10,0,-6)
- Position the camera to view the two pandas.
base.trackball.node().setPos(0, 60, 0)
- Now create some lights to apply to everything in the scene.
- Create Ambient Light
ambientLight = AmbientLight( 'ambientLight' ) ambientLight.setColor( Vec4( 0.1, 0.1, 0.1, 1 ) ) ambientLightNP = render.attachNewNode( ambientLight.upcastToPandaNode() ) render.setLight(ambientLightNP)
- Directional light 01
directionalLight = DirectionalLight( "directionalLight" ) directionalLight.setColor( Vec4( 0.8, 0.2, 0.2, 1 ) ) directionalLightNP = render.attachNewNode( directionalLight.upcastToPandaNode() )
- This light is facing backwards, towards the camera.
directionalLightNP.setHpr(180, -20, 0) render.setLight(directionalLightNP)
- Directional light 02
directionalLight = DirectionalLight( "directionalLight" ) directionalLight.setColor( Vec4( 0.2, 0.2, 0.8, 1 ) ) directionalLightNP = render.attachNewNode( directionalLight.upcastToPandaNode() )
- This light is facing forwards, away from the camera.
directionalLightNP.setHpr(0, -20, 0) render.setLight(directionalLightNP)
- Now attach a green light only to object x.
ambient = AmbientLight('ambient') ambient.setColor(Vec4(.5,1,.5,1)) ambientNP = x.attachNewNode(ambient.upcastToPandaNode())
- If we did not call setLightOff() first, the green light would add to
- the total set of lights on this object. Since we do call
- setLightOff(), we are turning off all the other lights on this
- object first, and then turning on only the green light.
x.setLightOff() x.setLight(ambientNP)
- run the example
run()