Compare commits
2
Commits
35526d0f28
...
6a611232c9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a611232c9 | ||
|
|
52e5e6a73e |
@@ -0,0 +1,29 @@
|
|||||||
|
# Clang-Format configuration
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
|
||||||
|
# Opening braces on new line (Allman style)
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
|
||||||
|
# This ensures:
|
||||||
|
# - Function opening braces on new line
|
||||||
|
# - Class opening braces on new line
|
||||||
|
# - Struct opening braces on new line
|
||||||
|
# - Control statements (if, while, for) opening braces on new line
|
||||||
|
|
||||||
|
IndentWidth: 4
|
||||||
|
TabWidth: 2
|
||||||
|
UseTab: Never
|
||||||
|
ColumnLimit: 100
|
||||||
|
|
||||||
|
# Namespace indentation
|
||||||
|
NamespaceIndentation: All
|
||||||
|
|
||||||
|
AlignAfterOpenBracket: true
|
||||||
|
|
||||||
|
# Additional formatting preferences
|
||||||
|
PointerAlignment: Left
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
+418
-47
@@ -32,57 +32,428 @@
|
|||||||
*.out
|
*.out
|
||||||
*.app
|
*.app
|
||||||
|
|
||||||
# ---> C
|
# ---> CUDA
|
||||||
# Prerequisites
|
*.i
|
||||||
*.d
|
*.ii
|
||||||
|
*.gpu
|
||||||
|
*.ptx
|
||||||
|
*.cubin
|
||||||
|
*.fatbin
|
||||||
|
|
||||||
# Object files
|
# ---> VisualStudio
|
||||||
*.o
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
*.ko
|
## files generated by popular Visual Studio add-ons.
|
||||||
*.obj
|
##
|
||||||
*.elf
|
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||||
|
|
||||||
# Linker output
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
build/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
*.ilk
|
*.ilk
|
||||||
*.map
|
*.meta
|
||||||
*.exp
|
*.obj
|
||||||
|
*.iobj
|
||||||
# Precompiled Headers
|
|
||||||
*.gch
|
|
||||||
*.pch
|
*.pch
|
||||||
|
|
||||||
# Libraries
|
|
||||||
*.lib
|
|
||||||
*.a
|
|
||||||
*.la
|
|
||||||
*.lo
|
|
||||||
|
|
||||||
# Shared objects (inc. Windows DLLs)
|
|
||||||
*.dll
|
|
||||||
*.so
|
|
||||||
*.so.*
|
|
||||||
*.dylib
|
|
||||||
|
|
||||||
# Executables
|
|
||||||
*.exe
|
|
||||||
*.out
|
|
||||||
*.app
|
|
||||||
*.i*86
|
|
||||||
*.x86_64
|
|
||||||
*.hex
|
|
||||||
|
|
||||||
# Debug files
|
|
||||||
*.dSYM/
|
|
||||||
*.su
|
|
||||||
*.idb
|
|
||||||
*.pdb
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
# but not Directory.Build.rsp, as it configures directory-level build defaults
|
||||||
|
!Directory.Build.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.tlog
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
# Kernel Module Compile Results
|
# Chutzpah Test files
|
||||||
*.mod*
|
_Chutzpah*
|
||||||
*.cmd
|
|
||||||
.tmp_versions/
|
# Visual C++ cache files
|
||||||
modules.order
|
ipch/
|
||||||
Module.symvers
|
*.aps
|
||||||
Mkfile.old
|
*.ncb
|
||||||
dkms.conf
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||||
|
*.vbp
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||||
|
*.dsw
|
||||||
|
*.dsp
|
||||||
|
|
||||||
|
# Visual Studio 6 technical files
|
||||||
|
*.ncb
|
||||||
|
*.aps
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# Visual Studio History (VSHistory) files
|
||||||
|
.vshistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# VS Code files for those working on multiple tools
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
# ---> VisualStudioCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
!.vscode/*.code-snippets
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Built Visual Studio Code Extensions
|
||||||
|
*.vsix
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,71 @@
|
|||||||
MIT License
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
Copyright (c) 2026 davoodrasti
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
1. Definitions.
|
||||||
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
||||||
following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||||
portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
||||||
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity.
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
||||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications, including software source code, documentation, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including compiled object code, generated documentation, and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice included in or attached to the work (an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by Your Authorized Representative.
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if provided alongside the Derivative Works.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file change history log be included.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
CXX ?= c++
|
||||||
|
CPPFLAGS += -Isrc
|
||||||
|
CXXFLAGS ?= -std=c++17 -O2 -Wall -Wextra
|
||||||
|
DEPFLAGS = -MMD -MP
|
||||||
|
|
||||||
|
TARGET := build/renderer
|
||||||
|
SOURCES := src/main.cpp src/prrpm.cpp src/stb_image_write.cpp
|
||||||
|
OBJECTS := $(patsubst src/%.cpp,build/%.o,$(SOURCES))
|
||||||
|
DEPFILES := $(OBJECTS:.o=.d)
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJECTS)
|
||||||
|
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
|
build/%.o: src/%.cpp
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEPFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
-include $(DEPFILES)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf build
|
||||||
@@ -1,2 +1,33 @@
|
|||||||
# ProgressivePhotonMapping-Non-Recursive
|
# Progressive Photon Mapping: Non-Recursive CPU
|
||||||
|
|
||||||
|
A small C++ CPU implementation of photon mapping(non-recursive verion based on original smallppm by T. Hachisuka), developed as a study companion to an earlier CUDA/GPGPU renderer. The project explores how the same photorealistic rendering approach can be implemented and compared on different architectures.
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
Around 2012, my brother Alireza Rasti and I developed a CUDA-based renderer as part of a student project on using GPGPU to accelerate photorealistic rendering. At the time, CUDA did not support recursive device code in the way ray tracing and photon mapping would naturally use it. We therefore used a non-recursive design in the CUDA version implementation.
|
||||||
|
|
||||||
|
We also built this C++ CPU version using a non-recursive approach. Keeping the CPU implementation close to the CUDA design gave us a more useful basis for comparing the two approaches and studying their trade-offs.
|
||||||
|
|
||||||
|
Note: We have made minor updates to our 2012 implementation to use modern C++.
|
||||||
|
|
||||||
|
## Build and Run
|
||||||
|
|
||||||
|
Build with Make:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
Run using the included scene file and specify the output image path:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./build/renderer ./scenes/Scene004.txt output.bmp
|
||||||
|
```
|
||||||
|
|
||||||
|
The renderer requires a scene file and output image path as positional arguments.
|
||||||
|
|
||||||
|
This project currently writes ouput images via stb_image_write. This library can output PNG, TGA, JPEG/JPG, and HDR files when the output writer is configured for those formats.
|
||||||
|
|
||||||
|
## Project Scope
|
||||||
|
|
||||||
|
This repository contains the CPU implementation. It is intended for learning, experimentation, and comparison with the original CUDA project, rather than as a production rendering system. The CUDA version will be available in the repo as well soon.
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
imagesize = 1280, 720;
|
||||||
|
numberOfPhotons = 100000;
|
||||||
|
numberOfPhotonPass = 1000;
|
||||||
|
numberOfBounces = 5;
|
||||||
|
|
||||||
|
/==================Scene 01======================
|
||||||
|
light = 1; 0.0,0.28125,1.5; 5,5,5; 0.1,0.0,0.1;
|
||||||
|
s = -0.35,-0.18125,1.85; 0.1; 1.0,1.0,1.0; 1;
|
||||||
|
s = 0.05,-0.18125,1.22; 0.1; 1.0,1.0,1.0; 2;
|
||||||
|
s = 0.25,-0.18125,1.7; 0.1; 0.5,1.0,0.5; 0;
|
||||||
|
s = -0.15,-0.23125,1.7; 0.05; 1.0,1.0,0.0; 0;
|
||||||
|
|
||||||
|
/Front
|
||||||
|
t = -0.5,0.28125,2.0; 0.5, 0.28125,2.0; -0.5,-0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = 0.5,0.28125,2.0; 0.5,-0.28125,2.0; -0.5,-0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
/Bottom
|
||||||
|
t = -0.5,-0.28125,2.0; 0.5,-0.28125,2.0; -0.5,-0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = 0.5,-0.28125,2.0; 0.5,-0.28125,1.0; -0.5,-0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
|
/Right
|
||||||
|
t = 0.5,0.28125,2.0; 0.5,0.28125,1.0; 0.5,-0.28125,2.0; 0.25,0.25,0.75; 0;
|
||||||
|
t = 0.5,0.28125,1.0; 0.5,-0.28125,1.0; 0.5,-0.28125,2.0; 0.25,0.25,0.75; 0;
|
||||||
|
/Left
|
||||||
|
t = -0.5,-0.28125,2.0; -0.5,0.28125,1.0; -0.5,0.28125,2.0; 0.75,0.25,0.25; 0;
|
||||||
|
t = -0.5,-0.28125,2.0; -0.5,-0.28125,1.0; -0.5,0.28125,1.0; 0.75,0.25,0.25; 0;
|
||||||
|
/Top
|
||||||
|
t = -0.5,0.28125,1.0; 0.5,0.28125,2.0; -0.5,0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = -0.5,0.28125,1.0; 0.5,0.28125,1.0; 0.5,0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
/Back
|
||||||
|
t = -0.5,-0.28125,1.0; 0.5,0.28125,1.0; -0.5,0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = -0.5,-0.28125,1.0; 0.5,-0.28125,1.0; 0.5,0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
imagesize = 640, 360;
|
||||||
|
numberOfPhotons = 1000000;
|
||||||
|
numberOfPhotonPass = 1000;
|
||||||
|
numberOfBounces = 5;
|
||||||
|
|
||||||
|
/==================Scene 03======================
|
||||||
|
/left lights
|
||||||
|
light = 0; -0.49,0.27925,1.75; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0; -0.49,0.27925,1.5; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0; -0.49,0.27925,1.25; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
/right
|
||||||
|
light = 0; 0.49,0.27925,1.75; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0; 0.49,0.27925,1.5; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0; 0.49,0.27925,1.25; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
/front
|
||||||
|
light = 0; 0.25,0.27925,1.99; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0; 0.0 ,0.27925,1.99; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0;-0.25,0.27925,1.99; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
/back
|
||||||
|
light = 0; 0.25,0.27925,1.01; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0; 0.0 ,0.27925,1.01; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0;-0.25,0.27925,1.01; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
/top
|
||||||
|
light = 0; 0.25,0.27925,1.25; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0; 0.0 ,0.27925,1.25; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0;-0.25,0.27925,1.25; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
|
||||||
|
light = 0; 0.25,0.27925,1.5; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0; 0.0 ,0.27925,1.5; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0;-0.25,0.27925,1.5; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
|
||||||
|
light = 0; 0.25,0.27925,1.75; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0; 0.0 ,0.27925,1.75; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
light = 0;-0.25,0.27925,1.75; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
s = 0.0,-0.18125,1.5; 0.1; 1.0,1.0,1.0; 2;
|
||||||
|
|
||||||
|
/Front
|
||||||
|
t = -0.5,0.28125,2.0; 0.5, 0.28125,2.0; -0.5,-0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = 0.5,0.28125,2.0; 0.5,-0.28125,2.0; -0.5,-0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
/Bottom
|
||||||
|
t = -0.5,-0.28125,2.0; 0.5,-0.28125,2.0; -0.5,-0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = 0.5,-0.28125,2.0; 0.5,-0.28125,1.0; -0.5,-0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
|
/Right
|
||||||
|
t = 0.5,0.28125,2.0; 0.5,0.28125,1.0; 0.5,-0.28125,2.0; 0.25,0.25,0.75; 0;
|
||||||
|
t = 0.5,0.28125,1.0; 0.5,-0.28125,1.0; 0.5,-0.28125,2.0; 0.25,0.25,0.75; 0;
|
||||||
|
/Left
|
||||||
|
t = -0.5,-0.28125,2.0; -0.5,0.28125,1.0; -0.5,0.28125,2.0; 0.75,0.25,0.25; 0;
|
||||||
|
t = -0.5,-0.28125,2.0; -0.5,-0.28125,1.0; -0.5,0.28125,1.0; 0.75,0.25,0.25; 0;
|
||||||
|
/Top
|
||||||
|
t = -0.5,0.28125,1.0; 0.5,0.28125,2.0; -0.5,0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = -0.5,0.28125,1.0; 0.5,0.28125,1.0; 0.5,0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
/Back
|
||||||
|
t = -0.5,-0.28125,1.0; 0.5,0.28125,1.0; -0.5,0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = -0.5,-0.28125,1.0; 0.5,-0.28125,1.0; 0.5,0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
imagesize = 640, 360;
|
||||||
|
photonCasting = off;
|
||||||
|
numberOfPhotons = 100000;
|
||||||
|
numberOfPhotonPass = 1000;
|
||||||
|
numberOfBounces = 5;
|
||||||
|
|
||||||
|
/==================Scene 02======================
|
||||||
|
light = 1; 0.0,0.28125,1.5; 2,2,2; 0.1,0.0,0.1;
|
||||||
|
s = -0.2,-0.18125,1.5; 0.1; 0.5,1.0,0.5; 1;
|
||||||
|
s = 0.37,-0.18125,1.27; 0.1; 1.0,1.0,1.0; 2;
|
||||||
|
|
||||||
|
/Front
|
||||||
|
t = -0.5,0.28125,2.0; 0.5, 0.28125,2.0; -0.5,-0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = 0.5,0.28125,2.0; 0.5,-0.28125,2.0; -0.5,-0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
/Bottom
|
||||||
|
t = -0.5,-0.28125,2.0; 0.5,-0.28125,2.0; -0.5,-0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = 0.5,-0.28125,2.0; 0.5,-0.28125,1.0; -0.5,-0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
|
/Right
|
||||||
|
t = 0.5,0.28125,2.0; 0.5,0.28125,1.0; 0.5,-0.28125,2.0; 0.25,0.25,0.75; 0;
|
||||||
|
t = 0.5,0.28125,1.0; 0.5,-0.28125,1.0; 0.5,-0.28125,2.0; 0.25,0.25,0.75; 0;
|
||||||
|
/Left
|
||||||
|
t = -0.5,-0.28125,2.0; -0.5,0.28125,1.0; -0.5,0.28125,2.0; 0.75,0.25,0.25; 0;
|
||||||
|
t = -0.5,-0.28125,2.0; -0.5,-0.28125,1.0; -0.5,0.28125,1.0; 0.75,0.25,0.25; 0;
|
||||||
|
/Top
|
||||||
|
t = -0.5,0.28125,1.0; 0.5,0.28125,2.0; -0.5,0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = -0.5,0.28125,1.0; 0.5,0.28125,1.0; 0.5,0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
/Back
|
||||||
|
t = -0.5,-0.28125,1.0; 0.5,0.28125,1.0; -0.5,0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = -0.5,-0.28125,1.0; 0.5,-0.28125,1.0; 0.5,0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
imagesize 800 800
|
||||||
|
numberOfPhotons 100000
|
||||||
|
numberOfPhotonPass 100
|
||||||
|
numberOfPhotonBounces 3
|
||||||
|
light pos 0.4 0.4 1.7
|
||||||
|
|
||||||
|
s 0.0 -0.1 1.7 0.10 1 0 1
|
||||||
|
s 0.0 -0.3 1.7 0.20 1 1 0
|
||||||
|
/
|
||||||
|
t 0.5 0.5 2.0 -0.5 -0.5 2.0 -0.5 0.5 2.0 1 1 1
|
||||||
|
t 0.5 0.5 2.0 0.5 -0.5 2.0 -0.5 -0.5 2.0 1 1 1
|
||||||
|
/
|
||||||
|
t -0.5 -0.5 2.0 0.5 -0.5 2.0 -0.5 -0.5 1.0 1 1 1
|
||||||
|
t 0.5 -0.5 2.0 0.5 -0.5 1.0 -0.5 -0.5 1.0 1 1 1
|
||||||
|
/
|
||||||
|
t 0.5 0.5 2.0 0.5 0.5 1.0 0.5 -0.5 2.0 0.4745098039215686 0.4392156862745098 0.7529411764705882
|
||||||
|
t 0.5 0.5 1.0 0.5 -0.5 1.0 0.5 -0.5 2.0 0.4745098039215686 0.4392156862745098 0.7529411764705882
|
||||||
|
/
|
||||||
|
t -0.5 -0.5 2.0 -0.5 0.5 1.0 -0.5 0.5 2.0 0.7529411764705882 0.4431372549019608 0.4823529411764706
|
||||||
|
t -0.5 -0.5 2.0 -0.5 -0.5 1.0 -0.5 0.5 1.0 0.7529411764705882 0.4431372549019608 0.4823529411764706
|
||||||
|
/
|
||||||
|
t -0.5 0.5 1.0 0.5 0.5 2.0 -0.5 0.5 2.0 1 1 1
|
||||||
|
t -0.5 0.5 1.0 0.5 0.5 1.0 0.5 0.5 2.0 1 1 1
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
imagesize = 1280, 720;
|
||||||
|
numberOfPhotons = 100000;
|
||||||
|
numberOfPhotonPass = 100;
|
||||||
|
numberOfBounces = 5;
|
||||||
|
|
||||||
|
/==================Scene 04======================
|
||||||
|
light = 0; 0.0,0.1,1.5; 10,10,10; 0.1,0.0,0.1;
|
||||||
|
light = 0; -1.5,0.3790,3.0; 10,10,10; 0.1,0.0,0.1;
|
||||||
|
light = 0; 1.5,0.3790,3.0; 10,10,10; 0.1,0.0,0.1;
|
||||||
|
s = 0.3,-0.18125,1.5; 0.1; 1.0,0.6,0.6; 2;
|
||||||
|
s = -0.3,-0.18125,1.5; 0.1; 0.7,1.0,0.7; 2;
|
||||||
|
s = 0.0,-0.18125,1.2; 0.1; 1.0,1.0,0.5; 2;
|
||||||
|
|
||||||
|
s = -0.15,-0.23125,1.25; 0.05; 1.0,1.0,0.1; 0;
|
||||||
|
s = 0.15,-0.23125,1.25; 0.05; 0.5,1.0,0.5; 0;
|
||||||
|
|
||||||
|
s = -0.45,-0.23125,1.06; 0.05; 1.0,1.0,0.1; 0;
|
||||||
|
s = 0.45,-0.23125,1.06; 0.05; 0.5,1.0,0.5; 0;
|
||||||
|
|
||||||
|
|
||||||
|
/Front
|
||||||
|
t = -0.5,0.28125,2.0; 0.5, 0.28125,2.0; -0.5,-0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = 0.5,0.28125,2.0; 0.5,-0.28125,2.0; -0.5,-0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
/Bottom
|
||||||
|
t = -0.5,-0.28125,2.0; 0.5,-0.28125,2.0; -0.5,-0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = 0.5,-0.28125,2.0; 0.5,-0.28125,1.0; -0.5,-0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
|
/Right
|
||||||
|
t = 0.5,0.28125,2.0; 0.5,0.28125,1.0; 0.5,-0.28125,2.0; 0.25,0.25,0.75; 0;
|
||||||
|
t = 0.5,0.28125,1.0; 0.5,-0.28125,1.0; 0.5,-0.28125,2.0; 0.25,0.25,0.75; 0;
|
||||||
|
/Left
|
||||||
|
t = -0.5,-0.28125,2.0; -0.5,0.28125,1.0; -0.5,0.28125,2.0; 0.75,0.25,0.25; 0;
|
||||||
|
t = -0.5,-0.28125,2.0; -0.5,-0.28125,1.0; -0.5,0.28125,1.0; 0.75,0.25,0.25; 0;
|
||||||
|
/Top
|
||||||
|
t = -0.5,0.28125,1.0; 0.5,0.28125,2.0; -0.5,0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = -0.5,0.28125,1.0; 0.5,0.28125,1.0; 0.5,0.28125,2.0; 0.75,0.75,0.75; 0;
|
||||||
|
/Back
|
||||||
|
t = -0.5,-0.28125,1.0; 0.5,0.28125,1.0; -0.5,0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
|
t = -0.5,-0.28125,1.0; 0.5,-0.28125,1.0; 0.5,0.28125,1.0; 0.75,0.75,0.75; 0;
|
||||||
+5456
File diff suppressed because it is too large
Load Diff
+25
@@ -0,0 +1,25 @@
|
|||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
// Copyright 2011 Intel Corporation
|
||||||
|
// All Rights Reserved
|
||||||
|
//
|
||||||
|
// Permission is granted to use, copy, distribute and prepare derivative works of this
|
||||||
|
// software for any purpose and without fee, provided, that the above copyright notice
|
||||||
|
// and this statement appear in all copies. Intel makes no representations about the
|
||||||
|
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
|
||||||
|
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
|
||||||
|
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
|
||||||
|
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
|
||||||
|
// assume any responsibility for any errors which may appear in this software nor any
|
||||||
|
// responsibility to update it.
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef __STB_IMAGE_H__
|
||||||
|
#define __STB_IMAGE_H__
|
||||||
|
|
||||||
|
#define STBI_HEADER_FILE_ONLY
|
||||||
|
|
||||||
|
#include "stb_image.c"
|
||||||
|
|
||||||
|
#endif // __STB_IMAGE_H__
|
||||||
+1724
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
/************************************************************
|
||||||
|
Title : A Photo-realistic Renderer Based on Photon Mapping
|
||||||
|
Students : Davood Rasti
|
||||||
|
Alireza Rasti
|
||||||
|
|
||||||
|
Version : 0.01
|
||||||
|
Date : 23-06-2012
|
||||||
|
Updated : 01-10-2026
|
||||||
|
*************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <math.h>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
namespace PRRPM
|
||||||
|
{
|
||||||
|
// typedef----------------------------------------
|
||||||
|
using i8 = std::int8_t;
|
||||||
|
using ui8 = std::uint8_t;
|
||||||
|
using i16 = std::int16_t;
|
||||||
|
using ui16 = std::uint16_t;
|
||||||
|
using i32 = std::int32_t;
|
||||||
|
using ui32 = std::uint32_t;
|
||||||
|
using i64 = std::int64_t;
|
||||||
|
using ui64 = std::uint64_t;
|
||||||
|
using f32 = float;
|
||||||
|
using pchar = char*;
|
||||||
|
//-----------------------------------------------
|
||||||
|
|
||||||
|
namespace MathUtility
|
||||||
|
{
|
||||||
|
inline constexpr f32 PI = 3.141592654f;
|
||||||
|
inline constexpr f32 HalfPI = 1.5708f;
|
||||||
|
inline constexpr f32 TwoPI = 6.28319f;
|
||||||
|
inline constexpr f32 DegreeToRadianCoefficient = PI / 180.0f;
|
||||||
|
inline constexpr f32 RadianToDegreeCoefficient = 180.0f / PI;
|
||||||
|
inline constexpr f32 InverstPI = 1.0f / PI;
|
||||||
|
|
||||||
|
inline f32 degreeToRadian(f32 degree)
|
||||||
|
{
|
||||||
|
return degree * DegreeToRadianCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline f32 radianToDegree(f32 radian)
|
||||||
|
{
|
||||||
|
return radian * RadianToDegreeCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline f32 minValue(f32 value1, f32 value2)
|
||||||
|
{
|
||||||
|
return value1 < value2 ? value1 : value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline f32 maxValue(f32 value1, f32 value2)
|
||||||
|
{
|
||||||
|
return value1 > value2 ? value1 : value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline f32 clamp(f32 value, f32 lowValue, f32 highValue)
|
||||||
|
{
|
||||||
|
return maxValue(minValue(value, highValue), lowValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void swap(f32& value1, f32& value2)
|
||||||
|
{
|
||||||
|
f32 tempValue = value1;
|
||||||
|
value1 = value2;
|
||||||
|
value2 = tempValue;
|
||||||
|
}
|
||||||
|
} // namespace MathUtility
|
||||||
|
|
||||||
|
}; // namespace PRRPM
|
||||||
+810
@@ -0,0 +1,810 @@
|
|||||||
|
|
||||||
|
/************************************************************
|
||||||
|
Title : A Photo-realistic Renderer Based on Photon Mapping
|
||||||
|
Students : Davood Rasti
|
||||||
|
Alireza Rasti
|
||||||
|
|
||||||
|
Version : 0.01
|
||||||
|
Date : 23-06-2012
|
||||||
|
Updated : 01-10-2026
|
||||||
|
*************************************************************/
|
||||||
|
|
||||||
|
#include "./3rdparty/stb_collection/stb_image_write.h"
|
||||||
|
#include "./prrpm.h"
|
||||||
|
|
||||||
|
#include <charconv>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cmath>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
using namespace PRRPM;
|
||||||
|
|
||||||
|
// Parse a complete numeric token so malformed scene values cannot silently become zero.
|
||||||
|
template <typename Value> Value parseNumber(std::string_view token)
|
||||||
|
{
|
||||||
|
Value value{};
|
||||||
|
const char* tokenEnd = token.data() + token.size();
|
||||||
|
const auto result = std::from_chars(token.data(), tokenEnd, value);
|
||||||
|
if (result.ec != std::errc{} || result.ptr != tokenEnd)
|
||||||
|
throw std::invalid_argument("invalid numeric value '" + std::string(token) + "'");
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> tokenizer(const std::string& line)
|
||||||
|
{
|
||||||
|
std::vector<std::string> stringList;
|
||||||
|
std::string normalizedLine = line;
|
||||||
|
// Scene files accept whitespace as well as '=', ',' and ';' as separators.
|
||||||
|
for (char& character : normalizedLine)
|
||||||
|
{
|
||||||
|
if (character == '=' || character == ',' || character == ';')
|
||||||
|
character = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istringstream lineStream(normalizedLine);
|
||||||
|
std::string token;
|
||||||
|
while (lineStream >> token)
|
||||||
|
stringList.push_back(token);
|
||||||
|
|
||||||
|
return stringList;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loadSceneFile(const std::string& fileName)
|
||||||
|
{
|
||||||
|
std::ifstream modelFile(fileName);
|
||||||
|
if (!modelFile)
|
||||||
|
{
|
||||||
|
std::cerr << "Unable to open scene file: " << fileName << '\n';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string code;
|
||||||
|
PRRPM::Triangle triangle;
|
||||||
|
PRRPM::Sphere sphere;
|
||||||
|
|
||||||
|
std::string lineToRead;
|
||||||
|
std::size_t lineNumber = 0;
|
||||||
|
while (std::getline(modelFile, lineToRead))
|
||||||
|
{
|
||||||
|
++lineNumber;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::vector<std::string> stringList;
|
||||||
|
stringList = tokenizer(lineToRead);
|
||||||
|
|
||||||
|
if (stringList.size() < 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
code = stringList[0];
|
||||||
|
|
||||||
|
if (code[0] == '*')
|
||||||
|
break;
|
||||||
|
else if (code[0] == '/')
|
||||||
|
continue;
|
||||||
|
// Each non-comment line begins with a directive such as imagesize, light, t, or s.
|
||||||
|
else if (code == "imagesize" && stringList.size() >= 3)
|
||||||
|
{
|
||||||
|
imageWidth = parseNumber<ui32>(stringList[1]);
|
||||||
|
imageHeight = parseNumber<ui32>(stringList[2]);
|
||||||
|
}
|
||||||
|
else if (code == "light" && stringList.size() >= 2)
|
||||||
|
{
|
||||||
|
if (stringList[1] == "on" || stringList[1] == "off")
|
||||||
|
isLightOn = stringList[1] == "on";
|
||||||
|
// Accept either the full numeric light record or the compact "light pos" form.
|
||||||
|
else if (stringList.size() >= 11)
|
||||||
|
{
|
||||||
|
PRRPM::LightSource lightSource{};
|
||||||
|
lightSource.type = parseNumber<ui8>(stringList[1]);
|
||||||
|
lightSource.position =
|
||||||
|
Vector3d(parseNumber<f32>(stringList[2]), parseNumber<f32>(stringList[3]),
|
||||||
|
parseNumber<f32>(stringList[4]));
|
||||||
|
lightSource.intensity =
|
||||||
|
Vector3d(parseNumber<f32>(stringList[5]), parseNumber<f32>(stringList[6]),
|
||||||
|
parseNumber<f32>(stringList[7]));
|
||||||
|
lightSource.size =
|
||||||
|
Vector3d(parseNumber<f32>(stringList[8]), parseNumber<f32>(stringList[9]),
|
||||||
|
parseNumber<f32>(stringList[10]));
|
||||||
|
lightSourcesList.push_back(lightSource);
|
||||||
|
}
|
||||||
|
else if (stringList[1] == "pos" && stringList.size() >= 5)
|
||||||
|
{
|
||||||
|
PRRPM::LightSource lightSource{};
|
||||||
|
lightSource.type = 0;
|
||||||
|
lightSource.position =
|
||||||
|
Vector3d(parseNumber<f32>(stringList[2]), parseNumber<f32>(stringList[3]),
|
||||||
|
parseNumber<f32>(stringList[4]));
|
||||||
|
lightSource.intensity = Vector3d(1.0f, 1.0f, 1.0f);
|
||||||
|
lightSourcesList.push_back(lightSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((code == "numberOfPhotons" || code == "numberOfPhotonPass" ||
|
||||||
|
code == "numberOfBounces" || code == "numberOfPhotonBounces") &&
|
||||||
|
stringList.size() >= 2)
|
||||||
|
{
|
||||||
|
const ui32 value = parseNumber<ui32>(stringList[1]);
|
||||||
|
if (code == "numberOfPhotons")
|
||||||
|
numberOfPhotons = value;
|
||||||
|
else if (code == "numberOfPhotonPass")
|
||||||
|
numberOfPhotonPass = value;
|
||||||
|
else
|
||||||
|
numberOfBounces = value;
|
||||||
|
}
|
||||||
|
else if (code == "photonCasting" && stringList.size() >= 2)
|
||||||
|
isPhotonMapping = stringList[1] == "on";
|
||||||
|
else if (code == "gui" && stringList.size() >= 2)
|
||||||
|
{
|
||||||
|
if (stringList[1] == "off")
|
||||||
|
isGUI = false;
|
||||||
|
else if (stringList[1] == "on")
|
||||||
|
isGUI = true;
|
||||||
|
}
|
||||||
|
else if (code == "t" && stringList.size() >= 13)
|
||||||
|
{
|
||||||
|
triangle.point1.x = parseNumber<f32>(stringList[1]);
|
||||||
|
triangle.point1.y = parseNumber<f32>(stringList[2]);
|
||||||
|
triangle.point1.z = parseNumber<f32>(stringList[3]);
|
||||||
|
|
||||||
|
triangle.point2.x = parseNumber<f32>(stringList[4]);
|
||||||
|
triangle.point2.y = parseNumber<f32>(stringList[5]);
|
||||||
|
triangle.point2.z = parseNumber<f32>(stringList[6]);
|
||||||
|
|
||||||
|
triangle.point3.x = parseNumber<f32>(stringList[7]);
|
||||||
|
triangle.point3.y = parseNumber<f32>(stringList[8]);
|
||||||
|
triangle.point3.z = parseNumber<f32>(stringList[9]);
|
||||||
|
|
||||||
|
triangle.color.x = parseNumber<f32>(stringList[10]);
|
||||||
|
triangle.color.y = parseNumber<f32>(stringList[11]);
|
||||||
|
triangle.color.z = parseNumber<f32>(stringList[12]);
|
||||||
|
|
||||||
|
triangle.materialID =
|
||||||
|
stringList.size() >= 14 ? parseNumber<ui8>(stringList[13]) : 0;
|
||||||
|
|
||||||
|
// The ray-triangle test uses the precomputed face normal.
|
||||||
|
PRRPM::Vector3d edge1 = triangle.point2 - triangle.point1;
|
||||||
|
PRRPM::Vector3d edge2 = triangle.point3 - triangle.point1;
|
||||||
|
triangle.normal = edge1.cross(edge2);
|
||||||
|
triangle.normal.normalize();
|
||||||
|
|
||||||
|
triangleList.push_back(triangle);
|
||||||
|
}
|
||||||
|
else if (code == "s" && stringList.size() >= 8)
|
||||||
|
{
|
||||||
|
sphere.position.x = parseNumber<f32>(stringList[1]);
|
||||||
|
sphere.position.y = parseNumber<f32>(stringList[2]);
|
||||||
|
sphere.position.z = parseNumber<f32>(stringList[3]);
|
||||||
|
|
||||||
|
sphere.radius = parseNumber<f32>(stringList[4]);
|
||||||
|
|
||||||
|
sphere.color.x = parseNumber<f32>(stringList[5]);
|
||||||
|
sphere.color.y = parseNumber<f32>(stringList[6]);
|
||||||
|
sphere.color.z = parseNumber<f32>(stringList[7]);
|
||||||
|
|
||||||
|
sphere.materialID = stringList.size() >= 9 ? parseNumber<ui8>(stringList[8]) : 0;
|
||||||
|
|
||||||
|
sphereList.push_back(sphere);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::invalid_argument& error)
|
||||||
|
{
|
||||||
|
// Include the source location so scene-file typos are easy to find.
|
||||||
|
std::cerr << fileName << ':' << lineNumber << ": " << error.what() << '\n';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance one queued secondary ray. Status values are -2 (finished), 0 (diffuse),
|
||||||
|
// 1 (mirror), and 2 (dielectric); storing these states makes recursion unnecessary.
|
||||||
|
void nextRayTracingPass(ui32 index)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (secondIntersectionPointsList[index].nubmerOfPhotonAndMaterialID == -2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PRRPM::Ray ray;
|
||||||
|
ray.direction = secondIntersectionPointsList[index].fluxAndDirection;
|
||||||
|
ray.direction.normalize();
|
||||||
|
ray.origin = secondIntersectionPointsList[index].positionAndOrigin;
|
||||||
|
ray.objectID = -1;
|
||||||
|
ray.distance = maxSceneDepth;
|
||||||
|
|
||||||
|
PRRPM::Vector3d color;
|
||||||
|
intersectObjects(&ray);
|
||||||
|
if (ray.objectID != -1)
|
||||||
|
{
|
||||||
|
if (getObjectMaterial(ray.objectID, ray.objectType) == 0)
|
||||||
|
{
|
||||||
|
if (secondIntersectionPointsList[index].radiusSquare != -1)
|
||||||
|
color = getObjectColor(ray.objectID, ray.objectType);
|
||||||
|
else
|
||||||
|
color = secondIntersectionPointsList[index].color *
|
||||||
|
getObjectColor(ray.objectID, ray.objectType);
|
||||||
|
|
||||||
|
int cellID = computeCellID(ray.intersectionPosition);
|
||||||
|
if (cellID >= 0 && cellID < gridSize)
|
||||||
|
{
|
||||||
|
secondIntersectionPointsList[index].color = color;
|
||||||
|
secondIntersectionPointsList[index].positionAndOrigin = ray.intersectionPosition;
|
||||||
|
secondIntersectionPointsList[index].normal = getSurfaceNormal(ray);
|
||||||
|
secondIntersectionPointsList[index].cellID = cellID;
|
||||||
|
// secondIntersectionPointsList[index].materialID = 0;
|
||||||
|
|
||||||
|
secondIntersectionPointsList[index].radiusSquare = irridianceRadiusSquare;
|
||||||
|
secondIntersectionPointsList[index].nubmerOfPhotonAndMaterialID = 0;
|
||||||
|
secondIntersectionPointsList[index].fluxAndDirection = PRRPM::Vector3d();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (getObjectMaterial(ray.objectID, ray.objectType) == 1)
|
||||||
|
{
|
||||||
|
PRRPM::Vector3d normal = getSurfaceNormal(ray);
|
||||||
|
secondIntersectionPointsList[index].positionAndOrigin = ray.intersectionPosition;
|
||||||
|
secondIntersectionPointsList[index].fluxAndDirection =
|
||||||
|
ray.direction - normal * normal.dot(ray.direction) * 2.0f;
|
||||||
|
secondIntersectionPointsList[index].nubmerOfPhotonAndMaterialID = 1;
|
||||||
|
}
|
||||||
|
else if (getObjectMaterial(ray.objectID, ray.objectType) == 2)
|
||||||
|
{
|
||||||
|
secondIntersectionPointsList[index].positionAndOrigin = ray.intersectionPosition;
|
||||||
|
secondIntersectionPointsList[index].normal = getSurfaceNormal(ray);
|
||||||
|
secondIntersectionPointsList[index].fluxAndDirection = ray.direction;
|
||||||
|
|
||||||
|
if (secondIntersectionPointsList[index].radiusSquare == -1)
|
||||||
|
secondIntersectionPointsList[index].color =
|
||||||
|
secondIntersectionPointsList[index].color *
|
||||||
|
getObjectColor(ray.objectID, ray.objectType);
|
||||||
|
else
|
||||||
|
secondIntersectionPointsList[index].color =
|
||||||
|
getObjectColor(ray.objectID, ray.objectType);
|
||||||
|
secondIntersectionPointsList[index].nubmerOfPhotonAndMaterialID = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
secondIntersectionPointsList[index].nubmerOfPhotonAndMaterialID = -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace each dielectric hit with its reflected and refracted paths, then discard finished paths.
|
||||||
|
void calculateReflectionFractionForAllPoints()
|
||||||
|
{
|
||||||
|
PRRPM::ui32 step = 0;
|
||||||
|
for (PRRPM::ui32 iPoint = 0; iPoint < secondIntersectionPointsList.size(); ++iPoint)
|
||||||
|
{
|
||||||
|
IntersectionPoint intersectionPoint = secondIntersectionPointsList[iPoint];
|
||||||
|
if (intersectionPoint.nubmerOfPhotonAndMaterialID == 2)
|
||||||
|
{
|
||||||
|
PRRPM::Vector3d reflectionRayDirection;
|
||||||
|
PRRPM::Vector3d refractionRayDirection;
|
||||||
|
f32 cosOutAngle;
|
||||||
|
f32 reflectionIntensity;
|
||||||
|
|
||||||
|
++step;
|
||||||
|
|
||||||
|
calculateReflectionFractionDirection(intersectionPoint.fluxAndDirection,
|
||||||
|
intersectionPoint.normal, &reflectionRayDirection,
|
||||||
|
&refractionRayDirection, &cosOutAngle,
|
||||||
|
&reflectionIntensity);
|
||||||
|
if (cosOutAngle < 0)
|
||||||
|
{
|
||||||
|
secondIntersectionPointsList[iPoint] = intersectionPoint;
|
||||||
|
secondIntersectionPointsList[iPoint].fluxAndDirection = reflectionRayDirection;
|
||||||
|
secondIntersectionPointsList[iPoint].radiusSquare = -1;
|
||||||
|
++iPoint;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
secondIntersectionPointsList[iPoint - 1] = intersectionPoint;
|
||||||
|
secondIntersectionPointsList[iPoint - 1].fluxAndDirection = refractionRayDirection;
|
||||||
|
secondIntersectionPointsList[iPoint - 1].color =
|
||||||
|
secondIntersectionPointsList[iPoint].color * (1.0 - reflectionIntensity);
|
||||||
|
secondIntersectionPointsList[iPoint - 1].radiusSquare = -1;
|
||||||
|
|
||||||
|
secondIntersectionPointsList[iPoint] = intersectionPoint;
|
||||||
|
secondIntersectionPointsList[iPoint].fluxAndDirection = reflectionRayDirection;
|
||||||
|
// secondIntersectionPointsList[iPoint].nubmerOfPhotonAndMaterialID = -2;
|
||||||
|
secondIntersectionPointsList[iPoint].color =
|
||||||
|
secondIntersectionPointsList[iPoint].color * reflectionIntensity;
|
||||||
|
secondIntersectionPointsList[iPoint].radiusSquare = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(secondIntersectionPointsList.begin(), secondIntersectionPointsList.end(),
|
||||||
|
compareByMetalID);
|
||||||
|
PRRPM::ui32 numberOfNonDiffusedPoint = int(std::count_if(
|
||||||
|
secondIntersectionPointsList.begin(), secondIntersectionPointsList.end(), isMetalIDOut));
|
||||||
|
secondIntersectionPointsList.erase(secondIntersectionPointsList.begin(),
|
||||||
|
secondIntersectionPointsList.begin() +
|
||||||
|
numberOfNonDiffusedPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cast one primary camera ray per pixel. Diffuse hits are photon-map gather points;
|
||||||
|
// mirror and dielectric hits are queued for the later non-recursive passes.
|
||||||
|
void firstRayTracingPass()
|
||||||
|
{
|
||||||
|
PRRPM::f32 screenRatio = (PRRPM::f32)imageWidth / (PRRPM::f32)imageHeight;
|
||||||
|
PRRPM::f32 inverseWidth = 1.0f / (PRRPM::f32)imageWidth;
|
||||||
|
PRRPM::f32 inverseHeight = 1.0f / (PRRPM::f32)imageHeight;
|
||||||
|
PRRPM::f32 inverseWidthOverTwo = inverseWidth / 4.0f;
|
||||||
|
PRRPM::f32 inverseHeightOverTwo = inverseHeight / 2.0f;
|
||||||
|
|
||||||
|
for (ui32 y = 0; y < imageHeight; ++y)
|
||||||
|
{
|
||||||
|
Ray ray;
|
||||||
|
unsigned int yPixel = y * imageWidth;
|
||||||
|
|
||||||
|
for (ui32 x = 0; x < imageWidth; ++x)
|
||||||
|
{
|
||||||
|
|
||||||
|
ray.direction.x = ((x + inverseWidthOverTwo) * inverseWidth - 0.5) * screenRatio;
|
||||||
|
ray.direction.y = ((y + inverseHeightOverTwo) * inverseHeight - 0.5);
|
||||||
|
ray.direction.z = screenRatio;
|
||||||
|
ray.direction.normalize();
|
||||||
|
ray.origin = Vector3d(0.0, 0.0, 0.0);
|
||||||
|
ray.objectID = -1;
|
||||||
|
ray.distance = maxSceneDepth;
|
||||||
|
|
||||||
|
intersectObjects(&ray);
|
||||||
|
if (ray.objectID != -1)
|
||||||
|
{
|
||||||
|
PRRPM::ui32 index = x + (y * imageWidth);
|
||||||
|
if (getObjectMaterial(ray.objectID, ray.objectType) == 0)
|
||||||
|
{
|
||||||
|
PRRPM::Vector3d color = getObjectColor(ray.objectID, ray.objectType);
|
||||||
|
int cellID = computeCellID(ray.intersectionPosition);
|
||||||
|
if (cellID >= 0 && cellID < gridSize)
|
||||||
|
{
|
||||||
|
intersectionPointsList[index].color = color;
|
||||||
|
intersectionPointsList[index].positionAndOrigin = ray.intersectionPosition;
|
||||||
|
intersectionPointsList[index].normal = getSurfaceNormal(ray);
|
||||||
|
intersectionPointsList[index].pixelIndex = x + yPixel;
|
||||||
|
intersectionPointsList[index].cellID = cellID;
|
||||||
|
// intersectionPointsList[index].materialID = 0;
|
||||||
|
|
||||||
|
intersectionPointsList[index].radiusSquare = irridianceRadiusSquare;
|
||||||
|
intersectionPointsList[index].nubmerOfPhotonAndMaterialID = 0;
|
||||||
|
intersectionPointsList[index].fluxAndDirection = Vector3d();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (getObjectMaterial(ray.objectID, ray.objectType) == 1)
|
||||||
|
{
|
||||||
|
PRRPM::Vector3d normal = getSurfaceNormal(ray);
|
||||||
|
intersectionPointsList[index].positionAndOrigin = ray.intersectionPosition;
|
||||||
|
intersectionPointsList[index].fluxAndDirection =
|
||||||
|
ray.direction - normal * normal.dot(ray.direction) * 2.0f;
|
||||||
|
intersectionPointsList[index].pixelIndex = x + yPixel;
|
||||||
|
intersectionPointsList[index].nubmerOfPhotonAndMaterialID = 1;
|
||||||
|
}
|
||||||
|
else if (getObjectMaterial(ray.objectID, ray.objectType) == 2)
|
||||||
|
{
|
||||||
|
intersectionPointsList[index].positionAndOrigin = ray.intersectionPosition;
|
||||||
|
intersectionPointsList[index].normal = getSurfaceNormal(ray);
|
||||||
|
intersectionPointsList[index].pixelIndex = x + yPixel;
|
||||||
|
intersectionPointsList[index].fluxAndDirection = ray.direction;
|
||||||
|
intersectionPointsList[index].color =
|
||||||
|
getObjectColor(ray.objectID, ray.objectType);
|
||||||
|
intersectionPointsList[index].nubmerOfPhotonAndMaterialID = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepareIntersectionPointsList()
|
||||||
|
{
|
||||||
|
// -1 cell/pixel indices mark pixels that did not produce a valid gather point.
|
||||||
|
intersectionPointsList.resize((imageWidth * imageHeight));
|
||||||
|
PRRPM::IntersectionPoint intersectionPoint;
|
||||||
|
intersectionPoint.color = PRRPM::Vector3d();
|
||||||
|
intersectionPoint.positionAndOrigin = PRRPM::Vector3d();
|
||||||
|
intersectionPoint.normal = PRRPM::Vector3d();
|
||||||
|
intersectionPoint.pixelIndex = -1;
|
||||||
|
intersectionPoint.cellID = -1;
|
||||||
|
intersectionPoint.radiusSquare = irridianceRadiusSquare;
|
||||||
|
intersectionPoint.nubmerOfPhotonAndMaterialID = 0;
|
||||||
|
intersectionPoint.fluxAndDirection = PRRPM::Vector3d();
|
||||||
|
std::fill(intersectionPointsList.begin(),
|
||||||
|
intersectionPointsList.begin() + (imageWidth * imageHeight), intersectionPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rayTracingPass()
|
||||||
|
{
|
||||||
|
firstRayTracingPass();
|
||||||
|
|
||||||
|
for (ui32 iPoint = 0; iPoint < intersectionPointsList.size(); ++iPoint)
|
||||||
|
{
|
||||||
|
if (intersectionPointsList[iPoint].nubmerOfPhotonAndMaterialID != 0)
|
||||||
|
{
|
||||||
|
PRRPM::IntersectionPoint intersectionPoint = intersectionPointsList[iPoint];
|
||||||
|
intersectionPoint.nubmerOfPhotonAndMaterialID = -2;
|
||||||
|
secondIntersectionPointsList.push_back(intersectionPoint);
|
||||||
|
secondIntersectionPointsList.push_back(intersectionPointsList[iPoint]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seed the work list with secondary paths, then advance it a fixed number of bounces.
|
||||||
|
calculateReflectionFractionForAllPoints();
|
||||||
|
|
||||||
|
for (ui32 iBounce = 1; iBounce < 5; ++iBounce)
|
||||||
|
{
|
||||||
|
for (ui32 iPoints = 0; iPoints < secondIntersectionPointsList.size(); ++iPoints)
|
||||||
|
nextRayTracingPass(iPoints);
|
||||||
|
|
||||||
|
for (ui32 iPoint = 0; iPoint < secondIntersectionPointsList.size(); ++iPoint)
|
||||||
|
{
|
||||||
|
if (secondIntersectionPointsList[iPoint].nubmerOfPhotonAndMaterialID == 0)
|
||||||
|
intersectionPointsList.push_back(secondIntersectionPointsList[iPoint]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(secondIntersectionPointsList.begin(), secondIntersectionPointsList.end(),
|
||||||
|
compareByCellID);
|
||||||
|
ui32 numberOfNonDiffusedPoint = int(std::count_if(
|
||||||
|
secondIntersectionPointsList.begin(), secondIntersectionPointsList.end(), isCellIDOut));
|
||||||
|
secondIntersectionPointsList.erase(
|
||||||
|
secondIntersectionPointsList.end() -
|
||||||
|
(secondIntersectionPointsList.size() - numberOfNonDiffusedPoint),
|
||||||
|
secondIntersectionPointsList.end());
|
||||||
|
|
||||||
|
std::vector<PRRPM::IntersectionPoint> tempsecondIntersectionPointsList;
|
||||||
|
for (ui32 iPoint = 0; iPoint < secondIntersectionPointsList.size(); ++iPoint)
|
||||||
|
{
|
||||||
|
PRRPM::IntersectionPoint intersectionPoint;
|
||||||
|
intersectionPoint.nubmerOfPhotonAndMaterialID = -2;
|
||||||
|
tempsecondIntersectionPointsList.push_back(intersectionPoint);
|
||||||
|
tempsecondIntersectionPointsList.push_back(secondIntersectionPointsList[iPoint]);
|
||||||
|
}
|
||||||
|
|
||||||
|
secondIntersectionPointsList.clear();
|
||||||
|
secondIntersectionPointsList = tempsecondIntersectionPointsList;
|
||||||
|
calculateReflectionFractionForAllPoints();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void findPointAndComputeFlux(const Ray& photonRay, const PRRPM::Vector3d& color)
|
||||||
|
{
|
||||||
|
// Gather this photon into nearby camera gather points and shrink their radii as they
|
||||||
|
// accumulate.
|
||||||
|
PRRPM::Vector3d surfaceNormal = getSurfaceNormal(photonRay);
|
||||||
|
for (std::size_t iNeighbor = 0; iNeighbor < std::size(neighborsDirection); ++iNeighbor)
|
||||||
|
{
|
||||||
|
int cellID = computeCellID(photonRay.intersectionPosition + neighborsDirection[iNeighbor]);
|
||||||
|
if (cellID < 0 || cellID >= gridSize)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const int firstCell = hastValueList[cellID];
|
||||||
|
if (firstCell >= 0)
|
||||||
|
{
|
||||||
|
std::size_t pointIndex = static_cast<std::size_t>(firstCell);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
|
||||||
|
Vector3d distanceVector = intersectionPointsList[pointIndex].positionAndOrigin -
|
||||||
|
photonRay.intersectionPosition;
|
||||||
|
f32 distance = distanceVector.dot(distanceVector);
|
||||||
|
IntersectionPoint* intersectionPoint = &intersectionPointsList[pointIndex];
|
||||||
|
f32 dotNormals = intersectionPoint->normal.dot(surfaceNormal);
|
||||||
|
if (dotNormals > -0.001 && distance <= intersectionPoint->radiusSquare)
|
||||||
|
{
|
||||||
|
f32 radiusReductionCoefficient =
|
||||||
|
(intersectionPointsList[pointIndex].nubmerOfPhotonAndMaterialID * alpha +
|
||||||
|
alpha) /
|
||||||
|
(intersectionPoint->nubmerOfPhotonAndMaterialID * alpha + 1.0);
|
||||||
|
intersectionPoint->radiusSquare *= radiusReductionCoefficient;
|
||||||
|
++intersectionPoint->nubmerOfPhotonAndMaterialID;
|
||||||
|
intersectionPoint->fluxAndDirection =
|
||||||
|
(intersectionPoint->fluxAndDirection +
|
||||||
|
intersectionPoint->color * color * MathUtility::InverstPI) *
|
||||||
|
radiusReductionCoefficient;
|
||||||
|
}
|
||||||
|
++pointIndex;
|
||||||
|
if (pointIndex >= intersectionPointsList.size() ||
|
||||||
|
intersectionPointsList[pointIndex].cellID != cellID)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void photonCasting(std::default_random_engine& randomNumberGenerator,
|
||||||
|
const LightSource& lightSource)
|
||||||
|
{
|
||||||
|
std::uniform_real_distribution<f32> uniform(0.0, 1.0);
|
||||||
|
|
||||||
|
PRRPM::Ray photonRay;
|
||||||
|
generatePhotonRayFromLighSource(&photonRay, lightSource, randomNumberGenerator);
|
||||||
|
photonRay.objectID = -1;
|
||||||
|
photonRay.distance = maxSceneDepth;
|
||||||
|
|
||||||
|
ui8 bounces = 0;
|
||||||
|
Vector3d color = lightSource.intensity;
|
||||||
|
bool isRefraction = false;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
intersectObjects(&photonRay);
|
||||||
|
if (photonRay.objectID != -1)
|
||||||
|
{
|
||||||
|
Vector3d objectColor = getObjectColor(photonRay.objectID, photonRay.objectType);
|
||||||
|
ui8 objectMaterialID = getObjectMaterial(photonRay.objectID, photonRay.objectType);
|
||||||
|
if (objectMaterialID == 0)
|
||||||
|
{
|
||||||
|
// Diffuse hits contribute flux; the next direction is sampled from the hemisphere.
|
||||||
|
findPointAndComputeFlux(photonRay, color);
|
||||||
|
++bounces;
|
||||||
|
f32 reflectionProbability =
|
||||||
|
std::max(objectColor.x, std::max(objectColor.y, objectColor.z));
|
||||||
|
if (bounces >= numberOfBounces ||
|
||||||
|
(bounces > 1 && uniform(randomNumberGenerator) <= reflectionProbability))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (isRefraction)
|
||||||
|
{
|
||||||
|
color = lightSource.intensity;
|
||||||
|
isRefraction = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
color = color * getObjectColor(photonRay.objectID, photonRay.objectType) /
|
||||||
|
reflectionProbability; // * 0.7f;
|
||||||
|
|
||||||
|
f32 r1 = MathUtility::TwoPI * uniform(randomNumberGenerator);
|
||||||
|
f32 r2 = uniform(randomNumberGenerator);
|
||||||
|
f32 r2s = sqrtf(r2);
|
||||||
|
PRRPM::Vector3d tempNormal = getSurfaceNormal(photonRay);
|
||||||
|
if (tempNormal.dot(photonRay.direction) >= 0)
|
||||||
|
tempNormal = tempNormal * -1.0f;
|
||||||
|
PRRPM::Vector3d w = tempNormal;
|
||||||
|
PRRPM::Vector3d u = PRRPM::Vector3d(1, 0, 0);
|
||||||
|
|
||||||
|
if (fabs(w.x) > 0.1)
|
||||||
|
u = PRRPM::Vector3d(0, 1, 0);
|
||||||
|
|
||||||
|
u = u.cross(w);
|
||||||
|
u.normalize();
|
||||||
|
PRRPM::Vector3d v = w.cross(u);
|
||||||
|
photonRay.direction =
|
||||||
|
u * cosf(r1) * r2s + v * sinf(r1) * r2s + w * sqrtf(1.0f - r2);
|
||||||
|
photonRay.direction.normalize();
|
||||||
|
|
||||||
|
photonRay.origin = photonRay.intersectionPosition;
|
||||||
|
photonRay.objectID = -1;
|
||||||
|
photonRay.distance = maxSceneDepth;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (objectMaterialID == 1)
|
||||||
|
{
|
||||||
|
// Mirror material: reflect the photon and continue its path.
|
||||||
|
PRRPM::Vector3d normal = getSurfaceNormal(photonRay);
|
||||||
|
photonRay.direction =
|
||||||
|
photonRay.direction - normal * normal.dot(photonRay.direction) * 2.0;
|
||||||
|
photonRay.origin = photonRay.intersectionPosition;
|
||||||
|
photonRay.objectID = -1;
|
||||||
|
photonRay.distance = maxSceneDepth;
|
||||||
|
++bounces;
|
||||||
|
if (bounces >= numberOfBounces)
|
||||||
|
break;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (objectMaterialID == 2)
|
||||||
|
{
|
||||||
|
// Dielectric material: choose reflection or refraction using Fresnel probability.
|
||||||
|
|
||||||
|
PRRPM::Vector3d reflectionRayDirection;
|
||||||
|
PRRPM::Vector3d refractionRayDirection;
|
||||||
|
f32 cosOutAngle;
|
||||||
|
f32 reflectionIntensity;
|
||||||
|
calculateReflectionFractionDirection(
|
||||||
|
photonRay.direction, getSurfaceNormal(photonRay), &reflectionRayDirection,
|
||||||
|
&refractionRayDirection, &cosOutAngle, &reflectionIntensity);
|
||||||
|
if (cosOutAngle < 0)
|
||||||
|
{
|
||||||
|
photonRay.origin = photonRay.intersectionPosition;
|
||||||
|
photonRay.direction = reflectionRayDirection;
|
||||||
|
photonRay.objectID = -1;
|
||||||
|
photonRay.distance = maxSceneDepth;
|
||||||
|
++bounces;
|
||||||
|
if (bounces >= numberOfBounces)
|
||||||
|
break;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
photonRay.origin = photonRay.intersectionPosition;
|
||||||
|
if (uniform(randomNumberGenerator) >= reflectionIntensity)
|
||||||
|
{
|
||||||
|
photonRay.direction = refractionRayDirection;
|
||||||
|
color = getObjectColor(photonRay.objectID, photonRay.objectType) *
|
||||||
|
lightSource.intensity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
photonRay.direction = reflectionRayDirection;
|
||||||
|
color = getObjectColor(photonRay.objectID, photonRay.objectType);
|
||||||
|
}
|
||||||
|
photonRay.objectID = -1;
|
||||||
|
photonRay.distance = maxSceneDepth;
|
||||||
|
isRefraction = true;
|
||||||
|
++bounces;
|
||||||
|
if (bounces >= numberOfBounces)
|
||||||
|
break;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void photonCastingPass()
|
||||||
|
{
|
||||||
|
if (lightSourcesList.empty())
|
||||||
|
{
|
||||||
|
std::cerr << "No light sources defined in the scene\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each pass launches a fresh set of photons; progress is updated in place on the console.
|
||||||
|
for (ui32 iPhotonPass = 0; iPhotonPass < numberOfPhotonPass; ++iPhotonPass)
|
||||||
|
{
|
||||||
|
std::default_random_engine randomNumberGenerator;
|
||||||
|
for (ui32 iPhoton = 0; iPhoton < numberOfPhotons; ++iPhoton)
|
||||||
|
{
|
||||||
|
LightSource lightSource = lightSourcesList[iPhoton % lightSourcesList.size()];
|
||||||
|
photonCasting(randomNumberGenerator, lightSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\rPass: " << iPhotonPass + 1 << '/' << numberOfPhotonPass << std::flush;
|
||||||
|
}
|
||||||
|
std::cout << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the spatial hash table for efficient photon gathering.
|
||||||
|
void buildHashTable()
|
||||||
|
{
|
||||||
|
// Sort gather points by cell so each hash entry can point to the start of its cell's range.
|
||||||
|
std::sort(intersectionPointsList.begin(), intersectionPointsList.end(), compareByCellID);
|
||||||
|
PRRPM::ui32 numberOfNonDiffusedPoint = int(
|
||||||
|
std::count_if(intersectionPointsList.begin(), intersectionPointsList.end(), isCellIDOut));
|
||||||
|
intersectionPointsList.erase(intersectionPointsList.begin(),
|
||||||
|
intersectionPointsList.begin() + numberOfNonDiffusedPoint);
|
||||||
|
|
||||||
|
hastValueList.resize(gridSize);
|
||||||
|
std::fill(hastValueList.begin(), hastValueList.begin() + gridSize, -1);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < intersectionPointsList.size(); ++i)
|
||||||
|
{
|
||||||
|
const int cellID = intersectionPointsList[i].cellID;
|
||||||
|
if (hastValueList[cellID] == -1)
|
||||||
|
hastValueList[cellID] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correct the flux at each gather point to compute the final irradiance.
|
||||||
|
void fluxCorrection()
|
||||||
|
{
|
||||||
|
// Convert accumulated photon flux to irradiance using each gather point's final disk area.
|
||||||
|
imageBufferList.resize((imageWidth * imageHeight));
|
||||||
|
std::fill(imageBufferList.begin(), imageBufferList.begin() + (imageWidth * imageHeight),
|
||||||
|
Vector3d(0, 0, 0));
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < intersectionPointsList.size(); ++i)
|
||||||
|
{
|
||||||
|
const int pixelIndex = intersectionPointsList[i].pixelIndex;
|
||||||
|
imageBufferList[pixelIndex] =
|
||||||
|
imageBufferList[pixelIndex] +
|
||||||
|
intersectionPointsList[i].fluxAndDirection *
|
||||||
|
(1.0 / (MathUtility::PI * intersectionPointsList[i].radiusSquare * numberOfPhotons *
|
||||||
|
numberOfPhotonPass));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveImage(void)
|
||||||
|
{
|
||||||
|
const std::size_t expectedPixelCount = static_cast<std::size_t>(imageWidth) * imageHeight;
|
||||||
|
if (imageBufferList.size() != expectedPixelCount)
|
||||||
|
{
|
||||||
|
std::cerr << "Image buffer size does not match image dimensions\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert linear floating-point RGB into display-encoded 8-bit RGB for the BMP writer.
|
||||||
|
std::vector<unsigned char> pixels(imageBufferList.size() * 3);
|
||||||
|
const auto toByte = [](f32 channel)
|
||||||
|
{
|
||||||
|
channel = std::clamp(channel, 0.0f, 1.0f);
|
||||||
|
const f32 srgb = channel <= 0.0031308f ? 12.92f * channel
|
||||||
|
: 1.055f * std::pow(channel, 1.0f / 2.4f) - 0.055f;
|
||||||
|
return static_cast<unsigned char>(std::lround(srgb * 255.0f));
|
||||||
|
};
|
||||||
|
|
||||||
|
for (std::size_t y = 0; y < imageHeight; ++y)
|
||||||
|
{
|
||||||
|
// Camera rows increase upward; image files store the top row first.
|
||||||
|
const std::size_t sourceRow = imageHeight - 1 - y;
|
||||||
|
for (std::size_t x = 0; x < imageWidth; ++x)
|
||||||
|
{
|
||||||
|
const std::size_t sourceIndex = sourceRow * imageWidth + x;
|
||||||
|
const std::size_t targetIndex = (y * imageWidth + x) * 3;
|
||||||
|
pixels[targetIndex] = toByte(imageBufferList[sourceIndex].x);
|
||||||
|
pixels[targetIndex + 1] = toByte(imageBufferList[sourceIndex].y);
|
||||||
|
pixels[targetIndex + 2] = toByte(imageBufferList[sourceIndex].z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stbi_write_bmp(outFileName.c_str(), static_cast<int>(imageWidth),
|
||||||
|
static_cast<int>(imageHeight), 3, pixels.data()))
|
||||||
|
std::cerr << "Failed to write image: " << outFileName << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanUp(void)
|
||||||
|
{
|
||||||
|
// delete[] imageBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayItroAndInfo(void)
|
||||||
|
{
|
||||||
|
std::cout << " Scene Information";
|
||||||
|
std::cout << "\n Number of triangles : " << triangleList.size();
|
||||||
|
std::cout << "\n Light : ";
|
||||||
|
if (isLightOn)
|
||||||
|
std::cout << "on";
|
||||||
|
else
|
||||||
|
std::cout << "off";
|
||||||
|
std::cout << "\n Image size : " << imageWidth << " X " << imageHeight;
|
||||||
|
std::cout << "\n Output file : " << outFileName << "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc != 3)
|
||||||
|
{
|
||||||
|
std::cerr << "Usage: " << argv[0] << " <scene-file> <output-file>\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::filesystem::path sceneFilePath = argv[1];
|
||||||
|
outFileName = argv[2];
|
||||||
|
|
||||||
|
if (!loadSceneFile(sceneFilePath.string()))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
displayItroAndInfo();
|
||||||
|
|
||||||
|
// Pipeline: trace camera paths, build the photon lookup table, cast photons, then write output.
|
||||||
|
const auto renderingStart = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
prepareIntersectionPointsList();
|
||||||
|
|
||||||
|
std::cout << "raytracing:1:start\n";
|
||||||
|
rayTracingPass();
|
||||||
|
std::cout << "raytracing:1:done\nphotontracing:start\n";
|
||||||
|
|
||||||
|
buildHashTable();
|
||||||
|
|
||||||
|
photonCastingPass();
|
||||||
|
|
||||||
|
std::cout << "photontracing:done\n";
|
||||||
|
|
||||||
|
// return 0;
|
||||||
|
|
||||||
|
fluxCorrection();
|
||||||
|
|
||||||
|
const auto renderingEnd = std::chrono::steady_clock::now();
|
||||||
|
const double totalRenderingTime =
|
||||||
|
std::chrono::duration<double, std::milli>(renderingEnd - renderingStart).count();
|
||||||
|
std::cout << "renderingtime:" << totalRenderingTime << std::endl;
|
||||||
|
|
||||||
|
// Save result image buffer in file
|
||||||
|
saveImage();
|
||||||
|
cleanUp();
|
||||||
|
std::cout << "done\n";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#include "prrpm.h"
|
||||||
|
|
||||||
|
namespace PRRPM
|
||||||
|
{
|
||||||
|
ui32 imageWidth = 800;
|
||||||
|
ui32 imageHeight = 800;
|
||||||
|
ui32 numberOfPhotons = 1000;
|
||||||
|
ui32 numberOfPhotonPass = 1000;
|
||||||
|
ui32 numberOfBounces = 5;
|
||||||
|
std::string outFileName = "output.bmp";
|
||||||
|
std::vector<Vector3d> imageBufferList;
|
||||||
|
bool isLightOn = true;
|
||||||
|
bool isPhotonMapping = true;
|
||||||
|
bool isGUI = true;
|
||||||
|
|
||||||
|
Vector3d neighborsDirection[27] = {
|
||||||
|
Vector3d(0.0, 0.0, 0.0), Vector3d(0.004, 0.0, 0.0),
|
||||||
|
Vector3d(-0.004, 0.0, 0.0), Vector3d(0.0, 0.004, 0.0),
|
||||||
|
Vector3d(0.0, -0.004, 0.0), Vector3d(0.004, 0.004, 0.0),
|
||||||
|
Vector3d(-0.004, 0.004, 0.0), Vector3d(0.004, -0.004, 0.0),
|
||||||
|
Vector3d(-0.004, -0.004, 0.0),
|
||||||
|
|
||||||
|
Vector3d(0.004, 0.0, 0.004), Vector3d(-0.004, 0.0, 0.004),
|
||||||
|
Vector3d(0.0, 0.004, 0.004), Vector3d(0.0, -0.004, 0.004),
|
||||||
|
Vector3d(0.004, 0.004, 0.004), Vector3d(-0.004, 0.004, 0.004),
|
||||||
|
Vector3d(0.004, -0.004, 0.004), Vector3d(-0.004, -0.004, 0.004),
|
||||||
|
|
||||||
|
Vector3d(0.004, 0.0, -0.004), Vector3d(-0.004, 0.0, -0.004),
|
||||||
|
Vector3d(0.0, 0.004, -0.004), Vector3d(0.0, -0.004, -0.004),
|
||||||
|
Vector3d(0.004, 0.004, -0.004), Vector3d(-0.004, 0.004, -0.004),
|
||||||
|
Vector3d(0.004, -0.004, -0.004), Vector3d(-0.004, -0.004, -0.004),
|
||||||
|
|
||||||
|
Vector3d(0.0, 0.0, -0.004), Vector3d(0.0, 0.0, 0.004)};
|
||||||
|
|
||||||
|
std::vector<Triangle> triangleList;
|
||||||
|
std::vector<Sphere> sphereList;
|
||||||
|
std::vector<LightSource> lightSourcesList;
|
||||||
|
std::vector<IntersectionPoint> intersectionPointsList;
|
||||||
|
std::vector<IntersectionPoint> secondIntersectionPointsList;
|
||||||
|
std::vector<int> hastValueList;
|
||||||
|
} // namespace PRRPM
|
||||||
+322
@@ -0,0 +1,322 @@
|
|||||||
|
|
||||||
|
/************************************************************
|
||||||
|
Title : A Photo-realistic Renderer Based on Photon Mapping
|
||||||
|
Students : Davood Rasti
|
||||||
|
Alireza Rasti
|
||||||
|
|
||||||
|
Version : 0.01
|
||||||
|
Date : 23-06-2012
|
||||||
|
Updated : 01-10-2026
|
||||||
|
*************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "./3rdparty/stb_collection/stb_image.h"
|
||||||
|
#include "vector3d.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace PRRPM
|
||||||
|
{
|
||||||
|
|
||||||
|
// Structures
|
||||||
|
struct Ray
|
||||||
|
{
|
||||||
|
Vector3d origin;
|
||||||
|
Vector3d direction;
|
||||||
|
int objectID;
|
||||||
|
ui32 objectType;
|
||||||
|
Vector3d intersectionPosition;
|
||||||
|
f32 distance;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Triangle
|
||||||
|
{
|
||||||
|
Vector3d point1;
|
||||||
|
Vector3d point2;
|
||||||
|
Vector3d point3;
|
||||||
|
Vector3d color;
|
||||||
|
Vector3d normal;
|
||||||
|
ui8 materialID;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sphere
|
||||||
|
{
|
||||||
|
Vector3d position;
|
||||||
|
float radius;
|
||||||
|
Vector3d color;
|
||||||
|
ui32 numberOfSpheres;
|
||||||
|
ui8 materialID;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IntersectionPoint
|
||||||
|
{
|
||||||
|
Vector3d color;
|
||||||
|
Vector3d positionAndOrigin;
|
||||||
|
Vector3d normal;
|
||||||
|
Vector3d fluxAndDirection;
|
||||||
|
f32 radiusSquare;
|
||||||
|
i32 nubmerOfPhotonAndMaterialID;
|
||||||
|
int pixelIndex;
|
||||||
|
int cellID;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LightSource
|
||||||
|
{
|
||||||
|
ui8 type;
|
||||||
|
Vector3d position;
|
||||||
|
Vector3d intensity;
|
||||||
|
Vector3d size;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ui32 imageWidth;
|
||||||
|
extern ui32 imageHeight;
|
||||||
|
extern ui32 numberOfPhotons;
|
||||||
|
extern ui32 numberOfPhotonPass;
|
||||||
|
extern ui32 numberOfBounces;
|
||||||
|
inline constexpr f32 maxSceneDepth = 1000.0f;
|
||||||
|
inline constexpr f32 alpha = 0.7f;
|
||||||
|
extern std::string outFileName;
|
||||||
|
extern std::vector<Vector3d> imageBufferList;
|
||||||
|
extern bool isLightOn;
|
||||||
|
extern bool isPhotonMapping;
|
||||||
|
extern bool isGUI;
|
||||||
|
inline constexpr f32 refractiveIndexIn = 1.0f;
|
||||||
|
inline constexpr f32 refractiveIndexOut = 1.5f;
|
||||||
|
|
||||||
|
inline constexpr int gridSize = 16000000;
|
||||||
|
inline constexpr f32 irridianceRadiusSquare = 0.000016f;
|
||||||
|
inline constexpr int numberOfGridCell = 250;
|
||||||
|
inline constexpr int numberOfGridCellXY = 252;
|
||||||
|
inline constexpr int numberOfGridCellXMY = 63000;
|
||||||
|
|
||||||
|
extern Vector3d neighborsDirection[27];
|
||||||
|
extern std::vector<Triangle> triangleList;
|
||||||
|
extern std::vector<Sphere> sphereList;
|
||||||
|
extern std::vector<LightSource> lightSourcesList;
|
||||||
|
extern std::vector<IntersectionPoint> intersectionPointsList;
|
||||||
|
extern std::vector<IntersectionPoint> secondIntersectionPointsList;
|
||||||
|
extern std::vector<int> hastValueList;
|
||||||
|
|
||||||
|
inline bool compareByCellID(const IntersectionPoint& firstPoint,
|
||||||
|
const IntersectionPoint& secondPoint)
|
||||||
|
{
|
||||||
|
return (firstPoint.cellID < secondPoint.cellID);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool compareByMetalID(const IntersectionPoint& firstPoint,
|
||||||
|
const IntersectionPoint& secondPoint)
|
||||||
|
{
|
||||||
|
return (firstPoint.nubmerOfPhotonAndMaterialID < secondPoint.nubmerOfPhotonAndMaterialID);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isCellIDOut(const IntersectionPoint& point)
|
||||||
|
{
|
||||||
|
return (point.cellID == -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isMetalIDOut(const IntersectionPoint& point)
|
||||||
|
{
|
||||||
|
return (point.nubmerOfPhotonAndMaterialID == -2);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int computeCellID(const Vector3d& position)
|
||||||
|
{
|
||||||
|
int x = (position.x + 0.6) * numberOfGridCell;
|
||||||
|
int y = (position.y + 0.6) * numberOfGridCell;
|
||||||
|
int z = (position.z - 1.0) * numberOfGridCell;
|
||||||
|
return (z * numberOfGridCellXMY + y * numberOfGridCellXY + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void generatePhotonRayFromLighSource(Ray* ray, const LightSource& lightSource,
|
||||||
|
std::default_random_engine& randomNumberGenerator)
|
||||||
|
{
|
||||||
|
std::uniform_real_distribution<f32> uniform(0.0, 1.0);
|
||||||
|
|
||||||
|
if (lightSource.type == 0)
|
||||||
|
{
|
||||||
|
f32 u = MathUtility::TwoPI * uniform(randomNumberGenerator);
|
||||||
|
f32 v = acosf(sqrtf(uniform(randomNumberGenerator))) * 2.0;
|
||||||
|
f32 w = sinf(v);
|
||||||
|
ray->direction = Vector3d(cosf(u) * w, cosf(v), sinf(u) * w);
|
||||||
|
ray->origin = lightSource.position;
|
||||||
|
}
|
||||||
|
else if (lightSource.type == 1)
|
||||||
|
{
|
||||||
|
std::uniform_real_distribution<f32> uniformX(-lightSource.size.x, lightSource.size.x);
|
||||||
|
std::uniform_real_distribution<f32> uniformZ(-lightSource.size.z, lightSource.size.z);
|
||||||
|
std::uniform_real_distribution<f32> uniformNP(-1.0, 1.0);
|
||||||
|
|
||||||
|
f32 u = uniform(randomNumberGenerator);
|
||||||
|
f32 v = MathUtility::TwoPI * uniform(randomNumberGenerator);
|
||||||
|
f32 uSquare = sqrtf(u);
|
||||||
|
f32 x = cosf(v) * uSquare;
|
||||||
|
f32 y = sin(v) * uSquare;
|
||||||
|
f32 z = sqrtf(1.0 - u);
|
||||||
|
|
||||||
|
ray->direction = Vector3d(x, -y, z * uniformNP(randomNumberGenerator));
|
||||||
|
|
||||||
|
ray->origin.x = uniformX(randomNumberGenerator);
|
||||||
|
ray->origin.y = 0;
|
||||||
|
ray->origin.z = uniformZ(randomNumberGenerator);
|
||||||
|
ray->origin = ray->origin + lightSource.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
ray->direction.normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void intersectTriangle(Ray* ray, unsigned int triangleIndex)
|
||||||
|
{
|
||||||
|
|
||||||
|
Vector3d edge1 = triangleList[triangleIndex].point2 - triangleList[triangleIndex].point1;
|
||||||
|
Vector3d edge2 = triangleList[triangleIndex].point3 - triangleList[triangleIndex].point1;
|
||||||
|
|
||||||
|
Vector3d pVector = ray->direction.cross(edge2);
|
||||||
|
f32 determinat = edge1.dot(pVector);
|
||||||
|
|
||||||
|
if (determinat < 0.000001)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vector3d tVector = ray->origin - triangleList[triangleIndex].point1;
|
||||||
|
|
||||||
|
f32 u = tVector.dot(pVector);
|
||||||
|
|
||||||
|
if (u < 0.0 || u > determinat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vector3d qVector = tVector.cross(edge1);
|
||||||
|
|
||||||
|
f32 v = ray->direction.dot(qVector);
|
||||||
|
|
||||||
|
if (v < 0.0 || (u + v) > determinat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float inverseDeterminat = 1.0f / determinat;
|
||||||
|
|
||||||
|
float t = edge2.dot(qVector) * inverseDeterminat;
|
||||||
|
u *= inverseDeterminat;
|
||||||
|
v *= inverseDeterminat;
|
||||||
|
|
||||||
|
ray->distance = t;
|
||||||
|
ray->intersectionPosition = triangleList[triangleIndex].point1 + (edge1 * u) + (edge2 * v);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void intersectSphere(Ray* ray, unsigned int sphereIndex)
|
||||||
|
{
|
||||||
|
Vector3d dist = sphereList[sphereIndex].position - ray->origin;
|
||||||
|
f32 b = ray->direction.dot(dist);
|
||||||
|
f32 delta = b * b - dist.dot(dist) +
|
||||||
|
(sphereList[sphereIndex].radius * sphereList[sphereIndex].radius);
|
||||||
|
if (delta < 0.0f)
|
||||||
|
return;
|
||||||
|
f32 t0 = b - sqrt(delta);
|
||||||
|
f32 t1 = b + sqrt(delta);
|
||||||
|
f32 distance = maxSceneDepth;
|
||||||
|
if ((t0 > 0.001f) && (t0 < distance))
|
||||||
|
distance = t0;
|
||||||
|
else if ((t1 > 0.001f) && (t1 < distance))
|
||||||
|
distance = t1;
|
||||||
|
|
||||||
|
ray->distance = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void intersectObjects(Ray* ray)
|
||||||
|
{
|
||||||
|
Ray tempRay;
|
||||||
|
tempRay.direction = ray->direction;
|
||||||
|
tempRay.origin = ray->origin;
|
||||||
|
tempRay.distance = maxSceneDepth;
|
||||||
|
ray->distance = maxSceneDepth;
|
||||||
|
|
||||||
|
for (unsigned int iTriangle = 0; iTriangle < triangleList.size(); ++iTriangle)
|
||||||
|
{
|
||||||
|
intersectTriangle(&tempRay, iTriangle);
|
||||||
|
if (tempRay.distance < ray->distance)
|
||||||
|
{
|
||||||
|
ray->intersectionPosition = tempRay.intersectionPosition;
|
||||||
|
ray->objectID = iTriangle;
|
||||||
|
ray->objectType = 0;
|
||||||
|
ray->distance = tempRay.distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tempRay.objectID = -1;
|
||||||
|
tempRay.distance = maxSceneDepth;
|
||||||
|
|
||||||
|
for (unsigned int iSphere = 0; iSphere < sphereList.size(); ++iSphere)
|
||||||
|
{
|
||||||
|
intersectSphere(&tempRay, iSphere);
|
||||||
|
if (tempRay.distance < ray->distance)
|
||||||
|
{
|
||||||
|
ray->objectID = iSphere;
|
||||||
|
ray->objectType = 1;
|
||||||
|
ray->distance = tempRay.distance;
|
||||||
|
ray->intersectionPosition = (ray->direction * ray->distance) + ray->origin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d getSurfaceNormal(const Ray& ray)
|
||||||
|
{
|
||||||
|
Vector3d surfaceNormal;
|
||||||
|
if (ray.objectType == 0)
|
||||||
|
surfaceNormal = triangleList[ray.objectID].normal;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
surfaceNormal = ray.intersectionPosition - sphereList[ray.objectID].position;
|
||||||
|
surfaceNormal.normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return surfaceNormal;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d getObjectColor(ui32 objectID, ui32 objectType)
|
||||||
|
{
|
||||||
|
if (objectType == 0)
|
||||||
|
return triangleList[objectID].color;
|
||||||
|
else
|
||||||
|
return sphereList[objectID].color;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ui8 getObjectMaterial(ui32 objectID, ui32 objectType)
|
||||||
|
{
|
||||||
|
if (objectType == 0)
|
||||||
|
return triangleList[objectID].materialID;
|
||||||
|
else
|
||||||
|
return sphereList[objectID].materialID;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void calculateReflectionFractionDirection(Vector3d rayDirection, Vector3d normal,
|
||||||
|
Vector3d* reflectionDirection,
|
||||||
|
Vector3d* refractionDirection,
|
||||||
|
f32* cosOutAngle, f32* reflectionIntensity)
|
||||||
|
{
|
||||||
|
Vector3d secondNormal;
|
||||||
|
if (normal.dot(rayDirection) < 0)
|
||||||
|
secondNormal = normal;
|
||||||
|
else
|
||||||
|
secondNormal = normal * -1;
|
||||||
|
|
||||||
|
*reflectionDirection = rayDirection - normal * normal.dot(rayDirection) * 2.0f;
|
||||||
|
|
||||||
|
bool isRayGoingToObject = (normal.dot(secondNormal) > 0.0f);
|
||||||
|
f32 refractiveIndex = isRayGoingToObject ? refractiveIndexIn / refractiveIndexOut
|
||||||
|
: refractiveIndexOut / refractiveIndexIn;
|
||||||
|
f32 cosInAngle = rayDirection.dot(secondNormal);
|
||||||
|
*cosOutAngle = 1.0f - refractiveIndex * refractiveIndex * (1.0f - cosInAngle * cosInAngle);
|
||||||
|
|
||||||
|
if (*cosOutAngle >= 0)
|
||||||
|
{
|
||||||
|
*refractionDirection = rayDirection * refractiveIndex -
|
||||||
|
normal * ((isRayGoingToObject ? 1 : -1) *
|
||||||
|
(cosInAngle * refractiveIndex + sqrt(*cosOutAngle)));
|
||||||
|
refractionDirection->normalize();
|
||||||
|
f32 reflectivity = pow((refractiveIndex - 1), 2) / pow((refractiveIndex + 1), 2);
|
||||||
|
f32 angle = (isRayGoingToObject ? -cosInAngle : refractionDirection->dot(normal));
|
||||||
|
*reflectionIntensity = reflectivity + (1.0f - reflectivity) * pow((1.0f - angle), 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace PRRPM
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
#include "./3rdparty/stb_collection/stb_image_write.h"
|
||||||
+167
@@ -0,0 +1,167 @@
|
|||||||
|
|
||||||
|
/************************************************************
|
||||||
|
Title : A Photo-realistic Renderer Based on Photon Mapping
|
||||||
|
Students : Davood Rasti
|
||||||
|
Alireza Rasti
|
||||||
|
|
||||||
|
Version : 0.01
|
||||||
|
Date : 23-06-2012
|
||||||
|
Updated : 01-10-2026
|
||||||
|
*************************************************************/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace PRRPM
|
||||||
|
{
|
||||||
|
class Vector3d
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Vector3d() = default;
|
||||||
|
|
||||||
|
constexpr Vector3d(PRRPM::f32 x, PRRPM::f32 y, PRRPM::f32 z) : x(x), y(y), z(z)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d operator+(const Vector3d& secondVector) const
|
||||||
|
{
|
||||||
|
return Vector3d(x + secondVector.x, y + secondVector.y, z + secondVector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d operator-(const Vector3d& secondVector) const
|
||||||
|
{
|
||||||
|
return Vector3d(x - secondVector.x, y - secondVector.y, z - secondVector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d operator*(const Vector3d& secondVector) const
|
||||||
|
{
|
||||||
|
return Vector3d(x * secondVector.x, y * secondVector.y, z * secondVector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d operator/(const Vector3d& secondVector) const
|
||||||
|
{
|
||||||
|
return Vector3d(x / secondVector.x, y / secondVector.y, z / secondVector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d& operator+=(const Vector3d& secondVector)
|
||||||
|
{
|
||||||
|
x += secondVector.x;
|
||||||
|
y += secondVector.y;
|
||||||
|
z += secondVector.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d& operator-=(const Vector3d& secondVector)
|
||||||
|
{
|
||||||
|
x -= secondVector.x;
|
||||||
|
y -= secondVector.y;
|
||||||
|
z -= secondVector.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d& operator*=(const Vector3d& secondVector)
|
||||||
|
{
|
||||||
|
x *= secondVector.x;
|
||||||
|
y *= secondVector.y;
|
||||||
|
z *= secondVector.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d& operator/=(const Vector3d& secondVector)
|
||||||
|
{
|
||||||
|
x /= secondVector.x;
|
||||||
|
y /= secondVector.y;
|
||||||
|
z /= secondVector.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const Vector3d& secondVector) const
|
||||||
|
{
|
||||||
|
return (x == secondVector.x && y == secondVector.y && z == secondVector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const Vector3d& secondVector) const
|
||||||
|
{
|
||||||
|
return !(*this == secondVector);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d operator+(f32 value) const
|
||||||
|
{
|
||||||
|
return Vector3d(x + value, y + value, z + value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d operator-(f32 value) const
|
||||||
|
{
|
||||||
|
return Vector3d(x - value, y - value, z - value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d operator*(f32 value) const
|
||||||
|
{
|
||||||
|
return Vector3d(x * value, y * value, z * value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d operator/(f32 value) const
|
||||||
|
{
|
||||||
|
return Vector3d(x / value, y / value, z / value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PRRPM::f32 dot(const Vector3d& secondVector) const
|
||||||
|
{
|
||||||
|
return x * secondVector.x + y * secondVector.y + z * secondVector.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PRRPM::f32 getLength() const
|
||||||
|
{
|
||||||
|
return std::sqrt(getLengthSquared());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PRRPM::f32 getLengthSquared() const
|
||||||
|
{
|
||||||
|
return x * x + y * y + z * z;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PRRPM::f32 getLengthSquard() const
|
||||||
|
{
|
||||||
|
return getLengthSquared();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PRRPM::f32 getDistance(const Vector3d& secondVector) const
|
||||||
|
{
|
||||||
|
return (*this - secondVector).getLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PRRPM::f32 getDistanceSquared(const Vector3d& secondVector) const
|
||||||
|
{
|
||||||
|
return (*this - secondVector).getLengthSquared();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PRRPM::f32 getDistanceSquard(const Vector3d& secondVector) const
|
||||||
|
{
|
||||||
|
return getDistanceSquared(secondVector);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3d cross(const Vector3d& secondVector) const
|
||||||
|
{
|
||||||
|
return Vector3d(y * secondVector.z - z * secondVector.y,
|
||||||
|
z * secondVector.x - x * secondVector.z,
|
||||||
|
x * secondVector.y - y * secondVector.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void normalize()
|
||||||
|
{
|
||||||
|
const PRRPM::f32 length = getLength();
|
||||||
|
if (length > 0.0f)
|
||||||
|
{
|
||||||
|
x /= length;
|
||||||
|
y /= length;
|
||||||
|
z /= length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRRPM::f32 x = 0.0f;
|
||||||
|
PRRPM::f32 y = 0.0f;
|
||||||
|
PRRPM::f32 z = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PRRPM
|
||||||
Reference in New Issue
Block a user