{"id":5694,"date":"2025-07-09T15:55:43","date_gmt":"2025-07-09T15:55:43","guid":{"rendered":"https:\/\/castle-engine.io\/wp\/?p=5694"},"modified":"2025-07-10T09:35:47","modified_gmt":"2025-07-10T09:35:47","slug":"support-for-new-tangent-node-in-x3d-with-vectors-as-4d-better-aligned-with-gltf","status":"publish","type":"post","link":"https:\/\/castle-engine.io\/wp\/2025\/07\/09\/support-for-new-tangent-node-in-x3d-with-vectors-as-4d-better-aligned-with-gltf\/","title":{"rendered":"Support for new Tangent node in X3D, with vectors as 4D, better aligned with glTF"},"content":{"rendered":"<table class=\"thumbnails thumbnails-align-right\"><tr><td>\n          <a href=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2025\/07\/scene_screenshot_castle_model_viewer.png\"\n             class=\"screenshot\"\n             title=\"Bump mapping with explicit tangent vectors. See https:\/\/github.com\/castle-engine\/demo-models\/tree\/master\/gltf\/tangents for info and credits.\"><img loading=\"lazy\" decoding=\"async\"\n            style=\"float: right\"\n            src=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2025\/07\/scene_screenshot_castle_model_viewer-200x113.png\"\n             width=\"200\" height=\"113\" \n            alt=\"Bump mapping with explicit tangent vectors. See https:\/\/github.com\/castle-engine\/demo-models\/tree\/master\/gltf\/tangents for info and credits.\"\n          ><\/a><\/td><\/tr><tr><td>\n          <a href=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2025\/07\/scene_screenshot_castle_model_viewer-1.png\"\n             class=\"screenshot\"\n             title=\"Bump mapping with explicit tangent vectors. See https:\/\/github.com\/castle-engine\/demo-models\/tree\/master\/gltf\/tangents for info and credits.\"><img loading=\"lazy\" decoding=\"async\"\n            style=\"float: right\"\n            src=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2025\/07\/scene_screenshot_castle_model_viewer-1-200x113.png\"\n             width=\"200\" height=\"113\" \n            alt=\"Bump mapping with explicit tangent vectors. See https:\/\/github.com\/castle-engine\/demo-models\/tree\/master\/gltf\/tangents for info and credits.\"\n          ><\/a><\/td><\/tr><tr><td>\n          <a href=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2025\/07\/scene_screenshot_castle_model_viewer-2.png\"\n             class=\"screenshot\"\n             title=\"Bump mapping with explicit tangent vectors. See https:\/\/github.com\/castle-engine\/demo-models\/tree\/master\/gltf\/tangents for info and credits.\"><img loading=\"lazy\" decoding=\"async\"\n            style=\"float: right\"\n            src=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2025\/07\/scene_screenshot_castle_model_viewer-2-200x113.png\"\n             width=\"200\" height=\"113\" \n            alt=\"Bump mapping with explicit tangent vectors. See https:\/\/github.com\/castle-engine\/demo-models\/tree\/master\/gltf\/tangents for info and credits.\"\n          ><\/a><\/td><\/tr><tr><td>\n          <a href=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2025\/07\/NormalTangentMirrorTest_0.png\"\n             class=\"screenshot\"\n             title=\"Tangent vectors test from Khronos sample assets\"><img loading=\"lazy\" decoding=\"async\"\n            style=\"float: right\"\n            src=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2025\/07\/NormalTangentMirrorTest_0-200x113.png\"\n             width=\"200\" height=\"113\" \n            alt=\"Tangent vectors test from Khronos sample assets\"\n          ><\/a><\/td><\/tr><\/table>\n<p>The short version of this post, if you don&#8217;t want to go into technical details, is that one aspect of using <em>bump mapping<\/em> is now better in <em>Castle Game Engine<\/em>. Our data transfer and logic is more efficient and more aligned with glTF and latest X3D specifications.<\/p>\n<p>And if you still don&#8217;t want to go into technical details, you can <a href=\"https:\/\/github.com\/castle-engine\/demo-models\">clone our demo-models repository<\/a> and open the models in subdirectory <a href=\"https:\/\/github.com\/castle-engine\/demo-models\/tree\/master\/bump_mapping\/tangents\">bump_mapping\/tangents\/<\/a>. There are 3 models there, and they are all available in both <a href=\"https:\/\/castle-engine.io\/gltf\">glTF<\/a> and <a href=\"https:\/\/castle-engine.io\/x3d\">X3D<\/a> model formats (<code>scene.gltf<\/code>, <code>scene.x3d<\/code>). Open them using the latest <a href=\"https:\/\/castle-engine.io\/castle-model-viewer\">Castle Model Viewer snapshot (5.3.0)<\/a> and they should work equally well and pretty.<\/p>\n<p>You can also <a href=\"https:\/\/github.com\/KhronosGroup\/glTF-Sample-Assets\/\">clone glTF-Sample-Assets<\/a> and open the testcase <a href=\"https:\/\/github.com\/KhronosGroup\/glTF-Sample-Assets\/tree\/main\/Models\/NormalTangentMirrorTest\">NormalTangentMirrorTest<\/a> there and observe that we handle it correctly (well, as much as we can without <a href=\"https:\/\/castle-engine.io\/roadmap#_environment_lighting\">environment lighting<\/a>).<\/p>\n<p>You can also watch our old video about <a href=\"https:\/\/www.youtube.com\/watch?v=3dA8IT8C_Js\">using normalmaps with Blender and Castle Game Engine<\/a>. When using <em>normal maps<\/em>, you do <em>bump mapping<\/em> and then exporting your models with <em>tangent vectors<\/em> makes sense. It&#8217;s literally one checkbox when doing Blender->glTF export.<\/p>\n<p>An if you&#8217;re still reading, time&#8217;s out! Now I assume you <em>want to go into technical details<\/em> \ud83d\ude42 So what are  <em>tangents<\/em> and what&#8217;s going on?<\/p>\n<ul>\n<li>To make <em>bump mapping<\/em> look good, the 3D models may provide explicit information about the <em>tangent vectors<\/em> at the surface.<\/p>\n<\/li>\n<li>\n<p>Our <a href=\"https:\/\/github.com\/michaliskambi\/x3d-tests\/wiki\/Tangent-node-in-X3D\">proposal of Tangent node<\/a> contains a good explanation what <em>tangent vectors<\/em> are and why do we recommend to provide them in 3D models (if you use bump mapping). In short, tangent vectors, along with normal vectors, define the <em>tangent coordinate space<\/em> in which the values of the <em>normal map<\/em> are provided. Whatever process you use to create normal maps (most of you <em>bake<\/em> normal maps), it&#8217;s best to provide to the rendering engine the same tangent vectors as have been assumed when creating the normal map. In other words, simplifying, it&#8217;s best if <a href=\"https:\/\/castle-engine.io\/blender\">Blender<\/a> calculates tangent vectors, and uses the same tangent vectors for normalmap baking and passes the same vectors to glTF.<\/p>\n<\/li>\n<li>\n<p>glTF standard defines how to store tangent vectors, Blender->glTF exporter can generate them, and we read the information from glTF, and convert it into X3D <code>Tangent<\/code> node.<\/p>\n<\/li>\n<li>\n<p>We already had <code>Tangent<\/code> node in our engine for some time, but with a definition that had a small simplification: I defined the vectors there as <em>3D, right-handed<\/em>. In contrast, glTF defines them as <em>4D, with XYZ designating direction, and W designating the handedness<\/em>. We think the glTF idea is quite smart and useful \ud83d\ude42<\/p>\n<\/li>\n<li>\n<p>We have recently recommended to add <code>Tangent<\/code> node to the X3D spec, <a href=\"https:\/\/github.com\/michaliskambi\/x3d-tests\/wiki\/Tangent-node-in-X3D\">the proposal is here<\/a>. While adding to X3D, we also proposed to add them in a version more aligned with glTF, so 4D.<\/p>\n<\/li>\n<li>\n<p>Of note is that <a href=\"https:\/\/create3000.github.io\/x_ite\/\">X_ITE<\/a>, another cool open-source X3D viewer, also has <a href=\"https:\/\/create3000.github.io\/x_ite\/components\/rendering\/tangent\/\">compatible Tangent node<\/a>. With 4D, matching also glTF. So after this, we&#8217;re all better aligned.<\/p>\n<\/li>\n<li>\n<p>The new <a href=\"https:\/\/www.web3d.org\/specifications\/X3Dv4Draft\/ISO-IEC19775-1v4.1-CD\/\/Part01\/components\/rendering.html#Tangent\">X3D prose about Tangent node is here<\/a>.<\/p>\n<\/li>\n<li>\n<p>And to close the circle, the <em>Castle Game Engine<\/em> has now adopted this <code>Tangent<\/code> node specification with 4D vectors. This means we display X3D models with the new <code>Tangent<\/code> node, and when reading glTF we convert the glTF -> X3D information in the trivial way (glTF 4D tangents -> X3D 4D tangents).<\/p>\n<\/li>\n<\/ul>\n<p>Does anyone still follow? \ud83d\ude42 Hopefully above was a good summary and  link to hopefully useful resources.<\/p>\n<p>If you like what we do, in <em>Castle Game Engine<\/em> but also around standardization efforts like <a href=\"https:\/\/castle-engine.io\/x3d\">X3D<\/a>, we always appreciate your <a href=\"https:\/\/castle-engine.io\/donate\">donations<\/a>. Thank you!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The short version of this post, if you don&#8217;t want to go into technical details, is that one aspect of using bump mapping is now better in Castle Game Engine. Our data transfer and logic is more efficient and more aligned with glTF and latest X3D specifications. And if you still don&#8217;t want to go &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/castle-engine.io\/wp\/2025\/07\/09\/support-for-new-tangent-node-in-x3d-with-vectors-as-4d-better-aligned-with-gltf\/\" class=\"more-link\">Continue reading  \u27a4<span class=\"screen-reader-text\"> &#8220;Support for new Tangent node in X3D, with vectors as 4D, better aligned with glTF&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":5696,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"publish_to_discourse":"0","publish_post_category":"9","wpdc_auto_publish_overridden":"1","wpdc_topic_tags":"","wpdc_pin_topic":"","wpdc_pin_until":"","discourse_post_id":"6949","discourse_permalink":"https:\/\/forum.castle-engine.io\/t\/support-for-new-tangent-node-in-x3d-with-vectors-as-4d-better-aligned-with-gltf\/1967","wpdc_publishing_response":"","wpdc_publishing_error":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":["post-5694","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2025\/07\/scene_screenshot_castle_model_viewer.png","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p9IgYW-1tQ","jetpack_likes_enabled":false,"_links":{"self":[{"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/posts\/5694","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/comments?post=5694"}],"version-history":[{"count":5,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/posts\/5694\/revisions"}],"predecessor-version":[{"id":5703,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/posts\/5694\/revisions\/5703"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/media\/5696"}],"wp:attachment":[{"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/media?parent=5694"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/categories?post=5694"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/tags?post=5694"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}