3D-AFrame-VR / app.py
awacke1's picture
Update app.py
390ce77 verified
raw
history blame
6.56 kB
import streamlit as st
import os
import random
@st.cache_data
def scan_assets():
"""Discover textures, bump maps, glTF models, and OBJ(+MTL) pairs."""
files = [f for f in os.listdir() if os.path.isfile(f)]
img_exts = (".jpg", ".jpeg", ".png", ".gif")
# Textures (exclude bump/normal)
textures = [
f for f in files
if f.lower().endswith(img_exts)
and not any(tag in f.lower() for tag in ("bump", "normal"))
]
# Bump/NORMAL map (take the first one, if any)
bump_maps = [
f for f in files
if f.lower().endswith(img_exts)
and any(tag in f.lower() for tag in ("bump", "normal"))
]
# glTF models
gltf_models = [f for f in files if f.lower().endswith((".glb", ".gltf"))]
# OBJ models + their MTL partners
obj_models = [f for f in files if f.lower().endswith(".obj")]
mtl_files = {
os.path.splitext(f)[0]: f
for f in files
if f.lower().endswith(".mtl")
}
models = []
idx = 0
# Register glTF entries
for gltf in gltf_models:
models.append({
"type": "gltf",
"asset_id": f"model{idx}",
"src": gltf
})
idx += 1
# Register OBJ entries
for obj in obj_models:
base = os.path.splitext(obj)[0]
mtl = mtl_files.get(base)
entry = {
"type": "obj",
"obj_id": f"model{idx}-obj",
"obj": obj,
"mtl_id": f"model{idx}-mtl" if mtl else None,
"mtl": mtl
}
models.append(entry)
idx += 1
return textures, bump_maps, models
def main():
st.title("🔳 A-Frame Tilemap with Mixed 3D Models")
grid_size = st.sidebar.slider("Grid Size", 1, 20, 10)
textures, bump_maps, models = scan_assets()
if not textures or not models:
st.warning("⚠️ Drop at least one .jpg/.png and one .glb/.obj (with optional .mtl) in this folder.")
return
# --- Build <a-assets> ---
asset_tags = []
for i, tex in enumerate(textures):
asset_tags.append(f'<img id="tex{i}" src="{tex}">')
if bump_maps:
asset_tags.append(f'<img id="bump0" src="{bump_maps[0]}">')
for m in models:
if m["type"] == "gltf":
asset_tags.append(
f'<a-asset-item id="{m["asset_id"]}" src="{m["src"]}"></a-asset-item>'
)
else:
asset_tags.append(
f'<a-asset-item id="{m["obj_id"]}" src="{m["obj"]}"></a-asset-item>'
)
if m["mtl_id"]:
asset_tags.append(
f'<a-asset-item id="{m["mtl_id"]}" src="{m["mtl"]}"></a-asset-item>'
)
assets_html = "\n ".join(asset_tags)
# JS arrays for textures & models
tex_js = ", ".join(f'"#tex{i}"' for i in range(len(textures)))
models_js_elems = []
for m in models:
if m["type"] == "gltf":
models_js_elems.append(f'{{type:"gltf", id:"#{m["asset_id"]}"}}')
else:
if m["mtl_id"]:
models_js_elems.append(
f'{{type:"obj", obj:"#{m["obj_id"]}", mtl:"#{m["mtl_id"]}"}}'
)
else:
models_js_elems.append(
f'{{type:"obj", obj:"#{m["obj_id"]}"}}'
)
models_js = ", ".join(models_js_elems)
# Ground material (with optional bump)
if bump_maps:
ground_mat = "ground.setAttribute('material','color:#228B22; bumpMap:#bump0; bumpScale:0.2');"
else:
ground_mat = "ground.setAttribute('material','color:#228B22');"
# --- Final HTML ---
html = f"""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Tilemap Scene</title>
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/aframe-extras.loaders.min.js"></script>
</head>
<body>
<a-scene>
<a-assets>
{assets_html}
</a-assets>
<!-- Lights -->
<a-entity light="type: ambient; color: #BBB"></a-entity>
<a-entity light="type: directional; color: #FFF; intensity:0.6" position="1 1 0"></a-entity>
<a-entity light="type: point; intensity:0.6" position="0 5 0"></a-entity>
<!-- Camera -->
<a-entity camera look-controls position="0 {grid_size} {grid_size}"></a-entity>
<!-- Tiles & Models -->
<a-entity id="tilemap"></a-entity>
</a-scene>
<script>
document.addEventListener('DOMContentLoaded', function() {{
var scene = document.querySelector('a-scene');
var tilemap = document.querySelector('#tilemap');
var textures = [{tex_js}];
var models = [{models_js}];
var grid = {grid_size};
for (var i = 0; i < grid; i++) {{
for (var j = 0; j < grid; j++) {{
var x = i - grid/2;
var z = j - grid/2;
// Base tile
var tile = document.createElement('a-box');
tile.setAttribute('width', 1);
tile.setAttribute('height', 0.1);
tile.setAttribute('depth', 1);
var tidx = Math.floor(Math.random() * textures.length);
tile.setAttribute('material', 'src:' + textures[tidx] + '; repeat:1 1');
tile.setAttribute('position', x + ' 0 ' + z);
tilemap.appendChild(tile);
// Random model
var m = models[Math.floor(Math.random() * models.length)];
var ent = document.createElement('a-entity');
if (m.type === 'gltf') {{
ent.setAttribute('gltf-model', m.id);
}} else {{
var cmd = 'obj: ' + m.obj;
if (m.mtl) cmd += '; mtl: ' + m.mtl;
ent.setAttribute('obj-model', cmd);
}}
ent.setAttribute('scale', '0.5 0.5 0.5');
ent.setAttribute('position', x + ' 0.5 ' + z);
tilemap.appendChild(ent);
}}
}}
// Ground plane
var ground = document.createElement('a-plane');
ground.setAttribute('width', grid * 2);
ground.setAttribute('height', grid * 2);
ground.setAttribute('rotation', '-90 0 0');
{ground_mat}
ground.setAttribute('position', '0 -0.05 0');
scene.insertBefore(ground, scene.firstChild);
}});
</script>
</body>
</html>
"""
st.components.v1.html(html, height=600, scrolling=False)
if __name__ == "__main__":
main()