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
|
||
}
|