@@ -356,40 +356,63 @@ function addBoxFace(group, positions, uv, material) {
356356 group . add ( new THREE . Mesh ( geom , material ) ) ;
357357}
358358
359- function addShieldBox ( group , from , to , frontUv , backUv , frontMat , backMat , sideMat ) {
359+ // Adds one MC-style addBox()+texOffs() cuboid to the group, expressed in
360+ // item-display coords (i.e. after the scale(1, -1, -1) flip that ShieldSpecial-
361+ // Renderer.DEFAULT_TRANSFORMATION applies to the entity model) plus the
362+ // standard GUI +8 origin shift. UVs for all six faces are unwrapped exactly
363+ // the way ModelPart.Cube does it — entity NORTH/SOUTH become item +Z/-Z and
364+ // entity DOWN/UP become item +Y/-Y; MC's UP face also flips V on the atlas
365+ // region, and we preserve that flip below.
366+ function addUnwrappedBox ( group , from , to , texU , texV , sx , sy , sz , mat , tw = 64 , th = 64 ) {
360367 const [ x1 , y1 , z1 ] = from ;
361368 const [ x2 , y2 , z2 ] = to ;
362- const full = [ 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 ] ;
363- addBoxFace ( group , [ x1 , y2 , z2 , x1 , y1 , z2 , x2 , y1 , z2 , x2 , y2 , z2 ] , frontUv , frontMat ) ; // south/front
364- addBoxFace ( group , [ x2 , y2 , z1 , x2 , y1 , z1 , x1 , y1 , z1 , x1 , y2 , z1 ] , backUv , backMat ) ; // north/back
365- addBoxFace ( group , [ x1 , y2 , z1 , x1 , y2 , z2 , x2 , y2 , z2 , x2 , y2 , z1 ] , full , sideMat ) ; // top
366- addBoxFace ( group , [ x1 , y1 , z2 , x1 , y1 , z1 , x2 , y1 , z1 , x2 , y1 , z2 ] , full , sideMat ) ; // bottom
367- addBoxFace ( group , [ x2 , y2 , z2 , x2 , y1 , z2 , x2 , y1 , z1 , x2 , y2 , z1 ] , full , sideMat ) ; // right
368- addBoxFace ( group , [ x1 , y2 , z1 , x1 , y1 , z1 , x1 , y1 , z2 , x1 , y2 , z2 ] , full , sideMat ) ; // left
369+ const u1 = texU + sz ;
370+ const u2 = u1 + sx ;
371+ const u3 = u2 + sz ;
372+ const u4 = u3 + sx ;
373+ const v1 = texV + sz ;
374+ const v2 = v1 + sy ;
375+ addBoxFace ( group , [ x1 , y2 , z2 , x1 , y1 , z2 , x2 , y1 , z2 , x2 , y2 , z2 ] ,
376+ atlasUv ( u1 , v1 , u2 , v2 , tw , th ) , mat ) ; // +Z (entity NORTH)
377+ addBoxFace ( group , [ x2 , y2 , z1 , x2 , y1 , z1 , x1 , y1 , z1 , x1 , y2 , z1 ] ,
378+ atlasUv ( u3 , v1 , u4 , v2 , tw , th ) , mat ) ; // -Z (entity SOUTH)
379+ addBoxFace ( group , [ x1 , y2 , z1 , x1 , y2 , z2 , x2 , y2 , z2 , x2 , y2 , z1 ] ,
380+ atlasUv ( u1 , texV , u2 , v1 , tw , th ) , mat ) ; // +Y (entity DOWN)
381+ addBoxFace ( group , [ x1 , y1 , z2 , x1 , y1 , z1 , x2 , y1 , z1 , x2 , y1 , z2 ] ,
382+ atlasUv ( u2 , v1 , u2 + sx , texV , tw , th ) , mat ) ; // -Y (entity UP, V flipped)
383+ addBoxFace ( group , [ x2 , y2 , z2 , x2 , y1 , z2 , x2 , y1 , z1 , x2 , y2 , z1 ] ,
384+ atlasUv ( u2 , v1 , u3 , v2 , tw , th ) , mat ) ; // +X (entity EAST)
385+ addBoxFace ( group , [ x1 , y2 , z1 , x1 , y1 , z1 , x1 , y1 , z2 , x1 , y2 , z2 ] ,
386+ atlasUv ( texU , v1 , u1 , v2 , tw , th ) , mat ) ; // -X (entity WEST)
369387}
370388
371389async function buildShieldSprite ( ) {
372390 const tex = await loadTexture ( 'entity/shield/shield_base_nopattern' ) ;
373- const textured = new THREE . MeshBasicMaterial ( {
391+ const mat = new THREE . MeshBasicMaterial ( {
374392 map : tex ,
375393 transparent : true ,
376394 alphaTest : 0.01 ,
377395 side : THREE . FrontSide ,
378396 } ) ;
379- const side = new THREE . MeshBasicMaterial ( { color : new THREE . Color ( 0.48 , 0.48 , 0.52 ) } ) ;
380- const handle = new THREE . MeshBasicMaterial ( { color : new THREE . Color ( 0.30 , 0.20 , 0.10 ) } ) ;
381397 const group = new THREE . Group ( ) ;
382398
383- // Vanilla shields are special entity models, so they don't expose normal
384- // item-model elements. Build a small cuboid approximation from the entity
385- // texture atlas instead of drawing a flat sprite.
386- addShieldBox ( group , [ 2 , - 3 , 7 ] , [ 14 , 19 , 9 ] , atlasUv ( 1 , 2 , 13 , 24 ) , atlasUv ( 15 , 2 , 27 , 24 ) , textured , textured , side ) ;
387- addShieldBox ( group , [ 5 , 4 , 5 ] , [ 11 , 12 , 7 ] , atlasUv ( 29 , 1 , 35 , 9 ) , atlasUv ( 36 , 1 , 42 , 9 ) , textured , textured , handle ) ;
399+ // Mirrors ShieldModel.createLayer() (net.minecraft.client.model.object.equipment.ShieldModel):
400+ // plate: texOffs(0, 0) + addBox(-6, -11, -2, 12, 22, 1)
401+ // handle: texOffs(26, 0) + addBox(-1, -3, -1, 2, 6, 6)
402+ // The from/to below are those addBox bounds after ShieldSpecialRenderer
403+ // .DEFAULT_TRANSFORMATION (scale 1, -1, -1) — left in entity coord space
404+ // (no +8 shift). applyGuiTransform's inner.position(-8,-8,-8) is the
405+ // analogue of MC's ItemTransform translate(-0.5,-0.5,-0.5), placing the
406+ // GUI rotation pivot at item-display (8,8,8). Because the shield is
407+ // centred on the entity origin rather than on (8,8,8), the pivot ends up
408+ // offset from the shield, so the display.gui rotation swings the shield
409+ // around just like vanilla — which is what positions it correctly in
410+ // the slot. The 64×64 atlas matches LayerDefinition.create(_, 64, 64).
411+ addUnwrappedBox ( group , [ - 6 , - 11 , 1 ] , [ 6 , 11 , 2 ] , 0 , 0 , 12 , 22 , 1 , mat ) ;
412+ addUnwrappedBox ( group , [ - 1 , - 3 , - 5 ] , [ 1 , 3 , 1 ] , 26 , 0 , 2 , 6 , 6 , mat ) ;
388413 return group ;
389414}
390415
391- const SHIELD_GUI_TRANSFORM = { rotation : [ 15 , - 35 , - 5 ] , translation : [ 0 , 0 , 0 ] , scale : [ 0.72 , 0.72 , 0.72 ] } ;
392-
393416function applyGuiTransform ( group , display , isBlockShape ) {
394417 const gui = ( display && display . gui ) || ( isBlockShape ? DEFAULT_BLOCK_GUI : DEFAULT_GUI_TRANSFORM ) ;
395418 const r = gui . rotation || [ 0 , 0 , 0 ] ;
@@ -437,7 +460,7 @@ async function renderItem(name) {
437460 : isBlockShape
438461 ? await buildElementsModel ( model , tintRgb )
439462 : await buildLayeredSprite ( model , tintRgb ) ;
440- const outer = applyGuiTransform ( inner , isShield ? { gui : SHIELD_GUI_TRANSFORM } : model . display , isBlockShape ) ;
463+ const outer = applyGuiTransform ( inner , model . display , isBlockShape ) ;
441464 // The next four lines must stay synchronous so concurrent
442465 // renderItem() callers can't interleave on the shared scene.
443466 scene . add ( outer ) ;
0 commit comments