Add a really rough version of an entity renderer.

Has an interface similar to Minecraft's internal renderer.
Renders Zombies, Skeletons, Spiders, Creepers, and Zombie Pigmen.
This commit is contained in:
David Vierra 2015-07-11 22:44:43 -10:00
parent 875a5d5a03
commit b2eff71a62
8 changed files with 446 additions and 1 deletions

View File

@ -0,0 +1,7 @@
"""
__init__.py
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import logging
log = logging.getLogger(__name__)

View File

@ -0,0 +1,80 @@
"""
biped
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import logging
from mcedit2.rendering.chunkmeshes.entity.modelrenderer import ModelRenderer
log = logging.getLogger(__name__)
class ModelBiped(object):
def __init__(self, expandOffset=0.0, headOffset=0.0):
self.bipedHead = ModelRenderer(self, 0, 0)
self.bipedHead.addBox(-4.0, -8.0, -4.0, 8, 8, 8, expandOffset)
self.bipedHead.setCenterPoint(0.0, 0.0 + headOffset, 0.0)
self.bipedHeadwear = ModelRenderer(self, 32, 0)
self.bipedHeadwear.addBox(-4.0, -8.0, -4.0, 8, 8, 8, expandOffset + 0.5)
self.bipedHeadwear.setCenterPoint(0.0, 0.0 + headOffset, 0.0)
self.bipedBody = ModelRenderer(self, 16, 16)
self.bipedBody.addBox(-4.0, 0.0, -2.0, 8, 12, 4, expandOffset)
self.bipedBody.setCenterPoint(0.0, 0.0 + headOffset, 0.0)
self.bipedRightArm = ModelRenderer(self, 40, 16)
self.bipedRightArm.addBox(-3.0, -2.0, -2.0, 4, 12, 4, expandOffset)
self.bipedRightArm.setCenterPoint(-5.0, 2.0 + headOffset, 0.0)
self.bipedLeftArm = ModelRenderer(self, 40, 16)
self.bipedLeftArm.mirror = True
self.bipedLeftArm.addBox(-1.0, -2.0, -2.0, 4, 12, 4, expandOffset)
self.bipedLeftArm.setCenterPoint(5.0, 2.0 + headOffset, 0.0)
self.bipedRightLeg = ModelRenderer(self, 0, 16)
self.bipedRightLeg.addBox(-2.0, 0.0, -2.0, 4, 12, 4, expandOffset)
self.bipedRightLeg.setCenterPoint(-1.9, 12.0 + headOffset, 0.0)
self.bipedLeftLeg = ModelRenderer(self, 0, 16)
self.bipedLeftLeg.mirror = True
self.bipedLeftLeg.addBox(-2.0, 0.0, -2.0, 4, 12, 4, expandOffset)
self.bipedLeftLeg.setCenterPoint(1.9, 12.0 + headOffset, 0.0)
@property
def parts(self):
return [
self.bipedHead,
self.bipedHeadwear,
self.bipedBody,
self.bipedRightArm,
self.bipedLeftArm,
self.bipedRightLeg,
self.bipedLeftLeg
]
class ModelZombie(ModelBiped):
modelTexture = "assets/minecraft/textures/entity/zombie/zombie.png"
id = "Zombie"
class ModelPigZombie(ModelBiped):
modelTexture = "assets/minecraft/textures/entity/zombie_pigman.png"
id = "PigZombie"
class ModelSkeleton(ModelBiped):
modelTexture = "assets/minecraft/textures/entity/skeleton/skeleton.png"
id = "Skeleton"
def __init__(self, expandOffset=1.0, headOffset=0.0):
super(ModelSkeleton, self).__init__(expandOffset, headOffset)
self.bipedRightArm = ModelRenderer(self, 40, 16)
self.bipedRightArm.addBox(-1.0, -2.0, -1.0, 2, 12, 2, expandOffset)
self.bipedRightArm.setCenterPoint(-5.0, 2.0, 0.0)
self.bipedLeftArm = ModelRenderer(self, 40, 16)
self.bipedLeftArm.mirror = True
self.bipedLeftArm.addBox(-1.0, -2.0, -1.0, 2, 12, 2, expandOffset)
self.bipedLeftArm.setCenterPoint(5.0, 2.0, 0.0)
self.bipedRightLeg = ModelRenderer(self, 0, 16)
self.bipedRightLeg.addBox(-1.0, 0.0, -1.0, 2, 12, 2, expandOffset)
self.bipedRightLeg.setCenterPoint(-2.0, 12.0, 0.0)
self.bipedLeftLeg = ModelRenderer(self, 0, 16)
self.bipedLeftLeg.mirror = True
self.bipedLeftLeg.addBox(-1.0, 0.0, -1.0, 2, 12, 2, expandOffset)
self.bipedLeftLeg.setCenterPoint(2.0, 12.0, 0.0)

View File

@ -0,0 +1,41 @@
"""
creeper
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import logging
from mcedit2.rendering.chunkmeshes.entity.modelrenderer import ModelRenderer
log = logging.getLogger(__name__)
class ModelCreeper(object):
modelTexture = "assets/minecraft/textures/entity/creeper/creeper.png"
id = "Creeper"
def __init__(self):
headCenterHeight = 6
head = ModelRenderer(self, 0, 0)
head.addBox(-4.0, -8.0, -4.0, 8, 8, 8)
head.setCenterPoint(0.0, headCenterHeight, 0.0)
# creeperArmor = ModelRenderer(self, 32, 0)
# creeperArmor.addBox(-4.0, -8.0, -4.0, 8, 8, 8)
# creeperArmor.setCenterPoint(0.0, headCenterHeight, 0.0)
body = ModelRenderer(self, 16, 16)
body.addBox(-4.0, 0.0, -2.0, 8, 12, 4)
body.setCenterPoint(0.0, headCenterHeight, 0.0)
leg1 = ModelRenderer(self, 0, 16)
leg1.addBox(-2.0, 0.0, -2.0, 4, 6, 4)
leg1.setCenterPoint(-2.0, (12 + headCenterHeight), 4.0)
leg2 = ModelRenderer(self, 0, 16)
leg2.addBox(-2.0, 0.0, -2.0, 4, 6, 4)
leg2.setCenterPoint(2.0, (12 + headCenterHeight), 4.0)
leg3 = ModelRenderer(self, 0, 16)
leg3.addBox(-2.0, 0.0, -2.0, 4, 6, 4)
leg3.setCenterPoint(-2.0, (12 + headCenterHeight), -4.0)
leg4 = ModelRenderer(self, 0, 16)
leg4.addBox(-2.0, 0.0, -2.0, 4, 6, 4)
leg4.setCenterPoint(2.0, (12 + headCenterHeight), -4.0)
self.parts = [
head, body, leg1, leg2, leg3, leg4
]

View File

@ -0,0 +1,60 @@
"""
modelrenderer
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import collections
import logging
log = logging.getLogger(__name__)
class ModelBox(collections.namedtuple(
'ModelBox',
'x y z w h l expandOffset mirror',
)):
@property
def x2(self):
return self.x + self.w
@property
def y2(self):
return self.y + self.h
@property
def z2(self):
return self.z + self.l
@property
def dx(self):
return self.w
@property
def dy(self):
return self.h
@property
def dz(self):
return self.l
class ModelRenderer(object):
def __init__(self, parent, u, v):
self.parent = parent
self.boxes = []
self.u = u
self.v = v
self.mirror = False
self.centerPoint = 0, 0, 0
self.rotation = 0, 0, 0
def addBox(self, x, y, z, w, h, l, expandOffset=0.0, mirror=None):
if mirror is None:
mirror = self.mirror
self.boxes.append(ModelBox(x, y, z, w, h, l, expandOffset, mirror))
def setCenterPoint(self, x, y, z):
self.centerPoint = x, y, z
def setRotation(self, rx, ry, rz):
self.rotation = rx, ry, rz

View File

@ -0,0 +1,139 @@
"""
models
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import logging
import math
import numpy
from mcedit2.rendering.chunkmeshes.entity.biped import ModelZombie, ModelSkeleton, \
ModelPigZombie
from mcedit2.rendering.chunkmeshes.entity.creeper import ModelCreeper
from mcedit2.rendering.chunkmeshes.entity.spider import ModelSpider
log = logging.getLogger(__name__)
def makeQuad(c1, c2, c3, c4, u1, v1, u2, v2):
return [
c1 + (u2, v1),
c2 + (u1, v1),
c3 + (u1, v2),
c4 + (u2, v2),
]
def makeBoxQuads(u, v, box):
x, y, z = box.x, box.y, box.z
x2, y2, z2 = box.x2, box.y2, box.z2
expandOffset = box.expandOffset
x -= expandOffset
y -= expandOffset
z -= expandOffset
x2 += expandOffset
y2 += expandOffset
z2 += expandOffset
if box.mirror:
x, x2 = x2, x
xyz = x, y, z
x2yz = x2, y, z
xy2z = x, y2, z
xyz2 = x, y, z2
x2y2z = x2, y2, z
x2yz2 = x2, y, z2
xy2z2 = x, y2, z2
x2y2z2 = x2, y2, z2
dx, dy, dz = box.dx, box.dy, box.dz
quadArgs = [
(x2yz2, x2yz, x2y2z, x2y2z2, u + dz + dx, v + dz, u + dz + dx + dz, v + dz + dy),
(xyz, xyz2, xy2z2, xy2z, u, v + dz, u + dz, v + dz + dy),
(x2yz2, xyz2, xyz, x2yz, u + dz, v, u + dz + dx, v + dz ),
(x2y2z, xy2z, xy2z2, x2y2z2, u + dz + dx, v + dz, u + dz + dx + dx, v ),
(x2yz, xyz, xy2z, x2y2z, u + dz, v + dz, u + dz + dx, v + dz + dy),
(xyz2, x2yz2, x2y2z2, xy2z2, u + dz + dx + dz, v + dz, u + dz + dx + dz + dx, v + dz + dy),
]
quads = []
for a in quadArgs:
quad = makeQuad(*a)
if box.mirror:
quad = reversed(quad)
quads.extend(quad)
return quads
# xxx dup from blockmodels.pyx
def npRotate(axis, angle, rescale=False):
# ( xx(1-c)+c xy(1-c)-zs xz(1-c)+ys 0 )
# | yx(1-c)+zs yy(1-c)+c yz(1-c)-xs 0 |
# | xz(1-c)-ys yz(1-c)+xs zz(1-c)+c 0 |
# ( 0 0 0 1 )
# axis:
# "x": (1, 0, 0)
# "y": (0, 1, 0)
# "z": (0, 0, 1)
x = y = z = 0
if axis == "x":
x = 1
elif axis == "y":
y = 1
elif axis == "z":
z = 1
else:
raise ValueError("Unknown axis: %r" % axis)
s = math.sin(angle)
c = math.cos(angle)
rotate = numpy.matrix([[x*x*(1-c)+c, x*y*(1-c)-z*s, x*z*(1-c)+y*s, 0],
[y*x*(1-c)+z*s, y*y*(1-c)+c, y*z*(1-c)-x*s, 0],
[x*z*(1-c)-y*s, y*z*(1-c)+x*s, z*z*(1-c)+c, 0],
[0, 0, 0, 1]])
# xxx rescale
return rotate
def cookEntityModel(model):
allVerts = []
for part in model.parts:
partVerts = []
u, v = part.u, part.v
for box in part.boxes:
partVerts.extend(makeBoxQuads(u, v, box))
cx, cy, cz = part.centerPoint
rx, ry, rz = part.rotation
partMatrix = numpy.identity(4)
if ry:
partMatrix = npRotate("y", ry) * partMatrix
if rx:
partMatrix = npRotate("x", rx) * partMatrix
if rz:
partMatrix = npRotate("z", rz) * partMatrix
for x, y, z, u, v in partVerts:
coord = numpy.matrix([x, y, z, 0]).T
x, y, z = numpy.array(partMatrix * coord)[:3, 0]
allVerts.append((x+cx, y+cy, z+cz, u, v))
return allVerts
cookedModels = {}
textures = {}
def addModel(model):
cookedModels[model.id] = cookEntityModel(model)
textures[model.id] = model.modelTexture
addModel(ModelCreeper())
addModel(ModelZombie())
addModel(ModelSkeleton())
addModel(ModelPigZombie())
addModel(ModelSpider())
if __name__ == '__main__':
from pprint import pprint
pprint(cookedModels["Spider"])

View File

@ -0,0 +1,76 @@
"""
spider
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import logging
import math
from mcedit2.rendering.chunkmeshes.entity.modelrenderer import ModelRenderer
log = logging.getLogger(__name__)
class ModelSpider(object):
id = "Spider"
modelTexture = "assets/minecraft/textures/entity/spider/spider.png"
def __init__(self):
var1 = 0.0
var2 = 15
self.spiderHead = ModelRenderer(self, 32, 4)
self.spiderHead.addBox(-4.0, -4.0, -8.0, 8, 8, 8, var1)
self.spiderHead.setCenterPoint(0.0, var2, -3.0)
self.spiderNeck = ModelRenderer(self, 0, 0)
self.spiderNeck.addBox(-3.0, -3.0, -3.0, 6, 6, 6, var1)
self.spiderNeck.setCenterPoint(0.0, var2, 0.0)
self.spiderBody = ModelRenderer(self, 0, 12)
self.spiderBody.addBox(-5.0, -4.0, -6.0, 10, 8, 12, var1)
self.spiderBody.setCenterPoint(0.0, var2, 9.0)
self.spiderLeg1 = ModelRenderer(self, 18, 0)
self.spiderLeg1.addBox(-15.0, -1.0, -1.0, 16, 2, 2, var1)
self.spiderLeg1.setCenterPoint(-4.0, var2, 2.0)
self.spiderLeg2 = ModelRenderer(self, 18, 0)
self.spiderLeg2.addBox(-1.0, -1.0, -1.0, 16, 2, 2, var1)
self.spiderLeg2.setCenterPoint(4.0, var2, 2.0)
self.spiderLeg3 = ModelRenderer(self, 18, 0)
self.spiderLeg3.addBox(-15.0, -1.0, -1.0, 16, 2, 2, var1)
self.spiderLeg3.setCenterPoint(-4.0, var2, 1.0)
self.spiderLeg4 = ModelRenderer(self, 18, 0)
self.spiderLeg4.addBox(-1.0, -1.0, -1.0, 16, 2, 2, var1)
self.spiderLeg4.setCenterPoint(4.0, var2, 1.0)
self.spiderLeg5 = ModelRenderer(self, 18, 0)
self.spiderLeg5.addBox(-15.0, -1.0, -1.0, 16, 2, 2, var1)
self.spiderLeg5.setCenterPoint(-4.0, var2, 0.0)
self.spiderLeg6 = ModelRenderer(self, 18, 0)
self.spiderLeg6.addBox(-1.0, -1.0, -1.0, 16, 2, 2, var1)
self.spiderLeg6.setCenterPoint(4.0, var2, 0.0)
self.spiderLeg7 = ModelRenderer(self, 18, 0)
self.spiderLeg7.addBox(-15.0, -1.0, -1.0, 16, 2, 2, var1)
self.spiderLeg7.setCenterPoint(-4.0, var2, -1.0)
self.spiderLeg8 = ModelRenderer(self, 18, 0)
self.spiderLeg8.addBox(-1.0, -1.0, -1.0, 16, 2, 2, var1)
self.spiderLeg8.setCenterPoint(4.0, var2, -1.0)
legYaw = 0.3926991
legPitch = math.pi / 4
self.spiderLeg1.setRotation(0, 2*legYaw, -legPitch)
self.spiderLeg2.setRotation(0, -2*legYaw, legPitch)
self.spiderLeg3.setRotation(0, legYaw, -legPitch*3/4.)
self.spiderLeg4.setRotation(0, -legYaw, legPitch*3/4.)
self.spiderLeg5.setRotation(0, -legYaw, -legPitch*3/4.)
self.spiderLeg6.setRotation(0, legYaw, legPitch*3/4.)
self.spiderLeg7.setRotation(0, -2*legYaw, -legPitch)
self.spiderLeg8.setRotation(0, 2*legYaw, legPitch)
self.parts = [
self.spiderHead,
self.spiderNeck,
self.spiderBody,
self.spiderLeg1,
self.spiderLeg2,
self.spiderLeg3,
self.spiderLeg4,
self.spiderLeg5,
self.spiderLeg6,
self.spiderLeg7,
self.spiderLeg8,
]

View File

@ -8,6 +8,7 @@ import numpy
from mcedit2.rendering import renderstates, scenegraph
from mcedit2.rendering.blockmeshes import standardCubeTemplates
from mcedit2.rendering.blockmeshes import ChunkMeshBase
from mcedit2.rendering.chunkmeshes.entity import models
from mcedit2.rendering.layers import Layer
from mcedit2.rendering.scenegraph import PolygonModeNode, DepthFuncNode
from mcedit2.rendering.slices import _XYZ
@ -126,6 +127,46 @@ class ItemFrameMesh(EntityMeshBase):
PCPaintingEntityRefBase.EastFacing: ((0.01, 0, 0), (0.01, 1, 0), (0.01, 1, 1), (0.01, 0, 1)),
}
class MonsterModelRenderer(ChunkMeshBase):
def makeChunkVertices(self, chunk, limitBox):
sceneNode = scenegraph.Node()
for i, ref in enumerate(chunk.Entities):
ID = ref.id
if ID not in models.cookedModels:
assert ID != "Zombie"
ID = "Creeper"
model = models.cookedModels[ID]
modelVerts = numpy.array(model)
modelVerts.shape = modelVerts.shape[0]/4, 4, modelVerts.shape[1]
# scale down
modelVerts[..., :3] *= 1/16.
modelVerts[..., 1] = -modelVerts[..., 1] + 1.5 + 1/64.
modelVerts[..., 0] = -modelVerts[..., 0]
vertexBuffer = QuadVertexArrayBuffer(len(modelVerts), lights=False, textures=True)
vertexBuffer.vertex[:] = modelVerts[..., :3]
vertexBuffer.texcoord[:] = modelVerts[..., 3:5]
node = scenegraph.VertexNode(vertexBuffer)
rotateNode = scenegraph.RotateNode(ref.Rotation[0], (0., 1., 0.))
rotateNode.addChild(node)
translateNode = scenegraph.TranslateNode((ref.Position - (chunk.cx << 4, 0, chunk.cz << 4)))
translateNode.addChild(rotateNode)
modelTex = self.chunkUpdate.updateTask.getModelTexture(models.textures[ID])
textureNode = scenegraph.BindTextureNode(modelTex, (1./modelTex.w, 1./modelTex.h, 1))
textureNode.addChild(translateNode)
sceneNode.addChild(textureNode)
yield
self.sceneNode = sceneNode
class MonsterRenderer(EntityMeshBase):
layer = Layer.Entities # xxx Monsters
notMonsters = {"Item", "XPOrb", "Painting", "ItemFrame"}

View File

@ -10,7 +10,7 @@ from mcedit2.rendering.modelmesh import BlockModelMesh
from mcedit2.rendering import layers
from mcedit2.rendering.chunkmeshes.chunksections import ChunkSectionsRenderer
from mcedit2.rendering.chunkmeshes.entitymesh import TileEntityMesh, MonsterRenderer, ItemRenderer, \
ItemFrameMesh
ItemFrameMesh, MonsterModelRenderer
from mcedit2.rendering.chunkmeshes.lowdetail import LowDetailBlockMesh, OverheadBlockMesh
from mcedit2.rendering.chunkmeshes.terrainpop import TerrainPopulatedRenderer
from mcedit2.rendering.chunkmeshes.tileticks import TileTicksRenderer
@ -125,6 +125,7 @@ class ChunkUpdate(object):
TileEntityMesh,
ItemFrameMesh,
MonsterRenderer,
MonsterModelRenderer,
ItemRenderer,
TileTicksRenderer,
TerrainPopulatedRenderer,