triview 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- triview-0.0.1/PKG-INFO +3 -0
- triview-0.0.1/README.md +107 -0
- triview-0.0.1/setup.cfg +4 -0
- triview-0.0.1/setup.py +17 -0
- triview-0.0.1/triview/__init__.py +2 -0
- triview-0.0.1/triview/__main__.py +89 -0
- triview-0.0.1/triview/models/teapot.obj +4663 -0
- triview-0.0.1/triview/triview.py +174 -0
- triview-0.0.1/triview.egg-info/PKG-INFO +3 -0
- triview-0.0.1/triview.egg-info/SOURCES.txt +11 -0
- triview-0.0.1/triview.egg-info/dependency_links.txt +1 -0
- triview-0.0.1/triview.egg-info/entry_points.txt +2 -0
- triview-0.0.1/triview.egg-info/top_level.txt +1 -0
triview-0.0.1/PKG-INFO
ADDED
triview-0.0.1/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Triview
|
|
2
|
+
A lightweight GUI-based Python library that renders .obj 3D models and polygon meshes entirely on the CPU without using a GPU or OpenGL. Built with Tkinter, it provides basic real-time 3D transformations, perspective projection, and interactive camera control.
|
|
3
|
+
|
|
4
|
+
Standard Libraries used :- tkinter (GUI), math (Math Operations)
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
- CPU-based 3D rendering (no GPU required)
|
|
8
|
+
- OBJ file loader (.obj support)
|
|
9
|
+
- Perspective projection system
|
|
10
|
+
- Camera movement (x, y, z)
|
|
11
|
+
- Yaw and pitch rotation
|
|
12
|
+
- Simple polygon mesh rendering
|
|
13
|
+
- Lightweight and easy to embed into projects
|
|
14
|
+
|
|
15
|
+
## API
|
|
16
|
+
### Class
|
|
17
|
+
```python
|
|
18
|
+
class TRIVIEW:
|
|
19
|
+
```
|
|
20
|
+
### Class Functions
|
|
21
|
+
```python
|
|
22
|
+
def initialize(self, window, bg, polygon_outline, polygon_fill, camera, zoom, yaw, pitch): # Initializes the Canvas for rendering
|
|
23
|
+
def project_vertices(self, vertices): # Takes 3D points and returns 2D screen points
|
|
24
|
+
def render_mesh(self, projected, faces): # Renders screen points as per faces
|
|
25
|
+
def load_obj(self, name): # Loads an obj file and returns [vertices, faces]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Example of a Rotating Cube
|
|
29
|
+
```python
|
|
30
|
+
import tkinter as tk
|
|
31
|
+
import math
|
|
32
|
+
from triview import TRIVIEW
|
|
33
|
+
|
|
34
|
+
vertices = [
|
|
35
|
+
[-1, -1, -1],
|
|
36
|
+
[ 1, -1, -1],
|
|
37
|
+
[ 1, 1, -1],
|
|
38
|
+
[-1, 1, -1],
|
|
39
|
+
[-1, -1, 1],
|
|
40
|
+
[ 1, -1, 1],
|
|
41
|
+
[ 1, 1, 1],
|
|
42
|
+
[-1, 1, 1],
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
faces = [
|
|
46
|
+
[2, 1, 0], [3, 2, 0],
|
|
47
|
+
[6, 5, 4], [7, 6, 4],
|
|
48
|
+
[5, 1, 0], [4, 5, 0],
|
|
49
|
+
[7, 3, 2], [6, 7, 2],
|
|
50
|
+
[6, 2, 1], [5, 6, 1],
|
|
51
|
+
[7, 0, 3], [4, 7, 0],
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
def rotate_vertex(v, yaw, pitch):
|
|
55
|
+
x, y, z = v
|
|
56
|
+
x1 = x * math.cos(yaw) - z * math.sin(yaw)
|
|
57
|
+
z1 = x * math.sin(yaw) + z * math.cos(yaw)
|
|
58
|
+
y2 = y * math.cos(pitch) - z1 * math.sin(pitch)
|
|
59
|
+
z2 = y * math.sin(pitch) + z1 * math.cos(pitch)
|
|
60
|
+
|
|
61
|
+
return [x1, y2, z2]
|
|
62
|
+
|
|
63
|
+
window = tk.Tk()
|
|
64
|
+
window.geometry("600x500")
|
|
65
|
+
window.title("TRIVIEW - Rotating Cube")
|
|
66
|
+
|
|
67
|
+
tv = TRIVIEW()
|
|
68
|
+
tv.initialize(
|
|
69
|
+
window=window,
|
|
70
|
+
bg="gray15",
|
|
71
|
+
polygon_outline="white",
|
|
72
|
+
polygon_fill="",
|
|
73
|
+
camera=[0, 0, -6],
|
|
74
|
+
zoom=500,
|
|
75
|
+
yaw=0,
|
|
76
|
+
pitch=0
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
angle = 0
|
|
80
|
+
FPS = 60
|
|
81
|
+
|
|
82
|
+
def update():
|
|
83
|
+
global angle
|
|
84
|
+
|
|
85
|
+
rotated = [
|
|
86
|
+
rotate_vertex(v, angle, angle * 0.5)
|
|
87
|
+
for v in vertices
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
projected = tv.project_vertices(rotated)
|
|
91
|
+
tv.render_mesh(projected, faces)
|
|
92
|
+
|
|
93
|
+
angle += 0.02
|
|
94
|
+
window.after(int(1000/FPS), update)
|
|
95
|
+
|
|
96
|
+
update()
|
|
97
|
+
window.mainloop()
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Limitations
|
|
101
|
+
- CPU-based rendering only → performance depends on system power
|
|
102
|
+
- Best suited for low-poly models (under ~2500 faces)
|
|
103
|
+
- No advanced lighting or shading (flat color only)
|
|
104
|
+
- No clipping system yet (can cause distortion at extreme angles)
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
MIT LICENSED @2026
|
triview-0.0.1/setup.cfg
ADDED
triview-0.0.1/setup.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name='triview',
|
|
5
|
+
version='0.0.1',
|
|
6
|
+
packages=find_packages(),
|
|
7
|
+
install_requires=[
|
|
8
|
+
],
|
|
9
|
+
package_data={
|
|
10
|
+
"triview": ["models/*"],
|
|
11
|
+
},
|
|
12
|
+
entry_points={
|
|
13
|
+
"console_scripts": [
|
|
14
|
+
"triview = triview:main",
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# __main__.py
|
|
2
|
+
import tkinter as tk
|
|
3
|
+
from tkinter import messagebox
|
|
4
|
+
from triview import TRIVIEW
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
ask = messagebox.askyesno("Triview", f"Are You Sure You Want to Load teapot.obj ?\n This can be very Laggy\n")
|
|
8
|
+
if not ask:
|
|
9
|
+
quit()
|
|
10
|
+
|
|
11
|
+
window = tk.Tk()
|
|
12
|
+
window.geometry("600x500")
|
|
13
|
+
window.resizable(False, False)
|
|
14
|
+
window.title("Triview")
|
|
15
|
+
render_frame = tk.Frame(window)
|
|
16
|
+
render_frame.pack(side="top", expand = True, fill = "both")
|
|
17
|
+
controls_frame = tk.Frame(window, height=20)
|
|
18
|
+
controls_frame.pack(side="bottom", expand = True, fill = "x")
|
|
19
|
+
controls_frame_left = tk.Frame(controls_frame)
|
|
20
|
+
controls_frame_left.pack(side="left", expand = True, fill = "x")
|
|
21
|
+
controls_frame_right = tk.Frame(controls_frame)
|
|
22
|
+
controls_frame_right.pack(side="right", expand = True, fill = "x")
|
|
23
|
+
tv = TRIVIEW()
|
|
24
|
+
tv.initialize(render_frame, "gray20", "white", "gray20", [0,1.5,-15], 1000,0,0)
|
|
25
|
+
BASE_DIR = os.path.dirname(__file__)
|
|
26
|
+
path = os.path.join(BASE_DIR, "models", "teapot.obj")
|
|
27
|
+
model = tv.load_obj(path)
|
|
28
|
+
if model is None:
|
|
29
|
+
print("Error : Cannot Load Model")
|
|
30
|
+
quit()
|
|
31
|
+
vertices, faces = model
|
|
32
|
+
|
|
33
|
+
def change_x(amount):
|
|
34
|
+
tv.camera[0] += amount
|
|
35
|
+
projected = tv.project_vertices(vertices)
|
|
36
|
+
tv.render_mesh(projected, faces)
|
|
37
|
+
|
|
38
|
+
def change_y(amount):
|
|
39
|
+
tv.camera[1] += amount
|
|
40
|
+
projected = tv.project_vertices(vertices)
|
|
41
|
+
tv.render_mesh(projected, faces)
|
|
42
|
+
|
|
43
|
+
def change_z(amount):
|
|
44
|
+
tv.camera[2] += amount
|
|
45
|
+
projected = tv.project_vertices(vertices)
|
|
46
|
+
tv.render_mesh(projected, faces)
|
|
47
|
+
|
|
48
|
+
def change_yaw(amount):
|
|
49
|
+
tv.yaw += amount
|
|
50
|
+
projected = tv.project_vertices(vertices)
|
|
51
|
+
tv.render_mesh(projected, faces)
|
|
52
|
+
|
|
53
|
+
def change_pitch(amount):
|
|
54
|
+
tv.pitch += amount
|
|
55
|
+
projected = tv.project_vertices(vertices)
|
|
56
|
+
tv.render_mesh(projected, faces)
|
|
57
|
+
|
|
58
|
+
window.update()
|
|
59
|
+
projected = tv.project_vertices(vertices)
|
|
60
|
+
tv.render_mesh(projected, faces)
|
|
61
|
+
|
|
62
|
+
tk.Label(controls_frame_left, text="W - Move Forward", font=('Arial', 15, "bold")).pack(anchor="w", padx=(40,0))
|
|
63
|
+
tk.Label(controls_frame_left, text="A - Move Left", font=('Arial', 15, "bold")).pack(anchor="w", padx=(40,0))
|
|
64
|
+
tk.Label(controls_frame_left, text="S - Move Backward", font=('Arial', 15, "bold")).pack(anchor="w", padx=(40,0))
|
|
65
|
+
tk.Label(controls_frame_left, text="D - Move Right", font=('Arial', 15, "bold")).pack(anchor="w", padx=(40,0))
|
|
66
|
+
|
|
67
|
+
tk.Label(controls_frame_right, text="Up - Move Neck up", font=('Arial', 15, "bold")).pack(anchor="w")
|
|
68
|
+
tk.Label(controls_frame_right, text="Down - Move Neck down", font=('Arial', 15, "bold")).pack(anchor="w")
|
|
69
|
+
tk.Label(controls_frame_right, text="Left - Move Neck Left", font=('Arial', 15, "bold")).pack(anchor="w")
|
|
70
|
+
tk.Label(controls_frame_right, text="Right - Move Neck Right", font=('Arial', 15, "bold")).pack(anchor="w")
|
|
71
|
+
|
|
72
|
+
window.bind("<space>", lambda e: change_y(0.1))
|
|
73
|
+
window.bind("f", lambda e: change_y(-0.1))
|
|
74
|
+
|
|
75
|
+
window.bind("a", lambda e: change_x(-0.1))
|
|
76
|
+
window.bind("d", lambda e: change_x(0.1))
|
|
77
|
+
|
|
78
|
+
window.bind("w", lambda e: change_z(0.1))
|
|
79
|
+
window.bind("s", lambda e: change_z(-0.1))
|
|
80
|
+
|
|
81
|
+
window.bind("<Up>", lambda e: change_pitch(0.01))
|
|
82
|
+
window.bind("<Down>", lambda e: change_pitch(-0.01))
|
|
83
|
+
|
|
84
|
+
window.bind("<Left>", lambda e: change_yaw(-0.01))
|
|
85
|
+
window.bind("<Right>", lambda e: change_yaw(0.01))
|
|
86
|
+
|
|
87
|
+
window.bind("<Configure>", lambda e: tv.render_mesh(tv.project_vertices(vertices),faces))
|
|
88
|
+
|
|
89
|
+
window.mainloop()
|