LightAndCameraProjections
From Odwiki
Contents |
Application Note: Using render-time Camera projections
In production it may often happen that you need to project textures from the camera perspective onto geometry. Here we will discuss using the NDC space of shaders to extract a screen-space position and using these coordinated for looking up into a texturemap.
One thing to keep in mid with the following techniques is that your camera and light projections need to have their projection CameraFrustum set to be the same exact PictureAspect as the texture image you wish to project or there will be some undesired misalignment. However, if you cannot avoid this or if you have a non-square PixelAspect you will have to manipulate the resultant coordinates yourself. Doing this is usually fairly simple but currently this AppNote doesn't cover it.
VEX Shaders: Projecting a texture from Camera
In order to texturemap the geometry with the corresponding location in the texture map, you need to know the screen-space position of the point you're currently shading. These coordinates are called the Neutral Device Coordinates - or NDC coordinates. To do this, you can take advantage of the VEX function toNDC() or the VOP node called the ToNDCVOP.
Into either of these functions, supply "P" - the Global Variable representing the point being shaded. The result will be a vector coordinate which will range between zero and one in the .x and .y components representing their position on the screen. Zeros mean bottom/left and ones mean top/right.
These components are now typically fed into a texture() call or TextureVOP and the results from this should contribute to the output colour (Cf).
In VEX:
vector camera_projection_uv = toNDC( P );
In VOPS:
- wire P from a GlobalVariablesVOP into a ToNDCVOP
- the output can now be wired into a TextureVOP (via a VectorToFloatVOP).
When to and when not to use the UVTextureSOP
Please note that for many cases using the UVTextureSOP may suffice. However, for very simplified geometry and cases where you need to have the texture extend right up to the borders of the screen you would be better off using this shading-time projection. The UVTextureSOP does not project sensible coordinates outside the CameraFrustum, and so unless you have geometry subdivided at the exact borders of the view to receive accurate texture coordinates, you will see mapping errors around the edges of geometry.
If you end up doing any amount of this type of projection mapping, you may find that you need to project textures from another camera in your scene. Mantra has no concept of more than one true camera (unfortunately), but it does support multiple lights which exhibit all the same projection capabilities as cameras. So here you have to use a light to do this.
VEX Shaders: Projecting a texture from Light
Firstly, read the text above for projecting from Camera because the concept is extremely similar. For example's sake, lets pretend you named the light you wish to project from "projection_light".
What you must do to project from a light is the following- take the point position you're rendering, find out where it is in the light's space and then perform the toNDC operation.
So, in VEX:
vector uv_from_light = toNDC( ltransform( "texture_light", P ) );
In VOPs:
- wire P from a GlobalVariablesVOP into a SpaceChangeToObjectVOP (type:Light, name:projection_light)
- wire the output of the SpaceChangeToObjectVOP into a ToNDCVOP
- the output can now be wired into a TextureVOP (via a VectorToFloatVOP).
LightShaders
Please note that this projection above describes how to perform the projection in a SurfaceShader or DisplacementShader - not a LightShader. If you wish to project textures from a light in a LightShader then you will have to transform the point into the space of the current object that the light shader is attached to. Now because you've attached the shader to a light already, there is no need to know the name of the light inside of the shader - merely transform the point (Ps) into the object space and then find the NDC space.
vector uv_from_light = toNDC( wo_space( Ps ) );



