前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用Python实现光线追踪效果:逼真的光影动画

用Python实现光线追踪效果:逼真的光影动画

作者头像
屿小夏
发布2024-09-25 08:36:00
1040
发布2024-09-25 08:36:00
举报
文章被收录于专栏:IT杂谈学习

引言

光线追踪是一种生成高质量图像的技术,通过模拟光线与物体之间的交互来生成逼真的光影效果。在这篇博客中,我们将使用Python来实现一个简单的光线追踪算法,生成一个具有光影效果的三维场景。本文将带你一步步实现这一效果,并展示如何使用Python编程实现光线追踪。

准备工作

前置条件

在开始之前,你需要确保你的系统已经安装了以下库:

  • Numpy:用于高效的数值计算
  • Pillow:用于图像处理

如果你还没有安装这些库,可以使用以下命令进行安装:

代码语言:javascript
复制
pip install numpy pillow

代码实现与解析

导入必要的库

我们首先需要导入Numpy和Pillow库:

代码语言:javascript
复制
import numpy as np
from PIL import Image
定义光线追踪函数

我们定义一个函数来处理光线追踪的主要逻辑:

代码语言:javascript
复制
def normalize(v):
    norm = np.linalg.norm(v)
    if norm == 0:
       return v
    return v / norm

def intersect_sphere(origin, direction, sphere):
    oc = origin - sphere['center']
    a = np.dot(direction, direction)
    b = 2.0 * np.dot(oc, direction)
    c = np.dot(oc, oc) - sphere['radius']**2
    discriminant = b**2 - 4*a*c
    if discriminant < 0:
        return False, None
    else:
        t = (-b - np.sqrt(discriminant)) / (2.0 * a)
        return True, t

def ray_trace(origin, direction, spheres):
    closest_t = float('inf')
    hit_sphere = None
    for sphere in spheres:
        hit, t = intersect_sphere(origin, direction, sphere)
        if hit and t < closest_t:
            closest_t = t
            hit_sphere = sphere
    if hit_sphere is None:
        return np.array([0, 0, 0])
    hit_point = origin + closest_t * direction
    normal = normalize(hit_point - hit_sphere['center'])
    light_dir = normalize(np.array([1, 1, -1]))
    intensity = max(np.dot(normal, light_dir), 0)
    color = intensity * hit_sphere['color']
    return color
设置场景和渲染图像

我们定义场景中的球体及其属性,然后进行光线追踪并渲染图像:

代码语言:javascript
复制
width, height = 800, 600
camera = np.array([0, 0, 1])
viewport = np.array([2, 1.5, 1])
image = Image.new("RGB", (width, height))
pixels = image.load()

spheres = [
    {'center': np.array([0, 0, -5]), 'radius': 1, 'color': np.array([255, 0, 0])},
    {'center': np.array([-2, 1, -6]), 'radius': 1, 'color': np.array([0, 255, 0])},
    {'center': np.array([2, 1, -6]), 'radius': 1, 'color': np.array([0, 0, 255])}
]

for y in range(height):
    for x in range(width):
        px = (x / width) * viewport[0] - viewport[0] / 2
        py = -(y / height) * viewport[1] + viewport[1] / 2
        direction = normalize(np.array([px, py, -viewport[2]]) - camera)
        color = ray_trace(camera, direction, spheres)
        pixels[x, y] = tuple(color.astype(int))

image.show()

完整代码

代码语言:javascript
复制
import numpy as np
from PIL import Image

def normalize(v):
    norm = np.linalg.norm(v)
    if norm == 0:
       return v
    return v / norm

def intersect_sphere(origin, direction, sphere):
    oc = origin - sphere['center']
    a = np.dot(direction, direction)
    b = 2.0 * np.dot(oc, direction)
    c = np.dot(oc, oc) - sphere['radius']**2
    discriminant = b**2 - 4*a*c
    if discriminant < 0:
        return False, None
    else:
        t = (-b - np.sqrt(discriminant)) / (2.0 * a)
        return True, t

def ray_trace(origin, direction, spheres):
    closest_t = float('inf')
    hit_sphere = None
    for sphere in spheres:
        hit, t = intersect_sphere(origin, direction, sphere)
        if hit and t < closest_t:
            closest_t = t
            hit_sphere = sphere
    if hit_sphere is None:
        return np.array([0, 0, 0])
    hit_point = origin + closest_t * direction
    normal = normalize(hit_point - hit_sphere['center'])
    light_dir = normalize(np.array([1, 1, -1]))
    intensity = max(np.dot(normal, light_dir), 0)
    color = intensity * hit_sphere['color']
    return color

width, height = 800, 600
camera = np.array([0, 0, 1])
viewport = np.array([2, 1.5, 1])
image = Image.new("RGB", (width, height))
pixels = image.load()

spheres = [
    {'center': np.array([0, 0, -5]), 'radius': 1, 'color': np.array([255, 0, 0])},
    {'center': np.array([-2, 1, -6]), 'radius': 1, 'color': np.array([0, 255, 0])},
    {'center': np.array([2, 1, -6]), 'radius': 1, 'color': np.array([0, 0, 255])}
]

for y in range(height):
    for x in range(width):
        px = (x / width) * viewport[0] - viewport[0] / 2
        py = -(y / height) * viewport[1] + viewport[1] / 2
        direction = normalize(np.array([px, py, -viewport[2]]) - camera)
        color = ray_trace(camera, direction, spheres)
        pixels[x, y] = tuple(color.astype(int))

image.show()
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-09-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • 准备工作
    • 前置条件
    • 代码实现与解析
      • 导入必要的库
        • 定义光线追踪函数
          • 设置场景和渲染图像
          • 完整代码
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档