This is a VRML engine, so many programs here do something non-trivial with VRML files. Not surprisingly, I needed at some point to extend what is allowed by VRML specifications, for various reasons. This page documents these extensions, so everyone can use them.
Note that some of these extensions may not be tolerated by other VRML viewers. However:
Many VRML 2.0 extensions may be preceeded by appropriate EXTERNPROTO statements, this will allow other VRML 2.0 implementations to at least gracefully omit them. Kambi VRML test suite uses this mechanism whenever possible, so that even things inside kambi_extensions/ should be partially handled by other VRML browsers.
Our extensions are identified by URN like "urn:vrmlengine.sourceforge.net:node:KambiTriangulation".
Some extensions may use fallback implementation on URL http://vrmlengine.sourceforge.net/fallback_prototypes.wrl. Such fallback URL will allow other VRML browsers to partially handle our extensions. For example, see EXTERNPROTO example for Text3D — browsers that don't handle Text3D node directly should use our fallback URL and render Text3D like normal 2D text node.
TODO: eventual goal is to make all extensions this way, so that they can be nicely omitted. Also, it would be nice to use VRML 1.0 similar feature, isA and fields, for the same purpose, but it's not implemented yet.
Some of VRML 1.0 extensions are borrowed from VRML 97 specification (e.g. attenuation field for lights), I just allow them also in VRML 1.0.
Some other extensions like compressing VRML files by gzip or multiple root nodes in VRML 1.0 are often implemented in other VRML viewers.
To understand specifications of these extensions you will need some basic knowledge of VRML. Here you can find official VRML 1.0 and 97 specifications if you want to educate yourself.
VRML fields and nodes are specified on this page in the convention somewhat similar to VRML 97 specification:
NodeName {
fieldKind FieldType fieldName default_value # short comment
...
}
Example VRML models that use these extensions may be found in Kambi VRML test suite — look inside vrml_1/kambi_extensions/ and vrml_2/kambi_extensions/ subdirectories.
Programmable shaders (X3D feature "backported" to VRML)
|
Although X3D is not supoorted yet by our engine, I already implemented some X3D features and they are available for VRML 2.0 authors. See VRML implementation status about X3D.
For now, these features are programmable shaders. ComposedShader and ShaderPart nodes allow you to write shaders in GLSL language. For example add inside Appearance node VRML code like
shaders ComposedShader {
language "GLSL"
parts [
ShaderPart { type "VERTEX" url "glsl_phong_shading.vs" }
ShaderPart { type "FRAGMENT" url "glsl_phong_shading.fs" }
]
}
See Kambi VRML test suite, directory vrml_2/kambi_extensions/shaders/ for working demos of this.
Oh, and some other programmable shader features are quite trivial to implement (attributes and uniforms for shaders in VRML). They are implemented in the engine classes anyway, it's only a matter of implementing link between VRML and them. If you have some interesting VRML / X3D models that use these programmable shaders features, feel free to contact me and I'll implement them in our engine.
(I mean, I will implement them anyway some day, but it's always much more interesting to implement features when you actually have a real use for them... In other words, I'm just dying to see some beautiful VRML/X3D models that heavily use programmable shaders :).
Bump mapping (normalMap, heightMap, heightMapScale fields of KambiAppearance)
Instead of Appearance node, you can use KambiApperance node that adds some new fields useful for bump mapping:
KambiAppearance {
... all normal Appearance fields ...
exposedField SFNode normalMap NULL # only texture nodes (ImageTexture, MovieTexture, PixelTexture) allowed
exposedField SFNode heightMap NULL # only texture nodes (ImageTexture, MovieTexture, PixelTexture) allowed
exposedField SFFloat heightMapScale 0.01 # must be > 0, meaningful only if heightMap specified
}
|
|
|
|
Texture specified as normalMap describes normal vector values on each texel. Normal vector values are actually encoded as colors: normal vector (x, y, z) should be encoded as RGB((x+1)/2, (y+1)/2, (z+1)/2). You can use e.g. GIMP normalmap plugin to generate such normal maps. (Hint: Remember to check "invert y" when generating normal maps, in image editing programs image Y grows down but we want Y (as interpreted by normals) to grow up, just like texture T coordinate.)
This allows bump mapping to be used. If you set BumpMappingMaximum attribute (and pass light position for bump mapping), our VRML engine will automatically do appropriate bump mapping.
normalMap is enough to use normal bump mapping ("dot product" method, done by pure multitexturing or GLSL programs, depending on OpenGL capabilities). If you additionally specify some texture as heightMap then parallax mapping (steep parallax mapping with self-shadowing, if used OpenGL will support it) will be additionally used. heightMapScale allows you to tweak the perceived height of bumps for parallax mapping.
You can test it in
You can turn it on and see the effects in view3dscene. In view3dscene, for simplicity, bump mapping light position is always set to current camera position. Sample models with normal maps and height maps are inside Kambi VRML test suite, in directory vrml_2/kambi_extensions/bump_mapping/.
You can see this used in The Castle "The Fountain" level. Authors of new levels are encouraged to use bump mapping !
Programmers may also compile and run example program 3dmodels.gl/examples/bump_mapping/ in engine sources, this allows to really play with bump mapping settings and see how to use this in your own programs.
Note that currently bump mapping is used only when normal texture ("normal" texture as in "texture used for normal purposes, in texture field of Appearance") is also specified. Also, it's used only with IndexedFaceSet nodes, and only when texture coordinates were specified explicitly.
We add new node:
Text3D {
exposedField MFString string []
exposedField SFNode fontStyle NULL
exposedField MFFloat length []
exposedField SFFloat maxExtent 0
exposedField SFFloat depth 0.1 # must be >= 0
exposedField SFBool solid TRUE
}
This renders the text, pretty much like Text node from VRML 97 (see VRML 97 specification about string, fontStyle, length, maxExtent fields). But the text is 3D: it's "pushed" by the amount depth into negative Z. The normal text is on Z = 0, the 3D text had front cap on Z = 0, back cap on Z = -Depth, and of course the extrusion (sides).
Also, it's natural to apply backface culling to such text, so we have a solid field. When true (default), then backface culling is done. This may provide much speedup, unless camera is able to enter "inside" the text geometry (in which case solid should be set to FALSE).
If depth is zero, then normal 2D text is rendered. However, backface culling may still be applied (if solid is true) — so this node also allows you to make 2D text that's supposed to be visible from only front side.
See Kambi VRML test suite, file vrml_2/kambi_extensions/text_depth.wrl for example use of this.
Compatibility:
EXTERNPROTO Text3D [
exposedField MFString string
exposedField SFNode fontStyle
exposedField MFFloat length
exposedField SFFloat maxExtent
exposedField SFFloat depth
exposedField SFBool solid
] [ "urn:vrmlengine.sourceforge.net:node:Text3D",
"http://vrmlengine.sourceforge.net/fallback_prototypes.wrl#Text3D" ]
This way other VRML browsers should be able to render Text3D node like normal 2D Text.
Mixing VRML 1.0 and 2.0 nodes and features
Because of the way how I implemented VRML 1.0 and 2.0 handling,
you have effectively the sum of VRML 1.0 and 2.0 features
available. Which means that actually you can mix VRML 1.0 and 2.0
nodes to some extent. If given node name exists in both VRML versions,
then VRML file header defines how the node behaves. Otherwise,
node behaves according to it's VRML specification.
For example, this means that a couple of VRML 2.0 nodes are available (and behave exactly like they should) also for VRML 1.0 authors:
Also VRML 1.0 things are available in VRML 2.0, e.g. OrthographicCamera (this is one thing not available to say to in VRML 2.0 specification).
You can also freely include VRML 1.0 files inside VRML 2.0, or the other way around.
Volumetric fog (additional fields for Fog node)
I add to Fog node some additional fields to allow
definition of volumetric fog:
Fog {
...
exposedField SFBool volumetric FALSE
exposedField SFVec3f volumetricDirection 0 -1 0 # any non-zero vector
exposedField SFFloat volumetricVisibilityStart 0
exposedField SFNode alternative # NULL or another Fog node
}
Meaning: when volumetric is FALSE (the default), every other volumetricXxx field is ignored and Fog behaves like defined in VRML 97 spec. If volumetric is TRUE, then the volumetric fog is used.
volumetricDirection is the direction of the volumetric fog, it must be any non-zero vector (it's length doesn't matter). Every vertex of the 3D scene is projected on volumetricDirection vector, and then the resulting distance (signed distance, i.e. along the direction of this vector) of this point is used to determine fog amount. For example: in the simple case when volumetricDirection is (0, 1, 0), then the Y coordinate of every vertex determines the amount of fog. In the default case when volumetricDirection is (0, -1, 0), then the negated Y coordinate of every vertex determines the amount of fog. I will call such calculated amount of fog the FogAmount.
Now FogAmount values between volumetricVisibilityStart and volumetricVisibilityStart + visibilityRange correspond to fog color being applied in appropriately 0 (none) and 1 (full) amount. fogType determines how values between are interpolated (in the simple LINEAR case they are interpolated linearly).
Note that volumetricVisibilityStart is transformed by the Fog node transformation scaling, just like visibilityRange in VRML spec.
Note that visibilityRange must stay >= 0, as required by VRML specification. This means that volumetricDirection always specifies the direction of the fog: the more into volumetricDirection, the more fog appears. For example, if your world is oriented such that the +Y is the "up", and ground is on Y = 0, and you want your fog to start from height Y = 20, you should set volumetricDirection to (0, -1, 0) (actually, that's the default) and set volumetricVisibilityStart to -20 (note -20 instead of 20; flipping volumetricDirection flips also the meaning of volumetricVisibilityStart).
Oh, and note that in our programs for now EXPONENTIAL fog (both volumetric and not) is actually approximated by OpenGL exponential fog. Equations for OpenGL exponential fog and VRML exponential fog are actually different and incompatible, so results will be a little different than they should be.
VRML test suite has test VRMLs for this (see vrml_1/kambi_extensions/fog_volumetric/ and vrml_2/kambi_extensions/fog_volumetric/ subdirectories). Also our games malfunction and The Castle use it.
One additional field not explained yet: alternative. This will be used if current graphic output (e.g. OpenGL implementation) for any reason doesn't allow volumetric fog (or at least doesn't allow it to be implemented efficiently). Currently, this means that GL_EXT_fog_coord extension is not supported. In such case we'll look at alternative field:
If alternative is NULL (the default), then no fog will be rendered.
Otherwise we'll try to use fog node recorded in alternative.
If fog node recorded in alternative is not suitable too (e.g. because it also uses volumetric fog) then we'll look at it's alternative field in turn... So in the usual case a fog node placed within the alternative will not use volumetric fog.
alternative will also be tried if the value specified in fogType field of Fog node is not recognized.
Special objects immune to fog (fogImmune field for Material node)
New field for Material node:
Material {
...
exposedField SFBool fogImmune FALSE
}
When fogImmune of given object's material is TRUE, then the fog effect (specified by Fog node) is not applied to the object. Object is "immune" to fog.
This should be used only in a very special cases, when the scene looks better with the material left without fog effect. For example, I used this in The Castle for a river surface material — it's a transparent material, and the whole level is covered with a volumetric fog. It just looks better when the river surface is not affected by the fog color.
Inline nodes allow to include 3D models in other handled formats (3DS, MD3, Wavefront OBJ, Collada) and any VRML version
Inline nodes (Inline and InlineLoadControls in VRML 2.0
and WWWInline in VRML 1.0) allow you to include not only
other VRML files, but also other 3DS, MD3, Wavefront OBJ, Collada models.
Internally, all those formats are converted to VRML before
displaying anyway. If you want to precisely know how the conversion
to VRML goes, you can always do the explicit conversion to VRML
by using "Save as VRML"
view3dscene command.
Also, you can freely mix VRML versions when including. You're free to include VRML 1.0 file inside VRML 2.0 file, or the other way around. Everything works.
Specify triangulation (node KambiTriangulation)
New node:
KambiTriangulation {
exposedField SFLong quadricSlices -1 # {-1} + [3, infinity)
exposedField SFLong quadricStacks -1 # {-1} + [2, infinity)
exposedField SFLong rectDivisions -1 # [-1, infinity)
}
This node affects rendering of subsequent Sphere, Cylinder, Cone and Cube nodes. For VRML 1.0 you can delimit the effect of this node by using Separator node, just like with other VRML "state changing" nodes. For VRML 2.0 every grouping node (like Group) always delimits this, so it only affects nodes within it's parent grouping node (like many other VRML 2.0 nodes, e.g. DirectionalLight or sensors).
When rendering sphere, cylinder, cone or cube we will triangulate (divide the surfaces into triangles) with settings specified in last KambiTriangulation node. quadricSlices divides like pizza slices, quadricStacks divides like tower stacks, rectDivisions divides rectangular surfaces of a Cube. More precise description of this triangulation is given at description of --detail-... options in view3dscene documentation. Comments given there about so-called over-triangulating apply also here.
Special value -1 for each of these fields means that the program can use it's default value. In case of view3dscene and rayhunter they will use values specified by command-line options --detail-... (or just compiled-in values (see source code) if you didn't specify --detail-... options).
Note that this node gives only a hints to the renderer. Various algorithms and programs may realize triangulation differently, and then hints given by this node may be interpreted somewhat differently or just ignored. That said, this node is useful when you're designing some VRML models and you want to fine-tune the compromise between OpenGL rendering speed and quality of some objects. Generally, triangulate more if the object is large or you want to see light effects (like light spot) looking good. If the object is small you can triangulate less, to get better rendering time.
VRML files may be compressed by gzip
All our programs can handle VRML files compressed with gzip.
E.g. you can call view3dscene like
view3dscene my_compressed_vrml_file.wrl.gz
and you can use WWWInline nodes that refer to gzip-compressed VRML
files, like
WWWInline { name "my_compressed_vrml_file.wrl.gz" }
Files with extensions .gz or .wrz are assumed to be always compressed by gzip.
Files with normal extension .wrl but actually compressed by gzip are also handled OK. Currently, there's a small exception to this: when you give view3dscene VRML file on stdin, this file must be already uncompressed (so you may need to pipe your files through gunzip -c). TODO: this is intended to be fixed, although honestly it has rather low priority now.
A personal feeling about this feature from the author (Kambi): I honestly dislike the tendency to compress the files with gzip and then change the extension back to normal .wrl. It's handled by our engine, but only because so many people do it. I agree that it's often sensible to compress VRML files by gzip (especially since before X3D, there was no binary encoding for VRML files). But when you do it, it's also sensible to leave the extension as .wrl.gz, instead of forcing it back into .wrl, hiding the fact that contents are compressed by gzip. Reason: while many VRML browsers detect the fact that file is compressed by gzip, many other programs, that look only at file extension, like text editors, do not recognize that it's gzip data. So they treat .wrl file as a stream of unknown binary data. Programs that analyze only file contents, like Unix file, see that it's a gzip data, but then they don't report that it's VRML file (since this would require decompressing).
Also note that WWW servers, like Apache, when queried by modern WWW browser, can compress your VRML files on the fly. So, assuming that VRML browsers that automatically fetch URLs, will be also intelligent, the compression is done magically over HTTP protocol, and you don't have to actually compress VRML files to save bandwidth.
Node NavigationInfo handling details
Various details about how we handle NavigationInfo node in
view3dscene:
When no NavigationInfo node is present in the scene, we try to intelligently guess related properties. (We try to guess "intelligently" because simply assuming that "no NavigationInfo node" is equivalent to "presence of default NavigationInfo" is not good for most scenes).
Fields direction and up and gravityUp for PerspectiveCamera, OrthographicCamera and Viewpoint nodes
Standard VRML way of specifying camera orientation
(look direction and up vector) is to use orientation field
that says how to rotate standard look direction vector (<0,0,-1>)
and standard up vector (<0,1,0>). While I agree that this
way of specifying camera orientation has some advantages
(e.g. we don't have the problem with the uncertainty
"Is look direction vector length meaningful ?")
I think that this is very uncomfortable for humans.
Reasoning:
Also, VRML 2.0 spec says that the gravity upward vector should be taken as +Y vector transformed by whatever transformation is applied to Viewpoint node. This also causes similar problems, since e.g. to have gravity upward vector in +Z you have to apply rotation to your Viewpoint node.
So I decided to create new fields for PerspectiveCamera, OrthographicCamera and Viewpoint nodes to allow alternative way to specify an orientation:
PerspectiveCamera / OrthographicCamera / Viewpoint {
...
exposedField MFVec3f direction []
exposedField MFVec3f up []
exposedField SFVec3f gravityUp 0 1 0
}
If at least one vector in direction field is specified, then this is taken as camera look vector. Analogous, if at least one vector in up field is specified, then this is taken as camera up vector. This means that if you specify some vectors for direction and up then the value of orientation field is ignored. direction and up fields should have either none or exactly one element.
As usual, direction and up vectors can't be parallel and can't be zero. They don't have to be orthogonal — up vector will be always silently corrected to be orthogonal to direction. Lengths of these vectors are always ignored.
As for gravity: VRML 2.0 spec says to take standard +Y vector and transform it by whatever transformation was applied to Viewpoint node. So we modify this to say take gravityUp vector and transform it by whatever transformation was applied to Viewpoint node. Since the default value for gravityUp vector is just +Y, so things work 100% conforming to VRML spec if you don't specify gravityUp field.
In view3dscene "Print current camera node" command (key shortcut Ctrl+C) writes camera node in both versions — one that uses orientation field and transformations to get gravity upward vector, and one that uses direction and up and gravityUp fields.
Mirror material (field mirror for Material node)
You can mark surfaces as being mirrors by using this field.
Material {
...
exposedField MFFloat / SFFloat mirror 0.0 # [0.0; 1.0]
}
Currently this is respected only by classic ray-tracer in view3dscene and rayhunter. Well, it's also respected by path-tracer, although it's much better to use fields describing physical properties (Phong's BRDF) for Material node when using path-tracer. In the future mirror field may be somehow respected with normal OpenGL rendering in view3dscene and others.
0.0 means no mirror (i.e. normal surface), 1.0 means the perfect mirror (i.e. only reflected color matters). Values between 0.0 and 1.0 mean that surface's color is partially taken from reflected color, partially from surface's own material color.
Note that this field can be (ab)used to specify completely unrealistic materials. That's because it's not correlated in any way with shininess and specularColor fields. In the Real World the shininess of material is obviously closely correlated with the ability to reflect environment (after all, almost all shiny materials are also mirrors, unless they have some weird curvature; both shininess and mirroring work by reflecting light rays). However, in classic ray-tracer these things are calculated in different places and differently affect the resulting look (shininess and specularColor calculate local effect of the lights, and mirror calculates how to mix with the reflected color). So the actual "shiny" or "matte" property of material is affected by shininess and specularColor fields as well as by mirror field.
Headlight properties (node KambiHeadLight)
If this node is present and headlight is turned on (e.g. because
headlight field of NavigationInfo is TRUE)
then this configures the headlight properties.
The default values of this node are compatible with VRML specification, that explicitly states that NavigationInfo.headlight should have intensity = 1, color = (1 1 1), ambientIntensity = 0.0, and direction = (0 0 -1).
KambiHeadLight {
exposedField SFFloat ambientIntensity 0 # [0.0, 1.0]
exposedField SFVec3f attenuation 1 0 0 # [0, infinity)
exposedField SFColor color 1 1 1 # [0, 1]
exposedField SFFloat intensity 1 # [0, 1]
exposedField SFBool spot FALSE
exposedField SFFloat spotDropOffRate 0
exposedField SFFloat spotCutOffAngle 0.785398
}
The meaning of these field should be self-explanatory: ambientIntensity, attenuation, color and intensity are the same as for PointLight or DirectionalLight in VRML 2.0. If spot is TRUE then the light makes a spot, meaning of spotDropOffRate and spotCutOffAngle is the same as in VRML 1.0 (I didn't use beamWidth from VRML 2.0 spec because it translates badly to OpenGL).
Specify how lights cast shadows (fields kambiShadows and kambiShadowsMain for light nodes)
To all VRML light nodes, we add two fields:
XxxLight {
...
exposedField SFBool kambiShadows FALSE
exposedField SFBool kambiShadowsMain FALSE # meaningfull only when kambiShadows = TRUE
}
These extensions specify the shadows behavior.
They are parsed and handled generally in our
Kambi VRML game engine.
But they actually do something only when we render with shadows —
which means, for now, that these extensions are usefull for you
only if you design levels for
"The Castle".
The idea is that shadows are actually projected from only one light source (with shadow volumes, number of light sources is limited, since more light sources mean more rendering passes; for now, I decided to use only one light). The scene lights are divided into three groups:
First of all, there's one and exactly one light that makes shadows. Which means that shadows are made where this light doesn't reach. This should usually be the dominant, most intensive light on the scene.
This is taken as the first light node with kambiShadowsMain and kambiShadows = TRUE. Usually you will set kambiShadowsMain to TRUE on only one light node.
There are other lights that don't determine where shadows are, but they are turned off where shadows are. This seems like a nonsense from "realistic" point of view — we turn off the lights, even though they may reach given scene point ? But, in practice, it's often needed to put many lights in this group. Otherwise, the scene could be so light, that shadows do not look "dark enough".
All lights with kambiShadows = TRUE are in this group. (As you see, the main light has to have kambiShadows = TRUE also, so the main light is always turned off where the shadow is).
These are lights with kambiShadows = FALSE (default).
Usually you have to experiment a little to make the shadows look good. This involves determining which light should be the main light (kambiShadowsMain = kambiShadows = TRUE), and which lights should be just turned off inside the shadow (only kambiShadows = TRUE). This system tries to be flexible, to allow you to make shadows look good — which usually means "dark, but not absolutely unrealistically black".
In "The Castle" you can experiment with this using Edit lights inside debug menu.
If no "main" light is found (kambiShadowsMain = kambiShadows = TRUE) then shadows are turned off on this level.
Trick: note that you can set the main light to have on = FALSE. This is the way to make "fake light" — this light will determine the shadows position (it will be treated as light source when calculating shadow placement), but will actually not make the scene lighter (be sure to set for some other lights kambiShadows = TRUE then). This is a useful trick when there is no comfortable main light on the scene, so you want to add it, but you don't want to make the scene actually brighter.
Field parts in Cone and Cylinder nodes may have value NONE
This way every possible value is allowed for parts
field. This is comfortable for operating on these nodes,
especially from programs — there is no special "forbidden" value.
Fields attenuation and ambientIntensity for light nodes
Lights that have a position, i.e. PointLight and SpotLight
nodes, have the field attenuation. The meaning of this
field is
exactly the same as in VRML 97.
I allow this for VRML 1.0 because this is really useful,
and because the default value of this field (1,0,0)
assures that standard VRML 1.0 files are interpreted correctly.
Moreover, all lights have ambientIntensity field, also defined exactly like in VRML 97. However, when reading VRML 1.0 files, we treat default value of ambientIntensity as -1 (while VRML 97 specification gives 0). And when rendering, we treat lights with ambientIntensity < 0 specially: we treat them like ambientIntensity = intensity. This way:
Parts of Inventor in VRML
Some Inventor-specific things are allowed:
These things allow me to handle many Inventor 1.0 files. They also allow me to handle many broken VRML 1.0 files that sometimes falsely claim that they are VRML 1.0 while in fact they use some Inventor-specific features.
Multi root node
VRML 1.0 file may have any number of root nodes
(VRML 1.0 spec requires that there is exactly one root node).
I implemented this because
Fields describing physical properties (Phong's BRDF) for Material node
In rayhunter's path-tracer I implemented Phong's BRDF.
To flexibly operate on material's properties understood
by Phong's BRDF you can use the following Material node's
fields:
Material {
...
exposedField MFColor reflSpecular [] # specular reflectance
exposedField MFColor reflDiffuse [] # diffuse reflectance
exposedField MFColor transSpecular [] # specular transmittance
exposedField MFColor transDiffuse [] # diffuse transmittance
exposedField MFFloat reflSpecularExp 1000000 # specular reflectance exponent
exposedField MFFloat transSpecularExp 1000000 # specular transmittance exponent
}
Short informal description how these properties work (for precise description see Phong's BRDF equations or source code of my programs):
All these fields have multi- type (like other fields of Material node) to allow you to specify many material kinds at once.
Two *SpecularExp fields have default values equal to 1 000 000 = 1 million = practically infinity (bear in mind that they are exponents for cosinus). Other four fields have very special default values. Formally, they are equal to zero-length arrays. If they are left as being zero-length arrays, they will be calculated as follows :
This way you don't have to use any of described here 6 fields. You can use only standard VRML fields (and maybe mirror field) and path tracer will use sensible values derived from other Material fields. If you will specify all 6 fields described here, then path tracer will completely ignore other Material fields.
You can use kambi_mgf2inv program to convert MGF files to VRML 1.0 with these six additional Material fields. So you can easily test my ray-tracer using your MGF files.
These fields are used only by path tracer in rayhunter and view3dscene.
Field separate for WWWInline node
I'm adding new field:
WWWInline {
...
exposedField SFBool separate TRUE
}
To explain this field, let's create an example. Assume you have file 1.wrl with following contents:
#VRML V1.0 ascii
Material { diffuseColor 1 0 0 }
And a file 2.wrl with following contents:
#VRML V1.0 ascii
Group {
WWWInline { name "1.wrl" }
Cube { }
}
Question: what material is used by the cube ? The red material (defined in 1.wrl) or the default material ? In other words, do the state changes inside 1.wrl "leak outside" of WWWInline node ?
The answer (stated by VRML specification, and followed by our programs when separate is TRUE (the default)) is that the cube uses the default material. Not the red material. In other words, state changes do not "leak" outside. This is definitely a sensible behavior. This is safer for the author of VRML files (you're not so "vulnerable" to changes done in included files). And it allows to delay loading of inlined file until it's really needed (e.g. is potentially visible). Effectively, this means that WWWInline behaves a little like a Separator node. File 2.wrl is equivalent to
#VRML V1.0 ascii
Group {
Separator {
Material { diffuseColor 1 0 0 }
}
Cube { }
}
On the other hand, when you set field separate to FALSE, the cube will be red. Every state change done inside inlined file will affect the things defined after WWWInline node. Effectively, this means that WWWInline behaves a little like a Group node. Two files below are equivalent:
#VRML V1.0 ascii
Group {
WWWInline { name "1.wrl" separare FALSE }
Cube { }
}
#VRML V1.0 ascii
Group {
Group {
Material { diffuseColor 1 0 0 }
}
Cube { }
}
Generally, setting field separate to FALSE is a little dangerous (because you have to be careful what you include), but it also allows you to do various tricks.
Test VRML file: see VRML test suite, file vrml_1/kambi_extensions/inline_not_separate.wrl.