#include "pch.h"
#include "Sphere.h"
#include <afxwin.h> // 包含 MFC 核心头文件
#include <algorithm> // 为了使用 std::max
#include <cmath> // 为了使用 std::round
CSphere::CSphere() : m_lightPos(100, 100, 100)
{
}
void CSphere::InitOctahedron(double radius)
{
m_vertices.clear();
m_triangles.clear();
m_normals.clear();
// 正八面体顶点 (位于球面上)
m_vertices.push_back(Point3D(0, 0, radius)); // 0: 上顶点
m_vertices.push_back(Point3D(0, 0, -radius)); // 1: 下顶点
m_vertices.push_back(Point3D(radius, 0, 0)); // 2: 右顶点
m_vertices.push_back(Point3D(-radius, 0, 0)); // 3: 左顶点
m_vertices.push_back(Point3D(0, radius, 0)); // 4: 前顶点
m_vertices.push_back(Point3D(0, -radius, 0)); // 5: 后顶点
// 正八面体三角形面
// 注意:这里存在重复的三角形,应该修正为每个面只定义一次
m_triangles.push_back(Triangle(0, 2, 4));
m_triangles.push_back(Triangle(0, 4, 3));
m_triangles.push_back(Triangle(0, 3, 5));
m_triangles.push_back(Triangle(0, 5, 2));
m_triangles.push_back(Triangle(1, 2, 5));
m_triangles.push_back(Triangle(1, 5, 3));
m_triangles.push_back(Triangle(1, 3, 4));
m_triangles.push_back(Triangle(1, 4, 2));
CalculateNormals();
}
void CSphere::CreateRecursiveSphere(double radius, int level)
{
InitOctahedron(radius);
if (level <= 0)
return;
std::vector<Triangle> newTriangles;
for (const auto& tri : m_triangles)
{
SubdivideTriangle(tri, level, newTriangles);
}
m_triangles = newTriangles;
CalculateNormals();
}
void CSphere::SubdivideTriangle(const Triangle& tri, int level, std::vector<Triangle>& result)
{
if (level == 0)
{
result.push_back(tri);
return;
}
// 计算各边中点
int v1 = tri.v1;
int v2 = tri.v2;
int v3 = tri.v3;
// 边v1-v2的中点
Point3D mid12 = (m_vertices[v1] + m_vertices[v2]) * 0.5;
mid12 = mid12.Normalize() * mid12.Magnitude(); // 拉伸到球面上
// 边v2-v3的中点
Point3D mid23 = (m_vertices[v2] + m_vertices[v3]) * 0.5;
mid23 = mid23.Normalize() * mid23.Magnitude(); // 拉伸到球面上
// 边v3-v1的中点
Point3D mid31 = (m_vertices[v3] + m_vertices[v1]) * 0.5;
mid31 = mid31.Normalize() * mid31.Magnitude(); // 拉伸到球面上
// 添加新顶点
// 修改:将 int 改为 size_t 避免 C4267 警告
size_t newV1 = m_vertices.size();
m_vertices.push_back(mid12);
size_t newV2 = m_vertices.size();
m_vertices.push_back(mid23);
size_t newV3 = m_vertices.size();
m_vertices.push_back(mid31);
// 递归细分四个小三角形
SubdivideTriangle(Triangle(v1, static_cast<int>(newV1), static_cast<int>(newV3)), level - 1, result);
SubdivideTriangle(Triangle(static_cast<int>(newV1), v2, static_cast<int>(newV2)), level - 1, result);
SubdivideTriangle(Triangle(static_cast<int>(newV3), static_cast<int>(newV2), v3), level - 1, result);
SubdivideTriangle(Triangle(static_cast<int>(newV1), static_cast<int>(newV2), static_cast<int>(newV3)), level - 1, result);
}
void CSphere::CalculateNormals()
{
m_normals.resize(m_vertices.size());
for (const auto& tri : m_triangles)
{
Point3D v1 = m_vertices[tri.v1];
Point3D v2 = m_vertices[tri.v2];
Point3D v3 = m_vertices[tri.v3];
Point3D edge1 = v2 - v1;
Point3D edge2 = v3 - v1;
Point3D normal = CrossProduct(edge1, edge2).Normalize();
m_normals[tri.v1] = m_normals[tri.v1] + normal;
m_normals[tri.v2] = m_normals[tri.v2] + normal;
m_normals[tri.v3] = m_normals[tri.v3] + normal;
}
// 归一化法向量
for (auto& normal : m_normals)
{
normal = normal.Normalize();
}
}
Point3D CSphere::CrossProduct(const Point3D& a, const Point3D& b) const
{
return Point3D(
a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x
);
}
double CSphere::DotProduct(const Point3D& a, const Point3D& b) const
{
return a.x * b.x + a.y * b.y + a.z * b.z;
}
void CSphere::DrawWireframe(CDC* pDC)
{
CPen pen(PS_SOLID, 1, RGB(255, 255, 255));
CPen* pOldPen = pDC->SelectObject(&pen);
for (const auto& tri : m_triangles)
{
Point3D v1 = m_vertices[tri.v1];
Point3D v2 = m_vertices[tri.v2];
Point3D v3 = m_vertices[tri.v3];
pDC->MoveTo(CPoint(v1.x, v1.y));
pDC->LineTo(CPoint(v2.x, v2.y));
pDC->LineTo(CPoint(v3.x, v3.y));
pDC->LineTo(CPoint(v1.x, v1.y));
}
pDC->SelectObject(pOldPen); // 恢复旧画笔
}
void CSphere::DrawLitWireframe(CDC* pDC)
{
for (const auto& tri : m_triangles)
{
Point3D v1 = m_vertices[tri.v1];
Point3D v2 = m_vertices[tri.v2];
Point3D v3 = m_vertices[tri.v3];
// 计算三角形法向量
Point3D edge1 = v2 - v1;
Point3D edge2 = v3 - v1;
Point3D normal = CrossProduct(edge1, edge2).Normalize();
// 计算光照强度
Point3D lightDir = (m_lightPos - v1).Normalize();
double intensity = DotProduct(normal, lightDir);
intensity = std::max(0.1, intensity); // 最小强度
// 根据光照强度计算颜色
// 修改:使用 std::round 避免 C4244 警告
int r = static_cast<int>(std::round(255 * intensity));
int g = static_cast<int>(std::round(255 * intensity));
int b = static_cast<int>(std::round(255 * intensity));
CPen pen(PS_SOLID, 1, RGB(r, g, b));
CPen* pOldPen = pDC->SelectObject(&pen);
pDC->MoveTo(CPoint(v1.x, v1.y));
pDC->LineTo(CPoint(v2.x, v2.y));
pDC->LineTo(CPoint(v3.x, v3.y));
pDC->LineTo(CPoint(v1.x, v1.y));
pDC->SelectObject(pOldPen); // 恢复旧画笔
}
}
void CSphere::DrawSurface(CDC* pDC)
{
CBrush brush(RGB(255, 255, 255));
CBrush* pOldBrush = pDC->SelectObject(&brush);
CPen pen(PS_SOLID, 1, RGB(0, 0, 0));
CPen* pOldPen = pDC->SelectObject(&pen);
for (const auto& tri : m_triangles)
{
Point3D v1 = m_vertices[tri.v1];
Point3D v2 = m_vertices[tri.v2];
Point3D v3 = m_vertices[tri.v3];
CPoint points[3] = {
CPoint(v1.x, v1.y),
CPoint(v2.x, v2.y),
CPoint(v3.x, v3.y)
};
pDC->Polygon(points, 3);
}
pDC->SelectObject(pOldBrush); // 恢复旧画刷
pDC->SelectObject(pOldPen); // 恢复旧画笔
}
void CSphere::DrawLitSurface(CDC* pDC)
{
CPen pen(PS_SOLID, 1, RGB(0, 0, 0));
CPen* pOldPen = pDC->SelectObject(&pen);
for (const auto& tri : m_triangles)
{
Point3D v1 = m_vertices[tri.v1];
Point3D v2 = m_vertices[tri.v2];
Point3D v3 = m_vertices[tri.v3];
// 计算各顶点的光照强度
Point3D normal1 = m_normals[tri.v1];
Point3D normal2 = m_normals[tri.v2];
Point3D normal3 = m_normals[tri.v3];
Point3D lightDir = (m_lightPos - v1).Normalize();
double intensity1 = std::max(0.1, DotProduct(normal1, lightDir));
double intensity2 = std::max(0.1, DotProduct(normal2, lightDir));
double intensity3 = std::max(0.1, DotProduct(normal3, lightDir));
// 计算颜色
// 修改:使用 std::round 避免 C4244 警告
int r1 = static_cast<int>(std::round(255 * intensity1)); int g1 = static_cast<int>(std::round(255 * intensity1)); int b1 = static_cast<int>(std::round(255 * intensity1));
int r2 = static_cast<int>(std::round(255 * intensity2)); int g2 = static_cast<int>(std::round(255 * intensity2)); int b2 = static_cast<int>(std::round(255 * intensity2));
int r3 = static_cast<int>(std::round(255 * intensity3)); int g3 = static_cast<int>(std::round(255 * intensity3)); int b3 = static_cast<int>(std::round(255 * intensity3));
// 使用平均颜色填充三角形(简化实现,真实Gouraud着色需要更复杂的算法)
int r = (r1 + r2 + r3) / 3;
int g = (g1 + g2 + g3) / 3;
int b = (b1 + b2 + b3) / 3;
CBrush brush(RGB(r, g, b));
CBrush* pOldBrush = pDC->SelectObject(&brush);
CPoint points[3] = {
CPoint(v1.x, v1.y),
CPoint(v2.x, v2.y),
CPoint(v3.x, v3.y)
};
pDC->Polygon(points, 3);
pDC->SelectObject(pOldBrush); // 恢复旧画刷
}
pDC->SelectObject(pOldPen); // 恢复旧画笔
}我的max部分报错,哪里出了问题