Create streamlit application which take a OBJ file in input, and display the 3d mesh in a 3D plotly chart
To upload files, please first save the app
import streamlit as st
import plotly.graph_objects as go
import numpy as np
def parse_obj(file_content):
vertices = []
faces = []
for line in file_content.decode('utf-8').split('\n'):
if line.startswith('v '): # Vertex
# Split line and convert coordinates to float
_, x, y, z = line.split()
vertices.append([float(x), float(y), float(z)])
elif line.startswith('f '): # Face
# Handle both formats: f v1 v2 v3 and f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3
_, *f = line.split()
face = []
for vert in f:
# Get only the vertex index (before any '/' character)
idx = int(vert.split('/')[0]) - 1 # OBJ indices start at 1
face.append(idx)
faces.append(face)
return np.array(vertices), faces
def create_3d_mesh_plot(vertices, faces):
# Create lists for the triangle vertices
i = []
j = []
k = []
# Convert face indices to triangle vertices
for face in faces:
if len(face) == 3: # Triangle
i.append(face[0])
j.append(face[1])
k.append(face[2])
elif len(face) == 4: # Quad - split into two triangles
i.extend([face[0], face[0]])
j.extend([face[1], face[2]])
k.extend([face[2], face[3]])
# Create the 3D mesh plot
fig = go.Figure(data=[
go.Mesh3d(
x=vertices[:, 0],
y=vertices[:, 1],
z=vertices[:, 2],
i=i,
j=j,
k=k,
opacity=1.0,
colorscale='Viridis',
intensity=vertices[:, 2], # Color based on z-coordinate
showscale=True
)
])
# Update layout for better visualization
fig.update_layout(
scene=dict(
aspectmode='data', # Preserve aspect ratio
camera=dict(
up=dict(x=0, y=1, z=0),
center=dict(x=0, y=0, z=0),
eye=dict(x=1.5, y=1.5, z=1.5)
),
xaxis_title='X',
yaxis_title='Y',
zaxis_title='Z'
),
title='3D Mesh Visualization',
width=800,
height=800
)
return fig
# Streamlit app
st.set_page_config(layout="wide")
st.title("3D OBJ File Viewer")
# File uploader
uploaded_file = st.file_uploader("Choose an OBJ file", type=['obj'])
if uploaded_file is not None:
try:
# Parse the OBJ file
vertices, faces = parse_obj(uploaded_file.read())
# Create visualization
fig = create_3d_mesh_plot(vertices, faces)
# Display the plot
st.plotly_chart(fig, use_container_width=True)
# Display mesh statistics
col1, col2 = st.columns(2)
with col1:
st.metric("Number of Vertices", len(vertices))
with col2:
st.metric("Number of Faces", len(faces))
# Add controls
st.sidebar.header("Visualization Controls")
color_scale = st.sidebar.selectbox(
"Color Scale",
['Viridis', 'Plasma', 'Inferno', 'Magma', 'Cividis']
)
opacity = st.sidebar.slider("Opacity", 0.0, 1.0, 1.0)
# Update visualization based on controls
fig.update_traces(
colorscale=color_scale,
opacity=opacity
)
st.plotly_chart(fig, use_container_width=True)
except Exception as e:
st.error(f"Error processing the OBJ file: {str(e)}")
st.write("Please make sure the file is a valid OBJ file.")
else:
st.info("Please upload an OBJ file to visualize it.")
# Example of expected file format
st.markdown("""
### Expected OBJ File Format:
```
v x1 y1 z1 # Vertex 1
v x2 y2 z2 # Vertex 2
v x3 y3 z3 # Vertex 3
...
f v1 v2 v3 # Face (triangle)
f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 # Face with texture/normal indices
...
```
""")
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?