package skin_renderer import ( "image" "image/color" ) // Polygon 表示一个四边形面片 type Polygon struct { dots [4]*Point color color.RGBA isProjected bool face string // 面的方向: "x", "y", "z" faceDepth float64 // 面的深度 } // NewPolygon 创建一个新的多边形 func NewPolygon(dots [4]*Point, c color.RGBA) *Polygon { p := &Polygon{ dots: dots, color: c, } // 确定面的方向 x0, y0, z0 := dots[0].GetOriginCoord() x1, y1, z1 := dots[1].GetOriginCoord() x2, y2, z2 := dots[2].GetOriginCoord() if x0 == x1 && x1 == x2 { p.face = "x" p.faceDepth = x0 } else if y0 == y1 && y1 == y2 { p.face = "y" p.faceDepth = y0 } else if z0 == z1 && z1 == z2 { p.face = "z" p.faceDepth = z0 } return p } // Project 投影多边形的所有顶点 func (p *Polygon) Project(cosAlpha, sinAlpha, cosOmega, sinOmega float64, minX, maxX, minY, maxY *float64) { for _, dot := range p.dots { if !dot.IsProjected() { dot.Project(cosAlpha, sinAlpha, cosOmega, sinOmega, minX, maxX, minY, maxY) } } p.isProjected = true } // PreProject 预投影多边形的所有顶点 func (p *Polygon) PreProject(dx, dy, dz, cosAlpha, sinAlpha, cosOmega, sinOmega float64) { for _, dot := range p.dots { dot.PreProject(dx, dy, dz, cosAlpha, sinAlpha, cosOmega, sinOmega) } } // IsProjected 返回是否已投影 func (p *Polygon) IsProjected() bool { return p.isProjected } // AddToImage 将多边形绘制到图像上 func (p *Polygon) AddToImage(img *image.RGBA, minX, minY, ratio float64) { // 检查透明度,完全透明则跳过 if p.color.A == 0 { return } // 获取投影后的 2D 坐标 points := make([][2]float64, 4) var coordX, coordY *float64 samePlanX := true samePlanY := true for i, dot := range p.dots { x, y, _ := dot.GetDestCoord() points[i] = [2]float64{ (x - minX) * ratio, (y - minY) * ratio, } if coordX == nil { coordX = &x coordY = &y } else { if *coordX != x { samePlanX = false } if *coordY != y { samePlanY = false } } } // 如果所有点在同一平面(退化面),跳过 if samePlanX || samePlanY { return } // 使用扫描线算法填充多边形 fillPolygon(img, points, p.color) } // fillPolygon 使用扫描线算法填充四边形 func fillPolygon(img *image.RGBA, points [][2]float64, c color.RGBA) { // 找到 Y 的范围 minY := points[0][1] maxY := points[0][1] for _, pt := range points { if pt[1] < minY { minY = pt[1] } if pt[1] > maxY { maxY = pt[1] } } bounds := img.Bounds() // 扫描每一行 for y := int(minY); y <= int(maxY); y++ { if y < bounds.Min.Y || y >= bounds.Max.Y { continue } // 找到这一行与多边形边的交点 var intersections []float64 n := len(points) for i := 0; i < n; i++ { j := (i + 1) % n y1, y2 := points[i][1], points[j][1] x1, x2 := points[i][0], points[j][0] // 检查这条边是否与当前扫描线相交 if (y1 <= float64(y) && y2 > float64(y)) || (y2 <= float64(y) && y1 > float64(y)) { // 计算交点的 X 坐标 t := (float64(y) - y1) / (y2 - y1) x := x1 + t*(x2-x1) intersections = append(intersections, x) } } // 排序交点 for i := 0; i < len(intersections)-1; i++ { for j := i + 1; j < len(intersections); j++ { if intersections[i] > intersections[j] { intersections[i], intersections[j] = intersections[j], intersections[i] } } } // 填充交点之间的像素 for i := 0; i+1 < len(intersections); i += 2 { xStart := int(intersections[i]) xEnd := int(intersections[i+1]) for x := xStart; x <= xEnd; x++ { if x >= bounds.Min.X && x < bounds.Max.X { // Alpha 混合 if c.A == 255 { img.SetRGBA(x, y, c) } else { existing := img.RGBAAt(x, y) blended := alphaBlend(existing, c) img.SetRGBA(x, y, blended) } } } } } } // alphaBlend 执行 Alpha 混合 func alphaBlend(dst, src color.RGBA) color.RGBA { if src.A == 0 { return dst } if src.A == 255 { return src } srcA := float64(src.A) / 255.0 dstA := float64(dst.A) / 255.0 outA := srcA + dstA*(1-srcA) if outA == 0 { return color.RGBA{} } return color.RGBA{ R: uint8((float64(src.R)*srcA + float64(dst.R)*dstA*(1-srcA)) / outA), G: uint8((float64(src.G)*srcA + float64(dst.G)*dstA*(1-srcA)) / outA), B: uint8((float64(src.B)*srcA + float64(dst.B)*dstA*(1-srcA)) / outA), A: uint8(outA * 255), } }