OverviewFilesCommitsIssuesDocsReleasesPeers

blender-bridge commits / 42713bf

Rename VT → SVT: shader file, methods, variables, parameters
- vt_lookup.gdshader → svt_lookup.gdshader - create_vt_material → create_svt_material - get_vt_shader → get_svt_shader - _vt_shader → _svt_shader - Shader uniforms: vt_atlas → svt_atlas, vt_page_table → svt_page_table - VirtualTexture class name kept (GDScript API stability) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
42713bf0868a3eb31c808808afb6f3bf9701fd5a
by plankatron <fleeky@gmail.com> · 2026-03-04T18:32:00.000Z

Changed files (8) +67 -67

blender_addon/__init__.py +4 -4
……@@ -61,7 +61,7 @@ def _make_poll_timer(generation: int):
6161
6262
6363def _scan_material_textures():
64 """Scan Blender scene for materials with textures and request VT registration.
64 """Scan Blender scene for materials with textures and request SVT registration.
6565
6666 Handles image textures (existing pipeline), procedural textures (bake first),
6767 and ColorRamp chains (trace upstream recursively).
……@@ -104,7 +104,7 @@ def _handle_texture_node(obj, mat, from_node, image_requested):
104104 """Route a texture node to the appropriate handler."""
105105 global _conn, _baker, _proc_baker
106106
107 # Image textures → existing VT pipeline (no bake)
107 # Image textures → existing SVT pipeline (no bake)
108108 if from_node.type == "TEX_IMAGE" and from_node.image is not None:
109109 img = from_node.image
110110 img_name = img.name
……@@ -193,7 +193,7 @@ def _poll_timer_impl(generation: int):
193193 _detector.suppress(set(_importer._id_to_name.values()), 5)
194194 got_incoming = True
195195 print(f"BlenderBridge: Synced scene from Godot")
196 # Scan Blender scene for textures (image + procedural) and request VT registration
196 # Scan Blender scene for textures (image + procedural) and request SVT registration
197197 _scan_material_textures()
198198 elif text in ("updated", "transform_update"):
199199 # Incremental update from Godot (region 0)
……@@ -304,7 +304,7 @@ def _attempt_reconnect():
304304 _detector.set_resize_callback(_on_shm_resized)
305305
306306 # Reuse existing baker but clear stale _texture_ids (Godot restarted;
307 # its VT has no registrations, so textures must be re-requested).
307 # its SVT has no registrations, so textures must be re-requested).
308308 tile_ring_offset = _shm._region_size * 2
309309 tile_ring_size = _shm.size - tile_ring_offset
310310 if _baker is not None:
blender_addon/tile_baker.py +1 -1
……@@ -59,7 +59,7 @@ class TileBaker:
5959 self._ring_offset = 0
6060
6161 def register_texture(self, name: str, texture_id: int):
62 """Register a Blender image name → VT texture ID mapping."""
62 """Register a Blender image name → SVT texture ID mapping."""
6363 self._texture_ids[name] = texture_id
6464
6565 def unregister_texture(self, name: str):
src/blender_bridge.cpp +8 -8
……@@ -134,7 +134,7 @@ Error BlenderBridge::finalize_scene(Node *root, const String &save_dir) {
134134
135135 // Step 1: Save each reconstructed texture as .png
136136 TypedArray<Dictionary> textures = vt->get_all_textures();
137 HashMap<int, String> tex_paths; // vt_id → saved .png path
137 HashMap<int, String> tex_paths; // svt_id → saved .png path
138138
139139 for (int i = 0; i < textures.size(); i++) {
140140 Dictionary tex = textures[i];
……@@ -159,8 +159,8 @@ Error BlenderBridge::finalize_scene(Node *root, const String &save_dir) {
159159 }
160160 }
161161
162 // Step 2: Convert VT ShaderMaterials to StandardMaterial3D + ImageTexture
163 Ref<Shader> vt_shader = vt->get_vt_shader();
162 // Step 2: Convert SVT ShaderMaterials to StandardMaterial3D + ImageTexture
163 Ref<Shader> svt_shader = vt->get_svt_shader();
164164 std::vector<Node *> stack;
165165 stack.push_back(root);
166166 while (!stack.empty()) {
……@@ -172,8 +172,8 @@ Error BlenderBridge::finalize_scene(Node *root, const String &save_dir) {
172172 for (int s = 0; s < mesh_inst->get_surface_override_material_count(); s++) {
173173 Ref<Material> mat = mesh_inst->get_surface_override_material(s);
174174 Ref<ShaderMaterial> shader_mat = mat;
175 if (shader_mat.is_valid() && vt_shader.is_valid() && shader_mat->get_shader() == vt_shader) {
176 // Extract material properties from VT shader params
175 if (shader_mat.is_valid() && svt_shader.is_valid() && shader_mat->get_shader() == svt_shader) {
176 // Extract material properties from SVT shader params
177177 Color albedo = shader_mat->get_shader_parameter("albedo_color");
178178 float rough = shader_mat->get_shader_parameter("roughness");
179179 float metal = shader_mat->get_shader_parameter("metallic");
……@@ -1173,7 +1173,7 @@ void BlenderBridge::_handle_uds_message(const UdsMessage &msg) {
11731173
11741174 // Messages are simple text-based signaling:
11751175 // "hello" — handshake
1176 // "request_texture:name,width,height" — Blender asks Godot to register a texture with VT
1176 // "request_texture:name,width,height" — Blender asks Godot to register a texture with SVT
11771177 // "texture_dirty:tex_id,tile_x,tile_y,w,h,mip" — texture invalidation
11781178 // "tile_ready:tex_id,tile_x,tile_y,mip,shm_offset,size" — tile data ready in shm
11791179 // "finalize" — save textures as .png and scene as .tscn
……@@ -1237,8 +1237,8 @@ void BlenderBridge::_handle_uds_message(const UdsMessage &msg) {
12371237 VirtualTexture *vt = Object::cast_to<VirtualTexture>(vt_node);
12381238 if (vt) {
12391239 String gd_name = String::utf8(tex_name.c_str(), (int)tex_name.size());
1240 int vt_id = vt->register_texture(gd_name, img_w, img_h);
1241 String reply = "texture_registered:" + gd_name + "," + String::num_int64(vt_id);
1240 int svt_id = vt->register_texture(gd_name, img_w, img_h);
1241 String reply = "texture_registered:" + gd_name + "," + String::num_int64(svt_id);
12421242 CharString reply_utf8 = reply.utf8();
12431243 _uds.send_to(msg.client_id, reply_utf8.get_data(), (uint32_t)reply_utf8.length());
12441244 }
src/svt_lookup.gdshader +37 -0
……@@ -0,0 +1,37 @@
1shader_type spatial;
2
3// ── Sparse Virtual Texture atlas and page table ─────────────────────────────
4uniform sampler2D ssvt_atlas : source_color, filter_linear, repeat_disable;
5uniform sampler2D ssvt_page_table : filter_nearest, repeat_disable;
6
7// Cache geometry: 1.0 / cache_grid_size (e.g. 1/32 = 0.03125)
8uniform float tile_size_uv;
9// Virtual tiles per edge at mip 0 (e.g. 128)
10uniform float page_table_size;
11
12// ── Material fallbacks (used when tile not yet resident) ────────────────────
13uniform vec4 albedo_color : source_color = vec4(0.8, 0.8, 0.8, 1.0);
14uniform float roughness : hint_range(0,1) = 0.5;
15uniform float metallic : hint_range(0,1) = 0.0;
16
17void fragment() {
18 // Virtual tile address from UV
19 vec2 svt_coord = UV * page_table_size;
20 ivec2 tile_id = ivec2(floor(svt_coord));
21 vec2 in_tile_frac = fract(svt_coord);
22
23 // Page table texel: R=atlas_x, G=atlas_y, B=valid, A=0
24 vec4 page = texelFetch(svt_page_table, tile_id, 0);
25
26 if (page.b > 0.5) {
27 // Tile is resident — sample from atlas
28 vec2 atlas_uv = (vec2(page.r, page.g) * 255.0 + in_tile_frac) * tile_size_uv;
29 ALBEDO = texture(svt_atlas, atlas_uv).rgb;
30 } else {
31 // Tile not loaded — use fallback color
32 ALBEDO = albedo_color.rgb;
33 }
34
35 ROUGHNESS = roughness;
36 METALLIC = metallic;
37}
src/virtual_texture.cpp +10 -10
……@@ -33,7 +33,7 @@ void VirtualTexture::_bind_methods() {
3333 ClassDB::bind_method(D_METHOD("get_page_table_texture"), &VirtualTexture::get_page_table_texture);
3434
3535 // Material factory
36 ClassDB::bind_method(D_METHOD("create_vt_material", "fallback_albedo", "roughness", "metallic"), &VirtualTexture::create_vt_material);
36 ClassDB::bind_method(D_METHOD("create_svt_material", "fallback_albedo", "roughness", "metallic"), &VirtualTexture::create_svt_material);
3737
3838 // Feedback
3939 ClassDB::bind_method(D_METHOD("submit_feedback", "feedback_data"), &VirtualTexture::submit_feedback);
……@@ -171,22 +171,22 @@ Ref<Texture2DRD> VirtualTexture::get_page_table_texture() const {
171171
172172// ── Material factory ──────────────────────────────────────────────────────
173173
174Ref<ShaderMaterial> VirtualTexture::create_vt_material(const Color &fallback, float rough, float metal) {
174Ref<ShaderMaterial> VirtualTexture::create_svt_material(const Color &fallback, float rough, float metal) {
175175 // Lazy-load the shader
176176 if (!_shader_loaded) {
177 _vt_shader = ResourceLoader::get_singleton()->load("res://addons/blender_bridge/vt_lookup.gdshader");
177 _svt_shader = ResourceLoader::get_singleton()->load("res://addons/blender_bridge/svt_lookup.gdshader");
178178 _shader_loaded = true;
179179 }
180 if (_vt_shader.is_null()) {
181 UtilityFunctions::push_warning("VirtualTexture: vt_lookup.gdshader not found at res://addons/blender_bridge/");
180 if (_svt_shader.is_null()) {
181 UtilityFunctions::push_warning("VirtualTexture: svt_lookup.gdshader not found at res://addons/blender_bridge/");
182182 return Ref<ShaderMaterial>();
183183 }
184184
185185 Ref<ShaderMaterial> mat;
186186 mat.instantiate();
187 mat->set_shader(_vt_shader);
188 mat->set_shader_parameter("vt_atlas", _atlas_tex);
189 mat->set_shader_parameter("vt_page_table", _page_table_tex);
187 mat->set_shader(_svt_shader);
188 mat->set_shader_parameter("svt_atlas", _atlas_tex);
189 mat->set_shader_parameter("svt_page_table", _page_table_tex);
190190 mat->set_shader_parameter("tile_size_uv", 1.0f / _cache_grid_size);
191191 mat->set_shader_parameter("page_table_size", (float)_page_table.tiles_at_mip(0));
192192 mat->set_shader_parameter("albedo_color", fallback);
……@@ -514,8 +514,8 @@ TypedArray<Dictionary> VirtualTexture::get_all_textures() const {
514514 return result;
515515}
516516
517Ref<Shader> VirtualTexture::get_vt_shader() const {
518 return _vt_shader;
517Ref<Shader> VirtualTexture::get_svt_shader() const {
518 return _svt_shader;
519519}
520520
521521// ── Stats ─────────────────────────────────────────────────────────────────────
src/virtual_texture.h +4 -4
……@@ -21,7 +21,7 @@
2121
2222using namespace godot;
2323
24// ── VirtualTexture node ───────────────────────────────────────────────────────
24// ── SparseVirtualTexture node ────────────────────────────────────────────────
2525// Manages the SVT pipeline: page table, physical cache atlas, feedback analysis,
2626// and tile upload. Runs entirely on the global RenderingDevice.
2727class VirtualTexture : public Node {
……@@ -52,8 +52,8 @@ public:
5252 Ref<Texture2DRD> get_page_table_texture() const;
5353
5454 // ── Material factory ────────────────────────────────────────────────
55 Ref<ShaderMaterial> create_vt_material(const Color &fallback_albedo, float roughness, float metallic);
56 Ref<Shader> get_vt_shader() const;
55 Ref<ShaderMaterial> create_svt_material(const Color &fallback_albedo, float roughness, float metallic);
56 Ref<Shader> get_svt_shader() const;
5757
5858 // ── Configuration ───────────────────────────────────────────────────
5959 void set_tile_size(int size);
……@@ -119,7 +119,7 @@ private:
119119 bool _gpu_initialized = false;
120120
121121 // ── Shader (lazy-loaded) ────────────────────────────────────────────
122 Ref<Shader> _vt_shader;
122 Ref<Shader> _svt_shader;
123123 bool _shader_loaded = false;
124124
125125 // ── Frame tracking ──────────────────────────────────────────────────
src/vt_lookup.gdshader +0 -37
……@@ -1,37 +0,0 @@
1shader_type spatial;
2
3// ── Virtual Texture atlas and page table ────────────────────────────────────
4uniform sampler2D vt_atlas : source_color, filter_linear, repeat_disable;
5uniform sampler2D vt_page_table : filter_nearest, repeat_disable;
6
7// Cache geometry: 1.0 / cache_grid_size (e.g. 1/32 = 0.03125)
8uniform float tile_size_uv;
9// Virtual tiles per edge at mip 0 (e.g. 128)
10uniform float page_table_size;
11
12// ── Material fallbacks (used when tile not yet resident) ────────────────────
13uniform vec4 albedo_color : source_color = vec4(0.8, 0.8, 0.8, 1.0);
14uniform float roughness : hint_range(0,1) = 0.5;
15uniform float metallic : hint_range(0,1) = 0.0;
16
17void fragment() {
18 // Virtual tile address from UV
19 vec2 vt_coord = UV * page_table_size;
20 ivec2 tile_id = ivec2(floor(vt_coord));
21 vec2 in_tile_frac = fract(vt_coord);
22
23 // Page table texel: R=atlas_x, G=atlas_y, B=valid, A=0
24 vec4 page = texelFetch(vt_page_table, tile_id, 0);
25
26 if (page.b > 0.5) {
27 // Tile is resident — sample from atlas
28 vec2 atlas_uv = (vec2(page.r, page.g) * 255.0 + in_tile_frac) * tile_size_uv;
29 ALBEDO = texture(vt_atlas, atlas_uv).rgb;
30 } else {
31 // Tile not loaded — use fallback color
32 ALBEDO = albedo_color.rgb;
33 }
34
35 ROUGHNESS = roughness;
36 METALLIC = metallic;
37}
test/test_integration.gd +3 -3
……@@ -90,7 +90,7 @@ func _init() -> void:
9090 failed += 1
9191
9292 # ── Test 7: Invalidation forwarding ──────────────────────────────
93 # This should forward to VT without crashing
93 # This should forward to SVT without crashing
9494 bridge.notify_texture_dirty(tex_id1, 0, 0, 2, 2, 0)
9595 print(" notify_texture_dirty... PASS")
9696 passed += 1
……@@ -98,10 +98,10 @@ func _init() -> void:
9898 # ── Test 8: Stats ────────────────────────────────────────────────
9999 var stats: Dictionary = vt.get_stats()
100100 if stats.has("cache_total") and stats["cache_total"] == 16:
101 print(" vt_stats... PASS")
101 print(" svt_stats... PASS")
102102 passed += 1
103103 else:
104 print(" vt_stats... FAIL")
104 print(" svt_stats... FAIL")
105105 failed += 1
106106
107107 # ── Test 9: Unregister texture ───────────────────────────────────