daydev-patch-1 #105443

Open
Banyapon Poolsawas wants to merge 2 commits from daydev/blender-addons:daydev-patch-1 into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
5 changed files with 245 additions and 0 deletions

23
aframe_exporter/LICENSE Normal file
View File

@ -0,0 +1,23 @@
MIT License
Copyright (c) 2024 Banyapon Poolsawas associated with
College of Creative Design and Entertainment Technology,
Dhurakij Pundit University and Daydev Co., Ltd.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

52
aframe_exporter/README.md Normal file
View File

@ -0,0 +1,52 @@
# Blender A-Frame Exporter
[![Blender Version](https://img.shields.io/badge/Blender-3.0+-orange.svg)](https://www.blender.org/) [![Blender Version](https://img.shields.io/badge/Blender-4.0+-orange.svg)](https://www.blender.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
This Blender add-on simplifies the process of exporting your 3D scenes into interactive web experiences using A-Frame, a popular web framework for building virtual reality (VR) and augmented reality (AR) experiences.
## Features
![Showcase](https://github.com/banyapon/Blender-Aframe-Exporter/blob/main/dist/8.png?raw=true)
* **Seamless Export:** Quickly export your entire Blender scene, including models, materials, and animations, to A-Frame HTML and GLB (binary glTF) files.
* **Collision Detection:** Automatically add collision detection to your exported models using A-Frame's physics system, enabling interactive experiences.
* **Camera Controls:** Easily set up basic WASD controls for navigating your A-Frame scene with the camera.
* **Customization:** Customize the generated A-Frame code to add additional features, components, or interactions.
## Installation
1. Download the latest release of the add-on (`.zip` file) from the [Releases](https://github.com/banyapon/Blender-Aframe-Exporter/releases/tag/release) page.
2. In Blender, go to `Edit` > `Preferences` > `Add-ons` > `Install...`
![Go to `Edit` > `Preferences` > `Add-ons` > `Install](https://raw.githubusercontent.com/banyapon/Blender-Aframe-Exporter/main/dist/1.png)
3. Select the downloaded `.zip` file and click `Install Add-on`.
![Zip File](https://github.com/banyapon/Blender-Aframe-Exporter/blob/main/dist/2.png?raw=true)
4. Enable the "A-Frame Exporter" add-on in the list.
![Enable add-on](https://github.com/banyapon/Blender-Aframe-Exporter/blob/main/dist/3.png?raw=true)
## Usage
1. Create your 3D scene in Blender.
![Create Scene](https://github.com/banyapon/Blender-Aframe-Exporter/blob/main/dist/5.png?raw=true)
2. Go to `File` > `Export` > `A-Frame (.html)`.
![Export Aframe](https://github.com/banyapon/Blender-Aframe-Exporter/blob/main/dist/6.png?raw=true)
3. Choose a location to save the files and click `Export A-Frame`.
![VS Code](https://github.com/banyapon/Blender-Aframe-Exporter/blob/main/dist/7.png?raw=true)
4. The add-on will generate an HTML file (`your_scene_name.html`) and a GLB file (`your_scene_name.glb`).
5. Open the HTML file in a web browser to view your interactive A-Frame scene.
![WebXR](https://github.com/banyapon/Blender-Aframe-Exporter/blob/main/dist/9.png?raw=true)
## Additional Notes
* Make sure you have a web server running to view the exported HTML file correctly.
* For more advanced A-Frame features and customization, refer to the [A-Frame documentation](https://aframe.io/docs/).
## Contributing
Contributions are welcome! Feel free to submit issues, feature requests, or pull requests.
## License
This add-on is released under the MIT License.

View File

@ -0,0 +1,27 @@
import bpy
from . import aframe_exporter
bl_info = {
"name": "A-Frame Exporter",
"author": "Banyapon Poolsawas",
"version": (1, 0, 2),
"blender": (4, 0, 1),
"location": "File > Export",
"description": "Export Blender scene to A-Frame HTML and GLB for WebXR",
"warning": "",
"category": "Export",
}
def menu_func_export(self, context):
self.layout.operator(aframe_exporter.ExportAFrame.bl_idname, text="A-Frame (.html)")
def register():
bpy.utils.register_class(aframe_exporter.ExportAFrame)
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
def unregister():
bpy.utils.unregister_class(aframe_exporter.ExportAFrame)
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
if __name__ == "__main__":
register()

View File

@ -0,0 +1,143 @@
import bpy
import os
import shutil
import http.server
import socketserver
import threading
import webbrowser
from bpy.props import BoolProperty, IntProperty
from bpy_extras.io_utils import ExportHelper
class ServerThread(threading.Thread):
def __init__(self, directory, port):
super().__init__()
self.directory = directory
self.port = port
self.httpd = None
self.error = None
def run(self):
os.chdir(self.directory)
# Error handling for the server
try:
handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", self.port), handler) as httpd:
self.httpd = httpd
print(f"Serving at port {self.port}")
httpd.serve_forever()
except OSError as e:
self.error = e
def stop(self):
if self.httpd:
self.httpd.shutdown()
class ExportAFrame(bpy.types.Operator, ExportHelper):
bl_idname = "export_scene.aframe"
bl_label = "Export A-Frame"
filename_ext = ".html"
start_server: BoolProperty(
name="Start Local Server",
description="Automatically start a local server after export",
default=False
)
port: IntProperty(
name="Port",
description="Port number for the local server",
default=8200,
min=1,
max=65535
)
def execute(self, context):
filepath = self.filepath
glb_filepath = os.path.splitext(filepath)[0] + ".glb"
# Export GLB
bpy.ops.export_scene.gltf(filepath=glb_filepath, export_format='GLB')
# Copy favicon
favicon_path = os.path.join(os.path.dirname(__file__), "icons", "favicon.ico")
if os.path.exists(favicon_path):
shutil.copy(favicon_path, os.path.dirname(filepath))
# Create HTML (A-Frame)
with open(filepath, "w") as f:
f.write(f"""
<!DOCTYPE html>
<html>
<head>
<link rel="icon" href="favicon.ico">
<title>Aframe Exporter</title>
<script src="https://aframe.io/releases/1.6.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/c-frame/aframe-extras@7.5.1/dist/aframe-extras.min.js"></script>
</head>
<body>
<a-scene>
<a-assets>
<a-asset-item id="model" src="{os.path.basename(glb_filepath)}"></a-asset-item>
</a-assets>
<a-entity id="cameraRig" movement-controls="fly: false; speed: 0.2;">
<a-entity id="camera" camera look-controls position="0 1.6 0"></a-entity>
<a-entity oculus-touch-controls="hand: left"></a-entity>
<a-entity oculus-touch-controls="hand: right"></a-entity>
</a-entity>
<a-entity gltf-model="#model" static-body></a-entity>
</a-scene>
</body>
</html>
""")
if self.start_server:
self.server_thread = ServerThread(os.path.dirname(filepath), self.port)
self.server_thread.start()
if self.server_thread.error: # Check for errors
self.report({'ERROR'}, f"Failed to start server: {self.server_thread.error}")
return {'CANCELLED'}
url = f"http://localhost:{self.port}/{os.path.basename(filepath)}"
else:
url = "file://" + filepath
webbrowser.open_new_tab(url)
return {'FINISHED'}
def start_local_server(self, directory, port):
os.chdir(directory)
handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", port), handler) as httpd:
print(f"Serving at port {port}")
threading.Thread(target=httpd.serve_forever).start()
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
class ExportAFramePanel(bpy.types.Panel):
bl_label = "A-Frame Export Settings" # Label for the panel
bl_idname = "OBJECT_PT_aframe_export" # Unique identifier for the panel
bl_space_type = 'PROPERTIES' # Panel location (Properties Editor)
bl_region_type = 'WINDOW' # Panel type (window)
bl_context = "scene" # Context for the panel (Scene)
bl_options = {'DEFAULT_CLOSED'} # Panel is closed by default
def draw(self, context):
layout = self.layout
# Export Button
layout.operator("export_scene.aframe", text="Export A-Frame") # Add the export operator button
# Local Server Options
row = layout.row() # Create a new row for the checkbox and button
row.prop(context.scene, "aframe_local_server", text="Start Local Server") # Checkbox to toggle local server
if context.scene.aframe_local_server: # Show port input if the checkbox is checked
row = layout.row() # Create a new row for the port input
row.prop(context.scene, "aframe_server_port", text="Port") # Input field for the port number

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB