For those who asked to see my latest project example. Here it is, a work in progress that will be available soon.
Note: this is GIF animation, the original graphics is real-time 60 FPS.
Stay tuned.
Cheers.
For those who asked to see my latest project example. Here it is, a work in progress that will be available soon.
Note: this is GIF animation, the original graphics is real-time 60 FPS.
Stay tuned.
Cheers.
// Initial 2D device coordinate. func setStart(point: CGPoint) { let startCoordWorld = unprojectTouch(point: point) start = startCoordWorld next = startCoordWorld startOrientation = targetNode.simdOrientation.normalized } // FUNC SET START // Follow up 2D device coordinate. func setNext(point: CGPoint) { let nextCoordWorld = unprojectTouch(point: point) next = nextCoordWorld planarToSpherical() addOrientation = simd_quatf(angle: angleRad, axis: axis).normalized } // FUNC SET NEXT // Makes the node change orientation (corresponding to start-next pair). func jumpToNext() { targetNode.simdOrientation = (addOrientation * startOrientation) } // FUNC ORIENT TO NEXT // Convert viewport point to a world coordinate on an imaginary plane facing camera. func unprojectTouch(point: CGPoint) -> simd_float3 { let ndcPoint = viewToNDC(point: point) let xyPlanePoint = ndcPoint * fovWorldSize * 0.5 // This point is on an imaginary plane that is perpendicular to a view. let worldPlaneTouchPoint = cameraPos + cameraUp * xyPlanePoint.y + cameraRight * xyPlanePoint.x + cameraFront * distanceCamToPlane return worldPlaneTouchPoint } // FUNC UNPROJECT TOUCH // View coordinates (screen pixels) to NDC (normalized device coordinates). // Only x and y can be recovered. func viewToNDC(point: CGPoint) -> simd_float2 { // Centered in the middle of view. let x = Float(point.x) - viewportSize.x * 0.5 let y = viewportSize.y * 0.5 - Float(point.y) let ndc = simd_float2(x * 2.0 / projectionSize, y * 2.0 / projectionSize) return ndc } // FUNC VIEW TO NDC // Convert plane movement in front of a camera to angular rotation. // Around "bounding" sphere of a target node. func planarToSpherical() { // Plane distance to the sphere center is targetRadius. let distance = simd_distance(start, next) angleRad = distance / (targetRadius) axis = simd_normalize(simd_cross(start, next)) } // FUNC PLANAR TO SPHERICAL // Intermediate rotation (from current to next). // Input is normalized in range [0, 1] func interpolateOrientation(t: Float) { // slerp has a problem - always takes the shortest arc. var interOr = simd_bezier(Self.identityOrientation, Self.identityOrientation, addOrientation, addOrientation, t) interOr = (interOr * startOrientation) targetNode.simdOrientation = interOr } // FUNC INTERPOLATE ORIENTATION
$ python3 -m pip install jupyterJupyter notebooks run a web server that can be queried either directly from web console, or via terminal. To find what localhost:port is used by a running server:
$ jupyter notebook list
$ jupyter notebook stop 8888
$ jupyter notebook
>>> import sys
>>> print('\n'.join(sys.path))
---------- EDITOR:
Opt-Tab - select previous file
F1 - focus to shell panel
F2 - focus to file editor
Cmd-/ - comment selection
Cmd-Opt-/ - uncomment
---------- RUN:
Cmd-R - run file as a script (in console restarts interpreter)
Cmd-Return - run cell with cursor (cells are delimited by #%%)
Opt-Return - run selection
---------- DEBUGGER:
Cmd-B - toggle breakpoint
F6 - step over
F7 - step in
F8 - step out
Ctrl-Cmd-Y - continue
Ctrl-Cmd-. - stop debugging
>>> x = np.ndarray(shape=(2, 2), dtype=np.int8, order='C')
>>> print(x)
[[1 0] [1 1]]Internal buffer is linear. Shape can be changed easily without reallocation if total element count remains the same:
>>> x.shape = (1,4)
>>> print(x)
[[1 0 1 1]]Other array constructors:
>>> print(np.array((1, 2, 3)))
[1 2 3]
>>> print(np.zeros((2, 3)))
[[0. 0. 0.]
[0. 0. 0.]]
>>> print(np.empty((2,)))
[7.74860419e-304 7.74860419e-304]
>>> x = np.array([(x, y) for x in [1,2,3] for y in [3,1,4] if x != y])
>>> print(x)
[[1 3]
[1 4]
[2 3]
[2 1]
[2 4]
[3 1]
[3 4]]
>>> x.shape = (2, -1)
>>> print(x)
[[1 3 1 4 2 3 2]
[1 2 4 3 1 3 4]]
>>> x.shape = (-1)
>>> print(x)
[1 3 1 4 2 3 2 1 2 4 3 1 3 4]
>>> y = np.array([e for e in x if not e % 2])
>>> print(y)
[4 2 2 2 4 4]
>>> x = np.arange(15).reshape(5, -1).T
>>> print(x)
[[ 0 3 6 9 12]
[ 1 4 7 10 13]
[ 2 5 8 11 14]]
#%% Timing init
import time
x1 = np.arange(1000000)
x2 = np.arange(1000000)
#%% Timing native
t0 = time.time()
for _ in range(10):
x1 **= 2
t1 = time.time()
print("x1 time = ", t1 - t0)
#%% Timing list comprehension
t0 = time.time()
for _ in range(10):
x2 = np.array([x ** 2 for x in x1])
t1 = time.time()
print("x2 time = ", t1 - t0)
#%%
----------------------------------------
x1 time = 0.015141725540161133
x2 time = 4.744795083999634
np.random.rand(d0,..dn) - with each value uniformly in range [0, 1).
np.random.randn(d0,..dn) - with each value in Gaussian distribution, where mean = 0, variance = 1 (sigma squared).
sigma * np.random.randn(d0,..dn) + mean - a full normal distribution.
x1 = np.arange(12)
print(x1)
x1_slice = x1[3:10]
print('x1_slice = ', x1_slice)
print('x1_slice[0:3] = ', x1_slice[0:3])
x1_slice[0:3] = 100
print(x1)
----------------------------------------
[ 0 1 2 3 4 5 6 7 8 9 10 11]
x1_slice = [3 4 5 6 7 8 9]
x1_slice[0:3] = [3 4 5]
[ 0 1 2 100 100 100 6 7 8 9 10 11]
x1 = np.arange(12).reshape(4,-1)
print(x1)
x1_slice = x1[2:4]
print(x1_slice)
print(x1_slice[0][1:3])
----------------------------------------
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
[[ 6 7 8]
[ 9 10 11]]
[7 8]
print(x1[:2, 1:3])
x1[:, 1:2] = 100
print(x1)
----------------------------------------
[[1 2]
[4 5]]
[[ 0 100 2]
[ 3 100 5]
[ 6 100 8]
[ 9 100 11]]
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Joe'])
data = np.random.randint(1, 10, (5, 4))
print(names)
print(data)
mask = (names == 'Bob') | (names == 'Will')
print(mask)
print(data[mask])
data[mask, 1:3] = 100.
print(data)
data[data > 5] = 0
print(data)
----------------------------------------
['Bob' 'Joe' 'Will' 'Bob' 'Joe']
[[1 4 3 6]
[6 1 3 3]
[7 1 6 1]
[3 3 9 4]
[4 7 8 9]]
[ True False True True False]
[[1 4 3 6]
[7 1 6 1]
[3 3 9 4]]
[[ 1 100 100 6]
[ 6 1 3 3]
[ 7 100 100 1]
[ 3 100 100 4]
[ 4 7 8 9]]
[[1 0 0 0]
[0 1 3 3]
[0 0 0 1]
[3 0 0 4]
[4 0 0 0]]
x1 = np.arange(20).reshape((5, 4))
print(x1)
x2 = x1[[1, 4, 2, 2], [0, 3, 1, 2]]
print(x2)
x1[[1, 4, 2, 2], [0, 3, 1, 2]] = 100
print(x1)
----------------------------------------
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]
[16 17 18 19]]
[ 4 19 9 10]
[[ 0 1 2 3]
[100 5 6 7]
[ 8 100 100 11]
[ 12 13 14 15]
[ 16 17 18 100]]
x1 = np.arange(15).reshape((3, 5))
print(x1)
x2 = x1.T
print(x2)
x2[2] = 100
print(x1)
----------------------------------------
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
[[ 0 5 10]
[ 1 6 11]
[ 2 7 12]
[ 3 8 13]
[ 4 9 14]]
[[ 0 1 100 3 4]
[ 5 6 100 8 9]
[ 10 11 100 13 14]]
// Enable depth test, inverted, front to back. glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_GREATER); // Render only back faces. glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); // Clear the buffers. // Note that the most distant shape will overwrite all others. glClearDepth(0.0); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //... Render the shape of the volume, i.e. a cloud. // Enable depth test, back to front. glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); // Render only front faces. glEnable(GL_CULL_FACE); glCullFace(GL_BACK); // Clear the buffers. glClearDepth(1.0); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //... Render the same shape of the volume.