This component defines nodes for using cube map textures.
Such textures generate a color based on a direction.
They are one of the common methods for environment mapping
(that is, simulation of mirror-like surfaces).
ComposedCubeMapTexture
and ImageCubeMapTexture
allow loading a cube map texture from file(s).
GeneratedCubeMapTexture
allows to create and use
an environment map capturing actual environment in your virtual 3D world,
thus making true realtime mirror.
See also X3D specification of the Cube map environmental texturing component.
Contents:
For demos and tests of these features,
see the cube_environment_mapping
subdirectory inside our VRML/X3D demo models.
The GeneratedCubeMapTexture
node is a ready solution
to simulate mirror-like surfaces. It should be coupled with
texture coordinates to reflect in world space to produce a mirror effect in a really easy way.
Choose a shape in your VRML/X3D model that should act like a mirror.
As it's texture set GeneratedCubeMapTexture
node.
This texture will be automatically generated to represent
the environment around the given shape (the shape itself
is not rendered into this texture, it doesn't mirror itself).
Set GeneratedCubeMapTexture.update
to specify when this texture
should be generated. Two sensible values are ALWAYS
(if the world around is dynamic) or NEXT_FRAME_ONLY
(if the world around is completely static).
The texture is actually kept as six square 2D textures inside
the graphic card. You can control the size of these squares
by GeneratedCubeMapTexture.size
: larger values
mean better quality, but also worse speed.
Note that if your shape already uses some texture,
you will have to convert it's textures into MultiTexture
node, with the 1st item containing the old texture,
and the 2nd item containing the new GeneratedCubeMapTexture
.
See "Texturing" component for multi-texture documentation.
As the texture coordinates set TextureCoordinateGenerator
node with mode
field set to WORLDSPACEREFLECTIONVECTOR
.
Note that if your shape already uses some texture coordinates,
you will have to convert them into MultiTextureCoordinate
,
see notes above about MultiTexture
.
Note that in our engine all 3D geometry nodes have the texCoord
field, so you can do this really with every shape.
Even with the primitives
like Box / Cone / Cylinder / Sphere.
Cubemaps are great for mirrors on a curved object (like a sphere, or a teapot). To display mirrors on a flat surface, it is better to use Castle Game Engine extensions for mirrors on flat objects.
As an example, consider this teapot, with bold text to emphasize the mirror stuff:
Shape { appearance Appearance { material Material { } texture GeneratedCubeMapTexture { update "ALWAYS" size 512 } } geometry Teapot { texCoord TextureCoordinateGenerator { mode "WORLDSPACEREFLECTIONVECTOR" } } }
Place this in some interesting environment to see the nice mirror :) This approach works best for curvy surfaces (perfectly flat surfaces usually look bad unless you use really large size), and only if the mirror object is small compared to the surrounding enviroment (as there are are no self-reflections).
ComposedCubeMapTexture
(Pascal API: TComposedCubeMapTextureNode
)
Orientation notes: The images are expected to be oriented just like for the VRML/X3D Background node. This is suggested by the drawing in the spec, although the spec doesn't specify exact orientation of the images. We use Background node orientation, as this is definitely sensible. See Background node spec, paragraph with words "... when viewed from the origin looking down the negative Z-axis ...".
Size notes: Texture size for cube maps is automatically adjusted to be power of two, square, and within OpenGL limits (GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB). So your textures do not necessarily have to be provided with required sizes (if you don't mind a little quality loss because of scaling).
You still must provide equally sized images for all six cube map sides. Our engine makes sure to scale them to be square and power-of-two, but we currently do not attempt to make all six textures equal — so you have to provide textures already satisfying this.
We add textureProperties
field to the ComposedCubeMapTexture
node, intended for TextureProperties
child, working just like
in other texture nodes (you can use it to set minification / magnification
filter, anisotropy and such). Although X3D 3.2 specification doesn't mention this,
it seems natural, and instantreality
also uses this.
We support for cube maps all normal texture filterings, including mipmaps.
ImageCubeMapTexture
(Pascal API: TImageCubeMapTextureNode
)
DDS file format to specify cube maps (including S3TC compressed cube maps) is supported.
GeneratedCubeMapTexture
(Pascal API: TGeneratedCubeMapTextureNode
)
Texture is rendered from the middle 3D point of bounding box
of the shape using this texture. You cannot reUSE the same GeneratedCubeMapTexture
node for various shapes (as then we would not know from which shape
to generate).
The texture before generation (e.g. if you have update = 'NONE' at the start) has pink color (RGB(255, 0, 255)), so you can easily recognize it.
All the generated textures are rendered in a separate
pass before actual rendering, and during this generation other shapes
use existing values of their textures. This means that recursive mirrors,
i.e. mirror that can be seen in another mirror, works to any level
(each frame rendered uses textures generated in the previous frame).
You can see recursive mirrors in our VRML/X3D demo models (see cube_environment_mapping/cubemap_generated_recursive.x3dv
cube_environment_mapping/cubemap_generated_in_dynamic_world.x3dv
).
Provided size
will automatically be adjusted to be power of two,
and within OpenGL limits (GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB).
Current player camera doesn't affect how cube map is generated. This is good, it means that generated texture is usable for as long as the scene remains unchanged, and doesn't have to be regenerated each time when the player moves.
When update = "ALWAYS"
, this optimization is automatically
used under the hood. Texture is internally not updated every frame
— when we know nothing visible changed on the scene, we do
not regenerate the texture (since it would be generated the same).
Note that using the headlight, or any other geometry/light following
the player, makes this optimization less effective (as then every
camera move changes the look of the scene, so rendered textures
have to be regenerated on every camera move).
This also means that generated cube map texture
is similar to static (from ImageCubeMapTexture
and ComposedCubeMapTexture
), and you usually want to
use "WORLDSPACEREFLECTIONVECTOR"
texture generation to simulate mirror.
When using cube maps with GLSL shaders, this often forces the need to
transform directions from eye-space to world-space,
you can obtain appropriate matrix easily by
Viewpoint.cameraRotationInverseMatrix output event.