在GPU上实现光线跟踪

2023-11-18

#include "cuda.h"
#include "book.h"
#include "cpu_bitmap.h"

#define DIM 1024   //生成图像的大小,DIM*DIM
#define SPHERES 20   //生成的图像中球体的个数

#define rnd( x ) (x * rand() / RAND_MAX)    //产生随机数
#define INF     2e10f    //定义的无穷大数
//球体的定义
struct Sphere {
    float   r,b,g;   //颜色分量的定义
    float   radius;
    float   x,y,z;   //位置信息,球心三维坐标
    __device__ float hit( float ox, float oy, float *n ) {
        float dx = ox - x;
        float dy = oy - y;
  //x*x+sy*sy+z*z=r*r,等价于z*z=r*r-x*xs-y*y
        if (dx*dx + dy*dy < radius*radius) {
            float dz = sqrtf( radius*radius - dx*dx - dy*dy );
            *n = dz /radius;   //n代表计算的Z分量与半径的比值,作用比值决定灰度的大小,比值大,灰度大
            return dz + z;
        }
        return -INF;
    }
};

 

__global__ void kernel( Sphere *s, unsigned char *ptr ) {
    // 从线程块中的线程标识到像素位置的映射
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * blockDim.x * gridDim.x;
 //计算当前像素与图形中心的距离
    float   ox = (x - DIM/2);
    float   oy = (y - DIM/2);

    float   r=0, g=0, b=0;   //背景色设置
    float   maxz = -INF;   //深度距投影面距离为无穷远,不用显示该点的颜色
 //绘制SPHERES指定个数的球体
    for(int i=0; i<SPHERES; i++) {
        float   n;
        float   t = s[i].hit( ox, oy, &n );
  //如果t不是无穷远的话,就根据n的值计算该像素点的颜色
        if (t > maxz) {
            float fscale = n;
            r = s[i].r * fscale;
            g = s[i].g * fscale;
            b = s[i].b * fscale;
            maxz = t;
        }
    }
//将颜色变换到0~255之间,并写回输出图像中
    ptr[offset*4 + 0] = (int)(r * 255);
    ptr[offset*4 + 1] = (int)(g * 255);
    ptr[offset*4 + 2] = (int)(b * 255);
    ptr[offset*4 + 3] = 255;
}


// 图像块的定义
struct DataBlock {
    unsigned char   *dev_bitmap;
    Sphere          *s;
};

int main( void ) {
    DataBlock   data;   //图像数据块变量的定义
    //定义记录起始时间的事件对象
    cudaEvent_t     start, stop;
    HANDLE_ERROR( cudaEventCreate( &start ) );
    HANDLE_ERROR( cudaEventCreate( &stop ) );
    HANDLE_ERROR( cudaEventRecord( start, 0 ) );

    CPUBitmap bitmap( DIM, DIM, &data );
    unsigned char   *dev_bitmap;
    Sphere   *s;


    // 在GPU上分配内存,以输出计算所得的位图
    HANDLE_ERROR( cudaMalloc( (void**)&dev_bitmap,bitmap.image_size() ) );
    // 为球体数据集分配内存,SPHERES个球体的内存空间
    HANDLE_ERROR( cudaMalloc( (void**)&s,sizeof(Sphere) * SPHERES ) );

    // 分配临时主机内存,对初始化球体的初始数据并赋值到GPU上的内存,然后释放临时内存
    Sphere *temp_s = (Sphere*)malloc( sizeof(Sphere) * SPHERES );
    for (int i=0; i<SPHERES; i++) {
  //用随机函数确定初始颜色、位置及半径
        temp_s[i].r = rnd( 1.0f );
        temp_s[i].g = rnd( 1.0f );
        temp_s[i].b = rnd( 1.0f );
        temp_s[i].x = rnd( 1000.0f ) - 500;
        temp_s[i].y = rnd( 1000.0f ) - 500;
        temp_s[i].z = rnd( 1000.0f ) - 500;
        temp_s[i].radius = rnd( 100.0f ) + 20;
    }
    HANDLE_ERROR( cudaMemcpy( s, temp_s,
                        sizeof(Sphere) * SPHERES,
                              cudaMemcpyHostToDevice ) );
    free( temp_s );

    // 建立与球体对应的的位图显存空间所需要的线程组织结构
    dim3    grids(DIM/16,DIM/16);
    dim3    threads(16,16);
    kernel<<<grids,threads>>>( s, dev_bitmap );

    //从GPU将数据拷回到主机内存以显示
    HANDLE_ERROR( cudaMemcpy( bitmap.get_ptr(), dev_bitmap,
                              bitmap.image_size(),
                              cudaMemcpyDeviceToHost ) );

    // 获取终止时间,以计算图像生成运行的时间
    HANDLE_ERROR( cudaEventRecord( stop, 0 ) );
    HANDLE_ERROR( cudaEventSynchronize( stop ) );
    float   elapsedTime;
    HANDLE_ERROR( cudaEventElapsedTime( &elapsedTime,
                                        start, stop ) );
    printf( "Time to generate:  %3.1f ms\n", elapsedTime );
     HANDLE_ERROR( cudaEventDestroy( start ) );
    HANDLE_ERROR( cudaEventDestroy( stop ) );
//释放显存空间
    HANDLE_ERROR( cudaFree( dev_bitmap ) );
    HANDLE_ERROR( cudaFree( s ) );

    // 显示图像
    bitmap.display_and_exit();
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在GPU上实现光线跟踪 的相关文章

  • 字符串类型的枚举与具有静态常量的结构

    似乎当需要使用枚举 字符串类型 时 也可以使用使用静态字段的结构来实现 e g enum Test String case TestCase1 case TestCase2 case TestCase3 or struct Test sta
  • 实体框架 - 包含在子查询中? - 第2部分

    我不确定这是否是正确的做法 我确信有人会告诉我是否正确 我问了一个问题 实体框架 包含在子查询中 https stackoverflow com questions 1662760 entity framework include in s
  • C Typedef 和 struct 问题

    这两种声明有什么区别 哪种声明优先于另一种 typedef struct IOPORT GPIO TypeDef port u16 pin IOPORT typedef struct GPIO TypeDef port u16 pin IO
  • 在 java 中返回多个原始对象。不推荐?

    我刚刚开始学习 Java 的 OOP 编程 我已经用 C 编写过一些程序 而我在 Java 中最怀念的事情之一就是可以返回多个值 确实 C 函数仅严格返回一个变量 但我们可以使用按引用参数返回更多变量 相反 在Java中我们不能做这样的事情
  • 如何编写一个函数来测试链接列表是否已排序

    我查看了其他帖子 但没有找到适合我的查询的很好的解决方案 我不想对链接列表进行实际排序 我想看看它是否已排序 我有一个 C 中的链表问题 我被要求编写一个给定链表定义的函数来查看它是否已排序 实现函数 isSorted 如果链表中的值按升序
  • Cocoa 结构体和 NSMutableArray

    我有一个 NSMutableArray 我正在尝试存储和访问一些结构 我该怎么做呢 addObject 给我一个错误 说 addObject 的参数 1 的类型不兼容 这是一个示例 in 是 NSFileHandle array 是 NSM
  • 如何在golang中嵌入其他包的结构

    我知道如何在同一包中的结构中嵌入其他结构 但是如何嵌入其他包的结构 dog go package dog import fmt type Dog struct Name string func this Dog callMyName fmt
  • 如何在 hive 中创建一个空的结构数组?

    我有一个观点Hive 1 1 0 根据条件 它应该返回一个空数组或一个数组struct
  • 将二进制文件读入结构体

    我正在尝试使用 C 读取二进制数据 我拥有有关我想要读取的文件中的数据布局的所有信息 我能够 逐块 读取数据 即将前 40 个字节的数据转换为字符串 然后获取接下来的 40 个字节 由于数据至少有三个略有不同的版本 我想将数据直接读入结构中
  • 在头文件中使用结构“未知类型”错误

    我在 Kubuntu 中使用 Kdevelop 我在 datasetup h 文件中声明了一个结构 ifndef A H define A H struct georeg val int p double h double hfov dou
  • 如何将 php 文件包含在主域的子域中

    我的服务器中有两个文件夹 MainDomain header php index php footer php Subdomain index php 现在我想包括header php来自主域index php这是在子域中 通过使用incl
  • 编译器处理包含保护头的开销有多大?

    为了加速大型源文件的编译 修剪翻译单元中使用的标头数量是否更有意义 或者编译代码的成本是否远远超过处理包含保护的时间标头 如果后者是真的 那么工程工作最好花在创建更多 轻量级的标头上 而不是更少 那么 现代编译器需要多长时间才能处理有效包含
  • Swift:ViewModel 应该是结构体还是类?

    我正在尝试在我的新项目中使用 MVVM 模式 第一次 我创建了所有的视图模型来构建 但是 当我使用闭包实现异步业务逻辑 例如 fetchDataFromNetwork 时 闭包捕获旧视图模型值 然后更新为该值 不是新的视图模型值 这是操场上
  • 与可变结构相比,不可变结构有哪些优点?

    我已经知道不变性相对于可变性的好处在于能够推理代码并引入更少的错误 尤其是在多线程代码中 不过 在创建结构时 我看不出创建一个完全不可变的结构比创建一个可变的结构有任何好处 让我们以保存一些分数的结构为例 struct ScoreKeepe
  • 如何将 typedef 结构传递给函数?

    此刻我正在努力 void avg everything 但这给了我错误 error subscripted value is neither array nor pointer 当我今天早些时候收到此错误时 这是 因为我没有正确地将 2D
  • C++ 头文件包含

    我正在开发一个项目 每个头文件都有一个预处理器包含防护 我的包含是这样的 文件 gt 包含 main cpp gt header h 字符 h header h gt 矢量 iostream DataFiles h Character h
  • * 对于结构体来说是非法的吗?

    我尝试编译以下代码 但编译器不会执行此操作 因为 对于结构来说是非法的 这是真的吗 struct String int length int capacity unsigned check char ptr 0 String void ma
  • 在 C 或 C++ 中返回结构是否安全?

    我的理解是不应该这样做 但我相信我已经看到过这样做的示例 注意代码不一定在语法上正确 但想法就在那里 typedef struct int a b mystruct 然后这是一个函数 mystruct func int c int d my
  • 结构体tag和name,为什么声明为name的局部变量会编译?

    在我最近看到的一些代码中 有一个如下定义的结构 typedef struct tagMyStruct int numberOne int numberTwo MYSTRUCT 按照我的理解 tagMyStruct是新的数据类型并且MYSTR
  • C 结构体信息隐藏(不透明指针)

    我目前对 C 结构信息隐藏的概念有点困惑 这道题的背景是一个嵌入式c项目 对OOP的了解几乎为零 到目前为止 我总是在相应模块的头文件中声明我的 typedef 结构 因此每个想要使用该结构的模块都知道该结构类型 但经过 MISRA C 检

随机推荐

  • 【分享】分享一个压缩 PNG 的网站 TinyPNG

    TinyPNG 能做什么 TinyPNG 采用智能的有损压缩技术来减少你的 PNG 文件的文件大小 通过选择性地减少图像中的颜色数量 更少的字节用于存储数据 效果几乎是看不见的 但它在文件大小方面差别很大 我为什么要用 TinyPNG PN
  • python实现广义线性模型

    广义线性模型 核心就是最小二乘法 最小二乘法简而言之就是求较小值 在极小值的时候值最小 一阶导数为0 import matplotlib pyplot as plt import numpy as np from sklearn impor
  • Stream流体系

    员工属性类 package Java project 1 public class Employee private String name 姓名 private char sex 性别 private double salary 薪水 p
  • CTF练习WP(week1)之二

    目录 1 flag in your hand1 2 HCTF 2018 WarmUp 1 flag in your hand1 题目链接 题目 xctf org cn 打开附件里的html 在网页上输入token获取flag 会发现每次输入
  • [Vue warn]: Error in render: “TypeError: Cannot read properties of undefined(reading“toString“)

    描述 在我们写了大量的标签但是实际上却出现了无任何东西 一查看控制台就出现了这样的错误提示 解决思路 渲染错误 TypeError 无法读取未定义的属性 读取 toString 全局搜友toSrtring 无变量toString 但是有一个
  • 数据链路层相关协议

    网络类型 根据数据链路层协议进行划分 MA 多点接入网络 BMA广播型 NBMA非广播型 P2P 点到点的网络 以太网协议 需要使用MAC地址对不同的主机设备进行区分和标识 主要因为利用以太网组件的二层网络可以包含 两个和两个以上 的接口
  • 学完责任链之后,逻辑思维上升了一个段位,我马上写了一个月薪3万的简历,HR看了让我去上班

    经过上一篇的文章 我们学习了责任链模式和策略模式 设计模式相对重要 对架构 项目拓展性 移植性要求比较高 下面我会说到简历 对于开发来说 简历是程序员的第二生命 技术是第一生命 简历第二生命 学历第三生命 简历到底是什么 简历是你的第二生命
  • js密码验证

    js密码验证
  • Paper Reading:《LISA: Reasoning Segmentation via Large Language Model》

    目录 简介 目标 创新点 方法 训练 实验 总结 简介 LISA Reasoning Segmentation via Large Language Model 基于大型语言模型的推理分割 日期 2023 8 1 v1 单位 香港中文大学
  • python函数参数里面带*是什么意思

    文章参考 https blog csdn net jiangkejkl article details 121346940 1 函数参数定义中使用独立的符号 在函数定义时 使用了一个独立的符号 这表示在符号后面的参数 调用函数时 必须使用k
  • NAPI机制分析

    NAPI机制分析 NAPI 的核心在于 在一个繁忙网络 每次有网络数据包到达时 不需要都引发中断 因为高频率的中断可能会影响系统的整体效率 假象一个场景 我们此时使用标准的 100M 网卡 可能实际达到的接收速率为 80MBits s 而此
  • 解决 IDEA中springboot项目 修改页面无法生效问题

    解决 IDEA中springboot项目 修改页面无法生效问题 之前网上找了很多解决办法 都是无效的 所以找到解决办法后 先发个博客说一下 至此就完成了springboot 无需重启则对html修改生效 如出现偶尔无效时 请刷新浏览器 之前
  • Linux下使用Git上传和更新代码

    一 上传代码 1 去github上根据网站的提示来创建自己的远程Repository 仓库 2 建立本地git仓库 git init 注意 此指令本地源码根目录执行 执行成功后 会在当前目录生成一个隐藏的名字为 git 的目录 所有对本地仓
  • 【ClickHouse数据库】如何在Win10的Ubuntu上通过ClickHouse存取行情数据

    如何在Win10的Ubuntu上通过ClickHouse存取行情数据 前言 一 ClickHouse是什么 二 如何在Ubuntu上安装ClickHouse 三 添加用户并设置密码 四 使用 1 使用DBeaver操作数据库 2 向Clic
  • 计算机图形学方向和前景&&3D

    我是刚入坑计算机图形学的小菜鸟 在百度上搜索计算机图形学方向和前景和3D 几乎不能搜到什么有用的东西 google还能搜到些有用的 但是需要翻墙 恰好前几天山大承办的games 北京大学陈宝权老师提出了图形学的新疆界 10个左右的国内图形学
  • vue 如何获取input中光标位置,并且点击按钮在当前光标后追加内容

    1 第一步 监听输入框的鼠标失焦事件
  • (原创)c++11中的日期和时间库

    c 11提供了日期时间相关的库chrono 通过chrono相关的库我们可以很方便的处理日期和时间 c 11还提供了字符串的宽窄转换功能 也提供了字符串和数字的相互转换的库 有了这些库提供的便利的工具类 我们能方便的处理日期和时间相关的转换
  • linux服务器管理与维护,linux服务器管理与维护速训..ppt

    linux服务器管理与维护速训 入门级命令 1990年秋天 Linus在芬兰首都赫尔辛基大学学习操作系统课程 因为上机需要排队等待 Linus买了台PC机 开发了第一个程序 程序包括两个进程 分别向屏幕上写字母A和B 然后用定时器来切换进程
  • mysql必考知识_可能是全网最好的MySQL重要知识点 !面试必备

    标题有点标题党的意思 但希望你在看了文章之后不会有这个想法 这篇文章是作者对之前总结的 MySQL 知识点做了完善后的产物 可以用来回顾MySQL基础知识以及备战MySQL常见面试问题 Python资源共享群 484031800 什么是My
  • 在GPU上实现光线跟踪

    include cuda h include book h include cpu bitmap h define DIM 1024 生成图像的大小 DIM DIM define SPHERES 20 生成的图像中球体的个数 define