feat/godot: work in progress [might break]
This commit is contained in:
parent
b265478960
commit
53b6527152
3 changed files with 92 additions and 37 deletions
|
|
@ -16,31 +16,46 @@ func _ready():
|
||||||
func _onXRF(event:String,data ):
|
func _onXRF(event:String,data ):
|
||||||
if event == "scene_loaded":
|
if event == "scene_loaded":
|
||||||
scene = data
|
scene = data
|
||||||
if event == 'href':
|
if event == 'href': # optional: hook into href events
|
||||||
|
print(data)
|
||||||
|
if event == 'src': # optional: hook into src metadata
|
||||||
print(data)
|
print(data)
|
||||||
if event == 'teleport':
|
if event == 'teleport':
|
||||||
print("teleport!")
|
print("teleport!")
|
||||||
|
#player.teleport( data ) # optional: use PlayerBody
|
||||||
find_child("XROrigin3D").position = data.origin
|
find_child("XROrigin3D").position = data.origin
|
||||||
#player.teleport( data )
|
|
||||||
|
# update URL bar
|
||||||
|
# spec 4 @ https://xrfragment.org/doc/RFC_XR_Fragments.html#navigating-content-href-portals
|
||||||
|
var URLbar:RichTextLabel = find_child("URLbar")
|
||||||
|
URLbar.text = xrf.URI.string
|
||||||
|
|
||||||
|
|
||||||
func _input(event):
|
func _input(event):
|
||||||
var cam = find_child("XRCamera3D")
|
var cam = find_child("XRCamera3D")
|
||||||
if event is InputEventMouseMotion:
|
if event is InputEventMouseMotion:
|
||||||
var mouse_sens = 0.2
|
var mouse_sens = 0.3
|
||||||
cam.rotate_y(deg_to_rad(-event.relative.x*mouse_sens))
|
cam.rotate_y(deg_to_rad(-event.relative.x*mouse_sens))
|
||||||
if event is InputEventMouseButton:
|
if event is InputEventMouseButton and event.pressed:
|
||||||
var mouse_pos = get_viewport().get_mouse_position()
|
if event.button_index == 2:
|
||||||
var from = cam.project_ray_origin(mouse_pos)
|
xrf.back()
|
||||||
var to = from + cam.project_ray_normal(mouse_pos) * 20000 #200
|
|
||||||
var space_state = get_world_3d().direct_space_state
|
if event.button_index == 3:
|
||||||
var handle_query = PhysicsRayQueryParameters3D.create(from, to)
|
xrf.forward()
|
||||||
handle_query.collide_with_areas = true
|
|
||||||
var mesh_query = PhysicsRayQueryParameters3D.create(from, to)
|
if event.button_index == 1:
|
||||||
mesh_query.collide_with_areas = true
|
# raycast to detect clicked item
|
||||||
var intersectMesh = space_state.intersect_ray(mesh_query)
|
var mouse_pos = get_viewport().get_mouse_position()
|
||||||
var intersectHandle = space_state.intersect_ray(handle_query)
|
var from = cam.project_ray_origin(mouse_pos)
|
||||||
if intersectMesh.has('collider'):
|
var to = from + cam.project_ray_normal(mouse_pos) * 20000 #200
|
||||||
xrf.traverse( intersectMesh.collider, xrf.href_click )
|
var space_state = get_world_3d().direct_space_state
|
||||||
|
var handle_query = PhysicsRayQueryParameters3D.create(from, to)
|
||||||
|
handle_query.collide_with_areas = true
|
||||||
|
var mesh_query = PhysicsRayQueryParameters3D.create(from, to)
|
||||||
|
mesh_query.collide_with_areas = true
|
||||||
|
var intersectMesh = space_state.intersect_ray(mesh_query)
|
||||||
|
var intersectHandle = space_state.intersect_ray(handle_query)
|
||||||
|
if intersectMesh.has('collider'):
|
||||||
|
xrf.traverse( intersectMesh.collider, xrf.href_click )
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,13 @@ shadow_enabled = true
|
||||||
[node name="XRCamera3D" type="XRCamera3D" parent="XROrigin3D"]
|
[node name="XRCamera3D" type="XRCamera3D" parent="XROrigin3D"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.7, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.7, 0)
|
||||||
|
|
||||||
|
[node name="URLbar" type="RichTextLabel" parent="XROrigin3D/XRCamera3D"]
|
||||||
|
offset_left = 20.0
|
||||||
|
offset_top = 20.0
|
||||||
|
offset_right = 1171.0
|
||||||
|
offset_bottom = 136.0
|
||||||
|
scale = Vector2(1.2, 1.2)
|
||||||
|
|
||||||
[node name="LeftHand" type="XRController3D" parent="XROrigin3D"]
|
[node name="LeftHand" type="XRController3D" parent="XROrigin3D"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0, 0)
|
||||||
tracker = &"left_hand"
|
tracker = &"left_hand"
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@ extends Node
|
||||||
class_name XRF
|
class_name XRF
|
||||||
|
|
||||||
var scene: Node3D
|
var scene: Node3D
|
||||||
var URI: Dictionary
|
var URI: Dictionary = {}
|
||||||
|
var history: Array
|
||||||
|
var animplayer: AnimationPlayer
|
||||||
var isModelLoading = false
|
var isModelLoading = false
|
||||||
var metadata
|
var metadata
|
||||||
var callback: Callable;
|
var callback: Callable;
|
||||||
|
|
@ -31,7 +33,7 @@ func _process(delta):
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
func parseURL(url: String) -> Dictionary:
|
func parseURL(url: String) -> Dictionary:
|
||||||
var URI = {"string":url}
|
var URI = {"string":url, "next": null}
|
||||||
|
|
||||||
# Split URL by '://' to get protocol and the rest of the URL
|
# Split URL by '://' to get protocol and the rest of the URL
|
||||||
var parts = url.split("://")
|
var parts = url.split("://")
|
||||||
|
|
@ -45,14 +47,18 @@ func parseURL(url: String) -> Dictionary:
|
||||||
parts = url.split("/")
|
parts = url.split("/")
|
||||||
URI["domain"] = parts[0]
|
URI["domain"] = parts[0]
|
||||||
if parts.size() > 1:
|
if parts.size() > 1:
|
||||||
var path_and_file = parts[1]
|
parts.remove_at(0)
|
||||||
|
var path_and_file = "/".join(parts)
|
||||||
|
path_and_file = path_and_file.split("?")[0]
|
||||||
|
path_and_file = path_and_file.split("#")[0]
|
||||||
var path_and_file_parts = path_and_file.split("/")
|
var path_and_file_parts = path_and_file.split("/")
|
||||||
if path_and_file_parts.size() > 1:
|
if path_and_file_parts.size() > 1:
|
||||||
URI["path"] = path_and_file_parts
|
URI["path"] = "/".join(path_and_file_parts)
|
||||||
var file = path_and_file_parts.pop_back()
|
|
||||||
URI["path"] = path_and_file_parts.join("/")
|
|
||||||
else:
|
else:
|
||||||
URI["path"] = path_and_file
|
URI["path"] = path_and_file
|
||||||
|
else:
|
||||||
|
URI["path"] = self.URI.path # copy from current URI
|
||||||
|
URI["domain"] = self.URI.domain
|
||||||
|
|
||||||
# Check if there's a query string
|
# Check if there's a query string
|
||||||
if url.find("?") != -1:
|
if url.find("?") != -1:
|
||||||
|
|
@ -117,12 +123,25 @@ func guess_type(str: String) -> Dictionary:
|
||||||
# Model Related functions
|
# Model Related functions
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
|
func back():
|
||||||
|
var prev = self.history.pop_back()
|
||||||
|
if prev != null:
|
||||||
|
prev.next = self.URI
|
||||||
|
self.to( prev.string, callback )
|
||||||
|
|
||||||
|
func forward():
|
||||||
|
if self.URI.next != null:
|
||||||
|
self.to( self.URI.next.string, callback )
|
||||||
|
|
||||||
# Download model by HTTP and run `downloadModelSuccess` if OK
|
# Download model by HTTP and run `downloadModelSuccess` if OK
|
||||||
func to(url, f:Callable ):
|
func to(url, f:Callable ):
|
||||||
print("navigating to "+url)
|
print("navigating to "+url)
|
||||||
var URI = self.parseURL(url)
|
var URI = self.parseURL(url)
|
||||||
callback = f
|
callback = f
|
||||||
|
|
||||||
|
if self.URI.has('domain') && URI.domain == self.URI.domain && URI.path == self.URI.path:
|
||||||
|
URI.isLocal = true
|
||||||
|
|
||||||
if !URI.isLocal:
|
if !URI.isLocal:
|
||||||
var http_request = HTTPRequest.new()
|
var http_request = HTTPRequest.new()
|
||||||
add_child(http_request)
|
add_child(http_request)
|
||||||
|
|
@ -130,10 +149,11 @@ func to(url, f:Callable ):
|
||||||
var error = http_request.request(url)
|
var error = http_request.request(url)
|
||||||
if error != OK:
|
if error != OK:
|
||||||
push_error("An error occurred in the HTTP request.")
|
push_error("An error occurred in the HTTP request.")
|
||||||
|
if self.URI:
|
||||||
|
self.URI.next = null
|
||||||
|
self.history.push_back(self.URI )
|
||||||
self.URI = URI
|
self.URI = URI
|
||||||
if URI.isLocal && URI.fragment.has('pos'):
|
if URI.isLocal && URI.fragment.has('pos'):
|
||||||
print(URI.fragment.pos)
|
|
||||||
callback.call("teleport", self.posToTransform3D( URI.fragment.pos ) )
|
callback.call("teleport", self.posToTransform3D( URI.fragment.pos ) )
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -153,18 +173,17 @@ func downloadModelSuccess(result, response_code, headers, body):
|
||||||
callback.call("scene_loaded", scene)
|
callback.call("scene_loaded", scene)
|
||||||
|
|
||||||
func loadModelFromBufferByGLTFDocument(body):
|
func loadModelFromBufferByGLTFDocument(body):
|
||||||
print("loadModelFromBuffer")
|
|
||||||
var doc = GLTFDocument.new()
|
var doc = GLTFDocument.new()
|
||||||
var state = GLTFState.new()
|
var state = GLTFState.new()
|
||||||
#state.set_handle_binary_image(GLTFState.HANDLE_BINARY_EMBED_AS_BASISU) # Fixed in new Godot version (4.3 as I see) https://github.com/godotengine/godot/blob/17e7f85c06366b427e5068c5b3e2940e27ff5f1d/scene/resources/portable_compressed_texture.cpp#L116
|
#state.set_handle_binary_image(GLTFState.HANDLE_BINARY_EMBED_AS_BASISU) # Fixed in new Godot version (4.3 as I see) https://github.com/godotengine/godot/blob/17e7f85c06366b427e5068c5b3e2940e27ff5f1d/scene/resources/portable_compressed_texture.cpp#L116
|
||||||
var error = doc.append_from_buffer(body, "", state)
|
var error = doc.append_from_buffer(body, "", state, 8) # 8 = force ENABLE_TANGENTS since it is required for mesh compression since 4.2
|
||||||
if error == OK:
|
if error == OK:
|
||||||
scene = doc.generate_scene(state)
|
scene = doc.generate_scene(state)
|
||||||
scene.name = "XRFscene"
|
scene.name = "XRFscene"
|
||||||
_addAnimations(state, scene)
|
|
||||||
metadata = _parseMetadata(state,scene)
|
metadata = _parseMetadata(state,scene)
|
||||||
add_child(scene)
|
add_child(scene)
|
||||||
print("model added")
|
print("model added")
|
||||||
|
_addAnimations(state, scene)
|
||||||
else:
|
else:
|
||||||
print("Couldn't load glTF scene (error code: %s). Are you connected to internet?" % error_string(error))
|
print("Couldn't load glTF scene (error code: %s). Are you connected to internet?" % error_string(error))
|
||||||
|
|
||||||
|
|
@ -177,9 +196,18 @@ func _parseXRFMetadata(node:Node):
|
||||||
XRF[ i ] = parseURL( extras[i] )
|
XRF[ i ] = parseURL( extras[i] )
|
||||||
node.set_meta("XRF", XRF)
|
node.set_meta("XRF", XRF)
|
||||||
|
|
||||||
func _addAnimations( state:GLTFState, scene):
|
func _addAnimations( state:GLTFState, scene:Node):
|
||||||
for i in state.get_animation_players_count(0):
|
self.animplayer == null
|
||||||
print(i) #add_child( state.get_animation_player(i) )
|
for i in scene.get_child_count():
|
||||||
|
var animplayer : AnimationPlayer = scene.get_child(i) as AnimationPlayer;
|
||||||
|
if animplayer == null:
|
||||||
|
continue;
|
||||||
|
self.animplayer = animplayer
|
||||||
|
print("playing animations")
|
||||||
|
print(animplayer.get_animation_library_list())
|
||||||
|
var anims = animplayer.get_animation_library_list()
|
||||||
|
for j in anims:
|
||||||
|
animplayer.play( j )
|
||||||
|
|
||||||
func traverse(node, f:Callable ):
|
func traverse(node, f:Callable ):
|
||||||
for N in node.get_children():
|
for N in node.get_children():
|
||||||
|
|
@ -249,6 +277,9 @@ func posToTransform3D(v:Dictionary):
|
||||||
func setPredefinedSceneView():
|
func setPredefinedSceneView():
|
||||||
var XRF = scene.get_meta("XRF")
|
var XRF = scene.get_meta("XRF")
|
||||||
if XRF && XRF.has("#") && XRF["#"]["fragment"]["pos"]:
|
if XRF && XRF.has("#") && XRF["#"]["fragment"]["pos"]:
|
||||||
|
self.URI.fragment = XRF["#"]["fragment"]
|
||||||
|
if !self.URI.string.match("#"):
|
||||||
|
self.URI.string += XRF["#"]["string"]
|
||||||
callback.call("teleport", posToTransform3D(XRF["#"]["fragment"]["pos"]) )
|
callback.call("teleport", posToTransform3D(XRF["#"]["fragment"]["pos"]) )
|
||||||
|
|
||||||
func href_init(node:Node):
|
func href_init(node:Node):
|
||||||
|
|
@ -275,11 +306,13 @@ func href_click(node:Node):
|
||||||
func src_init(node:Node):
|
func src_init(node:Node):
|
||||||
if node.has_meta("XRF"):
|
if node.has_meta("XRF"):
|
||||||
var XRF = node.get_meta("XRF")
|
var XRF = node.get_meta("XRF")
|
||||||
if (XRF.has('src') || (XRF.has('href') && XRF.has('src'))) && node is MeshInstance3D:
|
if XRF.has('src'):
|
||||||
var mesh = node as MeshInstance3D
|
var mesh = node as MeshInstance3D
|
||||||
var mat = mesh.get_active_material(0) as BaseMaterial3D
|
if mesh != null:
|
||||||
mat = mat.duplicate()
|
var mat = mesh.get_active_material(0) as BaseMaterial3D
|
||||||
mat.transparency = mat.TRANSPARENCY_ALPHA
|
mat = mat.duplicate()
|
||||||
mat.albedo = Color(1.0,1.0,1.0, 0.3) # 0.5 sets 50% opacity
|
mat.transparency = mat.TRANSPARENCY_ALPHA
|
||||||
mesh.set_surface_override_material(0,mat)
|
mat.albedo = Color(1.0,1.0,1.0, 0.3) # 0.5 sets 50% opacity
|
||||||
|
mesh.set_surface_override_material(0,mat)
|
||||||
|
callback.call("src", {"node":node,"XRF":XRF} )
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue