In [471]:
%reset -f
Based on: voxel painter (source)
TODO:
- Have rollOver helper snap to other voxel face
- Delete voxel when shift-clicked
In [472]:
from __future__ import division, print_function
In [473]:
from pythreejs import *
from IPython.display import display
from ipywidgets import HTML
from traitlets import link
In [474]:
import random
import math
import numpy as np
In [475]:
csize = 50 # size of voxel
stepx, stepy = csize, csize
sizex, sizey = 10*csize, 10*csize
In [476]:
def normalize(list):
"""
Normalize vector list
"""
return [x/sum(list) for x in list]
def rotation_matrix(angle, axis='x'):
"""
Return rotation matrix as list of rows used in the
Object3d.quaternion_from_rotation() class method
"""
if axis in ['x','y','z']:
sin = math.sin(angle)
cos = math.cos(angle)
# counter-clockwise rotation in yz-plane
if axis is 'x':
return [1, 0, 0, 0, cos, -sin, 0, sin, cos]
# counter-clockwise rotation in xz-plane
elif axis is 'y':
return [cos, 0, sin, 0, 1, 0, -sin, 0, cos]
# counter-clockwise rotation in xy-plane
elif axis is 'z':
return [cos, -sin, 0, sin, cos, 0, 0, 0, 1]
else:
raise ValueError('Cannot rotate about %s axis' % axis)
In [477]:
cube_tex = ImageTexture(
imageuri = 'textures/square-outline-textured.png'
)
cube_geo = BoxGeometry(
width = csize,
height = csize,
depth = csize
)
cube_mat = LambertMaterial(
color = 0xfeb74c,
shading = 'FlatShading',
map = cube_tex
)
In [478]:
rollOver_geo = cube_geo
rollOver_mat = BasicMaterial(
color = 0xff0000,
opacity = 0.5,
transparent = True
)
rollOver_point = Mesh(
geometry = rollOver_geo,
material = rollOver_mat
)
In [479]:
surf_geo = SurfaceGeometry(
z = [0]*sizex*sizey,
width = 2*sizex,
height = 2*sizey,
width_segments = 2*sizex//stepx,
height_segments = 2*sizey//stepy,
)
surf_grid = SurfaceGrid(
geometry = surf_geo,
material = LineBasicMaterial(
color = 0x000000,
opacity = 0.2,
transparant = True
),
)
surface = Mesh(
geometry = surf_geo,
material = BasicMaterial(
color = 'red',
opacity = 0.2,
),
visible = False
)
m = rotation_matrix(-math.pi/2)
surface.quaternion_from_rotation(m)
surf_grid.quaternion_from_rotation(m)
In [480]:
click_picker = Picker(
root = surface,
event = 'click'
)
mousemove_picker = Picker(
root = surface,
event = 'mousemove'
)
In [481]:
def map_to_grid(value):
"""
Convert continous to discrete coordinates
"""
# limit position to positive y-axis
if value[1] < 0:
value[1] = float(0)
# limit to discrete steps based on cube size
pos = [int(x//csize*csize+csize/2) for x in value]
# if block already exist at this position, shift up
while tuple(pos) in objects.keys():
pos[1] += csize
return pos
In [482]:
objects = {} # contains all voxels added to the scene
def on_click(name, value):
"""
Create new object when mouse is clicked
TODO: delete when shift-clicked
"""
# convert position to discrete coordinates
pos = map_to_grid(value)
# create new object
point = Mesh(
geometry = cube_geo,
material = cube_mat,
position = pos
)
# add new object to scene and object list
scene.children = scene.children + [point] #works
#scene.children.append(point) # doesnt work (see: https://github.com/jovyan/pythreejs/blob/master/pythreejs/pythreejs.py#L134)
objects[tuple(map(int,point.position))] = point
In [483]:
html = HTML()
def on_mousemove(name, value):
"""
Show rollOver helper on mousemove
TODO: Snap rollOver helper to existing voxel
"""
# convert to discrete coordinates
pos = map_to_grid(value)
# update rollOver helper position
rollOver_point.position = pos
# write coordinates to html container
html.value = "Coords: (%d, %d, %d)" % tuple(pos)
# initialize with starting position
on_mousemove(None, rollOver_point.position)
In [484]:
click_picker.on_trait_change(on_click, 'point')
link((rollOver_point, 'position'), (mousemove_picker, 'point'))
mousemove_picker.on_trait_change(on_mousemove, 'point')
In [485]:
camera = PerspectiveCamera(
position = [500, 800, 1300],
fov = 35,
aspect = 16/10,
near = 1,
far = 10000
)
camera.look_at(camera.position, [0,0,0])
In [486]:
scene = Scene(
children = [
surface,
surf_grid,
rollOver_point,
AmbientLight(
color = 0x606060
),
DirectionalLight(
color = 0xffffff,
position = normalize([1, 0.75, 0.5]),
intensity = 0.5
)
]
)
In [487]:
renderer = Renderer(
camera = camera,
scene = scene,
controls = [
OrbitControls(
controlling = camera
),
click_picker,
mousemove_picker
],
background = 0xf0f0f0,
antialias = True,
renderer_type = 'auto' #'auto', 'canvas', 'webgl'
)
In [488]:
display(html, renderer)