Spaces:
Sleeping
Sleeping
Update render/core.py
Browse files- render/core.py +8 -56
render/core.py
CHANGED
|
@@ -8,7 +8,6 @@ from .canvas import Canvas
|
|
| 8 |
from . import speedup
|
| 9 |
|
| 10 |
|
| 11 |
-
# 2D part
|
| 12 |
|
| 13 |
|
| 14 |
class Vec2d:
|
|
@@ -124,14 +123,13 @@ def draw_triangle(v1, v2, v3, canvas, color, wireframe=False):
|
|
| 124 |
fill_top_flat_triangle(v2, v4, v3)
|
| 125 |
|
| 126 |
|
| 127 |
-
# 3D part
|
| 128 |
|
| 129 |
|
| 130 |
class Vec3d:
|
| 131 |
__slots__ = "x", "y", "z", "arr"
|
| 132 |
|
| 133 |
def __init__(self, *args):
|
| 134 |
-
|
| 135 |
if len(args) == 1 and isinstance(args[0], Vec4d):
|
| 136 |
vec4 = args[0]
|
| 137 |
arr_value = (vec4.x, vec4.y, vec4.z)
|
|
@@ -183,7 +181,7 @@ class Vec4d(Mat4d):
|
|
| 183 |
self.arr = self.value.reshape((1, 4))
|
| 184 |
|
| 185 |
|
| 186 |
-
|
| 187 |
def normalize(v: Vec3d):
|
| 188 |
return Vec3d(*speedup.normalize(*v.arr))
|
| 189 |
|
|
@@ -210,16 +208,7 @@ def get_light_intensity(face) -> float:
|
|
| 210 |
|
| 211 |
|
| 212 |
def look_at(eye: Vec3d, target: Vec3d, up: Vec3d = Vec3d(0, -1, 0)) -> Mat4d:
|
| 213 |
-
|
| 214 |
-
http://www.songho.ca/opengl/gl_camera.html#lookat
|
| 215 |
-
|
| 216 |
-
Args:
|
| 217 |
-
eye: 摄像机的世界坐标位置
|
| 218 |
-
target: 观察点的位置
|
| 219 |
-
up: 就是你想让摄像机立在哪个方向
|
| 220 |
-
https://stackoverflow.com/questions/10635947/what-exactly-is-the-up-vector-in-opengls-lookat-function
|
| 221 |
-
这里默认使用了 0, -1, 0, 因为 blender 导出来的模型数据似乎有问题,导致y轴总是反的,于是把摄像机的up也翻一下得了。
|
| 222 |
-
"""
|
| 223 |
f = normalize(eye - target)
|
| 224 |
l = normalize(cross_product(up, f)) # noqa: E741
|
| 225 |
u = cross_product(f, l)
|
|
@@ -235,35 +224,7 @@ def look_at(eye: Vec3d, target: Vec3d, up: Vec3d = Vec3d(0, -1, 0)) -> Mat4d:
|
|
| 235 |
|
| 236 |
|
| 237 |
def perspective_project(r, t, n, f, b=None, l=None): # noqa: E741
|
| 238 |
-
|
| 239 |
-
目的:
|
| 240 |
-
把相机坐标转换成投影在视网膜的范围在(-1, 1)的笛卡尔坐标
|
| 241 |
-
|
| 242 |
-
原理:
|
| 243 |
-
对于x,y坐标,相似三角形可以算出投影点的x,y
|
| 244 |
-
对于z坐标,是假设了near是-1,far是1,然后带进去算的
|
| 245 |
-
http://www.songho.ca/opengl/gl_projectionmatrix.html
|
| 246 |
-
https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/opengl-perspective-projection-matrix
|
| 247 |
-
|
| 248 |
-
推导出来的矩阵:
|
| 249 |
-
[
|
| 250 |
-
2n/(r-l) 0 (r+l/r-l) 0
|
| 251 |
-
0 2n/(t-b) (t+b)/(t-b) 0
|
| 252 |
-
0 0 -(f+n)/f-n (-2*f*n)/(f-n)
|
| 253 |
-
0 0 -1 0
|
| 254 |
-
]
|
| 255 |
-
|
| 256 |
-
实际上由于我们用的视网膜(near pane)是个关于远点对称的矩形,所以矩阵简化为:
|
| 257 |
-
[
|
| 258 |
-
n/r 0 0 0
|
| 259 |
-
0 n/t 0 0
|
| 260 |
-
0 0 -(f+n)/f-n (-2*f*n)/(f-n)
|
| 261 |
-
0 0 -1 0
|
| 262 |
-
]
|
| 263 |
-
|
| 264 |
-
Args:
|
| 265 |
-
r: right, t: top, n: near, f: far, b: bottom, l: left
|
| 266 |
-
"""
|
| 267 |
return Mat4d(
|
| 268 |
[
|
| 269 |
[n / r, 0, 0, 0],
|
|
@@ -291,8 +252,7 @@ def draw(screen_vertices, world_vertices, model, canvas, wireframe=True):
|
|
| 291 |
|
| 292 |
|
| 293 |
def draw_with_z_buffer(screen_vertices, world_vertices, model, canvas):
|
| 294 |
-
|
| 295 |
-
"""
|
| 296 |
intensities = []
|
| 297 |
triangles = []
|
| 298 |
for i, triangle_indices in enumerate(model.indices):
|
|
@@ -319,13 +279,7 @@ def draw_with_z_buffer(screen_vertices, world_vertices, model, canvas):
|
|
| 319 |
|
| 320 |
|
| 321 |
def render(model, height, width, filename, cam_loc, wireframe=False):
|
| 322 |
-
|
| 323 |
-
Args:
|
| 324 |
-
model: the Model object
|
| 325 |
-
height: cavas height
|
| 326 |
-
width: cavas width
|
| 327 |
-
picname: picture file name
|
| 328 |
-
"""
|
| 329 |
model_matrix = Mat4d([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
|
| 330 |
# TODO: camera configration
|
| 331 |
view_matrix = look_at(Vec3d(cam_loc[0], cam_loc[1], cam_loc[2]), Vec3d(0, 0, 0))
|
|
@@ -339,9 +293,7 @@ def render(model, height, width, filename, cam_loc, wireframe=False):
|
|
| 339 |
return projection_matrix * view_matrix * world_vertex
|
| 340 |
|
| 341 |
def ndc(v):
|
| 342 |
-
|
| 343 |
-
各个坐标同时除以 w,得到 NDC 坐标
|
| 344 |
-
"""
|
| 345 |
v = v.value
|
| 346 |
w = v[3, 0]
|
| 347 |
x, y, z = v[0, 0] / w, v[1, 0] / w, v[2, 0] / w
|
|
@@ -357,7 +309,7 @@ def render(model, height, width, filename, cam_loc, wireframe=False):
|
|
| 357 |
0.5 * (f - n) * v.value[2, 0] + 0.5 * (f + n),
|
| 358 |
)
|
| 359 |
|
| 360 |
-
|
| 361 |
screen_vertices = [viewport(ndc(mvp(v))) for v in model.vertices]
|
| 362 |
|
| 363 |
with Canvas(filename, height, width) as canvas:
|
|
|
|
| 8 |
from . import speedup
|
| 9 |
|
| 10 |
|
|
|
|
| 11 |
|
| 12 |
|
| 13 |
class Vec2d:
|
|
|
|
| 123 |
fill_top_flat_triangle(v2, v4, v3)
|
| 124 |
|
| 125 |
|
|
|
|
| 126 |
|
| 127 |
|
| 128 |
class Vec3d:
|
| 129 |
__slots__ = "x", "y", "z", "arr"
|
| 130 |
|
| 131 |
def __init__(self, *args):
|
| 132 |
+
|
| 133 |
if len(args) == 1 and isinstance(args[0], Vec4d):
|
| 134 |
vec4 = args[0]
|
| 135 |
arr_value = (vec4.x, vec4.y, vec4.z)
|
|
|
|
| 181 |
self.arr = self.value.reshape((1, 4))
|
| 182 |
|
| 183 |
|
| 184 |
+
|
| 185 |
def normalize(v: Vec3d):
|
| 186 |
return Vec3d(*speedup.normalize(*v.arr))
|
| 187 |
|
|
|
|
| 208 |
|
| 209 |
|
| 210 |
def look_at(eye: Vec3d, target: Vec3d, up: Vec3d = Vec3d(0, -1, 0)) -> Mat4d:
|
| 211 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
f = normalize(eye - target)
|
| 213 |
l = normalize(cross_product(up, f)) # noqa: E741
|
| 214 |
u = cross_product(f, l)
|
|
|
|
| 224 |
|
| 225 |
|
| 226 |
def perspective_project(r, t, n, f, b=None, l=None): # noqa: E741
|
| 227 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
return Mat4d(
|
| 229 |
[
|
| 230 |
[n / r, 0, 0, 0],
|
|
|
|
| 252 |
|
| 253 |
|
| 254 |
def draw_with_z_buffer(screen_vertices, world_vertices, model, canvas):
|
| 255 |
+
|
|
|
|
| 256 |
intensities = []
|
| 257 |
triangles = []
|
| 258 |
for i, triangle_indices in enumerate(model.indices):
|
|
|
|
| 279 |
|
| 280 |
|
| 281 |
def render(model, height, width, filename, cam_loc, wireframe=False):
|
| 282 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 283 |
model_matrix = Mat4d([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
|
| 284 |
# TODO: camera configration
|
| 285 |
view_matrix = look_at(Vec3d(cam_loc[0], cam_loc[1], cam_loc[2]), Vec3d(0, 0, 0))
|
|
|
|
| 293 |
return projection_matrix * view_matrix * world_vertex
|
| 294 |
|
| 295 |
def ndc(v):
|
| 296 |
+
|
|
|
|
|
|
|
| 297 |
v = v.value
|
| 298 |
w = v[3, 0]
|
| 299 |
x, y, z = v[0, 0] / w, v[1, 0] / w, v[2, 0] / w
|
|
|
|
| 309 |
0.5 * (f - n) * v.value[2, 0] + 0.5 * (f + n),
|
| 310 |
)
|
| 311 |
|
| 312 |
+
|
| 313 |
screen_vertices = [viewport(ndc(mvp(v))) for v in model.vertices]
|
| 314 |
|
| 315 |
with Canvas(filename, height, width) as canvas:
|