Files
backend/internal/service/skin_renderer/point.go

96 lines
2.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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