Python光线追踪实现异常:输出图像仅黑白无色彩
光线追踪实现问题:输出黑白图像,物体形状正确但无色彩
我正在用Python实现光线追踪,输出的图像只有黑白两色,物体形状是对的,但没有预期的色彩。我是编程新手,找不到问题根源。以下是我的实现代码:
import matplotlib.pyplot as plt import numpy as np import matplotlib.pyplot def vector_nomalization(vector): # 向量归一化函数 return vector / np.linalg.norm(vector) def intersection_with_sphere(center, radius, origin, direction_vector): # 检测光线与球体的交点 b = 2 * np.dot(direction_vector, origin - center) c = np.linalg.norm(origin - center) ** 2 - radius ** 2 # (原点到球心距离)^2 - 半径^2 delta = b **2 - 4 * c if delta > 0: t1 = (-b +np.sqrt(delta))/2 t2 = (-b - np.sqrt(delta))/2 if t1 > 0 and t2 > 0: return min(t1,t2) # 返回原点到最近交点的距离 return None def closest_intersection(spheres, origin, direction): # 找到与光线相交的最近球体 distances = [intersection_with_sphere(sphere['center'], sphere['radius'], origin, direction) for sphere in spheres] closest_sphere = None min_distance = np.inf for index, distance in enumerate(distances): if distance and distance < min_distance: min_distance = distance closest_sphere = spheres[index] return closest_sphere, min_distance def reflection_ray(vector, axis): return vector - 2 * np.dot(vector, axis) * axis spheres =[ { 'center': np.array([-0.2, 0, -1]), 'radius': 0.7, 'ambient': np.array([0.1, 0, 0]), 'Diffuse': np.array([0.7, 0, 0]), 'specular': np.array([1, 1, 1]), 'shininess': 100, 'reflection': 0.5 }, { 'center': np.array([0.1, -0.3, 0]), 'radius': 0.1, 'ambient': np.array([0.1, 0, 0.1]), 'Diffuse': np.array([0.7, 0, 0.7]), 'specular': np.array([1, 1, 1]), 'shininess': 100, 'reflection': 0.5 }, { 'center': np.array([-0.3, 0, 0]), 'radius': 0.15, 'ambient': np.array([0, 0.1, 0]), 'Diffuse': np.array([0, 0.6, 0]), 'specular': np.array([1, 1, 1]), 'shininess': 100, 'reflection': 0.5 }, { 'center': np.array([0, -9000, 0]), 'radius': 9000 - 0.7, 'ambient': np.array([0.1, 0.1, 0.1]), 'Diffuse': np.array([0.6, 0.6, 0.6]), 'specular': np.array([1, 1, 1]), 'shininess': 100, 'reflection': 0.5} ] light = {'position': np.array([5, 5, 5]), 'ambient': np.array([1, 1, 1]), 'Diffuse': np.array([1, 1, 1]), 'specular': np.array([1, 1, 1])} width = 300 height = 200 max_depth = 3 camera = np.array([0, 0, 1]) ratio = float(width) / height # 图像宽高比 screen = ( -1, 1 / ratio, 1, -1 / ratio) # 屏幕边界:左、上、右、下 image = np.zeros((height, width, 3)) for i, y in enumerate(np.linspace(screen[1], screen[3], height)): # 遍历屏幕y方向像素 for j, x in enumerate(np.linspace(screen[0], screen[2], width)): # 遍历屏幕x方向像素 pixel = np.array([x, y, 0]) origin = camera direction_vector = vector_nomalization(pixel - origin) # 光线方向向量 color = np.zeros((3)) reflection = 1 for k in range(max_depth): # 检测是否有交点 closest_sphere, min_distance = closest_intersection(spheres, origin, direction_vector) if closest_sphere is None: break # 计算光线与最近球体的交点 intersection = origin + min_distance * direction_vector normalized_to_surface = vector_nomalization(intersection - closest_sphere['center']) shifted_point = intersection + 1e-5 * normalized_to_surface # 偏移点避免自遮挡 lights_intersection = vector_nomalization(light['position'] - shifted_point) # 检测是否在阴影中 _, min_distance = closest_intersection(spheres, shifted_point, lights_intersection) lights_intersection_distance = np.linalg.norm(light['position']-intersection) shadowed = min_distance < lights_intersection_distance # 计算光照 illumination = np.zeros((3)) # 环境光 illumination += closest_sphere['ambient'] * light['ambient'] if not shadowed: # 漫反射 dot_product = np.dot(lights_intersection, normalized_to_surface) illumination += closest_sphere['Diffuse'] * light['Diffuse'] * max(dot_product, 0) # 高光 reflection_light = reflection_ray(-lights_intersection, normalized_to_surface) view_dir = vector_nomalization(camera - intersection) spec_dot = np.dot(reflection_light, view_dir) illumination += closest_sphere['specular'] * light['specular'] * (max(spec_dot, 0) ** closest_sphere['shininess']) # 累加色彩(反射系数乘以光照值) color += reflection * illumination reflection *= closest_sphere['reflection'] # 更新光线参数用于反射计算 origin = shifted_point direction_vector = reflection_ray(direction_vector, normalized_to_surface) image[i, j] = np.clip(color, 0, 1) print("progress: %d/%d" % (i + 1, height)) plt.imsave('image.png', image)
图像说明
- 当前输出:黑白图像,可分辨球体和地面的形状,但所有物体均无色彩区分
- 预期效果:彩色图像,红色大球、蓝色小球、绿色小球和灰色地面清晰区分,带有高光和阴影效果
核心修复点
- 色彩累加逻辑错误:原代码
color += reflection + illumination改为color += reflection * illumination,用反射系数乘以光照值,避免标量与数组相加破坏色彩信息 - 添加环境光计算:加入环境光分量,确保物体在阴影中也有基础颜色
- 修正高光计算:使用标准Phong光照模型,计算反射光线与视线的点积并取shininess次方,还原高光效果
- 调整阴影逻辑:阴影时不再直接终止计算,而是仅关闭漫反射和高光,保留环境光,避免物体完全变黑
- 漫反射值取非负:对漫反射的点积结果取最大值,避免出现负色彩值
内容的提问来源于stack exchange,提问作者Steve J
相关产品推荐
相关产品推荐

