mirror of
https://github.com/3b1b/manim.git
synced 2025-11-14 10:37:45 +00:00
Change meaning of resolution for surfaces to be the number of posts, not fences
This commit is contained in:
parent
58fe0c79d8
commit
b8a1853692
1 changed files with 43 additions and 33 deletions
|
|
@ -14,7 +14,9 @@ class ParametricSurface(Mobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"u_range": (0, 1),
|
"u_range": (0, 1),
|
||||||
"v_range": (0, 1),
|
"v_range": (0, 1),
|
||||||
"resolution": (100, 100),
|
# Resolution counts number of points sampled, which is off by
|
||||||
|
# 1 from the number of actual approximating squares seen
|
||||||
|
"resolution": (101, 101),
|
||||||
"color": GREY,
|
"color": GREY,
|
||||||
"opacity": 1.0,
|
"opacity": 1.0,
|
||||||
"gloss": 0.3,
|
"gloss": 0.3,
|
||||||
|
|
@ -33,20 +35,15 @@ class ParametricSurface(Mobject):
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, function=None, **kwargs):
|
def __init__(self, uv_func, **kwargs):
|
||||||
self.passed_function = function
|
self.uv_func = uv_func
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
def uv_func(self, u, v):
|
|
||||||
# Typically to be implemented by a subclass
|
|
||||||
if self.passed_function is not None:
|
|
||||||
return self.passed_function(u, v)
|
|
||||||
return [u, v, 0]
|
|
||||||
|
|
||||||
def init_points(self):
|
def init_points(self):
|
||||||
|
dim = self.dim
|
||||||
nu, nv = self.resolution
|
nu, nv = self.resolution
|
||||||
u_range = np.linspace(*self.u_range, nu + 1)
|
u_range = np.linspace(*self.u_range, nu)
|
||||||
v_range = np.linspace(*self.v_range, nv + 1)
|
v_range = np.linspace(*self.v_range, nv)
|
||||||
|
|
||||||
# Get three lists:
|
# Get three lists:
|
||||||
# - Points generated by pure uv values
|
# - Points generated by pure uv values
|
||||||
|
|
@ -56,28 +53,33 @@ class ParametricSurface(Mobject):
|
||||||
for (du, dv) in [(0, 0), (self.epsilon, 0), (0, self.epsilon)]:
|
for (du, dv) in [(0, 0), (self.epsilon, 0), (0, self.epsilon)]:
|
||||||
uv_grid = np.array([[[u + du, v + dv] for v in v_range] for u in u_range])
|
uv_grid = np.array([[[u + du, v + dv] for v in v_range] for u in u_range])
|
||||||
point_grid = np.apply_along_axis(lambda p: self.uv_func(*p), 2, uv_grid)
|
point_grid = np.apply_along_axis(lambda p: self.uv_func(*p), 2, uv_grid)
|
||||||
point_lists.append(self.get_triangle_ready_array_from_grid(point_grid))
|
point_lists.append(point_grid.reshape((nu * nv, dim)))
|
||||||
# Rather than tracking normal vectors, the points list will hold on to the
|
# Rather than tracking normal vectors, the points list will hold on to the
|
||||||
# infinitesimal nudged values alongside the original values. This way, one
|
# infinitesimal nudged values alongside the original values. This way, one
|
||||||
# can perform all the manipulations they'd like to the surface, and normals
|
# can perform all the manipulations they'd like to the surface, and normals
|
||||||
# are still easily recoverable.
|
# are still easily recoverable.
|
||||||
self.points = np.vstack(point_lists)
|
self.points = np.vstack(point_lists)
|
||||||
|
|
||||||
def get_triangle_ready_array_from_grid(self, grid):
|
def get_triangle_ready_array(self, array):
|
||||||
# Given a grid, say of points or normals, this returns an Nx3 array
|
# Given an array of points representing a flattened grid, say of points or
|
||||||
# whose rows are elements from this grid in such such a way that successive
|
# normals, this returns an Nx3 array whose rows are elements from this grid
|
||||||
# triplets of points form triangles covering the grid.
|
# in such such a way that successive triplets of points form triangles covering
|
||||||
nu, nv, dim = grid.shape
|
# the grid.
|
||||||
nu -= 1
|
dim = array.shape[1]
|
||||||
nv -= 1
|
nu, nv = self.resolution
|
||||||
arr = np.zeros((nu * nv * 6, dim))
|
assert(array.shape == (nu * nv, dim))
|
||||||
|
grid = array.reshape((nu, nv, dim))
|
||||||
|
|
||||||
|
new_length = (nu - 1) * (nv - 1)
|
||||||
|
arr = np.zeros((6 * new_length, dim))
|
||||||
|
shape = (new_length, dim)
|
||||||
# To match the triangles covering this surface
|
# To match the triangles covering this surface
|
||||||
arr[0::6] = grid[:-1, :-1].reshape((nu * nv, dim)) # Top left
|
arr[0::6] = grid[:-1, :-1].reshape(shape) # Top left
|
||||||
arr[1::6] = grid[+1:, :-1].reshape((nu * nv, dim)) # Bottom left
|
arr[1::6] = grid[+1:, :-1].reshape(shape) # Bottom left
|
||||||
arr[2::6] = grid[:-1, +1:].reshape((nu * nv, dim)) # Top right
|
arr[2::6] = grid[:-1, +1:].reshape(shape) # Top right
|
||||||
arr[3::6] = grid[:-1, +1:].reshape((nu * nv, dim)) # Top right
|
arr[3::6] = grid[:-1, +1:].reshape(shape) # Top right
|
||||||
arr[4::6] = grid[+1:, :-1].reshape((nu * nv, dim)) # Bottom left
|
arr[4::6] = grid[+1:, :-1].reshape(shape) # Bottom left
|
||||||
arr[5::6] = grid[+1:, +1:].reshape((nu * nv, dim)) # Bottom right
|
arr[5::6] = grid[+1:, +1:].reshape(shape) # Bottom right
|
||||||
return arr
|
return arr
|
||||||
|
|
||||||
def init_colors(self):
|
def init_colors(self):
|
||||||
|
|
@ -120,7 +122,10 @@ class ParametricSurface(Mobject):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_shader_data(self):
|
def get_shader_data(self):
|
||||||
s_points, du_points, dv_points = self.get_surface_points_and_nudged_points()
|
s_points, du_points, dv_points = [
|
||||||
|
self.get_triangle_ready_array(array)
|
||||||
|
for array in self.get_surface_points_and_nudged_points()
|
||||||
|
]
|
||||||
data = self.get_blank_shader_data_array(len(s_points))
|
data = self.get_blank_shader_data_array(len(s_points))
|
||||||
data["point"] = s_points
|
data["point"] = s_points
|
||||||
data["du_point"] = du_points
|
data["du_point"] = du_points
|
||||||
|
|
@ -163,17 +168,22 @@ class TexturedSurface(ParametricSurface):
|
||||||
path = get_full_raster_image_path(filename)
|
path = get_full_raster_image_path(filename)
|
||||||
self.image = Image.open(path)
|
self.image = Image.open(path)
|
||||||
self.texture_path = path
|
self.texture_path = path
|
||||||
|
|
||||||
self.uv_surface = uv_surface
|
self.uv_surface = uv_surface
|
||||||
super().__init__(**kwargs)
|
self.uv_func = uv_surface.uv_func
|
||||||
|
self.u_range = uv_surface.u_range
|
||||||
|
self.v_range = uv_surface.v_range
|
||||||
|
self.resolution = uv_surface.resolution
|
||||||
|
super().__init__(self.uv_func, **kwargs)
|
||||||
|
|
||||||
def init_points(self):
|
def init_points(self):
|
||||||
self.points = self.uv_surface.points
|
self.points = self.uv_surface.points
|
||||||
# Init im_coords
|
# Init im_coords
|
||||||
nu, nv = self.uv_surface.resolution
|
nu, nv = self.uv_surface.resolution
|
||||||
u_range = np.linspace(0, 1, nu + 1)
|
u_range = np.linspace(0, 1, nu)
|
||||||
v_range = np.linspace(1, 0, nv + 1) # Reverse y-direction
|
v_range = np.linspace(1, 0, nv) # Reverse y-direction
|
||||||
uv_grid = np.array([[[u, v] for v in v_range] for u in u_range])
|
uv_grid = np.array([[u, v] for u in u_range for v in v_range])
|
||||||
self.im_coords = self.uv_surface.get_triangle_ready_array_from_grid(uv_grid)
|
self.im_coords = uv_grid
|
||||||
|
|
||||||
def init_colors(self):
|
def init_colors(self):
|
||||||
self.opacity = self.uv_surface.rgbas[:, 3]
|
self.opacity = self.uv_surface.rgbas[:, 3]
|
||||||
|
|
@ -187,7 +197,7 @@ class TexturedSurface(ParametricSurface):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def fill_in_shader_color_info(self, data):
|
def fill_in_shader_color_info(self, data):
|
||||||
data["im_coords"] = self.im_coords
|
data["im_coords"] = self.get_triangle_ready_array(self.im_coords)
|
||||||
data["opacity"] = self.opacity
|
data["opacity"] = self.opacity
|
||||||
data["gloss"] = self.gloss
|
data["gloss"] = self.gloss
|
||||||
return data
|
return data
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue