96 lines
2.4 KiB
Go
96 lines
2.4 KiB
Go
|
|
// Package skin_renderer 实现 Minecraft 皮肤的 3D 渲染
|
|||
|
|
// 移植自 blessing/texture-renderer
|
|||
|
|
package skin_renderer
|
|||
|
|
|
|||
|
|
// Point 表示 3D 空间中的一个点
|
|||
|
|
type Point struct {
|
|||
|
|
// 原始坐标
|
|||
|
|
originX, originY, originZ float64
|
|||
|
|
// 投影后的坐标
|
|||
|
|
destX, destY, destZ float64
|
|||
|
|
// 是否已投影
|
|||
|
|
isProjected bool
|
|||
|
|
isPreProjected bool
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewPoint 创建一个新的 3D 点
|
|||
|
|
func NewPoint(x, y, z float64) *Point {
|
|||
|
|
return &Point{
|
|||
|
|
originX: x,
|
|||
|
|
originY: y,
|
|||
|
|
originZ: z,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Project 将 3D 点投影到 2D 平面
|
|||
|
|
// 使用欧拉角旋转:alpha 为垂直旋转(X轴),omega 为水平旋转(Y轴)
|
|||
|
|
func (p *Point) Project(cosAlpha, sinAlpha, cosOmega, sinOmega float64, minX, maxX, minY, maxY *float64) {
|
|||
|
|
x := p.originX
|
|||
|
|
y := p.originY
|
|||
|
|
z := p.originZ
|
|||
|
|
|
|||
|
|
// 3D 旋转投影公式
|
|||
|
|
p.destX = x*cosOmega + z*sinOmega
|
|||
|
|
p.destY = x*sinAlpha*sinOmega + y*cosAlpha - z*sinAlpha*cosOmega
|
|||
|
|
p.destZ = -x*cosAlpha*sinOmega + y*sinAlpha + z*cosAlpha*cosOmega
|
|||
|
|
|
|||
|
|
p.isProjected = true
|
|||
|
|
|
|||
|
|
// 更新边界
|
|||
|
|
if p.destX < *minX {
|
|||
|
|
*minX = p.destX
|
|||
|
|
}
|
|||
|
|
if p.destX > *maxX {
|
|||
|
|
*maxX = p.destX
|
|||
|
|
}
|
|||
|
|
if p.destY < *minY {
|
|||
|
|
*minY = p.destY
|
|||
|
|
}
|
|||
|
|
if p.destY > *maxY {
|
|||
|
|
*maxY = p.destY
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// PreProject 预投影,用于部件独立旋转(如头部、手臂)
|
|||
|
|
// dx, dy, dz 为旋转中心点
|
|||
|
|
func (p *Point) PreProject(dx, dy, dz, cosAlpha, sinAlpha, cosOmega, sinOmega float64) {
|
|||
|
|
if p.isPreProjected {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 相对于旋转中心的坐标
|
|||
|
|
x := p.originX - dx
|
|||
|
|
y := p.originY - dy
|
|||
|
|
z := p.originZ - dz
|
|||
|
|
|
|||
|
|
// 旋转后加回偏移
|
|||
|
|
p.originX = x*cosOmega + z*sinOmega + dx
|
|||
|
|
p.originY = x*sinAlpha*sinOmega + y*cosAlpha - z*sinAlpha*cosOmega + dy
|
|||
|
|
p.originZ = -x*cosAlpha*sinOmega + y*sinAlpha + z*cosAlpha*cosOmega + dz
|
|||
|
|
|
|||
|
|
p.isPreProjected = true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetDestCoord 获取投影后的坐标
|
|||
|
|
func (p *Point) GetDestCoord() (x, y, z float64) {
|
|||
|
|
return p.destX, p.destY, p.destZ
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetOriginCoord 获取原始坐标
|
|||
|
|
func (p *Point) GetOriginCoord() (x, y, z float64) {
|
|||
|
|
return p.originX, p.originY, p.originZ
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// IsProjected 返回是否已投影
|
|||
|
|
func (p *Point) IsProjected() bool {
|
|||
|
|
return p.isProjected
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetDepth 获取深度值(用于排序)
|
|||
|
|
func (p *Point) GetDepth(cosAlpha, sinAlpha, cosOmega, sinOmega float64, minX, maxX, minY, maxY *float64) float64 {
|
|||
|
|
if !p.isProjected {
|
|||
|
|
p.Project(cosAlpha, sinAlpha, cosOmega, sinOmega, minX, maxX, minY, maxY)
|
|||
|
|
}
|
|||
|
|
return p.destZ
|
|||
|
|
}
|