processingは3Dも扱えるので、試しにマイクラのブロックを作ってみた。

当初テクスチャのサイズを原寸の16×16にしていたが、processingの場合、引き延ばすと汚くなってしまうので1600%の256pxにして使用することにした。
from MouseCamera import MouseCamera
from TextureBox import TextureBox
mouseCamera = None
blocks = list()
def square(r=5, y=0, tname="cobblestone"):
if r % 2 == 0:
return
herf = (r - 1) / 2
for x in range(-herf, herf+1):
blocks.append(TextureBox(tname, x, y, -herf))
blocks.append(TextureBox(tname, x, y, herf))
for z in range(-(herf-1), herf):
blocks.append(TextureBox(tname, -herf, y, z))
blocks.append(TextureBox(tname, herf, y, z))
def setup():
global mouseCamera, blocks
size(800,800, P3D)
textureMode(NORMAL)
mouseCamera = MouseCamera()
blocks.append(TextureBox("cobblestone", 0, -20, 0))
for x in range(-10, 11):
for z in range(-10, 11):
blocks.append(TextureBox("grass_block", x, 1, z))
y=0
for i in range(19, 0, -4):
square(i, y, "tnt")
y-=2
def draw():
background(200)
mouseCamera.update()
for block in blocks:
block.draw()
if blocks[0].y < 0:
blocks[0].y += 0.01
def mousePressed():
mouseCamera.mousePressed()
def mouseDragged():
mouseCamera.mouseDragged()
def mouseWheel(event):
mouseCamera.mouseWheel(event)# coding: utf-8
import copy
class MouseCamera(object):
def __init__(self):
self.radius = 800.0 # 仮想的な球の半径
self.eyeX = 0.0
self.eyeY = 0.0
self.eyeZ = (height / 2.0)/tan(PI*30.0/180.0)
self.centerX = 0.0
self.centerY = 0.0
self.centerZ = 0.0
self.upX = 0.0
self.upY = 1.0
self.upZ = 0.0
self.matrix = self.getIdentityMatrix() # 行列
self.preVector = PVector()
# def setView(self, radius, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ):
# self.radius = radius
# self.eyeX = eyeX
# self.eyeY = eyeY
# self.eyeZ = eyeZ
# self.centerX = centerX
# self.centerY = centerY
# self.centerZ = centerZ
# self.upX = upX
# self.upY = upY
# self.upZ = upZ
# self.matrix = self.getIdentityMatrix()
# 毎フレーム処理
def update(self):
beginCamera()
camera(self.eyeX, self.eyeY, self.eyeZ, self.centerX, self.centerY, self.centerZ, self.upX, self.upY, self.upZ)
applyMatrix(self.matrix[0][0], self.matrix[0][1], self.matrix[0][2], self.matrix[0][3],
self.matrix[1][0], self.matrix[1][1], self.matrix[1][2], self.matrix[1][3],
self.matrix[2][0], self.matrix[2][1], self.matrix[2][2], self.matrix[2][3],
self.matrix[3][0], self.matrix[3][1], self.matrix[3][2], self.matrix[3][3])
endCamera()
# クリックしたときに呼び出す関数
def mousePressed(self):
# 右ボタンをクリックをしたときの処理
if mouseButton == RIGHT:
matrix = self.getIdentityMatrix()
# 左ボタンをクリックをしたときの処理
elif mouseButton == LEFT:
self.preVector = self.mouseOnSphere(mouseX-width / 2.0, mouseY-height / 2.0)
# 中ボタンをクリックしたときの処理
elif mouseButton == CENTER:
self.preVector = PVector(mouseX-width / 2.0, mouseY-height / 2.0)
# ドラッグしたときに呼び出す関数
def mouseDragged(self):
# 左ボタンをドラッグしたときの処理
if mouseButton == LEFT:
v = self.mouseOnSphere(mouseX-width / 2.0, mouseY-height / 2.0)
self.matrix = self.mult(self.getRotationMatrix(self.preVector, v), self.matrix)
self.preVector = v
# 中ボタンをドラッグしたときの処理
elif mouseButton == CENTER:
v = PVector(mouseX-width / 2.0, mouseY-height / 2.0)
self.matrix = self.mult(self.getTranslationMatrix(self.preVector, v), self.matrix)
self.preVector = v
# マウスホイールを動かしたときに呼び出す関数
def mouseWheel(self, event):
self.matrix = self.mult(self.getScaleMatrix(event.getCount()), self.matrix)
# 単位行列の取得
def getIdentityMatrix(self):
return [[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0]]
# 回転行列の取得
def getRotationMatrix(self, v1, v2):
v1tmp = copy.copy(v1) # 保護するためにコピーして使う(normalizeの挙動がjavaと違うのか、値渡しができない影響か、オブジェクトの生成の挙動の違いかわからん)
v = v1tmp.cross(v2).normalize() # 回転軸
c = v1.dot(v2) # cos
s = v1.cross(v2).mag() # sin
return [[c + v.x*v.x*(1.0-c), v.x*v.y*(1.0-c) - v.z*s, v.x*v.z*(1.0-c) + v.y*s, 0.0],
[v.y*v.x*(1.0-c) + v.z*s, c + v.y*v.y*(1.0-c), v.y*v.z*(1.0-c) - v.x*s, 0.0],
[v.z*v.x*(1.0-c) - v.y*s, v.z*v.y*(1.0-c) + v.x*s, c + v.z*v.z*(1.0-c), 0.0],
[0.0, 0.0, 0.0, 1.0]]
# 平行移動行列の取得
def getTranslationMatrix(self, v1, v2):
return [[1.0, 0.0, 0.0, v2.x-v1.x],
[0.0, 1.0, 0.0, v2.y-v1.y],
[0.0, 0.0, 1.0, v2.z-v1.z],
[0.0, 0.0, 0.0, 1.0]]
# 拡大縮小行列の取得
def getScaleMatrix(self, wheelCount):
temp = 10.0 # wheelCountの値が大きいので定数で割る
return [[exp(-wheelCount/temp), 0.0, 0.0, 0.0],
[0.0, exp(-wheelCount/temp), 0.0, 0.0],
[0.0, 0.0, exp(-wheelCount/temp), 0.0],
[0.0, 0.0, 0.0, 1.0]]
# マウスの座標から球面上の位置ベクトルを取得する
def mouseOnSphere(self, x, y):
_x = x / self.radius
_y = y / self.radius
res = PVector(_x, _y, 0.0)
if _x * _x + _y * _y > 1.0:
res.normalize()
else:
res.z = sqrt(1.0 - _x * _x - _y * _y)
return res
# 行列の積 (m1 * m2)
def mult(self, m1, m2):
assert(len(m1[0]) == len(m2))
res = [[0 for i in range(len(m1))] for j in range(len(m2[0]))]
for i in range(len(m1)):
for j in range(len(m2[0])):
sum = 0.0
for k in range(len(m1[0])):
sum += m1[i][k] * m2[k][j]
res[i][j] = sum
return res# coding: utf-8
import os
class TextureBox:
NAME = list()
NAME.append("grass_block")
NAME.append("tnt")
NAME.append("cobblestone")
IMG = dict()
TEXTURE_LOADED = False
def __init__(self, textureName="tnt", x=0, y=0, z=0):
self.loadTexture()
imgs = TextureBox.IMG[textureName]
self.tex_top = imgs[0]
self.tex_side = imgs[0]
self.tex_bottom = imgs[0]
if len(imgs) >= 2:
self.tex_top = imgs[1]
if len(imgs) >= 3:
self.tex_bottom = imgs[2]
self.box_size = 50
self.x = x
self.y = y
self.z = z
def loadTexture(self):
if TextureBox.TEXTURE_LOADED == False:
for name in TextureBox.NAME:
imgs = list()
for i in range(3):
fname = name + str(i) + ".png"
path = os.getcwd() + "\\data\\" + fname
if os.path.isfile(path):
imgs.append(loadImage(fname))
TextureBox.IMG[name] = imgs
TextureBox.TEXTURE_LOADED = True
def draw(self):
noFill()
noStroke()
beginShape(QUADS)
pushMatrix()
scale(self.box_size, self.box_size, self.box_size)
translate(self.x - 0.5, self.y + 0.5, self.z + 0.5)
# +Z "front" face
texture(self.tex_side)
vertex(0, -1, -1, 0, 0)
vertex(1, -1, -1, 1, 0)
vertex(1, 0, -1, 1, 1)
vertex(0, 0, -1, 0, 1)
# -Z "back" face
vertex(0, -1, 0, 0, 0)
vertex(1, -1, 0, 1, 0)
vertex(1, 0, 0, 1, 1)
vertex(0, 0, 0, 0, 1)
# +X "right" face
vertex(1, -1, 0, 0, 0)
vertex(1, -1, -1, 1, 0)
vertex(1, 0, -1, 1, 1)
vertex(1, 0, 0, 0, 1)
# -X "left" face
vertex(0, -1, 0, 0, 0)
vertex(0, -1, -1, 1, 0)
vertex(0, 0, -1, 1, 1)
vertex(0, 0, 0, 0, 1)
endShape()
beginShape(QUADS)
# -Y "top" face
texture(self.tex_top)
vertex(1, -1, 0, 0, 0)
vertex(1, -1, -1, 1, 0)
vertex(0, -1, -1, 1, 1)
vertex(0, -1, 0, 0, 1)
endShape()
beginShape(QUADS)
# +Y "bottom" face
texture(self.tex_bottom)
vertex(1, 0, 0, 0, 0)
vertex(1, 0, -1, 1, 0)
vertex(0, 0, -1, 1, 1)
vertex(0, 0, 0, 0, 1)
endShape()
popMatrix()