├── .gitignore ├── .gitmodules ├── README.md ├── graphics ├── perlin_noise │ ├── CMakeLists.txt │ ├── data │ │ ├── siggraph-logo-mono-flipped.jpg │ │ ├── siggraph-logo-mono.jpg │ │ ├── siggraph-logo.jpg │ │ └── stripes.png │ ├── optimize_perlin.cu │ ├── optimize_perlin_2t.cu │ ├── optimize_perlin_colorized.cu │ ├── perlin.cuh │ ├── perlin_2t.cuh │ ├── perlin_colorized.cuh │ ├── render_perlin.cu │ ├── scripts │ │ └── get_cuda_sm.sh │ ├── siggraph-logo.jpg │ ├── teg_perlin_base.py │ ├── teg_perlin_colorized_base.py │ ├── teg_perlin_colorized_threshold_fwdderiv.py │ ├── teg_perlin_colorized_thresholded.py │ ├── teg_perlin_double_threshold_fwdderiv.py │ ├── teg_perlin_double_thresholded.py │ ├── teg_perlin_noise.py │ ├── teg_perlin_threshold_deriv.py │ ├── teg_perlin_threshold_fwdderiv.py │ ├── teg_perlin_thresholded.py │ └── types.cuh └── triangulation │ ├── CMakeLists.txt │ ├── common.cuh │ ├── data │ ├── chessboard.jpg │ └── sunset.jpg │ ├── integral.py │ ├── linear.cuh │ ├── loss.py │ ├── loss_function.py │ ├── quadratic.cuh │ ├── rasterize copy.cu │ ├── scripts │ └── get_cuda_sm.sh │ ├── teg_linear_base.py │ ├── teg_linear_bilinear_base.py │ ├── teg_linear_bilinear_deriv.py │ ├── teg_linear_bilinear_integral.py │ ├── teg_linear_deriv.py │ ├── teg_linear_deriv_nodelta.py │ ├── teg_linear_integral.py │ ├── teg_linear_loss.py │ ├── teg_quadratic_base.py │ ├── teg_quadratic_deriv.py │ ├── teg_quadratic_deriv_nodelta.py │ ├── teg_quadratic_integral.py │ ├── teg_quadratic_loss.py │ ├── tegpixel.py │ ├── test.cu │ ├── triangle.cuh │ ├── triangulate_const.cu │ ├── triangulate_linear.cu │ └── triangulate_quadratic.cu ├── physics ├── __init__.py ├── billiards3d_teg.py ├── billiards3d_teg_backup.py ├── billiards3d_teg_backup2.py ├── billiards3d_teg_backupexpbasic.py ├── billiards3d_teg_backupexpflat.py ├── billiards3d_teg_backupexpround.py ├── billiards3d_teg_backupwallflat.py ├── billiards3d_teg_backupwallround.py ├── billiards_constraints.py ├── billiards_technical_test.py ├── billiards_teg.py ├── billiards_teg_derivative_weirdness.py ├── billiardsmulti_teg_backup2ball1hole2.py ├── billiardsmulti_teg_backup2ball1hole3.py ├── billiardsmulti_teg_backup2ball1hole3nodelta.py ├── billiardsmulti_teg_backup2ball1holesquare.py ├── billiardsmulti_teg_backup2ball2hole.py ├── billiardsmulti_teg_backup2ball2hole2.py ├── gaussian_rasterize.py ├── smooth.py ├── springs.py ├── stress_strain.py └── test.py ├── requirements.txt └── util ├── __init__.py └── smooth.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | pip-wheel-metadata/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | .python-version 87 | 88 | # pipenv 89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 92 | # install all needed dependencies. 93 | #Pipfile.lock 94 | 95 | # celery beat schedule file 96 | celerybeat-schedule 97 | 98 | # SageMath parsed files 99 | *.sage.py 100 | 101 | # Environments 102 | .env 103 | .venv 104 | env/ 105 | venv/ 106 | ENV/ 107 | env.bak/ 108 | venv.bak/ 109 | 110 | # Spyder project settings 111 | .spyderproject 112 | .spyproject 113 | 114 | # Rope project settings 115 | .ropeproject 116 | 117 | # mkdocs documentation 118 | /site 119 | 120 | # mypy 121 | .mypy_cache/ 122 | .dmypy.json 123 | dmypy.json 124 | 125 | # Pyre type checker 126 | .pyre/ 127 | 128 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Teg"] 2 | path = Teg 3 | url = https://github.com/ChezJrk/Teg 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Teg Applications 2 | This is a research artifact for the paper: **[Systematically Optimizing Parametric Discontinuities](https://people.csail.mit.edu/sbangaru/projects/teg-2021/)**. This repository contains the implementation for the applications of our differentiable programming language Teg. The applications include image stylization, fitting shader parameters, trajectory optimization, and optimizing physical designs. The implementation for Teg can be found at [https://github.com/ChezJrk/Teg](https://github.com/ChezJrk/Teg). 3 | 4 | ## Setup 5 | To install the necessary Python packages run: 6 | ``` 7 | pip install -r requirements.txt 8 | ``` 9 | 10 | ## Optimizing Physical Design 11 | We study optimization of discontinuous parameters that control a physical design. 12 | We consider an idealized series of bungee cords that deform. 13 | After deformation, a string prevents further extension of the spring. 14 | We jointly minimize the time and acceleration of a person connected to this bungee-string system. 15 | We optimize the spring constants $k_1, k_2$ and the lengths of the strings $l_1, l_2$. 16 | We add the hard constraint that the person does not hit the ground to prevent death. 17 | 18 | To optimize using derivatives computed by Teg run: 19 | ``` 20 | python3 physics/springs.py 21 | ``` 22 | 23 | To optimize using Teg, but ignoring the derivative contribution from the discontinuities (as would be done in PyTorch, TensorFlow, etc.) run: 24 | ``` 25 | python3 physics/springs.py --ignore_deltas 26 | ``` 27 | 28 | To optimize using derivatives estimated using finite differences run: 29 | ``` 30 | python3 physics/springs.py --finite_diff 31 | ``` 32 | 33 | Running each of these should take more than a few minutes. 34 | 35 | ## Image triangulation 36 | This application approximates images with a colored triangle mesh, by formulating and minimizing an energy function over possible triangulations. 37 | Our implementation generates a device kernel for the energy of a single triangle-pixel pair and its derivative using the Teg differentiable programming language. We then call this function from a CUDA kernel for maximum performance. 38 | 39 | Compile the device code using (requires a CUDA toolkit installation): 40 | ``` 41 | mkdir graphics/triangulation/build && cd graphics/triangulation/build 42 | cmake .. 43 | make 44 | ``` 45 | (The build process also applies the necessary code transformations and compiles Teg functions, and therefore can take some time to complete.) 46 | 47 | To run the triangulation applications, use the following commands: 48 | 49 | (Constant color fragments) 50 | ``` 51 | ./triangulate_const 52 | ``` 53 | 54 | (Linear color fragments) 55 | ``` 56 | ./triangulate_linear 57 | ``` 58 | 59 | (Quadratic color fragments) 60 | ``` 61 | ./triangulate_quadratic 62 | ``` 63 | 64 | ## Thresholded Perlin shader optimization 65 | This application optimized the parameters of a thresholded Perlin shader to match a certain reference or guide image. 66 | We model such a thresholded shader by first generating Perlin noise (read more [https://adrianb.io/2014/08/09/perlinnoise.html](here)) 67 | and then colorizing the region with negative and positive noise values with a specific color (C_+ and C_- in the paper). 68 | 69 | For simplicity, we first calculate the value of the noise function at the four corners of each pixel and use bilinear interpolation to calculate noise values at continuous points within each pixel. 70 | 71 | As is the case for triangulation, the shader program is compiled for a single pixel and paralleized through a CUDA kernel. 72 | 73 | Compile the device code using (requires a CUDA toolkit installation): 74 | ``` 75 | mkdir graphics/perlin_noise/build && cd graphics/perlin_noise/build 76 | cmake .. 77 | make 78 | ``` 79 | 80 | To run the noise optimization (from the build folder) for the two-tone shader (two colors, one for positive and one for negative space) 81 | ``` 82 | ./optimize_perlin 83 | ``` 84 | grid-nx and grid-ny must perfectly divide the width and height respectively. Use seed=0 and learning-rate=1e-3 for default values. 85 | 86 | For another version of the shader that added a per-pixel color map for added representative power, use 87 | ``` 88 | ./optimize_perlin_colorized 89 | ``` 90 | 91 | ## Citation 92 | ``` 93 | @article{BangaruMichel2021DiscontinuousAutodiff, 94 | title = {Systematically Differentiating Parametric Discontinuities}, 95 | author = {Bangaru, Sai and Michel, Jesse and Mu, Kevin and Bernstein, Gilbert and Li, Tzu-Mao and Ragan-Kelley, Jonathan}, 96 | journal = {ACM Trans. Graph.}, 97 | volume = {40}, 98 | number = {107}, 99 | pages = {107:1-107:17}, 100 | year = {2021}, 101 | publisher = {ACM}, 102 | } 103 | ``` 104 | -------------------------------------------------------------------------------- /graphics/perlin_noise/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | # set the project name 4 | project(perlin LANGUAGES CXX CUDA) 5 | 6 | set(CMAKE_CXX_STANDARD 17) 7 | set(CMAKE_CXX_STANDARD_REQUIRED True) 8 | 9 | find_package(CUDA REQUIRED) 10 | include_directories("${CUDA_INCLUDE_DIRS}") 11 | 12 | find_package(OpenCV REQUIRED) 13 | include_directories(${OpenCV_INCLUDE_DIRS}) 14 | 15 | set(CUDA_NVCC_FLAGS_DEBUG "-g") 16 | set(CUDA_NVCC_FLAGS_RELEASE "-O3") 17 | 18 | # Credits: https://stackoverflow.com/users/1593077/einpoklum 19 | # Auto-detect GPU compute capability 20 | if (NOT CUDA_TARGET_COMPUTE_CAPABILITY) 21 | if("$ENV{CUDA_SM}" STREQUAL "") 22 | set(ENV{CUDA_INCLUDE_DIRS} "${CUDA_INCLUDE_DIRS}") 23 | set(ENV{CUDA_CUDART_LIBRARY} "${CUDA_CUDART_LIBRARY}") 24 | set(ENV{CMAKE_CXX_COMPILER} "${CMAKE_CXX_COMPILER}") 25 | execute_process(COMMAND 26 | bash -c "${CMAKE_CURRENT_SOURCE_DIR}/scripts/get_cuda_sm.sh" 27 | OUTPUT_VARIABLE CUDA_TARGET_COMPUTE_CAPABILITY_) 28 | else() 29 | set(CUDA_TARGET_COMPUTE_CAPABILITY_ $ENV{CUDA_SM}) 30 | endif() 31 | 32 | set(CUDA_TARGET_COMPUTE_CAPABILITY "${CUDA_TARGET_COMPUTE_CAPABILITY_}" 33 | CACHE STRING "CUDA compute capability of the (first) CUDA device on \ 34 | the system, in XY format (like the X.Y format but no dot); see table \ 35 | of features and capabilities by capability X.Y value at \ 36 | https://en.wikipedia.org/wiki/CUDA#Version_features_and_specifications") 37 | 38 | execute_process(COMMAND 39 | bash -c "echo -n $(echo ${CUDA_TARGET_COMPUTE_CAPABILITY})" 40 | OUTPUT_VARIABLE CUDA_TARGET_COMPUTE_CAPABILITY) 41 | execute_process(COMMAND 42 | bash -c "echo ${CUDA_TARGET_COMPUTE_CAPABILITY} | sed 's/^\\([0-9]\\)\\([0-9]\\)/\\1.\\2/;' | xargs echo -n" 43 | OUTPUT_VARIABLE FORMATTED_COMPUTE_CAPABILITY) 44 | 45 | message(STATUS 46 | "CUDA device-side code will assume compute capability \ 47 | ${FORMATTED_COMPUTE_CAPABILITY}") 48 | endif() 49 | 50 | set(CUDA_GENCODE 51 | "arch=compute_${CUDA_TARGET_COMPUTE_CAPABILITY}, code=compute_${CUDA_TARGET_COMPUTE_CAPABILITY}") 52 | set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -gencode ${CUDA_GENCODE} ) 53 | # ------------------------------ 54 | 55 | set(CMAKE_CXX_FLAGS "") 56 | set(CMAKE_CXX_FLAGS_DEBUG "-g") 57 | set(CMAKE_CXX_FLAGS_RELEASE "-O3") 58 | 59 | execute_process(COMMAND python3 -m teg --includes 60 | OUTPUT_VARIABLE TEG_INCLUDE_DIRS) 61 | include_directories("${TEG_INCLUDE_DIRS}") 62 | 63 | add_executable(render_perlin render_perlin.cu) 64 | add_executable(optimize_perlin optimize_perlin.cu) 65 | add_executable(optimize_perlin_2t optimize_perlin_2t.cu) 66 | add_executable(optimize_perlin_colorized optimize_perlin_colorized.cu) 67 | 68 | add_custom_target(teg 69 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_thresholded.h" 70 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_noise.h" 71 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_threshold_deriv.h" 72 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_threshold_fwdderiv.h" 73 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_double_threshold_fwdderiv.h" 74 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_double_thresholded.h" 75 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_colorized_thresholded.h" 76 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_colorized_threshold_fwdderiv.h") 77 | 78 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_thresholded.h" 79 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_thresholded.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_thresholded.h" -m teg_perlin_thresholded 80 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_thresholded.py" 81 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 82 | COMMENT "Building Teg kernels: teg_perlin_thresholded.py" 83 | ) 84 | 85 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_noise.h" 86 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_noise.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_noise.h" -m teg_perlin_noise 87 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_noise.py" 88 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 89 | COMMENT "Building Teg kernels: teg_perlin_noise.py" 90 | ) 91 | 92 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_threshold_deriv.h" 93 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_threshold_deriv.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_threshold_deriv.h" -m teg_perlin_threshold_deriv 94 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_threshold_deriv.py" 95 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 96 | COMMENT "Building Teg kernels: teg_perlin_threshold_deriv.py" 97 | ) 98 | 99 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_threshold_fwdderiv.h" 100 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_threshold_fwdderiv.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_threshold_fwdderiv.h" -m teg_perlin_threshold_fwdderiv 101 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_threshold_fwdderiv.py" 102 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 103 | COMMENT "Building Teg kernels: teg_perlin_threshold_fwdderiv.py" 104 | ) 105 | 106 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_double_thresholded.h" 107 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_double_thresholded.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_double_thresholded.h" -m teg_perlin_double_thresholded 108 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_double_thresholded.py" 109 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 110 | COMMENT "Building Teg kernels: teg_perlin_double_thresholded.py" 111 | ) 112 | 113 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_double_threshold_fwdderiv.h" 114 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_double_threshold_fwdderiv.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_double_threshold_fwdderiv.h" -m teg_perlin_double_threshold_fwdderiv 115 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_double_threshold_fwdderiv.py" 116 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 117 | COMMENT "Building Teg kernels: teg_perlin_double_threshold_fwdderiv.py" 118 | ) 119 | 120 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_colorized_thresholded.h" 121 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_colorized_thresholded.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_colorized_thresholded.h" -m teg_perlin_colorized_thresholded 122 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_colorized_thresholded.py" 123 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 124 | COMMENT "Building Teg kernels: teg_perlin_colorized_thresholded.py" 125 | ) 126 | 127 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_colorized_threshold_fwdderiv.h" 128 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_colorized_threshold_fwdderiv.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_colorized_threshold_fwdderiv.h" -m teg_perlin_colorized_threshold_fwdderiv 129 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_perlin_colorized_threshold_fwdderiv.py" 130 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 131 | COMMENT "Building Teg kernels: teg_perlin_colorized_threshold_fwdderiv.py" 132 | ) 133 | 134 | 135 | set_target_properties(render_perlin PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 136 | add_dependencies(render_perlin teg) 137 | target_link_libraries(render_perlin ${OpenCV_LIBRARIES}) 138 | 139 | 140 | set_target_properties(optimize_perlin PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 141 | add_dependencies(optimize_perlin teg) 142 | target_link_libraries(optimize_perlin ${OpenCV_LIBRARIES}) 143 | 144 | 145 | set_target_properties(optimize_perlin_2t PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 146 | add_dependencies(optimize_perlin_2t teg) 147 | target_link_libraries(optimize_perlin_2t ${OpenCV_LIBRARIES}) 148 | 149 | set_target_properties(optimize_perlin_colorized PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 150 | add_dependencies(optimize_perlin_colorized teg) 151 | target_link_libraries(optimize_perlin_colorized ${OpenCV_LIBRARIES}) -------------------------------------------------------------------------------- /graphics/perlin_noise/data/siggraph-logo-mono-flipped.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChezJrk/teg_applications/21fd77891a17af0d42abc3425abb734592b03c89/graphics/perlin_noise/data/siggraph-logo-mono-flipped.jpg -------------------------------------------------------------------------------- /graphics/perlin_noise/data/siggraph-logo-mono.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChezJrk/teg_applications/21fd77891a17af0d42abc3425abb734592b03c89/graphics/perlin_noise/data/siggraph-logo-mono.jpg -------------------------------------------------------------------------------- /graphics/perlin_noise/data/siggraph-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChezJrk/teg_applications/21fd77891a17af0d42abc3425abb734592b03c89/graphics/perlin_noise/data/siggraph-logo.jpg -------------------------------------------------------------------------------- /graphics/perlin_noise/data/stripes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChezJrk/teg_applications/21fd77891a17af0d42abc3425abb734592b03c89/graphics/perlin_noise/data/stripes.png -------------------------------------------------------------------------------- /graphics/perlin_noise/optimize_perlin.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include "math.h" 3 | #include 4 | 5 | // Image IO 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "types.cuh" 12 | // Output generated from Teg 13 | #include "perlin.cuh" 14 | 15 | 16 | // End Temporary placeholder. 17 | #define ALPHA_COLOR 0.000001 18 | #define ALPHA_VERTEX 0.005 19 | #define ALPHA_THRESHOLD 10e-8 20 | 21 | int main(int argc, char** argv) 22 | { 23 | if (argc != 6) { 24 | std::cout << "Usage: ./optimize_perlin " << std::endl; 25 | exit(1); 26 | } 27 | 28 | std::stringstream ss_nx(argv[2]); 29 | std::stringstream ss_ny(argv[3]); 30 | std::stringstream ss_seed(argv[4]); 31 | std::stringstream ss_learning_rate(argv[5]); 32 | 33 | int nx; 34 | int ny; 35 | int seed; 36 | float alpha_vertex; 37 | 38 | ss_nx >> nx; 39 | ss_ny >> ny; 40 | ss_seed >> seed; 41 | ss_learning_rate >> alpha_vertex; 42 | 43 | // Load an image. 44 | cv::Mat image; 45 | image = cv::imread(argv[1], cv::IMREAD_COLOR); 46 | 47 | if( !image.data ) { 48 | std::cout << "Could not open or find the image" << std::endl; 49 | return -1; 50 | } 51 | 52 | int rx = image.rows; 53 | int ry = image.cols; 54 | 55 | Image* target_image; 56 | cudaMallocManaged(&target_image, sizeof(Image)); 57 | 58 | target_image->rows = image.rows; 59 | target_image->cols = image.cols; 60 | cudaMallocManaged(&(target_image->colors), sizeof(Color) * image.rows * image.cols); 61 | 62 | // Load image data. 63 | for(int i = 0; i < image.rows; i++) 64 | for(int j = 0; j < image.cols; j++){ 65 | cv::Vec3b v = image.at(i, j); 66 | target_image->colors[(image.rows * j + i)].r = ((float)v[0]) / 255.0;//*(image.data + idx + 0); 67 | target_image->colors[(image.rows * j + i)].g = ((float)v[1]) / 255.0;//*(image.data + idx + 1); 68 | target_image->colors[(image.rows * j + i)].b = ((float)v[2]) / 255.0;//*(image.data + idx + 2); 69 | } 70 | 71 | std::cout << "Fitting " << rx << "x" << ry << " image" << std::endl; 72 | 73 | if (rx % nx || ry % ny) { 74 | std::cout << "Resoution must be a perfect multiple of grid dimensions" << std::endl; 75 | exit(1); 76 | } 77 | 78 | float* texture; 79 | Color* pcolor; 80 | Color* ncolor; 81 | DColor* d_pcolor; 82 | DColor* d_ncolor; 83 | 84 | float* threshold; 85 | float* d_threshold; 86 | 87 | Grid* grid; 88 | DGrid* d_grid; 89 | 90 | char* bimage = (char*) malloc(rx * ry * 3); 91 | 92 | build_grid(nx, ny, &grid, seed); 93 | build_d_grid(grid, &d_grid); 94 | //build_image(&texture, rx, ry); 95 | 96 | cudaMallocManaged(&texture, sizeof(float) * rx * ry * 3); 97 | cudaMallocManaged(&pcolor, sizeof(Color)); 98 | cudaMallocManaged(&ncolor, sizeof(Color)); 99 | cudaMallocManaged(&threshold, sizeof(float)); 100 | 101 | cudaMallocManaged(&d_pcolor, sizeof(DColor)); 102 | cudaMallocManaged(&d_ncolor, sizeof(DColor)); 103 | cudaMallocManaged(&d_threshold, sizeof(float)); 104 | 105 | // Baby blue. 106 | /* 107 | pcolor->b = 0.5373; 108 | pcolor->g = 0.8118; 109 | pcolor->r = 0.9412; 110 | */ 111 | 112 | pcolor->b = 0.3373; 113 | pcolor->g = 0.6118; 114 | pcolor->r = 0.7112; 115 | 116 | // Baby pink. 117 | /* 118 | ncolor->b = 0.9569; 119 | ncolor->g = 0.7608; 120 | ncolor->r = 0.7608; 121 | */ 122 | ncolor->b = 0.9569; 123 | ncolor->g = 0.9569; 124 | ncolor->r = 0.9569; 125 | 126 | *threshold = 0; 127 | *d_threshold = 0; 128 | 129 | std::cout << "Built structures" << std::endl; 130 | 131 | int num_jobs = rx * ry; 132 | int* qids; 133 | int* pids; 134 | 135 | cudaMallocManaged(&qids, num_jobs * sizeof(int)); 136 | cudaMallocManaged(&pids, num_jobs * sizeof(int)); 137 | 138 | for(int x = 0; x < rx; x++) 139 | for(int y = 0; y < ry; y++) 140 | for(int c = 0; c < 3; c++) 141 | texture[(y * rx + x) * 3 + c] = 0.f; 142 | 143 | int scale_x = rx / nx; 144 | int scale_y = ry / ny; 145 | int job_count = 0; 146 | for(int x = 0; x < rx; x++) { 147 | for(int y = 0; y < ry; y++) { 148 | pids[job_count] = y * rx + x; 149 | qids[job_count] = (y / scale_y) * nx + (x / scale_x); 150 | job_count ++; 151 | } 152 | } 153 | 154 | //std::cout << type2str(image.type()) << std::endl; 155 | 156 | std::cout << "Jobs: " << job_count; 157 | std::cout << "Scale: " << scale_x << ", " << scale_y << std::endl; 158 | // Render noise. 159 | /* 160 | perlin_threshold_kernel<<<(job_count / 256) + 1, 256>>>( 161 | qids, 162 | pids, 163 | job_count, 164 | grid, 165 | pcolor, 166 | ncolor, 167 | threshold, 168 | texture, 169 | rx, ry); 170 | */ 171 | for (int iter = 0; iter < 300; iter ++){ 172 | std::cout << "Iteration " << iter << std::endl; 173 | 174 | /* 175 | for(int x = 0; x < rx; x++) 176 | for(int y = 0; y < ry; y++) 177 | for(int c = 0; c < 3; c++) 178 | texture[(y * rx + x) * 3 + c] = 0.f; 179 | */ 180 | 181 | fast_zero(texture, rx * ry * 3); 182 | perlin_threshold_kernel<<<(job_count / 256) + 1, 256>>>( 183 | qids, 184 | pids, 185 | job_count, 186 | grid, 187 | pcolor, 188 | ncolor, 189 | threshold, 190 | texture, 191 | rx, ry); 192 | cudaDeviceSynchronize(); 193 | 194 | for(int idx = 0; idx < rx * ry * 3; idx ++){ 195 | // float val = (texture[idx] + 1) * 0.5; 196 | float val = texture[idx]; 197 | int _val = (int)(val * 256); 198 | // std::cout << "VAL: " << texture[idx] << std::endl; 199 | bimage[idx] = (char) ((_val < 0) ? 0 : (_val > 255 ? 255 : _val)); 200 | } 201 | 202 | std::stringstream ss; 203 | ss << "noise-" << iter << ".png"; 204 | cv::imwrite(ss.str(), cv::Mat(rx, ry, CV_8UC3, bimage)); 205 | 206 | // Zero derivatives before accumulating derivs. 207 | *d_threshold = 0.f; 208 | *d_pcolor = 0.f; 209 | *d_ncolor = 0.f; 210 | fast_zero(d_grid->d_vecs, (d_grid->rows + 1) * (d_grid->cols + 1)); 211 | 212 | // Compute and accumulate derivs. 213 | perlin_threshold_deriv<<<(job_count / 256) + 1, 256>>>( 214 | qids, 215 | pids, 216 | job_count, 217 | target_image, 218 | grid, 219 | d_grid, 220 | pcolor, 221 | ncolor, 222 | d_pcolor, 223 | d_ncolor, 224 | threshold, 225 | d_threshold, 226 | rx, ry); 227 | 228 | cudaDeviceSynchronize(); 229 | 230 | dim3 dimBlock(32, 32); 231 | dim3 dimGrid(((grid->rows + 1) / 32) + 1, ((grid->cols + 1) / 32) + 1); 232 | update_grid_positions<<>>(grid, d_grid, alpha_vertex); 233 | 234 | 235 | pcolor->r = pcolor->r - d_pcolor->r * ALPHA_COLOR; 236 | pcolor->g = pcolor->g - d_pcolor->g * ALPHA_COLOR; 237 | pcolor->b = pcolor->b - d_pcolor->b * ALPHA_COLOR; 238 | 239 | 240 | ncolor->r = ncolor->r - d_ncolor->r * ALPHA_COLOR; 241 | ncolor->g = ncolor->g - d_ncolor->g * ALPHA_COLOR; 242 | ncolor->b = ncolor->b - d_ncolor->b * ALPHA_COLOR; 243 | 244 | //*threshold = *threshold - (*d_threshold) * ALPHA_THRESHOLD; 245 | 246 | } 247 | 248 | 249 | /*for (int i = 0; i < 50; i++) 250 | for (int j = 0; j < 50; j++){ 251 | float f0 = d_tcolors[(i * 50 + j) * 3 + 0]; 252 | float f1 = d_tcolors[(i * 50 + j) * 3 + 1]; 253 | float f2 = d_tcolors[(i * 50 + j) * 3 + 2]; 254 | if (f0 != 0 || f1 != 0 || f2 != 0) 255 | std::cout << f0 << ", " << f1 << ", " << f2 << std::endl; 256 | } 257 | 258 | for (int i = 0; i < 50; i++) 259 | for (int j = 0; j < 50; j++){ 260 | float f0 = d_vertices[(i * 50 + j) * 2 + 0]; 261 | float f1 = d_vertices[(i * 50 + j) * 2 + 1]; 262 | if (f0 != 0 || f1 != 0) 263 | std::cout << f0 << ", " << f1 << std::endl; 264 | }*/ 265 | 266 | } -------------------------------------------------------------------------------- /graphics/perlin_noise/optimize_perlin_2t.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include "math.h" 3 | #include 4 | 5 | // Image IO 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "types.cuh" 12 | // Output generated from Teg 13 | #include "perlin_2t.cuh" 14 | 15 | 16 | // End Temporary placeholder. 17 | #define ALPHA_COLOR 0.000001 18 | #define ALPHA_VERTEX 0.005 19 | #define ALPHA_THRESHOLD 10e-8 20 | 21 | int main(int argc, char** argv) 22 | { 23 | if (argc != 6) { 24 | std::cout << "Usage: ./optimize_perlin_2t " << std::endl; 25 | exit(1); 26 | } 27 | 28 | std::stringstream ss_nx(argv[2]); 29 | std::stringstream ss_ny(argv[3]); 30 | std::stringstream ss_seed(argv[4]); 31 | std::stringstream ss_learning_rate(argv[5]); 32 | 33 | int nx; 34 | int ny; 35 | int seed; 36 | float alpha_vertex; 37 | 38 | ss_nx >> nx; 39 | ss_ny >> ny; 40 | ss_seed >> seed; 41 | ss_learning_rate >> alpha_vertex; 42 | 43 | // Load an image. 44 | cv::Mat image; 45 | image = cv::imread(argv[1], cv::IMREAD_COLOR); 46 | 47 | if( !image.data ) { 48 | std::cout << "Could not open or find the image" << std::endl; 49 | return -1; 50 | } 51 | 52 | int rx = image.rows; 53 | int ry = image.cols; 54 | 55 | Image* target_image; 56 | cudaMallocManaged(&target_image, sizeof(Image)); 57 | 58 | target_image->rows = image.rows; 59 | target_image->cols = image.cols; 60 | cudaMallocManaged(&(target_image->colors), sizeof(Color) * image.rows * image.cols); 61 | 62 | // Load image data. 63 | for(int i = 0; i < image.rows; i++) 64 | for(int j = 0; j < image.cols; j++){ 65 | cv::Vec3b v = image.at(i, j); 66 | target_image->colors[(image.rows * j + i)].r = ((float)v[0]) / 255.0;//*(image.data + idx + 0); 67 | target_image->colors[(image.rows * j + i)].g = ((float)v[1]) / 255.0;//*(image.data + idx + 1); 68 | target_image->colors[(image.rows * j + i)].b = ((float)v[2]) / 255.0;//*(image.data + idx + 2); 69 | } 70 | 71 | std::cout << "Fitting " << rx << "x" << ry << " image" << std::endl; 72 | 73 | if (rx % nx || ry % ny) { 74 | std::cout << "Resoution must be a perfect multiple of grid dimensions" << std::endl; 75 | exit(1); 76 | } 77 | 78 | float* texture; 79 | Color* pcolor; 80 | Color* ncolor; 81 | Color* mcolor; 82 | DColor* d_pcolor; 83 | DColor* d_ncolor; 84 | DColor* d_mcolor; 85 | 86 | float* threshold; 87 | float* threshold2; 88 | float* d_threshold; 89 | float* d_threshold2; 90 | 91 | Grid* grid; 92 | DGrid* d_grid; 93 | 94 | char* bimage = (char*) malloc(rx * ry * 3); 95 | 96 | build_grid(nx, ny, &grid, seed); 97 | build_d_grid(grid, &d_grid); 98 | //build_image(&texture, rx, ry); 99 | 100 | cudaMallocManaged(&texture, sizeof(float) * rx * ry * 3); 101 | cudaMallocManaged(&pcolor, sizeof(Color)); 102 | cudaMallocManaged(&ncolor, sizeof(Color)); 103 | cudaMallocManaged(&mcolor, sizeof(Color)); 104 | cudaMallocManaged(&threshold, sizeof(float)); 105 | cudaMallocManaged(&threshold2, sizeof(float)); 106 | 107 | cudaMallocManaged(&d_pcolor, sizeof(DColor)); 108 | cudaMallocManaged(&d_ncolor, sizeof(DColor)); 109 | cudaMallocManaged(&d_mcolor, sizeof(DColor)); 110 | cudaMallocManaged(&d_threshold, sizeof(float)); 111 | cudaMallocManaged(&d_threshold2, sizeof(float)); 112 | 113 | // Baby blue. 114 | /* 115 | pcolor->b = 0.5373; 116 | pcolor->g = 0.8118; 117 | pcolor->r = 0.9412; 118 | */ 119 | 120 | //pcolor->b = 0.3373; 121 | //pcolor->g = 0.6118; 122 | //pcolor->r = 0.7112; 123 | pcolor->b = 0.275; 124 | pcolor->g = 0.514; 125 | pcolor->r = 0.729; 126 | 127 | // Baby pink. 128 | //ncolor->b = 0.9569; 129 | //ncolor->g = 0.7608; 130 | //ncolor->r = 0.7608; 131 | ncolor->b = 0.659; 132 | ncolor->g = 0.020; 133 | ncolor->r = 0.196; 134 | 135 | 136 | // White. 137 | mcolor->b = 0.9569; 138 | mcolor->g = 0.9569; 139 | mcolor->r = 0.9569; 140 | 141 | *threshold = -0.13; 142 | *threshold2 = 0.13; 143 | *d_threshold = 0; 144 | *d_threshold2 = 0; 145 | 146 | std::cout << "Built structures" << std::endl; 147 | 148 | int num_jobs = rx * ry; 149 | int* qids; 150 | int* pids; 151 | 152 | cudaMallocManaged(&qids, num_jobs * sizeof(int)); 153 | cudaMallocManaged(&pids, num_jobs * sizeof(int)); 154 | 155 | for(int x = 0; x < rx; x++) 156 | for(int y = 0; y < ry; y++) 157 | for(int c = 0; c < 3; c++) 158 | texture[(y * rx + x) * 3 + c] = 0.f; 159 | 160 | int scale_x = rx / nx; 161 | int scale_y = ry / ny; 162 | int job_count = 0; 163 | for(int x = 0; x < rx; x++) { 164 | for(int y = 0; y < ry; y++) { 165 | pids[job_count] = y * rx + x; 166 | qids[job_count] = (y / scale_y) * nx + (x / scale_x); 167 | job_count ++; 168 | } 169 | } 170 | 171 | //std::cout << type2str(image.type()) << std::endl; 172 | 173 | std::cout << "Jobs: " << job_count; 174 | std::cout << "Scale: " << scale_x << ", " << scale_y << std::endl; 175 | // Render noise. 176 | /* 177 | perlin_threshold_kernel<<<(job_count / 256) + 1, 256>>>( 178 | qids, 179 | pids, 180 | job_count, 181 | grid, 182 | pcolor, 183 | ncolor, 184 | threshold, 185 | texture, 186 | rx, ry); 187 | */ 188 | for (int iter = 0; iter < 300; iter ++){ 189 | std::cout << "Iteration " << iter << std::endl; 190 | 191 | /* 192 | for(int x = 0; x < rx; x++) 193 | for(int y = 0; y < ry; y++) 194 | for(int c = 0; c < 3; c++) 195 | texture[(y * rx + x) * 3 + c] = 0.f; 196 | */ 197 | 198 | fast_zero(texture, rx * ry * 3); 199 | perlin_double_threshold_kernel<<<(job_count / 256) + 1, 256>>>( 200 | qids, 201 | pids, 202 | job_count, 203 | grid, 204 | pcolor, 205 | ncolor, 206 | mcolor, 207 | threshold, 208 | threshold2, 209 | texture, 210 | rx, ry); 211 | cudaDeviceSynchronize(); 212 | 213 | for(int idx = 0; idx < rx * ry * 3; idx ++){ 214 | // float val = (texture[idx] + 1) * 0.5; 215 | float val = texture[idx]; 216 | int _val = (int)(val * 256); 217 | // std::cout << "VAL: " << texture[idx] << std::endl; 218 | bimage[idx] = (char) ((_val < 0) ? 0 : (_val > 255 ? 255 : _val)); 219 | } 220 | 221 | std::stringstream ss; 222 | ss << "noise-" << iter << ".png"; 223 | cv::imwrite(ss.str(), cv::Mat(rx, ry, CV_8UC3, bimage)); 224 | 225 | // Zero derivatives before accumulating derivs. 226 | *d_threshold = 0.f; 227 | *d_threshold2 = 0.f; 228 | *d_pcolor = 0.f; 229 | *d_ncolor = 0.f; 230 | *d_mcolor = 0.f; 231 | fast_zero(d_grid->d_vecs, (d_grid->rows + 1) * (d_grid->cols + 1)); 232 | 233 | // Compute and accumulate derivs. 234 | perlin_double_threshold_deriv<<<(job_count / 256) + 1, 256>>>( 235 | qids, 236 | pids, 237 | job_count, 238 | target_image, 239 | grid, 240 | d_grid, 241 | pcolor, 242 | ncolor, 243 | mcolor, 244 | d_pcolor, 245 | d_ncolor, 246 | d_mcolor, 247 | threshold, 248 | threshold2, 249 | d_threshold, 250 | d_threshold2, 251 | rx, ry); 252 | 253 | cudaDeviceSynchronize(); 254 | 255 | dim3 dimBlock(32, 32); 256 | dim3 dimGrid(((grid->rows + 1) / 32) + 1, ((grid->cols + 1) / 32) + 1); 257 | update_grid_positions<<>>(grid, d_grid, alpha_vertex); 258 | 259 | /* 260 | pcolor->r = pcolor->r - d_pcolor->r * ALPHA_COLOR; 261 | pcolor->g = pcolor->g - d_pcolor->g * ALPHA_COLOR; 262 | pcolor->b = pcolor->b - d_pcolor->b * ALPHA_COLOR; 263 | 264 | ncolor->r = ncolor->r - d_ncolor->r * ALPHA_COLOR; 265 | ncolor->g = ncolor->g - d_ncolor->g * ALPHA_COLOR; 266 | ncolor->b = ncolor->b - d_ncolor->b * ALPHA_COLOR; 267 | 268 | mcolor->r = mcolor->r - d_mcolor->r * ALPHA_COLOR; 269 | mcolor->g = mcolor->g - d_mcolor->g * ALPHA_COLOR; 270 | mcolor->b = mcolor->b - d_mcolor->b * ALPHA_COLOR; 271 | */ 272 | 273 | //*threshold = *threshold - (*d_threshold) * ALPHA_THRESHOLD; 274 | //*threshold2 = *threshold2 - (*d_threshold2) * ALPHA_THRESHOLD; 275 | 276 | } 277 | 278 | 279 | /*for (int i = 0; i < 50; i++) 280 | for (int j = 0; j < 50; j++){ 281 | float f0 = d_tcolors[(i * 50 + j) * 3 + 0]; 282 | float f1 = d_tcolors[(i * 50 + j) * 3 + 1]; 283 | float f2 = d_tcolors[(i * 50 + j) * 3 + 2]; 284 | if (f0 != 0 || f1 != 0 || f2 != 0) 285 | std::cout << f0 << ", " << f1 << ", " << f2 << std::endl; 286 | } 287 | 288 | for (int i = 0; i < 50; i++) 289 | for (int j = 0; j < 50; j++){ 290 | float f0 = d_vertices[(i * 50 + j) * 2 + 0]; 291 | float f1 = d_vertices[(i * 50 + j) * 2 + 1]; 292 | if (f0 != 0 || f1 != 0) 293 | std::cout << f0 << ", " << f1 << std::endl; 294 | }*/ 295 | 296 | } -------------------------------------------------------------------------------- /graphics/perlin_noise/optimize_perlin_colorized.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include "math.h" 3 | #include 4 | 5 | // Image IO 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "types.cuh" 12 | // Output generated from Teg 13 | #include "perlin_colorized.cuh" 14 | 15 | 16 | // End Temporary placeholder. 17 | #define ALPHA_COLOR 0.000001 18 | #define ALPHA_VERTEX 0.005 19 | #define ALPHA_THRESHOLD 10e-8 20 | 21 | int main(int argc, char** argv) 22 | { 23 | if (argc != 6) { 24 | std::cout << "Usage: ./optimize_perlin " << std::endl; 25 | exit(1); 26 | } 27 | 28 | std::stringstream ss_nx(argv[2]); 29 | std::stringstream ss_ny(argv[3]); 30 | std::stringstream ss_seed(argv[4]); 31 | std::stringstream ss_learning_rate(argv[5]); 32 | 33 | int nx; 34 | int ny; 35 | int seed; 36 | float alpha_vertex; 37 | 38 | ss_nx >> nx; 39 | ss_ny >> ny; 40 | ss_seed >> seed; 41 | ss_learning_rate >> alpha_vertex; 42 | 43 | // Load an image. 44 | cv::Mat image; 45 | image = cv::imread(argv[1], cv::IMREAD_COLOR); 46 | 47 | if( !image.data ) { 48 | std::cout << "Could not open or find the image" << std::endl; 49 | return -1; 50 | } 51 | 52 | int rx = image.rows; 53 | int ry = image.cols; 54 | 55 | Image* target_image; 56 | cudaMallocManaged(&target_image, sizeof(Image)); 57 | 58 | target_image->rows = image.rows; 59 | target_image->cols = image.cols; 60 | cudaMallocManaged(&(target_image->colors), sizeof(Color) * image.rows * image.cols); 61 | 62 | // Load image data. 63 | for(int i = 0; i < image.rows; i++) 64 | for(int j = 0; j < image.cols; j++){ 65 | cv::Vec3b v = image.at(i, j); 66 | target_image->colors[(image.rows * j + i)].r = ((float)v[0]) / 255.0;//*(image.data + idx + 0); 67 | target_image->colors[(image.rows * j + i)].g = ((float)v[1]) / 255.0;//*(image.data + idx + 1); 68 | target_image->colors[(image.rows * j + i)].b = ((float)v[2]) / 255.0;//*(image.data + idx + 2); 69 | } 70 | 71 | std::cout << "Fitting " << rx << "x" << ry << " image" << std::endl; 72 | 73 | if (rx % nx || ry % ny) { 74 | std::cout << "Resoution must be a perfect multiple of grid dimensions" << std::endl; 75 | exit(1); 76 | } 77 | 78 | float* texture; 79 | //Color* pcolor; 80 | Color* ncolor; 81 | //DColor* d_pcolor; 82 | DColor* d_ncolor; 83 | 84 | float* threshold; 85 | float* d_threshold; 86 | 87 | Grid* grid; 88 | DGrid* d_grid; 89 | 90 | char* bimage = (char*) malloc(rx * ry * 3); 91 | 92 | build_grid(nx, ny, &grid, seed); 93 | build_d_grid(grid, &d_grid); 94 | //build_image(&texture, rx, ry); 95 | 96 | cudaMallocManaged(&texture, sizeof(float) * rx * ry * 3); 97 | //cudaMallocManaged(&pcolor, sizeof(Color)); 98 | cudaMallocManaged(&ncolor, sizeof(Color)); 99 | cudaMallocManaged(&threshold, sizeof(float)); 100 | 101 | //cudaMallocManaged(&d_pcolor, sizeof(DColor)); 102 | cudaMallocManaged(&d_ncolor, sizeof(DColor)); 103 | cudaMallocManaged(&d_threshold, sizeof(float)); 104 | 105 | // Baby blue. 106 | /* 107 | pcolor->b = 0.5373; 108 | pcolor->g = 0.8118; 109 | pcolor->r = 0.9412; 110 | */ 111 | 112 | //pcolor->b = 0.3373; 113 | //pcolor->g = 0.6118; 114 | //pcolor->r = 0.7112; 115 | 116 | // Baby pink. 117 | /* 118 | ncolor->b = 0.9569; 119 | ncolor->g = 0.7608; 120 | ncolor->r = 0.7608; 121 | */ 122 | ncolor->b = 0.8569; 123 | ncolor->g = 0.8569; 124 | ncolor->r = 0.8569; 125 | 126 | *threshold = 0; 127 | *d_threshold = 0; 128 | 129 | std::cout << "Built structures" << std::endl; 130 | 131 | int num_jobs = rx * ry; 132 | int* qids; 133 | int* pids; 134 | 135 | cudaMallocManaged(&qids, num_jobs * sizeof(int)); 136 | cudaMallocManaged(&pids, num_jobs * sizeof(int)); 137 | 138 | for(int x = 0; x < rx; x++) 139 | for(int y = 0; y < ry; y++) 140 | for(int c = 0; c < 3; c++) 141 | texture[(y * rx + x) * 3 + c] = 0.f; 142 | 143 | int scale_x = rx / nx; 144 | int scale_y = ry / ny; 145 | int job_count = 0; 146 | for(int x = 0; x < rx; x++) { 147 | for(int y = 0; y < ry; y++) { 148 | pids[job_count] = y * rx + x; 149 | qids[job_count] = (y / scale_y) * nx + (x / scale_x); 150 | job_count ++; 151 | } 152 | } 153 | 154 | //std::cout << type2str(image.type()) << std::endl; 155 | 156 | std::cout << "Jobs: " << job_count; 157 | std::cout << "Scale: " << scale_x << ", " << scale_y << std::endl; 158 | // Render noise. 159 | /* 160 | perlin_threshold_kernel<<<(job_count / 256) + 1, 256>>>( 161 | qids, 162 | pids, 163 | job_count, 164 | grid, 165 | pcolor, 166 | ncolor, 167 | threshold, 168 | texture, 169 | rx, ry); 170 | */ 171 | for (int iter = 0; iter < 300; iter ++){ 172 | std::cout << "Iteration " << iter << std::endl; 173 | 174 | /* 175 | for(int x = 0; x < rx; x++) 176 | for(int y = 0; y < ry; y++) 177 | for(int c = 0; c < 3; c++) 178 | texture[(y * rx + x) * 3 + c] = 0.f; 179 | */ 180 | 181 | fast_zero(texture, rx * ry * 3); 182 | perlin_colorized_threshold_kernel<<<(job_count / 256) + 1, 256>>>( 183 | qids, 184 | pids, 185 | job_count, 186 | grid, 187 | ncolor, 188 | threshold, 189 | texture, 190 | rx, ry); 191 | cudaDeviceSynchronize(); 192 | 193 | for(int idx = 0; idx < rx * ry * 3; idx ++){ 194 | // float val = (texture[idx] + 1) * 0.5; 195 | float val = texture[idx]; 196 | int _val = (int)(val * 256); 197 | // std::cout << "VAL: " << texture[idx] << std::endl; 198 | bimage[idx] = (char) ((_val < 0) ? 0 : (_val > 255 ? 255 : _val)); 199 | } 200 | 201 | std::stringstream ss; 202 | ss << "noise-" << iter << ".png"; 203 | cv::imwrite(ss.str(), cv::Mat(rx, ry, CV_8UC3, bimage)); 204 | 205 | // Zero derivatives before accumulating derivs. 206 | *d_threshold = 0.f; 207 | *d_ncolor = 0.f; 208 | fast_zero(d_grid->d_vecs, (d_grid->rows + 1) * (d_grid->cols + 1)); 209 | fast_zero(d_grid->d_colors, (d_grid->rows + 1) * (d_grid->cols + 1)); 210 | 211 | // Compute and accumulate derivs. 212 | perlin_colorized_threshold_deriv<<<(job_count / 256) + 1, 256>>>( 213 | qids, 214 | pids, 215 | job_count, 216 | target_image, 217 | grid, 218 | d_grid, 219 | ncolor, 220 | d_ncolor, 221 | threshold, 222 | d_threshold, 223 | rx, ry); 224 | 225 | cudaDeviceSynchronize(); 226 | 227 | dim3 dimBlock(32, 32); 228 | dim3 dimGrid(((grid->rows + 1) / 32) + 1, ((grid->cols + 1) / 32) + 1); 229 | update_grid_positions<<>>(grid, d_grid, alpha_vertex, ALPHA_COLOR * (grid->rows * grid->cols)); 230 | 231 | /* 232 | pcolor->r = pcolor->r - d_pcolor->r * ALPHA_COLOR; 233 | pcolor->g = pcolor->g - d_pcolor->g * ALPHA_COLOR; 234 | pcolor->b = pcolor->b - d_pcolor->b * ALPHA_COLOR; 235 | */ 236 | 237 | //ncolor->r = ncolor->r - d_ncolor->r * ALPHA_COLOR; 238 | //ncolor->g = ncolor->g - d_ncolor->g * ALPHA_COLOR; 239 | //ncolor->b = ncolor->b - d_ncolor->b * ALPHA_COLOR; 240 | 241 | //*threshold = *threshold - (*d_threshold) * ALPHA_THRESHOLD; 242 | 243 | } 244 | 245 | 246 | /*for (int i = 0; i < 50; i++) 247 | for (int j = 0; j < 50; j++){ 248 | float f0 = d_tcolors[(i * 50 + j) * 3 + 0]; 249 | float f1 = d_tcolors[(i * 50 + j) * 3 + 1]; 250 | float f2 = d_tcolors[(i * 50 + j) * 3 + 2]; 251 | if (f0 != 0 || f1 != 0 || f2 != 0) 252 | std::cout << f0 << ", " << f1 << ", " << f2 << std::endl; 253 | } 254 | 255 | for (int i = 0; i < 50; i++) 256 | for (int j = 0; j < 50; j++){ 257 | float f0 = d_vertices[(i * 50 + j) * 2 + 0]; 258 | float f1 = d_vertices[(i * 50 + j) * 2 + 1]; 259 | if (f0 != 0 || f1 != 0) 260 | std::cout << f0 << ", " << f1 << std::endl; 261 | }*/ 262 | 263 | } -------------------------------------------------------------------------------- /graphics/perlin_noise/perlin.cuh: -------------------------------------------------------------------------------- 1 | #include "types.cuh" 2 | 3 | #include "teg_perlin_thresholded.h" 4 | #include "teg_perlin_threshold_deriv.h" 5 | #include "teg_perlin_noise.h" 6 | 7 | #include 8 | 9 | 10 | 11 | template 12 | __global__ 13 | void set_zero(T* data, int max_id) { 14 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 15 | if(idx < max_id) 16 | data[idx] = 0; 17 | } 18 | 19 | template 20 | __host__ 21 | void fast_zero(T* data, int size) { 22 | set_zero<<<(size/256) + 1, 256>>>(data, size); 23 | cudaDeviceSynchronize(); 24 | } 25 | 26 | 27 | __global__ 28 | void update_grid_positions(Grid* grid, 29 | DGrid* d_grid, 30 | float alpha) 31 | { 32 | //int idx = blockIdx.x * blockDim.x + threadIdx.x; 33 | int x = blockIdx.x * blockDim.x + threadIdx.x; 34 | int y = blockIdx.y * blockDim.y + threadIdx.y; 35 | 36 | if (x >= (grid->rows + 1) || y >= (grid->cols + 1)) 37 | return; 38 | 39 | Vec2D* v = &grid->vecs[y * (grid->rows + 1) + x]; 40 | DVec2D* d_v = &d_grid->d_vecs[y * (grid->rows + 1) + x]; 41 | v->x = v->x - alpha * d_v->d_x; 42 | v->y = v->y - alpha * d_v->d_y; 43 | 44 | v->x = v->x / (v->x * v->x + v->y * v->y); 45 | v->y = v->y / (v->x * v->x + v->y * v->y); 46 | } 47 | 48 | 49 | __host__ 50 | void build_grid(int nx, int ny, Grid** grid, int seed) { 51 | 52 | cudaMallocManaged(grid, sizeof(Grid)); 53 | cudaMallocManaged(&(*grid)->vecs, sizeof(Vec2D) * (nx + 1) * (ny + 1)); 54 | (*grid)->rows = nx; 55 | (*grid)->cols = ny; 56 | 57 | srand(seed); 58 | // Randomize everything 59 | for(int x = 0; x < nx + 1; x++){ 60 | for(int y = 0; y < ny + 1; y++){ 61 | float theta = (static_cast(rand())/RAND_MAX) * 2 * 3.1415f; 62 | //float theta = 0; 63 | (*grid)->vecs[y * (nx + 1) + x] = Vec2D{cos(theta), sin(theta)}; 64 | } 65 | } 66 | 67 | } 68 | 69 | __host__ 70 | void build_image(Image** image, int rx, int ry) { 71 | 72 | cudaMallocManaged(image, sizeof(Image)); 73 | cudaMallocManaged(&(*image)->colors, sizeof(Color) * rx * ry); 74 | (*image)->rows = rx; 75 | (*image)->cols = ry; 76 | 77 | } 78 | 79 | __host__ 80 | void build_d_grid(Grid* grid, 81 | DGrid** d_grid) { 82 | 83 | cudaMallocManaged(d_grid, sizeof(DGrid)); 84 | (*d_grid)->rows = grid->rows; 85 | (*d_grid)->cols = grid->cols; 86 | 87 | cudaMallocManaged(&((*d_grid)->d_vecs), sizeof(DVec2D) * (grid->rows + 1) * (grid->cols + 1)); 88 | set_zero<<<((grid->rows + 1) * (grid->cols + 1) / 256) + 1, 256>>>(((*d_grid)->d_vecs), 89 | (grid->rows + 1) * (grid->cols + 1)); 90 | } 91 | 92 | 93 | __global__ 94 | void perlin_threshold_kernel(int* qids, 95 | int* pids, 96 | int num_jobs, 97 | Grid* grid, 98 | Color* pcolor, 99 | Color* ncolor, 100 | float* threshold, 101 | float* image, 102 | int w, int h) 103 | { 104 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 105 | if(idx >= num_jobs) return; 106 | 107 | auto quad_id = qids[idx]; 108 | auto pixel_id = pids[idx]; 109 | 110 | int y_low = static_cast(floorf(quad_id / grid->rows)); 111 | int y_high = static_cast(floorf(quad_id / grid->rows) + 1); 112 | int x_low = quad_id % grid->rows; 113 | int x_high = ((quad_id % grid->rows) + 1); 114 | 115 | Vec2D vec11 = grid->vecs[y_high * (grid->rows + 1) + x_high]; 116 | Vec2D vec10 = grid->vecs[y_low * (grid->rows + 1) + x_high]; 117 | Vec2D vec01 = grid->vecs[y_high * (grid->rows + 1) + x_low]; 118 | Vec2D vec00 = grid->vecs[y_low * (grid->rows + 1) + x_low]; 119 | 120 | // printf("Sample %f, %f\n", vec11.x, vec11.y); 121 | // Assumes grid dimensions are always smaller than image dimensions. 122 | int scale_y = h / grid->cols; 123 | int scale_x = w / grid->rows; 124 | 125 | // Run generated teg function. 126 | auto outvals = teg_perlin_thresholded( 127 | vec00.x, vec00.y, 128 | vec10.x, vec10.y, 129 | vec01.x, vec01.y, 130 | vec11.x, vec11.y, 131 | 132 | x_low * scale_x, x_high * scale_x, 133 | y_low * scale_y, y_high * scale_y, 134 | 135 | (float)(pixel_id % w), 136 | (float)(pixel_id % w + 1), 137 | floorf(pixel_id / w), 138 | floorf(pixel_id / w) + 1, 139 | 140 | pcolor->r, pcolor->g, pcolor->b, 141 | ncolor->r, ncolor->g, ncolor->b, 142 | 143 | *threshold 144 | ); 145 | 146 | // printf("%d: %f, %f, %f\n", pixel_id, outvals[0], outvals[1], outvals[2]); 147 | 148 | // Accumulate image. 149 | atomicAdd(&image[pixel_id * 3 + 0], outvals[0]); 150 | atomicAdd(&image[pixel_id * 3 + 1], outvals[1]); 151 | atomicAdd(&image[pixel_id * 3 + 2], outvals[2]); 152 | } 153 | 154 | 155 | __global__ 156 | void perlin_threshold_deriv(int* qids, 157 | int* pids, 158 | int num_jobs, 159 | Image* target_image, 160 | Grid* grid, 161 | DGrid* d_grid, 162 | Color* pcolor, 163 | Color* ncolor, 164 | DColor* d_pcolor, 165 | DColor* d_ncolor, 166 | float* threshold, 167 | float* d_threshold, 168 | int w, int h) 169 | { 170 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 171 | if(idx >= num_jobs) return; 172 | 173 | auto quad_id = qids[idx]; 174 | auto pixel_id = pids[idx]; 175 | 176 | int y_low = static_cast(floorf(quad_id / grid->rows)); 177 | int y_high = static_cast(floorf(quad_id / grid->rows) + 1); 178 | int x_low = quad_id % grid->rows; 179 | int x_high = ((quad_id % grid->rows) + 1); 180 | 181 | Vec2D vec11 = grid->vecs[y_high * (grid->rows + 1) + x_high]; 182 | Vec2D vec10 = grid->vecs[y_low * (grid->rows + 1) + x_high]; 183 | Vec2D vec01 = grid->vecs[y_high * (grid->rows + 1) + x_low]; 184 | Vec2D vec00 = grid->vecs[y_low * (grid->rows + 1) + x_low]; 185 | 186 | // printf("Sample %f, %f\n", vec11.x, vec11.y); 187 | // Assumes grid dimensions are always smaller than image dimensions. 188 | int scale_y = h / grid->cols; 189 | int scale_x = w / grid->rows; 190 | 191 | // Run generated teg function. 192 | auto outvals = teg_perlin_threshold_deriv( 193 | vec00.x, vec00.y, 194 | vec10.x, vec10.y, 195 | vec01.x, vec01.y, 196 | vec11.x, vec11.y, 197 | 198 | x_low * scale_x, x_high * scale_x, 199 | y_low * scale_y, y_high * scale_y, 200 | 201 | (float)(pixel_id % w), 202 | (float)(pixel_id % w + 1), 203 | floorf(pixel_id / w), 204 | floorf(pixel_id / w) + 1, 205 | 206 | pcolor->r, pcolor->g, pcolor->b, 207 | ncolor->r, ncolor->g, ncolor->b, 208 | 209 | target_image->colors[pixel_id].r, 210 | target_image->colors[pixel_id].g, 211 | target_image->colors[pixel_id].b, 212 | 213 | *threshold 214 | ); 215 | 216 | // printf("%d: %f, %f, %f\n", pixel_id, outvals[0], outvals[1], outvals[2]); 217 | 218 | // Accumulate image. 219 | // atomicAdd(&image[pixel_id * 3 + 0], outval); 220 | // atomicAdd(&image[pixel_id * 3 + 1], outval); 221 | // atomicAdd(&image[pixel_id * 3 + 2], outval); 222 | 223 | atomicAdd(&d_grid->d_vecs[y_low * (grid->rows + 1) + x_low].d_x, outvals[0]); 224 | atomicAdd(&d_grid->d_vecs[y_low * (grid->rows + 1) + x_low].d_y, outvals[1]); 225 | atomicAdd(&d_grid->d_vecs[y_low * (grid->rows + 1) + x_high].d_x, outvals[2]); 226 | atomicAdd(&d_grid->d_vecs[y_low * (grid->rows + 1) + x_high].d_y, outvals[3]); 227 | atomicAdd(&d_grid->d_vecs[y_high * (grid->rows + 1) + x_low].d_x, outvals[4]); 228 | atomicAdd(&d_grid->d_vecs[y_high * (grid->rows + 1) + x_low].d_y, outvals[5]); 229 | atomicAdd(&d_grid->d_vecs[y_high * (grid->rows + 1) + x_high].d_x, outvals[6]); 230 | atomicAdd(&d_grid->d_vecs[y_high * (grid->rows + 1) + x_high].d_y, outvals[7]); 231 | 232 | atomicAdd(&d_pcolor->r, outvals[8]); 233 | atomicAdd(&d_pcolor->g, outvals[9]); 234 | atomicAdd(&d_pcolor->b, outvals[10]); 235 | 236 | atomicAdd(&d_ncolor->r, outvals[11]); 237 | atomicAdd(&d_ncolor->g, outvals[12]); 238 | atomicAdd(&d_ncolor->b, outvals[13]); 239 | 240 | atomicAdd(d_threshold, outvals[14]); 241 | } 242 | 243 | __device__ 244 | float clamp(float x, float low, float high) { 245 | return (x >= high) ? (high-1) : ((x < low) ? low : x); 246 | } 247 | 248 | /* 249 | __global__ 250 | void linear_deriv_kernel(int* qids, 251 | int* pids, 252 | int num_jobs, 253 | Image* image, 254 | TriMesh* mesh, 255 | DTriMesh* d_mesh, 256 | LinearFragment* colors, 257 | DLinearFragment* d_colors) 258 | { 259 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 260 | 261 | if(idx >= num_jobs) 262 | return; 263 | 264 | auto tri_id = qids[idx]; 265 | auto pixel_id = pids[idx]; 266 | 267 | Vertex* a = mesh->tv0(tri_id); 268 | Vertex* b = mesh->tv1(tri_id); 269 | Vertex* c = mesh->tv2(tri_id); 270 | 271 | Color pixel = image->colors[pixel_id]; 272 | Color tricolor0 = colors[tri_id].c0; 273 | Color tricolor1 = colors[tri_id].c1; 274 | Color tricolor2 = colors[tri_id].c2; 275 | 276 | int h = image->cols; 277 | // Run generated teg function. 278 | auto outvals = teg_linear_deriv( 279 | a->x,a->y, 280 | b->x,b->y, 281 | c->x,c->y, 282 | 283 | floorf(pixel_id / h), 284 | floorf(pixel_id / h) + 1, 285 | (float)(pixel_id % h), 286 | (float)(pixel_id % h + 1), 287 | 288 | pixel.r, 289 | pixel.g, 290 | pixel.b, 291 | 292 | tricolor0.r, 293 | tricolor0.g, 294 | tricolor0.b, 295 | 296 | tricolor1.r, 297 | tricolor1.g, 298 | tricolor1.b, 299 | 300 | tricolor2.r, 301 | tricolor2.g, 302 | tricolor2.b 303 | ); 304 | 305 | DVertex* d_a = d_mesh->tv0(tri_id); 306 | DVertex* d_b = d_mesh->tv1(tri_id); 307 | DVertex* d_c = d_mesh->tv2(tri_id); 308 | 309 | DLinearFragment *d_pcolor = d_colors + tri_id; 310 | 311 | // Accumulate derivatives. 312 | // TODO: There needs to be an easier way to accumulate derivatives.. 313 | atomicAdd(&d_a->x, outvals[0]); 314 | atomicAdd(&d_b->x, outvals[1]); 315 | atomicAdd(&d_c->x, outvals[2]); 316 | 317 | atomicAdd(&d_a->y, outvals[3]); 318 | atomicAdd(&d_b->y, outvals[4]); 319 | atomicAdd(&d_c->y, outvals[5]); 320 | 321 | atomicAdd(&d_pcolor->d_c0.r, outvals[6]); 322 | atomicAdd(&d_pcolor->d_c0.g, outvals[7]); 323 | atomicAdd(&d_pcolor->d_c0.b, outvals[8]); 324 | 325 | atomicAdd(&d_pcolor->d_c1.r, outvals[9]); 326 | atomicAdd(&d_pcolor->d_c1.g, outvals[10]); 327 | atomicAdd(&d_pcolor->d_c1.b, outvals[11]); 328 | 329 | atomicAdd(&d_pcolor->d_c2.r, outvals[12]); 330 | atomicAdd(&d_pcolor->d_c2.g, outvals[13]); 331 | atomicAdd(&d_pcolor->d_c2.b, outvals[14]); 332 | 333 | }*/ -------------------------------------------------------------------------------- /graphics/perlin_noise/perlin_2t.cuh: -------------------------------------------------------------------------------- 1 | #include "types.cuh" 2 | 3 | #include "teg_perlin_double_thresholded.h" 4 | #include "teg_perlin_double_threshold_fwdderiv.h" 5 | #include "teg_perlin_noise.h" 6 | 7 | #include 8 | 9 | 10 | 11 | template 12 | __global__ 13 | void set_zero(T* data, int max_id) { 14 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 15 | if(idx < max_id) 16 | data[idx] = 0; 17 | } 18 | 19 | template 20 | __host__ 21 | void fast_zero(T* data, int size) { 22 | set_zero<<<(size/256) + 1, 256>>>(data, size); 23 | cudaDeviceSynchronize(); 24 | } 25 | 26 | 27 | __global__ 28 | void update_grid_positions(Grid* grid, 29 | DGrid* d_grid, 30 | float alpha) 31 | { 32 | //int idx = blockIdx.x * blockDim.x + threadIdx.x; 33 | int x = blockIdx.x * blockDim.x + threadIdx.x; 34 | int y = blockIdx.y * blockDim.y + threadIdx.y; 35 | 36 | if (x >= (grid->rows + 1) || y >= (grid->cols + 1)) 37 | return; 38 | 39 | Vec2D* v = &grid->vecs[y * (grid->rows + 1) + x]; 40 | DVec2D* d_v = &d_grid->d_vecs[y * (grid->rows + 1) + x]; 41 | v->x = v->x - alpha * d_v->d_x; 42 | v->y = v->y - alpha * d_v->d_y; 43 | 44 | v->x = v->x / (v->x * v->x + v->y * v->y); 45 | v->y = v->y / (v->x * v->x + v->y * v->y); 46 | } 47 | 48 | 49 | __host__ 50 | void build_grid(int nx, int ny, Grid** grid, int seed) { 51 | 52 | cudaMallocManaged(grid, sizeof(Grid)); 53 | cudaMallocManaged(&(*grid)->vecs, sizeof(Vec2D) * (nx + 1) * (ny + 1)); 54 | (*grid)->rows = nx; 55 | (*grid)->cols = ny; 56 | 57 | srand(seed); 58 | // Randomize everything 59 | for(int x = 0; x < nx + 1; x++){ 60 | for(int y = 0; y < ny + 1; y++){ 61 | float theta = (static_cast(rand())/RAND_MAX) * 2 * 3.1415f; 62 | //float theta = 0; 63 | (*grid)->vecs[y * (nx + 1) + x] = Vec2D{cos(theta), sin(theta)}; 64 | } 65 | } 66 | 67 | } 68 | 69 | __host__ 70 | void build_image(Image** image, int rx, int ry) { 71 | 72 | cudaMallocManaged(image, sizeof(Image)); 73 | cudaMallocManaged(&(*image)->colors, sizeof(Color) * rx * ry); 74 | (*image)->rows = rx; 75 | (*image)->cols = ry; 76 | 77 | } 78 | 79 | __host__ 80 | void build_d_grid(Grid* grid, 81 | DGrid** d_grid) { 82 | 83 | cudaMallocManaged(d_grid, sizeof(DGrid)); 84 | (*d_grid)->rows = grid->rows; 85 | (*d_grid)->cols = grid->cols; 86 | 87 | cudaMallocManaged(&((*d_grid)->d_vecs), sizeof(DVec2D) * (grid->rows + 1) * (grid->cols + 1)); 88 | set_zero<<<((grid->rows + 1) * (grid->cols + 1) / 256) + 1, 256>>>(((*d_grid)->d_vecs), 89 | (grid->rows + 1) * (grid->cols + 1)); 90 | } 91 | 92 | 93 | __global__ 94 | void perlin_double_threshold_kernel(int* qids, 95 | int* pids, 96 | int num_jobs, 97 | Grid* grid, 98 | Color* pcolor, 99 | Color* ncolor, 100 | Color* mcolor, 101 | float* threshold, 102 | float* threshold2, 103 | float* image, 104 | int w, int h) 105 | { 106 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 107 | if(idx >= num_jobs) return; 108 | 109 | auto quad_id = qids[idx]; 110 | auto pixel_id = pids[idx]; 111 | 112 | int y_low = static_cast(floorf(quad_id / grid->rows)); 113 | int y_high = static_cast(floorf(quad_id / grid->rows) + 1); 114 | int x_low = quad_id % grid->rows; 115 | int x_high = ((quad_id % grid->rows) + 1); 116 | 117 | Vec2D vec11 = grid->vecs[y_high * (grid->rows + 1) + x_high]; 118 | Vec2D vec10 = grid->vecs[y_low * (grid->rows + 1) + x_high]; 119 | Vec2D vec01 = grid->vecs[y_high * (grid->rows + 1) + x_low]; 120 | Vec2D vec00 = grid->vecs[y_low * (grid->rows + 1) + x_low]; 121 | 122 | // printf("Sample %f, %f\n", vec11.x, vec11.y); 123 | // Assumes grid dimensions are always smaller than image dimensions. 124 | int scale_y = h / grid->cols; 125 | int scale_x = w / grid->rows; 126 | 127 | // Run generated teg function. 128 | auto outvals = teg_perlin_double_thresholded( 129 | vec00.x, vec00.y, 130 | vec10.x, vec10.y, 131 | vec01.x, vec01.y, 132 | vec11.x, vec11.y, 133 | 134 | x_low * scale_x, x_high * scale_x, 135 | y_low * scale_y, y_high * scale_y, 136 | 137 | (float)(pixel_id % w), 138 | (float)(pixel_id % w + 1), 139 | floorf(pixel_id / w), 140 | floorf(pixel_id / w) + 1, 141 | 142 | pcolor->r, pcolor->g, pcolor->b, 143 | ncolor->r, ncolor->g, ncolor->b, 144 | mcolor->r, mcolor->g, mcolor->b, 145 | 146 | *threshold, 147 | *threshold2 148 | ); 149 | 150 | // printf("%d: %f, %f, %f\n", pixel_id, outvals[0], outvals[1], outvals[2]); 151 | 152 | // Accumulate image. 153 | atomicAdd(&image[pixel_id * 3 + 0], outvals[0]); 154 | atomicAdd(&image[pixel_id * 3 + 1], outvals[1]); 155 | atomicAdd(&image[pixel_id * 3 + 2], outvals[2]); 156 | } 157 | 158 | 159 | __global__ 160 | void perlin_double_threshold_deriv(int* qids, 161 | int* pids, 162 | int num_jobs, 163 | Image* target_image, 164 | Grid* grid, 165 | DGrid* d_grid, 166 | Color* pcolor, 167 | Color* ncolor, 168 | Color* mcolor, 169 | DColor* d_pcolor, 170 | DColor* d_ncolor, 171 | DColor* d_mcolor, 172 | float* threshold, 173 | float* threshold2, 174 | float* d_threshold, 175 | float* d_threshold2, 176 | int w, int h) 177 | { 178 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 179 | if(idx >= num_jobs) return; 180 | 181 | auto quad_id = qids[idx]; 182 | auto pixel_id = pids[idx]; 183 | 184 | int y_low = static_cast(floorf(quad_id / grid->rows)); 185 | int y_high = static_cast(floorf(quad_id / grid->rows) + 1); 186 | int x_low = quad_id % grid->rows; 187 | int x_high = ((quad_id % grid->rows) + 1); 188 | 189 | Vec2D vec11 = grid->vecs[y_high * (grid->rows + 1) + x_high]; 190 | Vec2D vec10 = grid->vecs[y_low * (grid->rows + 1) + x_high]; 191 | Vec2D vec01 = grid->vecs[y_high * (grid->rows + 1) + x_low]; 192 | Vec2D vec00 = grid->vecs[y_low * (grid->rows + 1) + x_low]; 193 | 194 | // printf("Sample %f, %f\n", vec11.x, vec11.y); 195 | // Assumes grid dimensions are always smaller than image dimensions. 196 | int scale_y = h / grid->cols; 197 | int scale_x = w / grid->rows; 198 | 199 | // Run generated teg function. 200 | auto outvals = teg_perlin_double_threshold_fwdderiv( 201 | vec00.x, vec00.y, 202 | vec10.x, vec10.y, 203 | vec01.x, vec01.y, 204 | vec11.x, vec11.y, 205 | 206 | x_low * scale_x, x_high * scale_x, 207 | y_low * scale_y, y_high * scale_y, 208 | 209 | (float)(pixel_id % w), 210 | (float)(pixel_id % w + 1), 211 | floorf(pixel_id / w), 212 | floorf(pixel_id / w) + 1, 213 | 214 | pcolor->r, pcolor->g, pcolor->b, 215 | ncolor->r, ncolor->g, ncolor->b, 216 | mcolor->r, mcolor->g, mcolor->b, 217 | 218 | target_image->colors[pixel_id].r, 219 | target_image->colors[pixel_id].g, 220 | target_image->colors[pixel_id].b, 221 | 222 | *threshold, 223 | *threshold2 224 | ); 225 | 226 | // printf("%d: %f, %f, %f\n", pixel_id, outvals[0], outvals[1], outvals[2]); 227 | 228 | // Accumulate image. 229 | // atomicAdd(&image[pixel_id * 3 + 0], outval); 230 | // atomicAdd(&image[pixel_id * 3 + 1], outval); 231 | // atomicAdd(&image[pixel_id * 3 + 2], outval); 232 | 233 | atomicAdd(&d_grid->d_vecs[y_low * (grid->rows + 1) + x_low].d_x, outvals[0]); 234 | atomicAdd(&d_grid->d_vecs[y_low * (grid->rows + 1) + x_low].d_y, outvals[1]); 235 | atomicAdd(&d_grid->d_vecs[y_low * (grid->rows + 1) + x_high].d_x, outvals[2]); 236 | atomicAdd(&d_grid->d_vecs[y_low * (grid->rows + 1) + x_high].d_y, outvals[3]); 237 | atomicAdd(&d_grid->d_vecs[y_high * (grid->rows + 1) + x_low].d_x, outvals[4]); 238 | atomicAdd(&d_grid->d_vecs[y_high * (grid->rows + 1) + x_low].d_y, outvals[5]); 239 | atomicAdd(&d_grid->d_vecs[y_high * (grid->rows + 1) + x_high].d_x, outvals[6]); 240 | atomicAdd(&d_grid->d_vecs[y_high * (grid->rows + 1) + x_high].d_y, outvals[7]); 241 | 242 | atomicAdd(&d_pcolor->r, outvals[8]); 243 | atomicAdd(&d_pcolor->g, outvals[9]); 244 | atomicAdd(&d_pcolor->b, outvals[10]); 245 | 246 | atomicAdd(&d_ncolor->r, outvals[11]); 247 | atomicAdd(&d_ncolor->g, outvals[12]); 248 | atomicAdd(&d_ncolor->b, outvals[13]); 249 | 250 | atomicAdd(&d_mcolor->r, outvals[14]); 251 | atomicAdd(&d_mcolor->g, outvals[15]); 252 | atomicAdd(&d_mcolor->b, outvals[16]); 253 | 254 | atomicAdd(d_threshold, outvals[17]); 255 | atomicAdd(d_threshold2, outvals[18]); 256 | } 257 | 258 | __device__ 259 | float clamp(float x, float low, float high) { 260 | return (x >= high) ? (high-1) : ((x < low) ? low : x); 261 | } 262 | 263 | /* 264 | __global__ 265 | void linear_deriv_kernel(int* qids, 266 | int* pids, 267 | int num_jobs, 268 | Image* image, 269 | TriMesh* mesh, 270 | DTriMesh* d_mesh, 271 | LinearFragment* colors, 272 | DLinearFragment* d_colors) 273 | { 274 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 275 | 276 | if(idx >= num_jobs) 277 | return; 278 | 279 | auto tri_id = qids[idx]; 280 | auto pixel_id = pids[idx]; 281 | 282 | Vertex* a = mesh->tv0(tri_id); 283 | Vertex* b = mesh->tv1(tri_id); 284 | Vertex* c = mesh->tv2(tri_id); 285 | 286 | Color pixel = image->colors[pixel_id]; 287 | Color tricolor0 = colors[tri_id].c0; 288 | Color tricolor1 = colors[tri_id].c1; 289 | Color tricolor2 = colors[tri_id].c2; 290 | 291 | int h = image->cols; 292 | // Run generated teg function. 293 | auto outvals = teg_linear_deriv( 294 | a->x,a->y, 295 | b->x,b->y, 296 | c->x,c->y, 297 | 298 | floorf(pixel_id / h), 299 | floorf(pixel_id / h) + 1, 300 | (float)(pixel_id % h), 301 | (float)(pixel_id % h + 1), 302 | 303 | pixel.r, 304 | pixel.g, 305 | pixel.b, 306 | 307 | tricolor0.r, 308 | tricolor0.g, 309 | tricolor0.b, 310 | 311 | tricolor1.r, 312 | tricolor1.g, 313 | tricolor1.b, 314 | 315 | tricolor2.r, 316 | tricolor2.g, 317 | tricolor2.b 318 | ); 319 | 320 | DVertex* d_a = d_mesh->tv0(tri_id); 321 | DVertex* d_b = d_mesh->tv1(tri_id); 322 | DVertex* d_c = d_mesh->tv2(tri_id); 323 | 324 | DLinearFragment *d_pcolor = d_colors + tri_id; 325 | 326 | // Accumulate derivatives. 327 | // TODO: There needs to be an easier way to accumulate derivatives.. 328 | atomicAdd(&d_a->x, outvals[0]); 329 | atomicAdd(&d_b->x, outvals[1]); 330 | atomicAdd(&d_c->x, outvals[2]); 331 | 332 | atomicAdd(&d_a->y, outvals[3]); 333 | atomicAdd(&d_b->y, outvals[4]); 334 | atomicAdd(&d_c->y, outvals[5]); 335 | 336 | atomicAdd(&d_pcolor->d_c0.r, outvals[6]); 337 | atomicAdd(&d_pcolor->d_c0.g, outvals[7]); 338 | atomicAdd(&d_pcolor->d_c0.b, outvals[8]); 339 | 340 | atomicAdd(&d_pcolor->d_c1.r, outvals[9]); 341 | atomicAdd(&d_pcolor->d_c1.g, outvals[10]); 342 | atomicAdd(&d_pcolor->d_c1.b, outvals[11]); 343 | 344 | atomicAdd(&d_pcolor->d_c2.r, outvals[12]); 345 | atomicAdd(&d_pcolor->d_c2.g, outvals[13]); 346 | atomicAdd(&d_pcolor->d_c2.b, outvals[14]); 347 | 348 | }*/ -------------------------------------------------------------------------------- /graphics/perlin_noise/render_perlin.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include "math.h" 3 | #include 4 | 5 | // Image IO 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "types.cuh" 12 | // Output generated from Teg 13 | #include "perlin.cuh" 14 | 15 | 16 | // End Temporary placeholder. 17 | #define ALPHA_COLOR 0.001 18 | #define ALPHA_VERTEX 0.08 19 | 20 | int main(int argc, char** argv) 21 | { 22 | if (argc != 6) { 23 | std::cout << "Usage: ./render_perlin " << std::endl; 24 | exit(1); 25 | } 26 | 27 | std::stringstream ss_rx(argv[1]); 28 | std::stringstream ss_ry(argv[2]); 29 | std::stringstream ss_nx(argv[3]); 30 | std::stringstream ss_ny(argv[4]); 31 | std::stringstream ss_seed(argv[5]); 32 | 33 | int nx; 34 | int ny; 35 | int rx; 36 | int ry; 37 | int seed; 38 | 39 | ss_nx >> nx; 40 | ss_ny >> ny; 41 | ss_rx >> rx; 42 | ss_ry >> ry; 43 | ss_seed >> seed; 44 | 45 | if (rx % nx || ry % ny) { 46 | std::cout << "Resoution must be a perfect multiple of grid dimensions" << std::endl; 47 | exit(1); 48 | } 49 | 50 | std::cout << "Rendering perlin noise, resolution: " << rx << "x" << ry << ", grid: " << nx << "x" << ny << std::endl; 51 | 52 | float* texture; 53 | Color* pcolor; 54 | Color* ncolor; 55 | DColor* d_pcolor; 56 | DColor* d_ncolor; 57 | 58 | float* threshold; 59 | float* d_threshold; 60 | 61 | Grid* grid; 62 | DGrid* d_grid; 63 | 64 | char* triangle_bimage = (char*) malloc(rx * ry * 3); 65 | 66 | build_grid(nx, ny, &grid, seed); 67 | build_d_grid(grid, &d_grid); 68 | //build_image(&texture, rx, ry); 69 | 70 | cudaMallocManaged(&texture, sizeof(float) * rx * ry * 3); 71 | cudaMallocManaged(&pcolor, sizeof(Color)); 72 | cudaMallocManaged(&ncolor, sizeof(Color)); 73 | cudaMallocManaged(&threshold, sizeof(float)); 74 | 75 | cudaMallocManaged(&d_pcolor, sizeof(DColor)); 76 | cudaMallocManaged(&d_ncolor, sizeof(DColor)); 77 | cudaMallocManaged(&d_threshold, sizeof(float)); 78 | 79 | // Baby blue. 80 | pcolor->b = 0.5373; 81 | pcolor->g = 0.8118; 82 | pcolor->r = 0.9412; 83 | 84 | // Baby pink. 85 | ncolor->b = 0.9569; 86 | ncolor->g = 0.7608; 87 | ncolor->r = 0.7608; 88 | 89 | *threshold = 0; 90 | *d_threshold = 0; 91 | 92 | std::cout << "Built structures" << std::endl; 93 | 94 | int num_jobs = rx * ry; 95 | int* qids; 96 | int* pids; 97 | 98 | cudaMallocManaged(&qids, num_jobs * sizeof(int)); 99 | cudaMallocManaged(&pids, num_jobs * sizeof(int)); 100 | 101 | for(int x = 0; x < rx; x++) 102 | for(int y = 0; y < ry; y++) 103 | for(int c = 0; c < 3; c++) 104 | texture[(y * rx + x) * 3 + c] = 0.f; 105 | 106 | int scale_x = rx / nx; 107 | int scale_y = ry / ny; 108 | int job_count = 0; 109 | for(int x = 0; x < rx; x++) { 110 | for(int y = 0; y < ry; y++) { 111 | pids[job_count] = y * rx + x; 112 | qids[job_count] = (y / scale_y) * nx + (x / scale_x); 113 | job_count ++; 114 | } 115 | } 116 | 117 | //std::cout << type2str(image.type()) << std::endl; 118 | 119 | std::cout << "Jobs: " << job_count; 120 | std::cout << "Scale: " << scale_x << ", " << scale_y << std::endl; 121 | // Render noise. 122 | /* 123 | perlin_threshold_kernel<<<(job_count / 256) + 1, 256>>>( 124 | qids, 125 | pids, 126 | job_count, 127 | grid, 128 | pcolor, 129 | ncolor, 130 | threshold, 131 | texture, 132 | rx, ry); 133 | */ 134 | perlin_threshold_kernel<<<(job_count / 256) + 1, 256>>>( 135 | qids, 136 | pids, 137 | job_count, 138 | grid, 139 | pcolor, 140 | ncolor, 141 | threshold, 142 | texture, 143 | rx, ry); 144 | 145 | cudaDeviceSynchronize(); 146 | 147 | for(int idx = 0; idx < rx * ry * 3; idx ++){ 148 | // float val = (texture[idx] + 1) * 0.5; 149 | float val = texture[idx]; 150 | int _val = (int)(val * 256); 151 | // std::cout << "VAL: " << texture[idx] << std::endl; 152 | triangle_bimage[idx] = (char) ((_val < 0) ? 0 : (_val > 255 ? 255 : _val)); 153 | } 154 | 155 | std::stringstream ss; 156 | ss << "noise-" << seed << ".png"; 157 | cv::imwrite(ss.str(), cv::Mat(rx, ry, CV_8UC3, triangle_bimage)); 158 | 159 | for(int x = 0; x < rx; x++) 160 | for(int y = 0; y < ry; y++) 161 | for(int c = 0; c < 3; c++) 162 | texture[(y * rx + x) * 3 + c] = 0.f; 163 | 164 | 165 | /*for (int i = 0; i < 50; i++) 166 | for (int j = 0; j < 50; j++){ 167 | float f0 = d_tcolors[(i * 50 + j) * 3 + 0]; 168 | float f1 = d_tcolors[(i * 50 + j) * 3 + 1]; 169 | float f2 = d_tcolors[(i * 50 + j) * 3 + 2]; 170 | if (f0 != 0 || f1 != 0 || f2 != 0) 171 | std::cout << f0 << ", " << f1 << ", " << f2 << std::endl; 172 | } 173 | 174 | for (int i = 0; i < 50; i++) 175 | for (int j = 0; j < 50; j++){ 176 | float f0 = d_vertices[(i * 50 + j) * 2 + 0]; 177 | float f1 = d_vertices[(i * 50 + j) * 2 + 1]; 178 | if (f0 != 0 || f1 != 0) 179 | std::cout << f0 << ", " << f1 << std::endl; 180 | }*/ 181 | 182 | } -------------------------------------------------------------------------------- /graphics/perlin_noise/scripts/get_cuda_sm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Credits: https://stackoverflow.com/users/1593077/einpoklum 4 | # 5 | # Prints the compute capability of the first CUDA device installed 6 | # on the system, or alternatively the device whose index is the 7 | # first command-line argument 8 | 9 | device_index=${1:-0} 10 | timestamp=$(date +%s.%N) 11 | gcc_binary=$(which g++) 12 | gcc_binary=${gcc_binary:-g++} 13 | cuda_root=${CUDA_DIR:-/usr/local/cuda} 14 | CUDA_INCLUDE_DIRS=${CUDA_INCLUDE_DIRS:-${cuda_root}/include} 15 | CUDA_CUDART_LIBRARY=${CUDA_CUDART_LIBRARY:-${cuda_root}/lib64/libcudart.so} 16 | generated_binary="/tmp/cuda-compute-version-helper-$$-$timestamp" 17 | # create a 'here document' that is code we compile and use to probe the card 18 | source_code="$(cat << EOF 19 | #include 20 | #include 21 | 22 | int main() 23 | { 24 | cudaDeviceProp prop; 25 | cudaError_t status; 26 | int device_count; 27 | status = cudaGetDeviceCount(&device_count); 28 | if (status != cudaSuccess) { 29 | fprintf(stderr,"cudaGetDeviceCount() failed: %s\n", cudaGetErrorString(status)); 30 | return -1; 31 | } 32 | if (${device_index} >= device_count) { 33 | fprintf(stderr, "Specified device index %d exceeds the maximum (the device count on this system is %d)\n", ${device_index}, device_count); 34 | return -1; 35 | } 36 | status = cudaGetDeviceProperties(&prop, ${device_index}); 37 | if (status != cudaSuccess) { 38 | fprintf(stderr,"cudaGetDeviceProperties() for device ${device_index} failed: %s\n", cudaGetErrorString(status)); 39 | return -1; 40 | } 41 | int v = prop.major * 10 + prop.minor; 42 | printf("%d\\n", v); 43 | } 44 | EOF 45 | )" 46 | echo "$source_code" | $gcc_binary -x c++ -I"$CUDA_INCLUDE_DIRS" -o "$generated_binary" - -x none "$CUDA_CUDART_LIBRARY" 47 | 48 | # probe the card and cleanup 49 | 50 | $generated_binary 51 | rm $generated_binary -------------------------------------------------------------------------------- /graphics/perlin_noise/siggraph-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChezJrk/teg_applications/21fd77891a17af0d42abc3425abb734592b03c89/graphics/perlin_noise/siggraph-logo.jpg -------------------------------------------------------------------------------- /graphics/perlin_noise/teg_perlin_base.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Const, 3 | Var, 4 | TegVar, 5 | IfElse, 6 | Teg, 7 | Tup, 8 | LetIn 9 | ) 10 | 11 | from teg.math import ( 12 | Sqr 13 | ) 14 | 15 | from teg.maps.smoothstep import teg_smoothstep 16 | from functools import partial 17 | 18 | def letify(*exprs): 19 | new_vars = [Var(f'_{idx}') for idx, expr in enumerate(exprs)] 20 | return new_vars, partial(LetIn, new_vars, exprs) 21 | 22 | def make_perlin_integrals(): 23 | # Quad boundaries 24 | grid_x0 = Var("gx0", 0) 25 | grid_x1 = Var("gx1", 1) 26 | grid_y0 = Var("gy0", 0) 27 | grid_y1 = Var("gy1", 1) 28 | 29 | # Boundary vectors. 30 | vec_x00 = Var('vx00x', 0), Var('vx00y', 0) 31 | vec_x10 = Var('vx10x', 0), Var('vx10y', 0) 32 | vec_x01 = Var('vx01x', 0), Var('vx01y', 0) 33 | vec_x11 = Var('vx11x', 0), Var('vx11y', 0) 34 | 35 | vecs = (vec_x00, vec_x10, vec_x01, vec_x11) 36 | 37 | # Pixel boundaries 38 | px0 = Var("px0", 2) 39 | px1 = Var("px1", 2) 40 | 41 | py0 = Var("py0", 2) 42 | py1 = Var("py1", 2) 43 | 44 | # Pixel colors. 45 | pix = Var('pix_r', 0), Var('pix_g', 0), Var('pix_b', 0) 46 | 47 | # Positive-region color 48 | pc = (Var("pc0", 0), Var("pc1", 0), Var("pc2", 0)) 49 | # Negative-region color 50 | nc = (Var("nc0", 0), Var("nc1", 0), Var("nc2", 0)) 51 | 52 | # Mid-region color (for two threshold variant) 53 | mc = (Var("mc0", 0), Var("mc1", 0), Var("mc2", 0)) 54 | 55 | # Region threshold value(s). 56 | t = Var('t') 57 | t2 = Var('t2') 58 | 59 | # Variables of integration. 60 | x = TegVar("x") 61 | y = TegVar("y") 62 | 63 | def interpolate(val00, val10, val01, val11, interp_x, interp_y): 64 | return ((val00) * (1 - interp_x) + (val10) * (interp_x)) * (1 - interp_y) +\ 65 | ((val01) * (1 - interp_x) + (val11) * (interp_x)) * (interp_y) 66 | 67 | def dot(xs, ys): 68 | return sum(_x * _y for _x, _y in zip(xs, ys)) 69 | 70 | """ 71 | def perlin_contribs_at(x0, y0, x1, y1, interp_x, interp_y, vecs): 72 | # Compute interpolated perlin value at the four corners of the pixel. 73 | return tuple(interpolate(*[dot(c_dist, vec) for vec in vecs], 74 | interp_x, interp_y) for c_dist in [(x0, y0), (x1, y0), (x0, y1), (x1, y1)]) 75 | """ 76 | 77 | def perlin_contrib_at(_x, _y, grid_bounds, grid_vecs): 78 | x0 = (_x - grid_bounds[0][0]) / (grid_bounds[1][0] - grid_bounds[0][0]) 79 | y0 = (_y - grid_bounds[0][1]) / (grid_bounds[1][1] - grid_bounds[0][1]) 80 | x1 = (_x - grid_bounds[1][0]) / (grid_bounds[1][0] - grid_bounds[0][0]) 81 | y1 = (_y - grid_bounds[1][1]) / (grid_bounds[1][1] - grid_bounds[0][1]) 82 | 83 | s_x0, s_y0 = teg_smoothstep(x0), teg_smoothstep(y0) 84 | return interpolate(dot((x0, y0), grid_vecs[0][0]), 85 | dot((x1, y0), grid_vecs[1][0]), 86 | dot((x0, y1), grid_vecs[0][1]), 87 | dot((x1, y1), grid_vecs[1][1]), 88 | s_x0, 89 | s_y0) 90 | 91 | grid_bounds = ((grid_x0, grid_y0), (grid_x1, grid_y1)) 92 | grid_vecs = ((vec_x00, vec_x01), (vec_x10, vec_x11)) 93 | c00 = perlin_contrib_at(px0, py0, grid_bounds, grid_vecs) 94 | c10 = perlin_contrib_at(px1, py0, grid_bounds, grid_vecs) 95 | c01 = perlin_contrib_at(px0, py1, grid_bounds, grid_vecs) 96 | c11 = perlin_contrib_at(px1, py1, grid_bounds, grid_vecs) 97 | 98 | # (c00, c10, c01, c11) = perlin_contribs_at(x0, y0, x1, y1, s_x0, s_y1, vecs) 99 | 100 | # Use let expressions for quicker compilation and smaller programs. 101 | (c00, c10, c01, c11), c_let_expr = letify(c00, c10, c01, c11) 102 | 103 | bilinear_lerp = (c00 * (px1 - x) + c10 * (x - px0)) * (py1 - y) +\ 104 | (c01 * (px1 - x) + c11 * (x - px0)) * (y - py0) 105 | 106 | bilinear_lerp = bilinear_lerp / ((px1 - px0) * (py1 - py0)) 107 | 108 | # Derivative of threshold only. 109 | thresholded_integral = Teg(px0, px1, 110 | Teg(py0, py1, 111 | c_let_expr( 112 | IfElse(bilinear_lerp > t, Tup(*pc), Tup(*nc)) 113 | #IfElse(bilinear_lerp > t, pc[2] * pc[1] * pc[0], nc[2] * nc[1] * nc[0]) 114 | ), y 115 | ), x 116 | ) 117 | 118 | point_loss_pc = Sqr(pc[0] - pix[0]) + Sqr(pc[1] - pix[1]) + Sqr(pc[2] - pix[2]) 119 | point_loss_nc = Sqr(nc[0] - pix[0]) + Sqr(nc[1] - pix[1]) + Sqr(nc[2] - pix[2]) 120 | point_loss_mc = Sqr(mc[0] - pix[0]) + Sqr(mc[1] - pix[1]) + Sqr(mc[2] - pix[2]) 121 | 122 | loss_integral = Teg(px0, px1, 123 | Teg(py0, py1, 124 | c_let_expr( 125 | IfElse(bilinear_lerp > t, point_loss_pc, point_loss_nc) 126 | ), y 127 | ), x 128 | ) 129 | 130 | thresholded_integral_2t = Teg(px0, px1, 131 | Teg(py0, py1, 132 | c_let_expr( 133 | IfElse(bilinear_lerp > t, 134 | IfElse(bilinear_lerp > t2, Tup(*pc), Tup(*mc)), Tup(*nc)) 135 | ), y 136 | ), x 137 | ) 138 | 139 | loss_integral_2t = Teg(px0, px1, 140 | Teg(py0, py1, 141 | c_let_expr( 142 | IfElse(bilinear_lerp > t, 143 | IfElse(bilinear_lerp > t2, point_loss_pc, point_loss_mc), point_loss_nc) 144 | ), y 145 | ), x 146 | ) 147 | 148 | noise_integral = Teg(px0, px1, 149 | Teg(py0, py1, 150 | c_let_expr( 151 | bilinear_lerp 152 | ), y 153 | ), x 154 | ) 155 | 156 | l_arglist = (*vec_x00, *vec_x10, *vec_x01, *vec_x11, 157 | grid_x0, grid_x1, 158 | grid_y0, grid_y1, 159 | px0, px1, 160 | py0, py1, 161 | *pc, *nc, *pix, 162 | t) 163 | 164 | l2_arglist = (*vec_x00, *vec_x10, *vec_x01, *vec_x11, 165 | grid_x0, grid_x1, 166 | grid_y0, grid_y1, 167 | px0, px1, 168 | py0, py1, 169 | *pc, *nc, *mc, 170 | *pix, 171 | t, t2) 172 | 173 | t_arglist = (*vec_x00, *vec_x10, *vec_x01, *vec_x11, 174 | grid_x0, grid_x1, 175 | grid_y0, grid_y1, 176 | px0, px1, 177 | py0, py1, 178 | *pc, *nc, t) 179 | 180 | t2_arglist = (*vec_x00, *vec_x10, *vec_x01, *vec_x11, 181 | grid_x0, grid_x1, 182 | grid_y0, grid_y1, 183 | px0, px1, 184 | py0, py1, 185 | *pc, *nc, *mc, 186 | t, t2) 187 | 188 | n_arglist = (*vec_x00, *vec_x10, *vec_x01, *vec_x11, 189 | grid_x0, grid_x1, 190 | grid_y0, grid_y1, 191 | px0, px1, 192 | py0, py1) 193 | 194 | return ((thresholded_integral, t_arglist), 195 | (noise_integral, n_arglist), 196 | (loss_integral, l_arglist), 197 | (thresholded_integral_2t, t2_arglist), 198 | (loss_integral_2t, l2_arglist)) 199 | -------------------------------------------------------------------------------- /graphics/perlin_noise/teg_perlin_colorized_base.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Const, 3 | Var, 4 | TegVar, 5 | IfElse, 6 | Teg, 7 | Tup, 8 | LetIn 9 | ) 10 | 11 | from teg.math import ( 12 | Sqr 13 | ) 14 | 15 | from teg.maps.smoothstep import teg_smoothstep 16 | from functools import partial 17 | 18 | def letify(*exprs): 19 | new_vars = [Var(f'_{idx}') for idx, expr in enumerate(exprs)] 20 | return new_vars, partial(LetIn, new_vars, exprs) 21 | 22 | def make_perlin_integrals(): 23 | # Quad boundaries 24 | grid_x0 = Var("gx0", 0) 25 | grid_x1 = Var("gx1", 1) 26 | grid_y0 = Var("gy0", 0) 27 | grid_y1 = Var("gy1", 1) 28 | 29 | # Boundary vectors. 30 | vec_x00 = Var('vx00x', 0), Var('vx00y', 0) 31 | vec_x10 = Var('vx10x', 0), Var('vx10y', 0) 32 | vec_x01 = Var('vx01x', 0), Var('vx01y', 0) 33 | vec_x11 = Var('vx11x', 0), Var('vx11y', 0) 34 | 35 | col_00 = Var('col00r', 0), Var('col00g', 0), Var('col00b', 0) 36 | col_10 = Var('col10r', 0), Var('col10g', 0), Var('col10b', 0) 37 | col_01 = Var('col01r', 0), Var('col01g', 0), Var('col01b', 0) 38 | col_11 = Var('col11r', 0), Var('col11g', 0), Var('col11b', 0) 39 | 40 | cols = (col_00, col_10, col_01, col_11) 41 | vecs = (vec_x00, vec_x10, vec_x01, vec_x11) 42 | 43 | # Pixel boundaries 44 | px0 = Var("px0", 2) 45 | px1 = Var("px1", 2) 46 | 47 | py0 = Var("py0", 2) 48 | py1 = Var("py1", 2) 49 | 50 | # Pixel colors. 51 | pix = Var('pix_r', 0), Var('pix_g', 0), Var('pix_b', 0) 52 | 53 | # Negative-region color 54 | nc = (Var("nc0", 0), Var("nc1", 0), Var("nc2", 0)) 55 | 56 | # Region threshold value(s). 57 | t = Var('t') 58 | t2 = Var('t2') 59 | 60 | # Variables of integration. 61 | x = TegVar("x") 62 | y = TegVar("y") 63 | 64 | def interpolate(val00, val10, val01, val11, interp_x, interp_y): 65 | return ((val00) * (1 - interp_x) + (val10) * (interp_x)) * (1 - interp_y) +\ 66 | ((val01) * (1 - interp_x) + (val11) * (interp_x)) * (interp_y) 67 | 68 | def dot(xs, ys): 69 | return sum(_x * _y for _x, _y in zip(xs, ys)) 70 | 71 | """ 72 | def perlin_contribs_at(x0, y0, x1, y1, interp_x, interp_y, vecs): 73 | # Compute interpolated perlin value at the four corners of the pixel. 74 | return tuple(interpolate(*[dot(c_dist, vec) for vec in vecs], 75 | interp_x, interp_y) for c_dist in [(x0, y0), (x1, y0), (x0, y1), (x1, y1)]) 76 | """ 77 | 78 | def perlin_contrib_at(_x, _y, grid_bounds, grid_vecs): 79 | x0 = (_x - grid_bounds[0][0]) / (grid_bounds[1][0] - grid_bounds[0][0]) 80 | y0 = (_y - grid_bounds[0][1]) / (grid_bounds[1][1] - grid_bounds[0][1]) 81 | x1 = (_x - grid_bounds[1][0]) / (grid_bounds[1][0] - grid_bounds[0][0]) 82 | y1 = (_y - grid_bounds[1][1]) / (grid_bounds[1][1] - grid_bounds[0][1]) 83 | 84 | s_x0, s_y0 = teg_smoothstep(x0), teg_smoothstep(y0) 85 | return interpolate(dot((x0, y0), grid_vecs[0][0]), 86 | dot((x1, y0), grid_vecs[1][0]), 87 | dot((x0, y1), grid_vecs[0][1]), 88 | dot((x1, y1), grid_vecs[1][1]), 89 | s_x0, 90 | s_y0) 91 | 92 | def colorization_at(_x, _y, grid_bounds, grid_cols): 93 | x0 = (_x - grid_bounds[0][0]) / (grid_bounds[1][0] - grid_bounds[0][0]) 94 | y0 = (_y - grid_bounds[0][1]) / (grid_bounds[1][1] - grid_bounds[0][1]) 95 | x1 = (_x - grid_bounds[1][0]) / (grid_bounds[1][0] - grid_bounds[0][0]) 96 | y1 = (_y - grid_bounds[1][1]) / (grid_bounds[1][1] - grid_bounds[0][1]) 97 | 98 | #s_x0, s_y0 = teg_smoothstep(x0), teg_smoothstep(y0) 99 | return interpolate(grid_cols[0], 100 | grid_cols[1], 101 | grid_cols[2], 102 | grid_cols[3], 103 | x0, 104 | y0) 105 | 106 | grid_bounds = ((grid_x0, grid_y0), (grid_x1, grid_y1)) 107 | grid_vecs = ((vec_x00, vec_x01), (vec_x10, vec_x11)) 108 | c00 = perlin_contrib_at(px0, py0, grid_bounds, grid_vecs) 109 | c10 = perlin_contrib_at(px1, py0, grid_bounds, grid_vecs) 110 | c01 = perlin_contrib_at(px0, py1, grid_bounds, grid_vecs) 111 | c11 = perlin_contrib_at(px1, py1, grid_bounds, grid_vecs) 112 | 113 | # (c00, c10, c01, c11) = perlin_contribs_at(x0, y0, x1, y1, s_x0, s_y1, vecs) 114 | 115 | # Use let expressions for quicker compilation and smaller programs. 116 | (c00, c10, c01, c11), c_let_expr = letify(c00, c10, c01, c11) 117 | 118 | bilinear_lerp = (c00 * (px1 - x) + c10 * (x - px0)) * (py1 - y) +\ 119 | (c01 * (px1 - x) + c11 * (x - px0)) * (y - py0) 120 | 121 | bilinear_lerp = bilinear_lerp / ((px1 - px0) * (py1 - py0)) 122 | 123 | pc0 = colorization_at(x, y, 124 | grid_bounds, 125 | (cols[0][0], 126 | cols[1][0], 127 | cols[2][0], 128 | cols[3][0])) 129 | pc1 = colorization_at(x, y, 130 | grid_bounds, 131 | (cols[0][1], 132 | cols[1][1], 133 | cols[2][1], 134 | cols[3][1])) 135 | pc2 = colorization_at(x, y, 136 | grid_bounds, 137 | (cols[0][2], 138 | cols[1][2], 139 | cols[2][2], 140 | cols[3][2])) 141 | 142 | pc = (pc0, pc1, pc2) 143 | # Derivative of threshold only. 144 | thresholded_integral = Teg(px0, px1, 145 | Teg(py0, py1, 146 | c_let_expr( 147 | IfElse(bilinear_lerp > t, Tup(*pc), Tup(*nc)) 148 | #IfElse(bilinear_lerp > t, pc[2] * pc[1] * pc[0], nc[2] * nc[1] * nc[0]) 149 | ), y 150 | ), x 151 | ) 152 | 153 | point_loss_pc = Sqr(pc[0] - pix[0]) + Sqr(pc[1] - pix[1]) + Sqr(pc[2] - pix[2]) 154 | point_loss_nc = Sqr(nc[0] - pix[0]) + Sqr(nc[1] - pix[1]) + Sqr(nc[2] - pix[2]) 155 | 156 | loss_integral = Teg(px0, px1, 157 | Teg(py0, py1, 158 | c_let_expr( 159 | IfElse(bilinear_lerp > t, point_loss_pc, point_loss_nc) 160 | ), y 161 | ), x 162 | ) 163 | 164 | noise_integral = Teg(px0, px1, 165 | Teg(py0, py1, 166 | c_let_expr( 167 | bilinear_lerp 168 | ), y 169 | ), x 170 | ) 171 | 172 | l_arglist = (*vec_x00, *vec_x10, *vec_x01, *vec_x11, 173 | grid_x0, grid_x1, 174 | grid_y0, grid_y1, 175 | px0, px1, 176 | py0, py1, 177 | *col_00, *col_10, *col_01, *col_11, 178 | *nc, *pix, 179 | t) 180 | 181 | t_arglist = (*vec_x00, *vec_x10, *vec_x01, *vec_x11, 182 | grid_x0, grid_x1, 183 | grid_y0, grid_y1, 184 | px0, px1, 185 | py0, py1, 186 | *col_00, *col_10, *col_01, *col_11, 187 | *nc, t) 188 | 189 | n_arglist = (*vec_x00, *vec_x10, *vec_x01, *vec_x11, 190 | grid_x0, grid_x1, 191 | grid_y0, grid_y1, 192 | px0, px1, 193 | py0, py1) 194 | 195 | return ((thresholded_integral, t_arglist), 196 | (noise_integral, n_arglist), 197 | (loss_integral, l_arglist)) 198 | -------------------------------------------------------------------------------- /graphics/perlin_noise/teg_perlin_colorized_threshold_fwdderiv.py: -------------------------------------------------------------------------------- 1 | from teg_perlin_colorized_base import make_perlin_integrals 2 | #from teg.derivs.reverse_deriv import reverse_deriv 3 | from teg.derivs.fwd_deriv import fwd_deriv 4 | from teg.passes.simplify import simplify 5 | from teg.passes.reduce import reduce_to_base 6 | 7 | from teg import (Tup, Const) 8 | def make_teg_program(): 9 | _, _, (loss_integral, arglist) = make_perlin_integrals() 10 | (vec_00x, vec_00y, vec_10x, vec_10y, 11 | vec_01x, vec_01y, vec_11x, vec_11y, 12 | grid_x0, grid_x1, 13 | grid_y0, grid_y1, 14 | px0, px1, 15 | py0, py1, 16 | c00r, c00g, c00b, 17 | c10r, c10g, c10b, 18 | c01r, c01g, c01b, 19 | c11r, c11g, c11b, 20 | nc0, nc1, nc2, 21 | pix_r, pix_g, pix_b, t) = arglist 22 | 23 | output_list = (vec_00x, vec_00y, vec_10x, vec_10y, 24 | vec_01x, vec_01y, vec_11x, vec_11y, 25 | c00r, c00g, c00b, 26 | c10r, c10g, c10b, 27 | c01r, c01g, c01b, 28 | c11r, c11g, c11b, 29 | nc0, nc1, nc2, t) 30 | 31 | derivs = [] 32 | for output in output_list: 33 | print(f'Constructing derivative for: {output.name}') 34 | _deriv = fwd_deriv(loss_integral, [(output, 1)], replace_derivs=True) 35 | deriv = reduce_to_base(simplify(_deriv)) 36 | derivs.append(deriv) 37 | 38 | return Tup(*derivs), arglist 39 | 40 | __PROGRAM__, __ARGLIST__ = make_teg_program() -------------------------------------------------------------------------------- /graphics/perlin_noise/teg_perlin_colorized_thresholded.py: -------------------------------------------------------------------------------- 1 | from teg_perlin_colorized_base import make_perlin_integrals 2 | 3 | def make_teg_program(): 4 | (integral_thresholded, arglist), _, _ = make_perlin_integrals() 5 | return integral_thresholded, arglist 6 | 7 | __PROGRAM__, __ARGLIST__ = make_teg_program() -------------------------------------------------------------------------------- /graphics/perlin_noise/teg_perlin_double_threshold_fwdderiv.py: -------------------------------------------------------------------------------- 1 | from teg_perlin_base import make_perlin_integrals 2 | #from teg.derivs.reverse_deriv import reverse_deriv 3 | from teg.derivs.fwd_deriv import fwd_deriv 4 | from teg.passes.simplify import simplify 5 | from teg.passes.reduce import reduce_to_base 6 | 7 | from teg import (Tup, Const) 8 | def make_teg_program(): 9 | _, _, _, _, (loss_integral, arglist) = make_perlin_integrals() 10 | (vec_00x, vec_00y, vec_10x, vec_10y, 11 | vec_01x, vec_01y, vec_11x, vec_11y, 12 | grid_x0, grid_x1, 13 | grid_y0, grid_y1, 14 | px0, px1, 15 | py0, py1, 16 | pc0, pc1, pc2, 17 | nc0, nc1, nc2, 18 | mc0, mc1, mc2, 19 | pix_r, pix_g, pix_b, 20 | t, t2) = arglist 21 | 22 | output_list = (vec_00x, vec_00y, vec_10x, vec_10y, 23 | vec_01x, vec_01y, vec_11x, vec_11y, 24 | pc0, pc1, pc2, 25 | nc0, nc1, nc2, 26 | mc0, mc1, mc2, 27 | t, t2) 28 | 29 | derivs = [] 30 | for output in output_list: 31 | print(f'Constructing derivative for: {output.name}') 32 | _deriv = fwd_deriv(loss_integral, [(output, Const(1))], replace_derivs=True) 33 | deriv = reduce_to_base(simplify(_deriv)) 34 | derivs.append(deriv) 35 | 36 | return Tup(*derivs), arglist 37 | 38 | __PROGRAM__, __ARGLIST__ = make_teg_program() -------------------------------------------------------------------------------- /graphics/perlin_noise/teg_perlin_double_thresholded.py: -------------------------------------------------------------------------------- 1 | from teg_perlin_base import make_perlin_integrals 2 | 3 | def make_teg_program(): 4 | _, _, _, (integral_thresholded, arglist), _ = make_perlin_integrals() 5 | return integral_thresholded, arglist 6 | 7 | __PROGRAM__, __ARGLIST__ = make_teg_program() -------------------------------------------------------------------------------- /graphics/perlin_noise/teg_perlin_noise.py: -------------------------------------------------------------------------------- 1 | from teg_perlin_base import make_perlin_integrals 2 | 3 | def make_teg_program(): 4 | _, (integral_noise, arglist), _, _, _ = make_perlin_integrals() 5 | return integral_noise, arglist 6 | 7 | __PROGRAM__, __ARGLIST__ = make_teg_program() -------------------------------------------------------------------------------- /graphics/perlin_noise/teg_perlin_threshold_deriv.py: -------------------------------------------------------------------------------- 1 | from teg_perlin_base import make_perlin_integrals 2 | from teg.derivs.reverse_deriv import reverse_deriv 3 | from teg.passes.simplify import simplify 4 | from teg.passes.reduce import reduce_to_base 5 | 6 | from teg import (Tup, Const) 7 | def make_teg_program(): 8 | _, _, (loss_integral, arglist), _, _ = make_perlin_integrals() 9 | (vec_00x, vec_00y, vec_10x, vec_10y, 10 | vec_01x, vec_01y, vec_11x, vec_11y, 11 | grid_x0, grid_x1, 12 | grid_y0, grid_y1, 13 | px0, px1, 14 | py0, py1, 15 | pc0, pc1, pc2, 16 | nc0, nc1, nc2, 17 | pix_r, pix_g, pix_b, t) = arglist 18 | 19 | output_list = (vec_00x, vec_00y, vec_10x, vec_10y, 20 | vec_01x, vec_01y, vec_11x, vec_11y, 21 | pc0, pc1, pc2, 22 | nc0, nc1, nc2, t) 23 | 24 | derivs = [] 25 | for output in output_list: 26 | print(f'Constructing derivative for: {output.name}') 27 | _, _deriv = reverse_deriv(loss_integral, Tup(Const(1)), output_list=[output]) 28 | deriv = reduce_to_base(simplify(_deriv)) 29 | derivs.append(deriv) 30 | 31 | return Tup(*derivs), arglist 32 | 33 | __PROGRAM__, __ARGLIST__ = make_teg_program() -------------------------------------------------------------------------------- /graphics/perlin_noise/teg_perlin_threshold_fwdderiv.py: -------------------------------------------------------------------------------- 1 | from teg_perlin_base import make_perlin_integrals 2 | #from teg.derivs.reverse_deriv import reverse_deriv 3 | from teg.derivs.fwd_deriv import fwd_deriv 4 | from teg.passes.simplify import simplify 5 | from teg.passes.reduce import reduce_to_base 6 | 7 | from teg import (Tup, Const) 8 | def make_teg_program(): 9 | _, _, (loss_integral, arglist), _, _ = make_perlin_integrals() 10 | (vec_00x, vec_00y, vec_10x, vec_10y, 11 | vec_01x, vec_01y, vec_11x, vec_11y, 12 | grid_x0, grid_x1, 13 | grid_y0, grid_y1, 14 | px0, px1, 15 | py0, py1, 16 | pc0, pc1, pc2, 17 | nc0, nc1, nc2, 18 | pix_r, pix_g, pix_b, t) = arglist 19 | 20 | output_list = (vec_00x, vec_00y, vec_10x, vec_10y, 21 | vec_01x, vec_01y, vec_11x, vec_11y, 22 | pc0, pc1, pc2, 23 | nc0, nc1, nc2, t) 24 | 25 | derivs = [] 26 | for output in output_list: 27 | print(f'Constructing derivative for: {output.name}') 28 | _deriv = fwd_deriv(loss_integral, [(output, 1)]) 29 | deriv = reduce_to_base(simplify(_deriv)) 30 | derivs.append(deriv) 31 | 32 | return Tup(*derivs), arglist 33 | 34 | __PROGRAM__, __ARGLIST__ = make_teg_program() -------------------------------------------------------------------------------- /graphics/perlin_noise/teg_perlin_thresholded.py: -------------------------------------------------------------------------------- 1 | from teg_perlin_base import make_perlin_integrals 2 | 3 | def make_teg_program(): 4 | (integral_thresholded, arglist), _, _, _, _ = make_perlin_integrals() 5 | return integral_thresholded, arglist 6 | 7 | __PROGRAM__, __ARGLIST__ = make_teg_program() -------------------------------------------------------------------------------- /graphics/perlin_noise/types.cuh: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_CUH 2 | #define TYPES_CUH 3 | 4 | struct Color { 5 | float r; 6 | float g; 7 | float b; 8 | }; 9 | 10 | struct DColor { 11 | float r; 12 | float g; 13 | float b; 14 | 15 | __device__ __host__ void operator=(const float in) { 16 | r = in; 17 | g = in; 18 | b = in; 19 | } 20 | }; 21 | 22 | struct Vertex { 23 | float x; 24 | float y; 25 | }; 26 | 27 | struct Vec2D { 28 | float x; 29 | float y; 30 | }; 31 | 32 | struct DVec2D { 33 | float d_x; 34 | float d_y; 35 | 36 | __device__ __host__ void operator=(const float in) { 37 | d_x = in; 38 | d_y = in; 39 | } 40 | }; 41 | 42 | struct DVertex { 43 | float x; 44 | float y; 45 | 46 | __device__ __host__ void operator=(const float in) { 47 | x = in; 48 | y = in; 49 | } 50 | }; 51 | 52 | struct Image { 53 | int rows; 54 | int cols; 55 | Color* colors; 56 | }; 57 | 58 | struct Grid { 59 | int rows; 60 | int cols; 61 | Vec2D* vecs; 62 | Color* colors; 63 | }; 64 | 65 | struct DGrid { 66 | int rows; 67 | int cols; 68 | DVec2D* d_vecs; 69 | DColor* d_colors; 70 | }; 71 | 72 | #endif -------------------------------------------------------------------------------- /graphics/triangulation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | # set the project name 4 | project(triangulate LANGUAGES CXX CUDA) 5 | 6 | set(CMAKE_CXX_STANDARD 17) 7 | set(CMAKE_CXX_STANDARD_REQUIRED True) 8 | 9 | find_package(CUDA REQUIRED) 10 | include_directories("${CUDA_INCLUDE_DIRS}") 11 | 12 | find_package(OpenCV REQUIRED) 13 | include_directories(${OpenCV_INCLUDE_DIRS}) 14 | 15 | set(CUDA_NVCC_FLAGS_DEBUG "-g") 16 | set(CUDA_NVCC_FLAGS_RELEASE "-O3") 17 | 18 | # Credits: https://stackoverflow.com/users/1593077/einpoklum 19 | # Auto-detect GPU compute capability 20 | if (NOT CUDA_TARGET_COMPUTE_CAPABILITY) 21 | if("$ENV{CUDA_SM}" STREQUAL "") 22 | set(ENV{CUDA_INCLUDE_DIRS} "${CUDA_INCLUDE_DIRS}") 23 | set(ENV{CUDA_CUDART_LIBRARY} "${CUDA_CUDART_LIBRARY}") 24 | set(ENV{CMAKE_CXX_COMPILER} "${CMAKE_CXX_COMPILER}") 25 | execute_process(COMMAND 26 | bash -c "${CMAKE_CURRENT_SOURCE_DIR}/scripts/get_cuda_sm.sh" 27 | OUTPUT_VARIABLE CUDA_TARGET_COMPUTE_CAPABILITY_) 28 | else() 29 | set(CUDA_TARGET_COMPUTE_CAPABILITY_ $ENV{CUDA_SM}) 30 | endif() 31 | 32 | set(CUDA_TARGET_COMPUTE_CAPABILITY "${CUDA_TARGET_COMPUTE_CAPABILITY_}" 33 | CACHE STRING "CUDA compute capability of the (first) CUDA device on \ 34 | the system, in XY format (like the X.Y format but no dot); see table \ 35 | of features and capabilities by capability X.Y value at \ 36 | https://en.wikipedia.org/wiki/CUDA#Version_features_and_specifications") 37 | 38 | execute_process(COMMAND 39 | bash -c "echo -n $(echo ${CUDA_TARGET_COMPUTE_CAPABILITY})" 40 | OUTPUT_VARIABLE CUDA_TARGET_COMPUTE_CAPABILITY) 41 | execute_process(COMMAND 42 | bash -c "echo ${CUDA_TARGET_COMPUTE_CAPABILITY} | sed 's/^\\([0-9]\\)\\([0-9]\\)/\\1.\\2/;' | xargs echo -n" 43 | OUTPUT_VARIABLE FORMATTED_COMPUTE_CAPABILITY) 44 | 45 | message(STATUS 46 | "CUDA device-side code will assume compute capability \ 47 | ${FORMATTED_COMPUTE_CAPABILITY}") 48 | endif() 49 | 50 | set(CUDA_GENCODE 51 | "arch=compute_${CUDA_TARGET_COMPUTE_CAPABILITY}, code=compute_${CUDA_TARGET_COMPUTE_CAPABILITY}") 52 | set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -gencode ${CUDA_GENCODE} ) 53 | # ------------------------------ 54 | 55 | set(CMAKE_CXX_FLAGS "") 56 | set(CMAKE_CXX_FLAGS_DEBUG "-g") 57 | set(CMAKE_CXX_FLAGS_RELEASE "-O3") 58 | 59 | execute_process(COMMAND python3 -m teg --includes 60 | OUTPUT_VARIABLE TEG_INCLUDE_DIRS) 61 | include_directories("${TEG_INCLUDE_DIRS}") 62 | 63 | add_executable(triangulate_const triangulate_const.cu) 64 | add_executable(triangulate_linear triangulate_linear.cu) 65 | add_executable(triangulate_quadratic triangulate_quadratic.cu) 66 | add_executable(test test.cu) 67 | 68 | add_custom_target(teg 69 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/renderpixel.h" 70 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/tegpixel.h" 71 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/tegloss.h" 72 | 73 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_deriv.h" 74 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_loss.h" 75 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_deriv_nodelta.h" 76 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_integral.h" 77 | 78 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_bilinear_deriv.h" 79 | 80 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_deriv.h" 81 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_loss.h" 82 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_deriv_nodelta.h" 83 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_integral.h") 84 | 85 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/renderpixel.h" 86 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/integral.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/renderpixel.h" -m renderpixel 87 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/integral.py" 88 | COMMENT "Building Teg kernels: integral.py" 89 | ) 90 | 91 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/tegpixel.h" 92 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/loss_function.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/tegpixel.h" -m tegpixel 93 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/loss_function.py" 94 | COMMENT "Building Teg kernels: loss_function.py" 95 | ) 96 | 97 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/tegloss.h" 98 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/loss.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/tegloss.h" -m pixel_loss 99 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/loss.py" 100 | COMMENT "Building Teg kernels: loss.py" 101 | ) 102 | 103 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_deriv.h" 104 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_deriv.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_deriv.h" -m teg_linear_deriv 105 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_deriv.py" 106 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 107 | COMMENT "Building Teg kernels: teg_linear_deriv.py" 108 | ) 109 | 110 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_deriv_nodelta.h" 111 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_deriv_nodelta.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_deriv_nodelta.h" -m teg_linear_deriv_nodelta 112 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_deriv_nodelta.py" 113 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 114 | COMMENT "Building Teg kernels: teg_linear_deriv_nodelta.py" 115 | ) 116 | 117 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_integral.h" 118 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_integral.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_integral.h" -m teg_linear_integral 119 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_integral.py" 120 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 121 | COMMENT "Building Teg kernels: teg_linear_integral.py" 122 | ) 123 | 124 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_loss.h" 125 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_loss.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_loss.h" -m teg_linear_loss 126 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_loss.py" 127 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 128 | COMMENT "Building Teg kernels: teg_linear_loss.py" 129 | ) 130 | 131 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_deriv.h" 132 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_deriv.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_deriv.h" -m teg_quadratic_deriv 133 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_deriv.py" 134 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 135 | COMMENT "Building Teg kernels: teg_quadratic_deriv.py" 136 | ) 137 | 138 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_integral.h" 139 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_integral.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_integral.h" -m teg_quadratic_integral 140 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_integral.py" 141 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 142 | COMMENT "Building Teg kernels: teg_quadratic_integral.py" 143 | ) 144 | 145 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_deriv_nodelta.h" 146 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_deriv_nodelta.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_deriv_nodelta.h" -m teg_quadratic_deriv_nodelta 147 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_deriv_nodelta.py" 148 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 149 | COMMENT "Building Teg kernels: teg_quadratic_deriv_nodelta.py" 150 | ) 151 | 152 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_loss.h" 153 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_loss.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_loss.h" -m teg_quadratic_loss 154 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_quadratic_loss.py" 155 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 156 | COMMENT "Building Teg kernels: teg_quadratic_loss.py" 157 | ) 158 | 159 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_bilinear_deriv.h" 160 | COMMAND python3 -m teg --compile "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_bilinear_deriv.py" -f single -t CUDA_C -o "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_bilinear_deriv.h" -m teg_linear_bilinear_deriv 161 | MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/teg_linear_bilinear_deriv.py" 162 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 163 | COMMENT "Building Teg kernels: teg_linear_bilinear_deriv.py" 164 | ) 165 | 166 | set_target_properties(triangulate_const PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 167 | add_dependencies(triangulate_const teg) 168 | target_link_libraries(triangulate_const ${OpenCV_LIBRARIES}) 169 | 170 | set_target_properties(triangulate_linear PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 171 | add_dependencies(triangulate_linear teg) 172 | target_link_libraries(triangulate_linear ${OpenCV_LIBRARIES}) 173 | 174 | set_target_properties(triangulate_quadratic PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 175 | add_dependencies(triangulate_quadratic teg) 176 | target_link_libraries(triangulate_quadratic ${OpenCV_LIBRARIES}) 177 | 178 | set_target_properties(test PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 179 | add_dependencies(test teg) 180 | target_link_libraries(test ${OpenCV_LIBRARIES}) -------------------------------------------------------------------------------- /graphics/triangulation/common.cuh: -------------------------------------------------------------------------------- 1 | #include "triangle.cuh" 2 | 3 | #define BETA_1 0.9 4 | #define BETA_2 0.99 5 | #define EPS 10e-8 6 | 7 | int generate_jobs(int image_width, int image_height, 8 | TriMesh* trimesh, 9 | int* tids, int* pids ) { 10 | int job_count = 0; 11 | for (int tid = 0; tid < trimesh->num_triangles; tid++) { 12 | 13 | AABB aabb = trimesh->triangles[tid].aabb(trimesh->vertices); 14 | 15 | int max_x = std::ceil(aabb.max.x) + 2; //(int)(std::ceil( std::max(vx0, std::max(vx1, vx2)))) + 1; 16 | int max_y = std::ceil(aabb.max.y) + 2; //(int)(std::ceil( std::max(vy0, std::max(vy1, vy2)))) + 1; 17 | int min_x = std::floor(aabb.min.x) - 2; //(int)(std::floor( std::min(vx0, std::min(vx1, vx2)))) - 1; 18 | int min_y = std::floor(aabb.min.y) - 2; //(int)(std::floor( std::min(vy0, std::min(vy1, vy2)))) - 1; 19 | 20 | if (min_x < 0) min_x = 0; 21 | if (min_y < 0) min_y = 0; 22 | if (max_x >= image_width) max_x = image_width - 1; 23 | if (max_y >= image_height) max_y = image_height - 1; 24 | 25 | for (int tx = min_x; tx <= max_x; tx++) { 26 | for (int ty = min_y; ty <= max_y; ty++) { 27 | tids[job_count] = tid; 28 | pids[job_count] = tx * image_height + ty; 29 | //if(job_count % 100000 == 0) std::cout << job_count << " " << tid << " " << max_x << " " << max_y << " " << min_x << " " << min_y << std::endl; 30 | job_count ++; 31 | } 32 | } 33 | } 34 | 35 | return job_count; 36 | } 37 | 38 | float sgn(float x){ 39 | return (x > 0) ? 1: -1; 40 | } 41 | 42 | int compute_triangle_regularization(TriMesh* mesh, 43 | DTriMesh* d_mesh, 44 | float alpha=1) { 45 | 46 | for (int tid = 0; tid < mesh->num_triangles; tid++) { 47 | Vertex* a = mesh->tv0(tid); 48 | Vertex* b = mesh->tv1(tid); 49 | Vertex* c = mesh->tv2(tid); 50 | 51 | // Cross-product for area 52 | float area = ((a->x - b->x)*(a->y - c->y) - (a->x - c->x)*(a->y - b->y)) / alpha; 53 | 54 | DVertex* d_a = d_mesh->tv0(tid); 55 | DVertex* d_b = d_mesh->tv1(tid); 56 | DVertex* d_c = d_mesh->tv2(tid); 57 | 58 | d_a->x += (-1.0/area) * (b->y - c->y); 59 | d_a->y += (-1.0/area) * (c->x - b->x); 60 | 61 | d_b->x += (-1.0/area) * (c->y - a->y); 62 | d_b->y += (-1.0/area) * (a->x - c->x); 63 | 64 | d_c->x += (-1.0/area) * (a->y - b->y); 65 | d_c->y += (-1.0/area) * (b->x - a->x); 66 | 67 | } 68 | 69 | } 70 | 71 | /* 72 | int build_initial_triangles(TriMesh* trimesh, 73 | int nx, int ny, 74 | int image_width, int image_height) { 75 | 76 | float tri_width = (float)(image_width) / nx; 77 | float tri_height = (float)(image_height) / ny; 78 | 79 | cudaMallocManaged(&trimesh->vertices, sizeof(Vertex) * (nx + 1) * (ny + 1)); 80 | cudaMallocManaged(&trimesh->weights, sizeof(float) * (nx + 1) * (ny + 1)); 81 | int num_vertices = 0; 82 | for(int i = 0; i < nx + 1; i++) { 83 | for(int j = 0; j < ny + 1; j++) { 84 | Vertex* a = trimesh->vertices + (i * (ny + 1) + j); 85 | a->x = tri_width * i; 86 | a->y = tri_height * j; 87 | trimesh->weights[(i * (ny + 1) + j)] = !((i == 0) || (j == 0) || (i == nx) || (j == ny)); 88 | num_vertices ++; 89 | } 90 | } 91 | 92 | cudaMallocManaged(&trimesh->triangles, sizeof(Triangle) * (nx) * (ny) * 2); 93 | 94 | int num_triangles = 0; 95 | for(int i = 0; i < nx; i++) { 96 | for(int j = 0; j < ny; j++) { 97 | trimesh->triangles[2 * (i * ny + j)] = Triangle{((i + 0) * (ny + 1) + j + 0), 98 | ((i + 0) * (ny + 1) + j + 1), 99 | ((i + 1) * (ny + 1) + j + 1)}; 100 | 101 | trimesh->triangles[2 * (i * ny + j) + 1] = Triangle{((i + 0) * (ny + 1) + j + 0), 102 | ((i + 1) * (ny + 1) + j + 1), 103 | ((i + 1) * (ny + 1) + j + 0)}; 104 | 105 | num_triangles += 2; 106 | } 107 | } 108 | 109 | trimesh->num_triangles = num_triangles; 110 | trimesh->num_vertices = num_vertices; 111 | 112 | std::cout << "Built triangles " << num_triangles << ", " << num_vertices << std::endl; 113 | return num_triangles; 114 | }*/ 115 | 116 | int build_initial_triangles(TriMesh* trimesh, 117 | int nx, int ny, 118 | int image_width, int image_height) { 119 | 120 | float tri_width = (float)(image_width) / nx; 121 | float tri_height = (float)(image_height) / ny; 122 | 123 | 124 | cudaMallocManaged(&trimesh->vertices, sizeof(Vertex) * (nx + 1) * (ny + 1)); 125 | cudaMallocManaged(&trimesh->weights, sizeof(float) * (nx + 1) * (ny + 1)); 126 | int num_vertices = 0; 127 | for(int i = 0; i < nx + 1; i++) { 128 | for(int j = 0; j < ny + 1; j++) { 129 | Vertex* a = trimesh->vertices + (i * (ny + 1) + j); 130 | a->x = tri_width * i; 131 | a->y = tri_height * j; 132 | trimesh->weights[(i * (ny + 1) + j)] = !((i == 0) || (j == 0) || (i == nx) || (j == ny)); 133 | num_vertices ++; 134 | } 135 | } 136 | 137 | cudaMallocManaged(&trimesh->triangles, sizeof(Triangle) * (nx) * (ny) * 2); 138 | 139 | int num_triangles = 0; 140 | for(int i = 0; i < nx; i++) { 141 | for(int j = 0; j < ny; j++) { 142 | trimesh->triangles[2 * (i * ny + j)] = Triangle{((i + 0) * (ny + 1) + j + 0), 143 | ((i + 0) * (ny + 1) + j + 1), 144 | ((i + 1) * (ny + 1) + j + 1)}; 145 | 146 | trimesh->triangles[2 * (i * ny + j) + 1] = Triangle{((i + 0) * (ny + 1) + j + 0), 147 | ((i + 1) * (ny + 1) + j + 1), 148 | ((i + 1) * (ny + 1) + j + 0)}; 149 | 150 | num_triangles += 2; 151 | } 152 | } 153 | 154 | trimesh->num_triangles = num_triangles; 155 | trimesh->num_vertices = num_vertices; 156 | 157 | std::cout << "Built triangles " << num_triangles << ", " << num_vertices << std::endl; 158 | return num_triangles; 159 | } 160 | 161 | template 162 | __global__ 163 | void set_zero(T* data, int max_id) { 164 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 165 | if(idx < max_id) 166 | data[idx] = 0; 167 | } 168 | 169 | 170 | template 171 | __global__ 172 | void set_value(T* data, T val, int max_id) { 173 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 174 | if(idx < max_id) 175 | data[idx] = val; 176 | } 177 | 178 | 179 | __host__ 180 | void build_d_mesh(TriMesh* trimesh, 181 | DTriMesh** d_trimesh) { 182 | 183 | cudaMallocManaged(d_trimesh, sizeof(DTriMesh)); 184 | cudaMallocManaged(&((*d_trimesh)->d_vertices), sizeof(DVertex) * trimesh->num_vertices); 185 | cudaMallocManaged(&((*d_trimesh)->d_mean), sizeof(DVertex) * trimesh->num_vertices); 186 | cudaMallocManaged(&((*d_trimesh)->d_variance), sizeof(DVertex) * trimesh->num_vertices); 187 | (*d_trimesh)->trimesh = trimesh; 188 | (*d_trimesh)->num_vertices = trimesh->num_vertices; 189 | set_zero<<<((trimesh->num_vertices) / 256) + 1, 256>>>((*d_trimesh)->d_vertices, trimesh->num_vertices); 190 | set_zero<<<((trimesh->num_vertices) / 256) + 1, 256>>>((*d_trimesh)->d_mean, trimesh->num_vertices); 191 | set_zero<<<((trimesh->num_vertices) / 256) + 1, 256>>>((*d_trimesh)->d_variance, trimesh->num_vertices); 192 | cudaDeviceSynchronize(); 193 | } 194 | 195 | __global__ 196 | void update_vertices(TriMesh* mesh, 197 | DTriMesh* d_mesh, 198 | float alpha) 199 | { 200 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 201 | 202 | if (idx > mesh->num_vertices) 203 | return; 204 | 205 | Vertex* a = mesh->vertices + idx; 206 | DVertex* d_a = d_mesh->d_vertices + idx; 207 | DVertex* d_mean = d_mesh->d_mean + idx; 208 | DVertex* d_variance = d_mesh->d_variance + idx; 209 | 210 | d_mean->x = (d_mean->x) * BETA_1 + (1 - BETA_1) * d_a->x; 211 | d_variance->x = (d_variance->x) * BETA_2 + (1 - BETA_2) * d_a->x * d_a->x; 212 | 213 | d_mean->y = (d_mean->y) * BETA_1 + (1 - BETA_1) * d_a->y; 214 | d_variance->y = (d_variance->y) * BETA_2 + (1 - BETA_2) * d_a->y * d_a->y; 215 | 216 | float mean_x_hat = d_mean->x / (1 - BETA_1); 217 | float variance_x_hat = d_variance->x / (1 - BETA_2); 218 | 219 | float mean_y_hat = d_mean->y / (1 - BETA_1); 220 | float variance_y_hat = d_variance->y / (1 - BETA_2); 221 | 222 | // a->x = a->x - alpha * d_a->x * mesh->weights[idx]; 223 | // a->y = a->y - alpha * d_a->y * mesh->weights[idx]; 224 | a->x = a->x - (alpha * mean_x_hat) / (sqrt(variance_x_hat) + EPS); 225 | a->y = a->y - (alpha * mean_y_hat) / (sqrt(variance_y_hat) + EPS); 226 | 227 | } 228 | 229 | 230 | std::string type2str(int type) { 231 | std::string r; 232 | 233 | uchar depth = type & CV_MAT_DEPTH_MASK; 234 | uchar chans = 1 + (type >> CV_CN_SHIFT); 235 | 236 | switch ( depth ) { 237 | case CV_8U: r = "8U"; break; 238 | case CV_8S: r = "8S"; break; 239 | case CV_16U: r = "16U"; break; 240 | case CV_16S: r = "16S"; break; 241 | case CV_32S: r = "32S"; break; 242 | case CV_32F: r = "32F"; break; 243 | case CV_64F: r = "64F"; break; 244 | default: r = "User"; break; 245 | } 246 | 247 | r += "C"; 248 | r += (chans+'0'); 249 | 250 | return r; 251 | } -------------------------------------------------------------------------------- /graphics/triangulation/data/chessboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChezJrk/teg_applications/21fd77891a17af0d42abc3425abb734592b03c89/graphics/triangulation/data/chessboard.jpg -------------------------------------------------------------------------------- /graphics/triangulation/data/sunset.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChezJrk/teg_applications/21fd77891a17af0d42abc3425abb734592b03c89/graphics/triangulation/data/sunset.jpg -------------------------------------------------------------------------------- /graphics/triangulation/integral.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Var, 3 | TegVar, 4 | IfElse, 5 | Teg, 6 | Tup 7 | ) 8 | 9 | 10 | def make_teg_program(): 11 | # Triangle vertices 12 | tx1 = Var("tx1", 2) 13 | tx2 = Var("tx2", 2) 14 | tx3 = Var("tx3", 2) 15 | 16 | ty1 = Var("ty1", 2) 17 | ty2 = Var("ty2", 2) 18 | ty3 = Var("ty3", 2) 19 | 20 | # Pixel boundaries 21 | px0 = Var("px0", 2) 22 | px1 = Var("px1", 2) 23 | 24 | py0 = Var("py0", 2) 25 | py1 = Var("py1", 2) 26 | 27 | # Triangle color 28 | tc0, tc1, tc2 = (Var("tc0", 0), Var("tc1", 0), Var("tc2", 0)) 29 | 30 | # Variables of integration. 31 | x = TegVar("x") 32 | y = TegVar("y") 33 | 34 | line12_determinant = (tx1 * ty2 - tx2 * ty1) + (ty1 - ty2) * x + (tx2 - tx1) * y 35 | line23_determinant = (tx2 * ty3 - tx3 * ty2) + (ty2 - ty3) * x + (tx3 - tx2) * y 36 | line31_determinant = (tx3 * ty1 - tx1 * ty3) + (ty3 - ty1) * x + (tx1 - tx3) * y 37 | 38 | # Build active mask. 39 | point_mask = (IfElse(line12_determinant < 0, 1, 0) * 40 | IfElse(line23_determinant < 0, 1, 0) * 41 | IfElse(line31_determinant < 0, 1, 0)) 42 | 43 | point_color = Tup(tc0, tc1, tc2) 44 | 45 | integral_x = Teg(px0, px1, point_color * point_mask, x) 46 | integral = Teg(py0, py1, integral_x, y) 47 | 48 | # Specify argument ordering. 49 | arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 50 | px0, px1, 51 | py0, py1, 52 | tc0, tc1, tc2) 53 | 54 | return integral, arglist 55 | 56 | 57 | __PROGRAM__, __ARGLIST__ = make_teg_program() 58 | -------------------------------------------------------------------------------- /graphics/triangulation/loss.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Const, 3 | Var, 4 | TegVar, 5 | IfElse, 6 | Teg, 7 | Tup 8 | ) 9 | 10 | from teg.math import ( 11 | Sqr 12 | ) 13 | 14 | 15 | from teg.derivs.reverse_deriv import reverse_deriv 16 | from teg.passes.reduce import reduce_to_base 17 | from teg.passes.simplify import simplify 18 | 19 | 20 | def make_teg_program(): 21 | # Triangle vertices 22 | tx1 = Var("tx1", 2) 23 | tx2 = Var("tx2", 2) 24 | tx3 = Var("tx3", 2) 25 | 26 | ty1 = Var("ty1", 2) 27 | ty2 = Var("ty2", 2) 28 | ty3 = Var("ty3", 2) 29 | 30 | # Pixel boundaries 31 | px0 = Var("px0", 2) 32 | px1 = Var("px1", 2) 33 | 34 | py0 = Var("py0", 2) 35 | py1 = Var("py1", 2) 36 | 37 | # Pixel color 38 | c0, c1, c2 = (Var("pc0", 0), Var("pc1", 0), Var("pc2", 0)) 39 | 40 | # Triangle color 41 | tc0, tc1, tc2 = (Var("tc0", 0), Var("tc1", 0), Var("tc2", 0)) 42 | 43 | # Variables of integration. 44 | x = TegVar("x") 45 | y = TegVar("y") 46 | 47 | line12_determinant = (tx1 * ty2 - tx2 * ty1) + (ty1 - ty2) * x + (tx2 - tx1) * y 48 | line23_determinant = (tx2 * ty3 - tx3 * ty2) + (ty2 - ty3) * x + (tx3 - tx2) * y 49 | line31_determinant = (tx3 * ty1 - tx1 * ty3) + (ty3 - ty1) * x + (tx1 - tx3) * y 50 | 51 | # Build active mask. 52 | point_mask = (IfElse(line12_determinant < 0, 1, 0) * 53 | IfElse(line23_determinant < 0, 1, 0) * 54 | IfElse(line31_determinant < 0, 1, 0)) 55 | 56 | point_loss = Sqr(tc0 - c0) + Sqr(tc1 - c1) + Sqr(tc2 - c2) 57 | 58 | integral_x = Teg(px0, px1, point_loss * point_mask, x) 59 | integral_xy = Teg(py0, py1, integral_x, y) 60 | 61 | # Specify argument ordering. 62 | arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 63 | px0, px1, 64 | py0, py1, 65 | c0, c1, c2, 66 | tc0, tc1, tc2) 67 | 68 | return integral_xy, arglist 69 | 70 | 71 | __PROGRAM__, __ARGLIST__ = make_teg_program() 72 | -------------------------------------------------------------------------------- /graphics/triangulation/loss_function.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Const, 3 | Var, 4 | TegVar, 5 | IfElse, 6 | Teg, 7 | Tup 8 | ) 9 | 10 | from teg.math import ( 11 | Sqr 12 | ) 13 | 14 | 15 | from teg.derivs.reverse_deriv import reverse_deriv 16 | from teg.passes.reduce import reduce_to_base 17 | from teg.passes.simplify import simplify 18 | 19 | 20 | def make_teg_program(): 21 | # Triangle vertices 22 | tx1 = Var("tx1", 2) 23 | tx2 = Var("tx2", 2) 24 | tx3 = Var("tx3", 2) 25 | 26 | ty1 = Var("ty1", 2) 27 | ty2 = Var("ty2", 2) 28 | ty3 = Var("ty3", 2) 29 | 30 | # Pixel boundaries 31 | px0 = Var("px0", 2) 32 | px1 = Var("px1", 2) 33 | 34 | py0 = Var("py0", 2) 35 | py1 = Var("py1", 2) 36 | 37 | # Pixel color 38 | c0, c1, c2 = (Var("pc0", 0), Var("pc1", 0), Var("pc2", 0)) 39 | 40 | # Triangle color 41 | tc0, tc1, tc2 = (Var("tc0", 0), Var("tc1", 0), Var("tc2", 0)) 42 | 43 | # Variables of integration. 44 | x = TegVar("x") 45 | y = TegVar("y") 46 | 47 | line12_determinant = (tx1 * ty2 - tx2 * ty1) + (ty1 - ty2) * x + (tx2 - tx1) * y 48 | line23_determinant = (tx2 * ty3 - tx3 * ty2) + (ty2 - ty3) * x + (tx3 - tx2) * y 49 | line31_determinant = (tx3 * ty1 - tx1 * ty3) + (ty3 - ty1) * x + (tx1 - tx3) * y 50 | 51 | # Build active mask. 52 | point_mask = (IfElse(line12_determinant < 0, 1, 0) * 53 | IfElse(line23_determinant < 0, 1, 0) * 54 | IfElse(line31_determinant < 0, 1, 0)) 55 | 56 | point_loss = Sqr(tc0 - c0) + Sqr(tc1 - c1) + Sqr(tc2 - c2) 57 | 58 | integral_x = Teg(px0, px1, point_loss * point_mask, x) 59 | _, integral = reverse_deriv(Teg(py0, py1, integral_x, y), Tup(Const(1))) 60 | integral = reduce_to_base(simplify(integral)) 61 | 62 | # Specify argument ordering. 63 | arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 64 | px0, px1, 65 | py0, py1, 66 | c0, c1, c2, 67 | tc0, tc1, tc2) 68 | 69 | return integral, arglist 70 | 71 | 72 | __PROGRAM__, __ARGLIST__ = make_teg_program() 73 | -------------------------------------------------------------------------------- /graphics/triangulation/quadratic.cuh: -------------------------------------------------------------------------------- 1 | #include "triangle.cuh" 2 | 3 | #include "teg_quadratic_integral.h" 4 | #include "teg_quadratic_deriv.h" 5 | #include "teg_quadratic_loss.h" 6 | #include "teg_quadratic_deriv_nodelta.h" 7 | 8 | __global__ 9 | void update_quadratic_colors(int num_colors, 10 | QuadraticFragment* colors, 11 | DQuadraticFragment* d_colors, 12 | float alpha) 13 | { 14 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 15 | 16 | if (idx > num_colors) 17 | return; 18 | 19 | Color* c0 = &colors[idx].c0; 20 | DColor* d_c0 = &d_colors[idx].d_c0; 21 | c0->r = c0->r - alpha * d_c0->r; 22 | c0->g = c0->g - alpha * d_c0->g; 23 | c0->b = c0->b - alpha * d_c0->b; 24 | 25 | Color* c1 = &colors[idx].c1; 26 | DColor* d_c1 = &d_colors[idx].d_c1; 27 | c1->r = c1->r - alpha * d_c1->r; 28 | c1->g = c1->g - alpha * d_c1->g; 29 | c1->b = c1->b - alpha * d_c1->b; 30 | 31 | Color* c2 = &colors[idx].c2; 32 | DColor* d_c2 = &d_colors[idx].d_c2; 33 | c2->r = c2->r - alpha * d_c2->r; 34 | c2->g = c2->g - alpha * d_c2->g; 35 | c2->b = c2->b - alpha * d_c2->b; 36 | 37 | Color* c0h = &colors[idx].c0h; 38 | DColor* d_c0h = &d_colors[idx].d_c0h; 39 | c0h->r = c0h->r - alpha * d_c0h->r; 40 | c0h->g = c0h->g - alpha * d_c0h->g; 41 | c0h->b = c0h->b - alpha * d_c0h->b; 42 | 43 | Color* c1h = &colors[idx].c1h; 44 | DColor* d_c1h = &d_colors[idx].d_c1h; 45 | c1h->r = c1h->r - alpha * d_c1h->r; 46 | c1h->g = c1h->g - alpha * d_c1h->g; 47 | c1h->b = c1h->b - alpha * d_c1h->b; 48 | 49 | Color* c2h = &colors[idx].c2h; 50 | DColor* d_c2h = &d_colors[idx].d_c2h; 51 | c2h->r = c2h->r - alpha * d_c2h->r; 52 | c2h->g = c2h->g - alpha * d_c2h->g; 53 | c2h->b = c2h->b - alpha * d_c2h->b; 54 | } 55 | 56 | 57 | __host__ 58 | void build_quadratic_colors(TriMesh* trimesh, 59 | QuadraticFragment** colors) { 60 | 61 | cudaMallocManaged(colors, sizeof(QuadraticFragment) * trimesh->num_triangles); 62 | Color def = Color{0.5, 0.5, 0.5}; 63 | set_value<<<((trimesh->num_triangles) / 256) + 1, 256>>>( 64 | *colors, QuadraticFragment{def, def, def, def, def, def}, trimesh->num_triangles); 65 | cudaDeviceSynchronize(); 66 | 67 | } 68 | 69 | __host__ 70 | void build_d_quadratic_colors(TriMesh* trimesh, 71 | DQuadraticFragment** d_colors) { 72 | 73 | cudaMallocManaged(d_colors, sizeof(DQuadraticFragment) * trimesh->num_triangles); 74 | set_zero<<<((trimesh->num_triangles) / 256) + 1, 256>>>(*d_colors, trimesh->num_triangles); 75 | cudaDeviceSynchronize(); 76 | 77 | } 78 | 79 | 80 | __global__ 81 | void quadratic_integral_kernel(int* tids, 82 | int* pids, 83 | int num_jobs, 84 | TriMesh* mesh, 85 | QuadraticFragment* colors, 86 | float* image, 87 | int w, int h) 88 | { 89 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 90 | if(idx >= num_jobs) return; 91 | 92 | auto tri_id = tids[idx]; 93 | auto pixel_id = pids[idx]; 94 | 95 | Vertex* a = mesh->tv0(tri_id); 96 | Vertex* b = mesh->tv1(tri_id); 97 | Vertex* c = mesh->tv2(tri_id); 98 | 99 | Color tricolor0 = colors[tri_id].c0; 100 | Color tricolor1 = colors[tri_id].c1; 101 | Color tricolor2 = colors[tri_id].c2; 102 | 103 | Color tricolor0h = colors[tri_id].c0h; 104 | Color tricolor1h = colors[tri_id].c1h; 105 | Color tricolor2h = colors[tri_id].c2h; 106 | 107 | // Run generated teg function. 108 | auto outvals = teg_quadratic_integral( 109 | a->x,a->y, 110 | b->x,b->y, 111 | c->x,c->y, 112 | 113 | floorf(pixel_id / h), 114 | floorf(pixel_id / h) + 1, 115 | (float)(pixel_id % h), 116 | (float)(pixel_id % h + 1), 117 | 118 | tricolor0.r, tricolor0.g, tricolor0.b, 119 | tricolor1.r, tricolor1.g, tricolor1.b, 120 | tricolor2.r, tricolor2.g, tricolor2.b, 121 | 122 | tricolor0h.r, tricolor0h.g, tricolor0h.b, 123 | tricolor1h.r, tricolor1h.g, tricolor1h.b, 124 | tricolor2h.r, tricolor2h.g, tricolor2h.b 125 | ); 126 | 127 | // Accumulate image. 128 | atomicAdd(&image[pixel_id * 3 + 0], outvals[0]); 129 | atomicAdd(&image[pixel_id * 3 + 1], outvals[1]); 130 | atomicAdd(&image[pixel_id * 3 + 2], outvals[2]); 131 | } 132 | 133 | __device__ 134 | float clamp(float x, float low, float high) { 135 | return (x >= high) ? (high-1) : ((x < low) ? low : x); 136 | } 137 | 138 | 139 | __global__ 140 | void quadratic_loss_kernel(int* tids, 141 | int* pids, 142 | int num_jobs, 143 | Image* image, 144 | TriMesh* mesh, 145 | QuadraticFragment* colors, 146 | float* loss_image) 147 | { 148 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 149 | 150 | if(idx >= num_jobs) 151 | return; 152 | 153 | auto tri_id = tids[idx]; 154 | auto pixel_id = pids[idx]; 155 | 156 | Vertex* a = mesh->tv0(tri_id); 157 | Vertex* b = mesh->tv1(tri_id); 158 | Vertex* c = mesh->tv2(tri_id); 159 | 160 | Color pixel = image->colors[pixel_id]; 161 | Color tricolor0 = colors[tri_id].c0; 162 | Color tricolor1 = colors[tri_id].c1; 163 | Color tricolor2 = colors[tri_id].c2; 164 | 165 | Color tricolor0h = colors[tri_id].c0h; 166 | Color tricolor1h = colors[tri_id].c1h; 167 | Color tricolor2h = colors[tri_id].c2h; 168 | 169 | int h = image->cols; 170 | // Run generated teg function. 171 | auto outval = teg_quadratic_loss( 172 | a->x,a->y, 173 | b->x,b->y, 174 | c->x,c->y, 175 | 176 | floorf(pixel_id / h), 177 | floorf(pixel_id / h) + 1, 178 | (float)(pixel_id % h), 179 | (float)(pixel_id % h + 1), 180 | 181 | pixel.r, 182 | pixel.g, 183 | pixel.b, 184 | 185 | tricolor0.r, tricolor0.g, tricolor0.b, 186 | tricolor1.r, tricolor1.g, tricolor1.b, 187 | tricolor2.r, tricolor2.g, tricolor2.b, 188 | 189 | tricolor0h.r, tricolor0h.g, tricolor0h.b, 190 | tricolor1h.r, tricolor1h.g, tricolor1h.b, 191 | tricolor2h.r, tricolor2h.g, tricolor2h.b 192 | ); 193 | 194 | // Accumulate derivatives. 195 | // TODO: There needs to be an easier way to accumulate derivatives.. 196 | atomicAdd(&loss_image[pixel_id], outval); 197 | 198 | } 199 | 200 | __global__ 201 | void quadratic_deriv_kernel(int* tids, 202 | int* pids, 203 | int num_jobs, 204 | Image* image, 205 | TriMesh* mesh, 206 | DTriMesh* d_mesh, 207 | QuadraticFragment* colors, 208 | DQuadraticFragment* d_colors) 209 | { 210 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 211 | 212 | if(idx >= num_jobs) 213 | return; 214 | 215 | auto tri_id = tids[idx]; 216 | auto pixel_id = pids[idx]; 217 | 218 | Vertex* a = mesh->tv0(tri_id); 219 | Vertex* b = mesh->tv1(tri_id); 220 | Vertex* c = mesh->tv2(tri_id); 221 | 222 | Color pixel = image->colors[pixel_id]; 223 | Color tricolor0 = colors[tri_id].c0; 224 | Color tricolor1 = colors[tri_id].c1; 225 | Color tricolor2 = colors[tri_id].c2; 226 | 227 | Color tricolor0h = colors[tri_id].c0h; 228 | Color tricolor1h = colors[tri_id].c1h; 229 | Color tricolor2h = colors[tri_id].c2h; 230 | 231 | int h = image->cols; 232 | // Run generated teg function. 233 | auto outvals = teg_quadratic_deriv( 234 | a->x,a->y, 235 | b->x,b->y, 236 | c->x,c->y, 237 | 238 | floorf(pixel_id / h), 239 | floorf(pixel_id / h) + 1, 240 | (float)(pixel_id % h), 241 | (float)(pixel_id % h + 1), 242 | 243 | pixel.r, 244 | pixel.g, 245 | pixel.b, 246 | 247 | tricolor0.r, tricolor0.g, tricolor0.b, 248 | tricolor1.r, tricolor1.g, tricolor1.b, 249 | tricolor2.r, tricolor2.g, tricolor2.b, 250 | 251 | tricolor0h.r, tricolor0h.g, tricolor0h.b, 252 | tricolor1h.r, tricolor1h.g, tricolor1h.b, 253 | tricolor2h.r, tricolor2h.g, tricolor2h.b 254 | ); 255 | 256 | DVertex* d_a = d_mesh->tv0(tri_id); 257 | DVertex* d_b = d_mesh->tv1(tri_id); 258 | DVertex* d_c = d_mesh->tv2(tri_id); 259 | 260 | DQuadraticFragment *d_pcolor = d_colors + tri_id; 261 | 262 | // Accumulate derivatives. 263 | // TODO: There needs to be an easier way to accumulate derivatives.. 264 | atomicAdd(&d_a->x, outvals[0]); 265 | atomicAdd(&d_b->x, outvals[1]); 266 | atomicAdd(&d_c->x, outvals[2]); 267 | 268 | atomicAdd(&d_a->y, outvals[3]); 269 | atomicAdd(&d_b->y, outvals[4]); 270 | atomicAdd(&d_c->y, outvals[5]); 271 | 272 | atomicAdd(&d_pcolor->d_c0.r, outvals[6]); 273 | atomicAdd(&d_pcolor->d_c0.g, outvals[7]); 274 | atomicAdd(&d_pcolor->d_c0.b, outvals[8]); 275 | 276 | atomicAdd(&d_pcolor->d_c1.r, outvals[9]); 277 | atomicAdd(&d_pcolor->d_c1.g, outvals[10]); 278 | atomicAdd(&d_pcolor->d_c1.b, outvals[11]); 279 | 280 | atomicAdd(&d_pcolor->d_c2.r, outvals[12]); 281 | atomicAdd(&d_pcolor->d_c2.g, outvals[13]); 282 | atomicAdd(&d_pcolor->d_c2.b, outvals[14]); 283 | 284 | atomicAdd(&d_pcolor->d_c0h.r, outvals[15]); 285 | atomicAdd(&d_pcolor->d_c0h.g, outvals[16]); 286 | atomicAdd(&d_pcolor->d_c0h.b, outvals[17]); 287 | 288 | atomicAdd(&d_pcolor->d_c1h.r, outvals[18]); 289 | atomicAdd(&d_pcolor->d_c1h.g, outvals[19]); 290 | atomicAdd(&d_pcolor->d_c1h.b, outvals[20]); 291 | 292 | atomicAdd(&d_pcolor->d_c2h.r, outvals[21]); 293 | atomicAdd(&d_pcolor->d_c2h.g, outvals[22]); 294 | atomicAdd(&d_pcolor->d_c2h.b, outvals[23]); 295 | 296 | } 297 | 298 | 299 | __global__ 300 | void quadratic_deriv_kernel_nodelta(int* tids, 301 | int* pids, 302 | int num_jobs, 303 | Image* image, 304 | TriMesh* mesh, 305 | DTriMesh* d_mesh, 306 | QuadraticFragment* colors, 307 | DQuadraticFragment* d_colors) 308 | { 309 | int idx = blockIdx.x * blockDim.x + threadIdx.x; 310 | 311 | if(idx >= num_jobs) 312 | return; 313 | 314 | auto tri_id = tids[idx]; 315 | auto pixel_id = pids[idx]; 316 | 317 | Vertex* a = mesh->tv0(tri_id); 318 | Vertex* b = mesh->tv1(tri_id); 319 | Vertex* c = mesh->tv2(tri_id); 320 | 321 | Color pixel = image->colors[pixel_id]; 322 | Color tricolor0 = colors[tri_id].c0; 323 | Color tricolor1 = colors[tri_id].c1; 324 | Color tricolor2 = colors[tri_id].c2; 325 | 326 | Color tricolor0h = colors[tri_id].c0h; 327 | Color tricolor1h = colors[tri_id].c1h; 328 | Color tricolor2h = colors[tri_id].c2h; 329 | 330 | int h = image->cols; 331 | // Run generated teg function. 332 | auto outvals = teg_quadratic_deriv_nodelta( 333 | a->x,a->y, 334 | b->x,b->y, 335 | c->x,c->y, 336 | 337 | floorf(pixel_id / h), 338 | floorf(pixel_id / h) + 1, 339 | (float)(pixel_id % h), 340 | (float)(pixel_id % h + 1), 341 | 342 | pixel.r, 343 | pixel.g, 344 | pixel.b, 345 | 346 | tricolor0.r, tricolor0.g, tricolor0.b, 347 | tricolor1.r, tricolor1.g, tricolor1.b, 348 | tricolor2.r, tricolor2.g, tricolor2.b, 349 | 350 | tricolor0h.r, tricolor0h.g, tricolor0h.b, 351 | tricolor1h.r, tricolor1h.g, tricolor1h.b, 352 | tricolor2h.r, tricolor2h.g, tricolor2h.b 353 | ); 354 | 355 | DVertex* d_a = d_mesh->tv0(tri_id); 356 | DVertex* d_b = d_mesh->tv1(tri_id); 357 | DVertex* d_c = d_mesh->tv2(tri_id); 358 | 359 | DQuadraticFragment *d_pcolor = d_colors + tri_id; 360 | 361 | // Accumulate derivatives. 362 | // TODO: There needs to be an easier way to accumulate derivatives.. 363 | atomicAdd(&d_a->x, outvals[0]); 364 | atomicAdd(&d_b->x, outvals[1]); 365 | atomicAdd(&d_c->x, outvals[2]); 366 | 367 | atomicAdd(&d_a->y, outvals[3]); 368 | atomicAdd(&d_b->y, outvals[4]); 369 | atomicAdd(&d_c->y, outvals[5]); 370 | 371 | atomicAdd(&d_pcolor->d_c0.r, outvals[6]); 372 | atomicAdd(&d_pcolor->d_c0.g, outvals[7]); 373 | atomicAdd(&d_pcolor->d_c0.b, outvals[8]); 374 | 375 | atomicAdd(&d_pcolor->d_c1.r, outvals[9]); 376 | atomicAdd(&d_pcolor->d_c1.g, outvals[10]); 377 | atomicAdd(&d_pcolor->d_c1.b, outvals[11]); 378 | 379 | atomicAdd(&d_pcolor->d_c2.r, outvals[12]); 380 | atomicAdd(&d_pcolor->d_c2.g, outvals[13]); 381 | atomicAdd(&d_pcolor->d_c2.b, outvals[14]); 382 | 383 | atomicAdd(&d_pcolor->d_c0h.r, outvals[15]); 384 | atomicAdd(&d_pcolor->d_c0h.g, outvals[16]); 385 | atomicAdd(&d_pcolor->d_c0h.b, outvals[17]); 386 | 387 | atomicAdd(&d_pcolor->d_c1h.r, outvals[18]); 388 | atomicAdd(&d_pcolor->d_c1h.g, outvals[19]); 389 | atomicAdd(&d_pcolor->d_c1h.b, outvals[20]); 390 | 391 | atomicAdd(&d_pcolor->d_c2h.r, outvals[21]); 392 | atomicAdd(&d_pcolor->d_c2h.g, outvals[22]); 393 | atomicAdd(&d_pcolor->d_c2h.b, outvals[23]); 394 | 395 | } -------------------------------------------------------------------------------- /graphics/triangulation/scripts/get_cuda_sm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Credits: https://stackoverflow.com/users/1593077/einpoklum 4 | # 5 | # Prints the compute capability of the first CUDA device installed 6 | # on the system, or alternatively the device whose index is the 7 | # first command-line argument 8 | 9 | device_index=${1:-0} 10 | timestamp=$(date +%s.%N) 11 | gcc_binary=$(which g++) 12 | gcc_binary=${gcc_binary:-g++} 13 | cuda_root=${CUDA_DIR:-/usr/local/cuda} 14 | CUDA_INCLUDE_DIRS=${CUDA_INCLUDE_DIRS:-${cuda_root}/include} 15 | CUDA_CUDART_LIBRARY=${CUDA_CUDART_LIBRARY:-${cuda_root}/lib64/libcudart.so} 16 | generated_binary="/tmp/cuda-compute-version-helper-$$-$timestamp" 17 | # create a 'here document' that is code we compile and use to probe the card 18 | source_code="$(cat << EOF 19 | #include 20 | #include 21 | 22 | int main() 23 | { 24 | cudaDeviceProp prop; 25 | cudaError_t status; 26 | int device_count; 27 | status = cudaGetDeviceCount(&device_count); 28 | if (status != cudaSuccess) { 29 | fprintf(stderr,"cudaGetDeviceCount() failed: %s\n", cudaGetErrorString(status)); 30 | return -1; 31 | } 32 | if (${device_index} >= device_count) { 33 | fprintf(stderr, "Specified device index %d exceeds the maximum (the device count on this system is %d)\n", ${device_index}, device_count); 34 | return -1; 35 | } 36 | status = cudaGetDeviceProperties(&prop, ${device_index}); 37 | if (status != cudaSuccess) { 38 | fprintf(stderr,"cudaGetDeviceProperties() for device ${device_index} failed: %s\n", cudaGetErrorString(status)); 39 | return -1; 40 | } 41 | int v = prop.major * 10 + prop.minor; 42 | printf("%d\\n", v); 43 | } 44 | EOF 45 | )" 46 | echo "$source_code" | $gcc_binary -x c++ -I"$CUDA_INCLUDE_DIRS" -o "$generated_binary" - -x none "$CUDA_CUDART_LIBRARY" 47 | 48 | # probe the card and cleanup 49 | 50 | $generated_binary 51 | rm $generated_binary -------------------------------------------------------------------------------- /graphics/triangulation/teg_linear_base.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Const, 3 | Var, 4 | TegVar, 5 | IfElse, 6 | Teg, 7 | Tup 8 | ) 9 | 10 | from teg.math import ( 11 | Sqr 12 | ) 13 | 14 | 15 | def make_linear_integral(): 16 | # Triangle vertices 17 | tx1 = Var("tx1", 2) 18 | tx2 = Var("tx2", 2) 19 | tx3 = Var("tx3", 2) 20 | 21 | ty1 = Var("ty1", 2) 22 | ty2 = Var("ty2", 2) 23 | ty3 = Var("ty3", 2) 24 | 25 | # Pixel boundaries 26 | px0 = Var("px0", 2) 27 | px1 = Var("px1", 2) 28 | 29 | py0 = Var("py0", 2) 30 | py1 = Var("py1", 2) 31 | 32 | # Pixel color 33 | c0, c1, c2 = (Var("pc0", 0), Var("pc1", 0), Var("pc2", 0)) 34 | 35 | # Tri-vertex colors 36 | tc00, tc10, tc20 = (Var("tc00", 0), Var("tc10", 0), Var("tc20", 0)) 37 | tc01, tc11, tc21 = (Var("tc01", 0), Var("tc11", 0), Var("tc21", 0)) 38 | tc02, tc12, tc22 = (Var("tc02", 0), Var("tc12", 0), Var("tc22", 0)) 39 | 40 | # Variables of integration. 41 | x = TegVar("x") 42 | y = TegVar("y") 43 | 44 | line12_determinant = (tx1 * ty2 - tx2 * ty1) + (ty1 - ty2) * x + (tx2 - tx1) * y 45 | line23_determinant = (tx2 * ty3 - tx3 * ty2) + (ty2 - ty3) * x + (tx3 - tx2) * y 46 | line31_determinant = (tx3 * ty1 - tx1 * ty3) + (ty3 - ty1) * x + (tx1 - tx3) * y 47 | 48 | # Build active mask. 49 | point_mask = (IfElse(line12_determinant < 0, 1, 0) * 50 | IfElse(line23_determinant < 0, 1, 0) * 51 | IfElse(line31_determinant < 0, 1, 0)) 52 | 53 | # Barycentric interpolation 54 | alpha = (((x - tx2) * (y - ty3) - (x - tx3) * (y - ty2))) 55 | beta = (((x - tx3) * (y - ty1) - (x - tx1) * (y - ty3))) 56 | gamma = (((x - tx1) * (y - ty2) - (x - tx2) * (y - ty1))) 57 | 58 | norm = alpha + beta + gamma 59 | tc0 = (alpha * tc00 + beta * tc01 + gamma * tc02) / norm 60 | tc1 = (alpha * tc10 + beta * tc11 + gamma * tc12) / norm 61 | tc2 = (alpha * tc20 + beta * tc21 + gamma * tc22) / norm 62 | 63 | point_loss = Sqr(tc0 - c0) + Sqr(tc1 - c1) + Sqr(tc2 - c2) 64 | point_color = Tup(tc0, tc1, tc2) 65 | 66 | integral_x = Teg(px0, px1, point_loss * point_mask, x) 67 | integral_xy = Teg(py0, py1, integral_x, y) 68 | 69 | color_integral_x = Teg(px0, px1, point_color * point_mask, x) 70 | color_integral_xy = Teg(py0, py1, color_integral_x, y) 71 | 72 | arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 73 | px0, px1, 74 | py0, py1, 75 | c0, c1, c2, 76 | tc00, tc10, tc20, 77 | tc01, tc11, tc21, 78 | tc02, tc12, tc22) 79 | 80 | color_arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 81 | px0, px1, 82 | py0, py1, 83 | tc00, tc10, tc20, 84 | tc01, tc11, tc21, 85 | tc02, tc12, tc22) 86 | 87 | return (integral_xy, arglist), (color_integral_xy, color_arglist) 88 | -------------------------------------------------------------------------------- /graphics/triangulation/teg_linear_bilinear_base.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Const, 3 | Var, 4 | TegVar, 5 | IfElse, 6 | Teg, 7 | Tup 8 | ) 9 | 10 | from teg.math import ( 11 | Sqr 12 | ) 13 | 14 | 15 | def make_linear_bilinear_integral(): 16 | # Triangle vertices 17 | tx1 = Var("tx1", 2) 18 | tx2 = Var("tx2", 2) 19 | tx3 = Var("tx3", 2) 20 | 21 | ty1 = Var("ty1", 2) 22 | ty2 = Var("ty2", 2) 23 | ty3 = Var("ty3", 2) 24 | 25 | # Pixel boundaries 26 | px0 = Var("px0", 2) 27 | px1 = Var("px1", 2) 28 | 29 | py0 = Var("py0", 2) 30 | py1 = Var("py1", 2) 31 | 32 | # Pixel corner color 33 | c00r, c00g, c00b = (Var("pc00r", 0), Var("pc00g", 0), Var("pc00b", 0)) 34 | c01r, c01g, c01b = (Var("pc01r", 0), Var("pc01g", 0), Var("pc01b", 0)) 35 | c10r, c10g, c10b = (Var("pc10r", 0), Var("pc10g", 0), Var("pc10b", 0)) 36 | c11r, c11g, c11b = (Var("pc11r", 0), Var("pc11g", 0), Var("pc11b", 0)) 37 | 38 | # Tri-vertex colors 39 | tc00, tc10, tc20 = (Var("tc00", 0), Var("tc10", 0), Var("tc20", 0)) 40 | tc01, tc11, tc21 = (Var("tc01", 0), Var("tc11", 0), Var("tc21", 0)) 41 | tc02, tc12, tc22 = (Var("tc02", 0), Var("tc12", 0), Var("tc22", 0)) 42 | 43 | # Variables of integration. 44 | x = TegVar("x") 45 | y = TegVar("y") 46 | 47 | line12_determinant = (tx1 * ty2 - tx2 * ty1) + (ty1 - ty2) * x + (tx2 - tx1) * y 48 | line23_determinant = (tx2 * ty3 - tx3 * ty2) + (ty2 - ty3) * x + (tx3 - tx2) * y 49 | line31_determinant = (tx3 * ty1 - tx1 * ty3) + (ty3 - ty1) * x + (tx1 - tx3) * y 50 | 51 | # Build active mask. 52 | point_mask = (IfElse(line12_determinant < 0, 1, 0) * 53 | IfElse(line23_determinant < 0, 1, 0) * 54 | IfElse(line31_determinant < 0, 1, 0)) 55 | 56 | # Barycentric interpolation 57 | alpha = (((x - tx2) * (y - ty3) - (x - tx3) * (y - ty2))) 58 | beta = (((x - tx3) * (y - ty1) - (x - tx1) * (y - ty3))) 59 | gamma = (((x - tx1) * (y - ty2) - (x - tx2) * (y - ty1))) 60 | 61 | norm = alpha + beta + gamma 62 | tc0 = (alpha * tc00 + beta * tc01 + gamma * tc02) / norm 63 | tc1 = (alpha * tc10 + beta * tc11 + gamma * tc12) / norm 64 | tc2 = (alpha * tc20 + beta * tc21 + gamma * tc22) / norm 65 | 66 | # Bilinear interpolation 67 | c0r = (x - px0) * c10r + (px1 - x) * c00r 68 | c0g = (x - px0) * c10g + (px1 - x) * c00g 69 | c0b = (x - px0) * c10b + (px1 - x) * c00b 70 | 71 | c1r = (x - px0) * c11r + (px1 - x) * c01r 72 | c1g = (x - px0) * c11g + (px1 - x) * c01g 73 | c1b = (x - px0) * c11b + (px1 - x) * c01b 74 | 75 | cr = (y - py0) * c1r + (py1 - y) * c0r 76 | cg = (y - py0) * c1g + (py1 - y) * c0g 77 | cb = (y - py0) * c1b + (py1 - y) * c0b 78 | 79 | point_loss = Sqr(tc0 - cr) + Sqr(tc1 - cg) + Sqr(tc2 - cb) 80 | point_color = Tup(tc0, tc1, tc2) 81 | 82 | integral_x = Teg(px0, px1, point_loss * point_mask, x) 83 | integral_xy = Teg(py0, py1, integral_x, y) 84 | 85 | color_integral_x = Teg(px0, px1, point_color * point_mask, x) 86 | color_integral_xy = Teg(py0, py1, color_integral_x, y) 87 | 88 | arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 89 | px0, px1, 90 | py0, py1, 91 | 92 | c00r, c00g, c00b, 93 | c01r, c01g, c01b, 94 | c10r, c10g, c10b, 95 | c11r, c11g, c11b, 96 | 97 | tc00, tc10, tc20, 98 | tc01, tc11, tc21, 99 | tc02, tc12, tc22) 100 | 101 | color_arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 102 | px0, px1, 103 | py0, py1, 104 | tc00, tc10, tc20, 105 | tc01, tc11, tc21, 106 | tc02, tc12, tc22) 107 | 108 | return (integral_xy, arglist), (color_integral_xy, color_arglist) 109 | -------------------------------------------------------------------------------- /graphics/triangulation/teg_linear_bilinear_deriv.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Tup, 3 | Const 4 | ) 5 | 6 | from teg.derivs.reverse_deriv import reverse_deriv 7 | from teg.passes.reduce import reduce_to_base 8 | from teg.passes.simplify import simplify 9 | 10 | from teg_linear_bilinear_base import make_linear_bilinear_integral 11 | 12 | 13 | def make_teg_program(): 14 | (integral_xy, arglist), _ = make_linear_bilinear_integral() 15 | 16 | (tx1, ty1, tx2, ty2, tx3, ty3, 17 | px0, px1, 18 | py0, py1, 19 | 20 | c00r, c00g, c00b, 21 | c01r, c01g, c01b, 22 | c10r, c10g, c10b, 23 | c11r, c11g, c11b, 24 | 25 | tc00, tc10, tc20, 26 | tc01, tc11, tc21, 27 | tc02, tc12, tc22) = arglist 28 | 29 | output_list = [tx1, tx2, tx3, 30 | ty1, ty2, ty3, 31 | tc00, tc10, tc20, 32 | tc01, tc11, tc21, 33 | tc02, tc12, tc22] 34 | 35 | _, integral = reverse_deriv(integral_xy, Tup(Const(1)), output_list=output_list) 36 | integral = reduce_to_base(simplify(integral)) 37 | 38 | return integral, arglist 39 | 40 | 41 | __PROGRAM__, __ARGLIST__ = make_teg_program() 42 | -------------------------------------------------------------------------------- /graphics/triangulation/teg_linear_bilinear_integral.py: -------------------------------------------------------------------------------- 1 | from teg_linear_bilinear_base import make_linear_bilinear_integral 2 | 3 | 4 | def make_teg_program(): 5 | _, (integral_xy, arglist) = make_linear_bilinear_integral() 6 | 7 | return integral_xy, arglist 8 | 9 | 10 | __PROGRAM__, __ARGLIST__ = make_teg_program() 11 | -------------------------------------------------------------------------------- /graphics/triangulation/teg_linear_deriv.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Tup, 3 | Const 4 | ) 5 | 6 | from teg.derivs.reverse_deriv import reverse_deriv 7 | from teg.passes.reduce import reduce_to_base 8 | from teg.passes.simplify import simplify 9 | 10 | from teg_linear_base import make_linear_integral 11 | 12 | 13 | def make_teg_program(): 14 | (integral_xy, arglist), _ = make_linear_integral() 15 | 16 | (tx1, ty1, tx2, ty2, tx3, ty3, 17 | px0, px1, 18 | py0, py1, 19 | c0, c1, c2, 20 | tc00, tc10, tc20, 21 | tc01, tc11, tc21, 22 | tc02, tc12, tc22) = arglist 23 | 24 | output_list = [tx1, tx2, tx3, 25 | ty1, ty2, ty3, 26 | tc00, tc10, tc20, 27 | tc01, tc11, tc21, 28 | tc02, tc12, tc22] 29 | 30 | _, integral = reverse_deriv(integral_xy, Tup(Const(1)), output_list=output_list) 31 | integral = reduce_to_base(simplify(integral)) 32 | 33 | # Specify argument ordering. 34 | arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 35 | px0, px1, 36 | py0, py1, 37 | c0, c1, c2, 38 | tc00, tc10, tc20, 39 | tc01, tc11, tc21, 40 | tc02, tc12, tc22) 41 | 42 | return integral, arglist 43 | 44 | 45 | __PROGRAM__, __ARGLIST__ = make_teg_program() 46 | -------------------------------------------------------------------------------- /graphics/triangulation/teg_linear_deriv_nodelta.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Tup, 3 | Const 4 | ) 5 | 6 | from teg.derivs.reverse_deriv import reverse_deriv 7 | from teg.passes.reduce import reduce_to_base 8 | from teg.passes.simplify import simplify 9 | 10 | from teg_linear_base import make_linear_integral 11 | 12 | 13 | def make_teg_program(): 14 | (integral_xy, arglist), _ = make_linear_integral() 15 | 16 | (tx1, ty1, tx2, ty2, tx3, ty3, 17 | px0, px1, 18 | py0, py1, 19 | c0, c1, c2, 20 | tc00, tc10, tc20, 21 | tc01, tc11, tc21, 22 | tc02, tc12, tc22) = arglist 23 | 24 | output_list = [tx1, tx2, tx3, 25 | ty1, ty2, ty3, 26 | tc00, tc10, tc20, 27 | tc01, tc11, tc21, 28 | tc02, tc12, tc22] 29 | 30 | _, integral = reverse_deriv(integral_xy, Tup(Const(1)), output_list=output_list, args={'ignore_deltas': True}) 31 | integral = reduce_to_base(simplify(integral)) 32 | 33 | # Specify argument ordering. 34 | arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 35 | px0, px1, 36 | py0, py1, 37 | c0, c1, c2, 38 | tc00, tc10, tc20, 39 | tc01, tc11, tc21, 40 | tc02, tc12, tc22) 41 | 42 | return integral, arglist 43 | 44 | 45 | __PROGRAM__, __ARGLIST__ = make_teg_program() 46 | -------------------------------------------------------------------------------- /graphics/triangulation/teg_linear_integral.py: -------------------------------------------------------------------------------- 1 | from teg_linear_base import make_linear_integral 2 | 3 | 4 | def make_teg_program(): 5 | _, (integral_xy, arglist) = make_linear_integral() 6 | 7 | return integral_xy, arglist 8 | 9 | 10 | __PROGRAM__, __ARGLIST__ = make_teg_program() 11 | -------------------------------------------------------------------------------- /graphics/triangulation/teg_linear_loss.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Tup, 3 | Const 4 | ) 5 | 6 | from teg.derivs.reverse_deriv import reverse_deriv 7 | from teg.passes.reduce import reduce_to_base 8 | from teg.passes.simplify import simplify 9 | 10 | from teg_linear_base import make_linear_integral 11 | 12 | 13 | def make_teg_program(): 14 | (integral_xy, arglist), _ = make_linear_integral() 15 | return integral_xy, arglist 16 | 17 | 18 | __PROGRAM__, __ARGLIST__ = make_teg_program() 19 | -------------------------------------------------------------------------------- /graphics/triangulation/teg_quadratic_base.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Const, 3 | Var, 4 | TegVar, 5 | IfElse, 6 | Teg, 7 | Tup 8 | ) 9 | 10 | from teg.math import ( 11 | Sqr 12 | ) 13 | 14 | 15 | def make_quadratic_integral(): 16 | # Triangle vertices 17 | tx1 = Var("tx1", 2) 18 | tx2 = Var("tx2", 2) 19 | tx3 = Var("tx3", 2) 20 | 21 | ty1 = Var("ty1", 2) 22 | ty2 = Var("ty2", 2) 23 | ty3 = Var("ty3", 2) 24 | 25 | # Pixel boundaries 26 | px0 = Var("px0", 2) 27 | px1 = Var("px1", 2) 28 | 29 | py0 = Var("py0", 2) 30 | py1 = Var("py1", 2) 31 | 32 | # Pixel color 33 | c0, c1, c2 = (Var("pc0", 0), Var("pc1", 0), Var("pc2", 0)) 34 | 35 | # Tri-vertex colors 36 | tc00, tc10, tc20 = (Var("tc00", 0), Var("tc10", 0), Var("tc20", 0)) 37 | tc01, tc11, tc21 = (Var("tc01", 0), Var("tc11", 0), Var("tc21", 0)) 38 | tc02, tc12, tc22 = (Var("tc02", 0), Var("tc12", 0), Var("tc22", 0)) 39 | 40 | # Half-edge colors. 41 | tch00, tch10, tch20 = (Var("tch00", 0), Var("tch10", 0), Var("tch20", 0)) 42 | tch01, tch11, tch21 = (Var("tch01", 0), Var("tch11", 0), Var("tch21", 0)) 43 | tch02, tch12, tch22 = (Var("tch02", 0), Var("tch12", 0), Var("tch22", 0)) 44 | 45 | # Variables of integration. 46 | x = TegVar("x") 47 | y = TegVar("y") 48 | 49 | line12_determinant = (tx1 * ty2 - tx2 * ty1) + (ty1 - ty2) * x + (tx2 - tx1) * y 50 | line23_determinant = (tx2 * ty3 - tx3 * ty2) + (ty2 - ty3) * x + (tx3 - tx2) * y 51 | line31_determinant = (tx3 * ty1 - tx1 * ty3) + (ty3 - ty1) * x + (tx1 - tx3) * y 52 | 53 | # Build active mask. 54 | point_mask = (IfElse(line12_determinant < 0, 1, 0) * 55 | IfElse(line23_determinant < 0, 1, 0) * 56 | IfElse(line31_determinant < 0, 1, 0)) 57 | 58 | # Quadratic FEM interpolation 59 | alpha = (((x - tx2) * (y - ty3) - (x - tx3) * (y - ty2))) 60 | beta = (((x - tx3) * (y - ty1) - (x - tx1) * (y - ty3))) 61 | gamma = (((x - tx1) * (y - ty2) - (x - tx2) * (y - ty1))) 62 | norm = alpha + beta + gamma 63 | 64 | alpha = alpha / norm 65 | beta = beta / norm 66 | gamma = gamma / norm 67 | 68 | N_200 = (alpha) * (2*alpha - 1) 69 | N_020 = (beta) * (2*beta - 1) 70 | N_002 = (gamma) * (2*gamma - 1) 71 | 72 | N_011 = 4 * beta * gamma 73 | N_101 = 4 * alpha * gamma 74 | N_110 = 4 * alpha * beta 75 | 76 | tc0 = (N_200 * tc00 + N_020 * tc01 + N_002 * tc02 + N_011 * tch00 + N_101 * tch01 + N_110 * tch02) 77 | tc1 = (N_200 * tc10 + N_020 * tc11 + N_002 * tc12 + N_011 * tch10 + N_101 * tch11 + N_110 * tch12) 78 | tc2 = (N_200 * tc20 + N_020 * tc21 + N_002 * tc22 + N_011 * tch20 + N_101 * tch21 + N_110 * tch22) 79 | 80 | point_loss = Sqr(tc0 - c0) + Sqr(tc1 - c1) + Sqr(tc2 - c2) 81 | point_color = Tup(tc0, tc1, tc2) 82 | 83 | integral_x = Teg(px0, px1, point_loss * point_mask, x) 84 | integral_xy = Teg(py0, py1, integral_x, y) 85 | 86 | color_integral_x = Teg(px0, px1, point_color * point_mask, x) 87 | color_integral_xy = Teg(py0, py1, color_integral_x, y) 88 | 89 | arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 90 | px0, px1, 91 | py0, py1, 92 | c0, c1, c2, 93 | tc00, tc10, tc20, 94 | tc01, tc11, tc21, 95 | tc02, tc12, tc22, 96 | tch00, tch10, tch20, 97 | tch01, tch11, tch21, 98 | tch02, tch12, tch22) 99 | 100 | color_arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 101 | px0, px1, 102 | py0, py1, 103 | tc00, tc10, tc20, 104 | tc01, tc11, tc21, 105 | tc02, tc12, tc22, 106 | tch00, tch10, tch20, 107 | tch01, tch11, tch21, 108 | tch02, tch12, tch22) 109 | 110 | return (integral_xy, arglist), (color_integral_xy, color_arglist) 111 | -------------------------------------------------------------------------------- /graphics/triangulation/teg_quadratic_deriv.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Tup, 3 | Const 4 | ) 5 | 6 | from teg.derivs.reverse_deriv import reverse_deriv 7 | from teg.passes.reduce import reduce_to_base 8 | from teg.passes.simplify import simplify 9 | 10 | from teg_quadratic_base import make_quadratic_integral 11 | 12 | 13 | def make_teg_program(): 14 | (integral_xy, arglist), _ = make_quadratic_integral() 15 | 16 | (tx1, ty1, tx2, ty2, tx3, ty3, 17 | px0, px1, 18 | py0, py1, 19 | c0, c1, c2, 20 | tc00, tc10, tc20, 21 | tc01, tc11, tc21, 22 | tc02, tc12, tc22, 23 | tch00, tch10, tch20, 24 | tch01, tch11, tch21, 25 | tch02, tch12, tch22) = arglist 26 | 27 | deriv_list = [tx1, tx2, tx3, 28 | ty1, ty2, ty3, 29 | tc00, tc10, tc20, 30 | tc01, tc11, tc21, 31 | tc02, tc12, tc22, 32 | tch00, tch10, tch20, 33 | tch01, tch11, tch21, 34 | tch02, tch12, tch22] 35 | 36 | _, integral = reverse_deriv(integral_xy, Tup(Const(1)), output_list=deriv_list) 37 | integral = reduce_to_base(simplify(integral)) 38 | 39 | # Specify argument ordering. 40 | arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 41 | px0, px1, 42 | py0, py1, 43 | c0, c1, c2, 44 | tc00, tc10, tc20, 45 | tc01, tc11, tc21, 46 | tc02, tc12, tc22, 47 | tch00, tch10, tch20, 48 | tch01, tch11, tch21, 49 | tch02, tch12, tch22) 50 | 51 | return integral, arglist 52 | 53 | 54 | __PROGRAM__, __ARGLIST__ = make_teg_program() 55 | -------------------------------------------------------------------------------- /graphics/triangulation/teg_quadratic_deriv_nodelta.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Tup, 3 | Const 4 | ) 5 | 6 | from teg.derivs.reverse_deriv import reverse_deriv 7 | from teg.passes.reduce import reduce_to_base 8 | from teg.passes.simplify import simplify 9 | 10 | from teg_quadratic_base import make_quadratic_integral 11 | 12 | 13 | def make_teg_program(): 14 | (integral_xy, arglist), _ = make_quadratic_integral() 15 | 16 | (tx1, ty1, tx2, ty2, tx3, ty3, 17 | px0, px1, 18 | py0, py1, 19 | c0, c1, c2, 20 | tc00, tc10, tc20, 21 | tc01, tc11, tc21, 22 | tc02, tc12, tc22, 23 | tch00, tch10, tch20, 24 | tch01, tch11, tch21, 25 | tch02, tch12, tch22) = arglist 26 | 27 | deriv_list = [tx1, tx2, tx3, 28 | ty1, ty2, ty3, 29 | tc00, tc10, tc20, 30 | tc01, tc11, tc21, 31 | tc02, tc12, tc22, 32 | tch00, tch10, tch20, 33 | tch01, tch11, tch21, 34 | tch02, tch12, tch22] 35 | 36 | _, integral = reverse_deriv(integral_xy, Tup(Const(1)), output_list=deriv_list, args={'ignore_deltas': True}) 37 | integral = reduce_to_base(simplify(integral)) 38 | 39 | # Specify argument ordering. 40 | arglist = (tx1, ty1, tx2, ty2, tx3, ty3, 41 | px0, px1, 42 | py0, py1, 43 | c0, c1, c2, 44 | tc00, tc10, tc20, 45 | tc01, tc11, tc21, 46 | tc02, tc12, tc22, 47 | tch00, tch10, tch20, 48 | tch01, tch11, tch21, 49 | tch02, tch12, tch22) 50 | 51 | return integral, arglist 52 | 53 | 54 | __PROGRAM__, __ARGLIST__ = make_teg_program() 55 | -------------------------------------------------------------------------------- /graphics/triangulation/teg_quadratic_integral.py: -------------------------------------------------------------------------------- 1 | from teg_quadratic_base import make_quadratic_integral 2 | 3 | 4 | def make_teg_program(): 5 | _, (integral_xy, arglist) = make_quadratic_integral() 6 | 7 | return integral_xy, arglist 8 | 9 | 10 | __PROGRAM__, __ARGLIST__ = make_teg_program() 11 | -------------------------------------------------------------------------------- /graphics/triangulation/teg_quadratic_loss.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | Tup, 3 | Const 4 | ) 5 | 6 | from teg.derivs.reverse_deriv import reverse_deriv 7 | from teg.passes.reduce import reduce_to_base 8 | from teg.passes.simplify import simplify 9 | 10 | from teg_quadratic_base import make_quadratic_integral 11 | 12 | 13 | def make_teg_program(): 14 | (integral_xy, arglist), _ = make_quadratic_integral() 15 | return integral_xy, arglist 16 | 17 | 18 | __PROGRAM__, __ARGLIST__ = make_teg_program() 19 | -------------------------------------------------------------------------------- /graphics/triangulation/tegpixel.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChezJrk/teg_applications/21fd77891a17af0d42abc3425abb734592b03c89/graphics/triangulation/tegpixel.py -------------------------------------------------------------------------------- /graphics/triangulation/test.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include "math.h" 3 | #include 4 | 5 | // Image IO 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "common.cuh" 12 | #include "triangle.cuh" 13 | // Output generated from Teg 14 | #include "quadratic.cuh" 15 | //#include "linear.cuh" 16 | 17 | int main(int argc, char** argv) 18 | { 19 | 20 | 21 | TriMesh* mesh; 22 | 23 | cudaMallocManaged(&mesh, sizeof(TriMesh)); 24 | 25 | mesh->num_vertices = 3; 26 | cudaMallocManaged(&(mesh->vertices), sizeof(Vertex) * mesh->num_vertices); 27 | 28 | cudaMallocManaged(&(mesh->weights), sizeof(float) * 3); 29 | 30 | mesh->num_triangles = 1; 31 | cudaMallocManaged(&(mesh->triangles), sizeof(Triangle) * mesh->num_triangles); 32 | 33 | mesh->vertices[0] = Vertex{100, 100}; 34 | mesh->vertices[1] = Vertex{400, 100}; 35 | mesh->vertices[2] = Vertex{100, 400}; 36 | 37 | mesh->triangles[0] = Triangle{0, 2, 1}; 38 | 39 | 40 | QuadraticFragment* colors; 41 | cudaMallocManaged(&colors, sizeof(QuadraticFragment) * 1); 42 | colors[0] = QuadraticFragment{Color{0, 1, 0}, Color{0, 0, 1}, Color{1, 0, 0}, 43 | Color{1, 0, 1}, Color{1, 1, 0}, Color{0, 1, 1}}; 44 | 45 | /* 46 | LinearFragment* colors; 47 | cudaMallocManaged(&colors, sizeof(LinearFragment) * 1); 48 | colors[0] = LinearFragment{Color{0, 1, 0}, Color{0, 0, 1}, Color{1, 0, 0}}; 49 | */ 50 | 51 | 52 | int h = 512; 53 | int w = 512; 54 | 55 | float* triangle_image; 56 | char* triangle_bimage = (char*) malloc(w * h * 3); 57 | cudaMallocManaged(&triangle_image, sizeof(float) * w * h * 3); 58 | 59 | int* tids; 60 | int* pids; 61 | 62 | int num_jobs = w * h; 63 | cudaMallocManaged(&tids, num_jobs * sizeof(int)); 64 | cudaMallocManaged(&pids, num_jobs * sizeof(int)); 65 | 66 | for (int i = 0; i < h * w; i++) { 67 | tids[i] = 0; 68 | pids[i] = i; 69 | } 70 | 71 | set_zero<<<((w * h * 3) / 256) + 1, 256>>>(triangle_image, (w * h * 3) ); 72 | 73 | // Render triangles to image. 74 | quadratic_integral_kernel<<<(num_jobs / 256) + 1, 256>>>( 75 | tids, 76 | pids, 77 | num_jobs, 78 | mesh, 79 | colors, 80 | triangle_image, 81 | w, h); 82 | 83 | cudaDeviceSynchronize(); 84 | 85 | for(int idx = 0; idx < w * h * 3; idx ++){ 86 | int _val = (int)(triangle_image[idx] * 256); 87 | triangle_bimage[idx] = (char) ((_val < 0) ? 0 : (_val > 255 ? 255 : _val)); 88 | } 89 | 90 | std::stringstream ss; 91 | ss << "test.png"; 92 | cv::imwrite(ss.str(), cv::Mat(w, h, CV_8UC3, triangle_bimage)); 93 | 94 | 95 | cudaFree(triangle_image); 96 | cudaFree(tids); 97 | cudaFree(pids); 98 | 99 | } -------------------------------------------------------------------------------- /graphics/triangulation/triangle.cuh: -------------------------------------------------------------------------------- 1 | #ifndef TRIANGLE_CUH 2 | #define TRIANGLE_CUH 3 | 4 | struct Color { 5 | float r; 6 | float g; 7 | float b; 8 | }; 9 | 10 | struct DColor { 11 | float r; 12 | float g; 13 | float b; 14 | }; 15 | 16 | struct Vertex { 17 | float x; 18 | float y; 19 | }; 20 | 21 | struct DVertex { 22 | float x; 23 | float y; 24 | 25 | __device__ __host__ void operator=(const float in) { 26 | x = in; 27 | y = in; 28 | } 29 | }; 30 | 31 | struct ConstFragment{ 32 | Color c; 33 | __device__ __host__ void operator=(const float in) { 34 | c = Color{in, in, in}; 35 | } 36 | __device__ __host__ void operator=(const Color in) { 37 | c = in; 38 | } 39 | }; 40 | 41 | struct DConstFragment{ 42 | DColor d_c; 43 | __device__ __host__ void operator=(const float in) { 44 | d_c = DColor{in, in, in}; 45 | } 46 | __device__ __host__ void operator=(const DColor d_in) { 47 | d_c = d_in; 48 | } 49 | }; 50 | 51 | struct LinearFragment{ 52 | Color c0; 53 | Color c1; 54 | Color c2; 55 | 56 | __device__ __host__ void operator=(const float in) { 57 | c0 = Color{in, in, in}; 58 | c1 = Color{in, in, in}; 59 | c2 = Color{in, in, in}; 60 | } 61 | __device__ __host__ void operator=(const Color in) { 62 | c0 = in; 63 | c1 = in; 64 | c2 = in; 65 | } 66 | }; 67 | 68 | struct DLinearFragment{ 69 | DColor d_c0; 70 | DColor d_c1; 71 | DColor d_c2; 72 | 73 | __device__ __host__ void operator=(const float in) { 74 | d_c0 = DColor{in, in, in}; 75 | d_c1 = DColor{in, in, in}; 76 | d_c2 = DColor{in, in, in}; 77 | } 78 | __device__ __host__ void operator=(const DColor in) { 79 | d_c0 = in; 80 | d_c1 = in; 81 | d_c2 = in; 82 | } 83 | }; 84 | 85 | struct QuadraticFragment{ 86 | Color c0; // vertex-colors 87 | Color c1; 88 | Color c2; 89 | Color c0h; // half-colors 90 | Color c1h; 91 | Color c2h; 92 | 93 | __device__ __host__ void operator=(const float in) { 94 | c0 = Color{in, in, in}; 95 | c1 = Color{in, in, in}; 96 | c2 = Color{in, in, in}; 97 | c0h = Color{in, in, in}; 98 | c1h = Color{in, in, in}; 99 | c2h = Color{in, in, in}; 100 | } 101 | __device__ __host__ void operator=(const Color in) { 102 | c0 = in; 103 | c1 = in; 104 | c2 = in; 105 | c0h = in; 106 | c1h = in; 107 | c2h = in; 108 | } 109 | }; 110 | 111 | struct DQuadraticFragment{ 112 | DColor d_c0; // vertex-colors 113 | DColor d_c1; 114 | DColor d_c2; 115 | DColor d_c0h; // half-colors 116 | DColor d_c1h; 117 | DColor d_c2h; 118 | 119 | __device__ __host__ void operator=(const float in) { 120 | d_c0 = DColor{in, in, in}; 121 | d_c1 = DColor{in, in, in}; 122 | d_c2 = DColor{in, in, in}; 123 | d_c0h = DColor{in, in, in}; 124 | d_c1h = DColor{in, in, in}; 125 | d_c2h = DColor{in, in, in}; 126 | } 127 | __device__ __host__ void operator=(const DColor in) { 128 | d_c0 = in; 129 | d_c1 = in; 130 | d_c2 = in; 131 | d_c0h = in; 132 | d_c1h = in; 133 | d_c2h = in; 134 | } 135 | }; 136 | 137 | struct AABB { 138 | Vertex max; 139 | Vertex min; 140 | }; 141 | 142 | struct Triangle { 143 | int a; 144 | int b; 145 | int c; 146 | 147 | __device__ __host__ AABB aabb(Vertex* v) { 148 | Vertex a = v[this->a]; 149 | Vertex b = v[this->b]; 150 | Vertex c = v[this->c]; 151 | return AABB{Vertex{(a.x > b.x) ? ((a.x > c.x) ? a.x : c.x) : ((b.x > c.x) ? b.x : c.x), 152 | (a.y > b.y) ? ((a.y > c.y) ? a.y : c.y) : ((b.y > c.y) ? b.y : c.y)}, 153 | Vertex{(a.x < b.x) ? ((a.x < c.x) ? a.x : c.x) : ((b.x < c.x) ? b.x : c.x), 154 | (a.y < b.y) ? ((a.y < c.y) ? a.y : c.y) : ((b.y < c.y) ? b.y : c.y)}}; 155 | } 156 | }; 157 | 158 | struct SplineTriangle { 159 | int a; 160 | int b; 161 | int c; 162 | 163 | int ah; 164 | int bh; 165 | int ch; 166 | 167 | __device__ __host__ AABB aabb(Vertex* v) { 168 | // TODO: Figure this out. 169 | } 170 | }; 171 | 172 | struct TriMesh { 173 | int num_triangles; 174 | Triangle* triangles; 175 | int num_vertices; 176 | Vertex* vertices; 177 | float* weights; 178 | 179 | __device__ __host__ Vertex* tv0(int i) { 180 | return vertices + triangles[i].a; 181 | } 182 | 183 | __device__ __host__ Vertex* tv1(int i) { 184 | return vertices + triangles[i].b; 185 | } 186 | 187 | __device__ __host__ Vertex* tv2(int i) { 188 | return vertices + triangles[i].c; 189 | } 190 | 191 | __device__ __host__ float wt(int i) { 192 | return weights[i]; 193 | } 194 | }; 195 | 196 | struct DTriMesh { 197 | TriMesh* trimesh; 198 | int num_vertices; 199 | DVertex* d_vertices; 200 | DVertex* d_mean; 201 | DVertex* d_variance; 202 | 203 | __device__ __host__ DVertex* tv0(int i) { 204 | return d_vertices + trimesh->triangles[i].a; 205 | } 206 | 207 | __device__ __host__ DVertex* tv1(int i) { 208 | return d_vertices + trimesh->triangles[i].b; 209 | } 210 | 211 | __device__ __host__ DVertex* tv2(int i) { 212 | return d_vertices + trimesh->triangles[i].c; 213 | } 214 | 215 | __device__ __host__ DVertex* grad_mean(int i) { 216 | return d_mean + trimesh->triangles[i].c; 217 | } 218 | 219 | __device__ __host__ DVertex* grad_variance(int i) { 220 | return d_variance + trimesh->triangles[i].c; 221 | } 222 | 223 | }; 224 | 225 | struct Image { 226 | int rows; 227 | int cols; 228 | Color* colors; 229 | }; 230 | 231 | #endif -------------------------------------------------------------------------------- /graphics/triangulation/triangulate_linear.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include "math.h" 3 | #include 4 | 5 | // Image IO 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "common.cuh" 13 | #include "triangle.cuh" 14 | // Output generated from Teg 15 | #include "linear.cuh" 16 | 17 | 18 | // End Temporary placeholder. 19 | //#define ALPHA_COLOR 0.001 20 | //#define ALPHA_VERTEX 0.08 21 | 22 | #define ALPHA_COLOR 0.3 23 | #define ALPHA_VERTEX 10000 24 | 25 | int main(int argc, char** argv) 26 | { 27 | if (argc != 5) { 28 | std::cout << "Usage: ./triangulate_linear " << std::endl; 29 | exit(1); 30 | } 31 | 32 | std::stringstream ss_nx(argv[2]); 33 | std::stringstream ss_ny(argv[3]); 34 | std::stringstream ss_delta(argv[4]); 35 | 36 | int nx; 37 | int ny; 38 | ss_nx >> nx; 39 | ss_ny >> ny; 40 | 41 | char c_use_deltas; 42 | ss_delta >> c_use_deltas; 43 | if (c_use_deltas != 'y' && c_use_deltas != 'n') { 44 | std::cout << "Please specify y/n for 4th argument" << std::endl; 45 | return -1; 46 | } 47 | bool use_deltas = c_use_deltas == 'y'; 48 | 49 | // Load an image. 50 | cv::Mat image; 51 | image = cv::imread(argv[1], cv::IMREAD_COLOR); 52 | 53 | if( !image.data ) { 54 | std::cout << "Could not open or find the image" << std::endl; 55 | return -1; 56 | } 57 | 58 | std::cout << "Fitting " << image.rows << "x" << image.cols << " image" << std::endl; 59 | 60 | auto pcolor_num = image.rows * image.cols; 61 | auto pcolor_sz = pcolor_num * sizeof(float) * 3; 62 | 63 | auto tcolor_num = nx * ny * 2; 64 | auto tcolor_sz = tcolor_num * sizeof(float) * 3; 65 | 66 | auto vertices_num = (nx + 1) * (ny + 1); 67 | auto vertices_sz = vertices_num * sizeof(float) * 2; 68 | 69 | auto indices_num = nx * ny * 2; 70 | auto indices_sz = indices_num * sizeof(int) * 3; 71 | 72 | auto image_pcs = image.rows * image.cols * 3; 73 | auto image_sz = image_pcs * sizeof(float); 74 | 75 | Image* tri_image; 76 | LinearFragment* colors; 77 | DLinearFragment* d_colors; 78 | TriMesh* mesh; 79 | DTriMesh* d_mesh; 80 | 81 | cudaMallocManaged(&tri_image, sizeof(Image)); 82 | cudaMallocManaged(&mesh, sizeof(TriMesh)); 83 | 84 | build_initial_triangles(mesh, nx, ny, image.rows, image.cols); 85 | build_d_mesh(mesh, &d_mesh); 86 | 87 | std::cout << "Build meshes" << std::endl; 88 | // Const fragments. 89 | build_linear_colors(mesh, &colors); 90 | build_d_linear_colors(mesh, &d_colors); 91 | 92 | std::cout << "Build colors" << std::endl; 93 | 94 | float* triangle_image; 95 | char* triangle_bimage = (char*) malloc(image_pcs * 1); 96 | cudaMallocManaged(&triangle_image, image_sz); 97 | 98 | float* loss_image; 99 | char* loss_bimage = (char*) malloc(image.rows * image.cols * 1); 100 | cudaMallocManaged(&loss_image, sizeof(float) * image.rows * image.cols); 101 | 102 | int max_jobs = image.rows * image.cols * 10 * sizeof(int); 103 | int* tids; 104 | int* pids; 105 | 106 | cudaMallocManaged(&tids, max_jobs * sizeof(int)); 107 | cudaMallocManaged(&pids, max_jobs * sizeof(int)); 108 | 109 | std::cout << type2str(image.type()) << std::endl; 110 | 111 | tri_image->rows = image.rows; 112 | tri_image->cols = image.cols; 113 | cudaMallocManaged(&(tri_image->colors), sizeof(Color) * image.rows * image.cols); 114 | // Load image data. 115 | for(int i = 0; i < image.rows; i++) 116 | for(int j = 0; j < image.cols; j++){ 117 | cv::Vec3b v = image.at(i, j); 118 | tri_image->colors[(image.cols * i + j)].r = ((float)v[0]) / 255.0;//*(image.data + idx + 0); 119 | tri_image->colors[(image.cols * i + j)].g = ((float)v[1]) / 255.0;//*(image.data + idx + 1); 120 | tri_image->colors[(image.cols * i + j)].b = ((float)v[2]) / 255.0;//*(image.data + idx + 2); 121 | } 122 | 123 | //x = (float*) malloc(N*sizeof(float)); 124 | //y = (float*) malloc(N*sizeof(float)); 125 | 126 | int num_jobs = 0; 127 | 128 | std::stringstream loss_string; 129 | for (int iter = 0; iter < 150; iter ++){ 130 | printf("Iteration %d", iter); 131 | 132 | // Zero buffers. 133 | // set_zero<<<((tcolor_num * 3) / 256), 256>>>(d_tcolors); 134 | // set_zero<<<((vertices_num * 2) / 256), 256>>>(d_vertices); 135 | set_zero<<<((mesh->num_triangles) / 256 + 1), 256>>>(d_colors, mesh->num_triangles); 136 | set_zero<<<((mesh->num_vertices) / 256 + 1), 256>>>(d_mesh->d_vertices, mesh->num_triangles); 137 | set_zero<<<(image_pcs / 256) + 1, 256>>>(triangle_image, image_pcs); 138 | set_zero<<<(image.rows * image.cols / 256) + 1, 256>>>(loss_image, image.rows * image.cols); 139 | 140 | num_jobs = generate_jobs(image.rows, image.cols, mesh, tids, pids); 141 | printf("jobs: %d\n", num_jobs); 142 | assert(num_jobs <= max_jobs); 143 | 144 | cudaDeviceSynchronize(); 145 | 146 | // Compute derivatives. 147 | if (use_deltas) { 148 | linear_deriv_kernel<<<(num_jobs / 256) + 1, 256>>>( 149 | tids, 150 | pids, 151 | num_jobs, 152 | tri_image, 153 | mesh, 154 | d_mesh, 155 | colors, 156 | d_colors); 157 | } else { 158 | linear_deriv_kernel_nodelta<<<(num_jobs / 256) + 1, 256>>>( 159 | tids, 160 | pids, 161 | num_jobs, 162 | tri_image, 163 | mesh, 164 | d_mesh, 165 | colors, 166 | d_colors); 167 | } 168 | 169 | cudaDeviceSynchronize(); 170 | 171 | linear_loss_kernel<<<(num_jobs / 256) + 1, 256>>>( 172 | tids, 173 | pids, 174 | num_jobs, 175 | tri_image, 176 | mesh, 177 | colors, 178 | loss_image); 179 | 180 | cudaDeviceSynchronize(); 181 | // TODO: temp disable regularization 182 | // compute_triangle_regularization(mesh, d_mesh); 183 | // Update values. 184 | /*update_values<<< (nx * ny) / 256 + 1, 256 >>>( 185 | nx, ny, vertices, tcolors, d_vertices, d_tcolors, ALPHA 186 | );*/ 187 | compute_triangle_regularization(mesh, d_mesh, 30); 188 | float avg_total_pixel_area = image.rows * image.cols / (nx * ny); 189 | float avg_triangle_surface_area = image.rows * image.cols / (sqrt(nx * ny)); 190 | 191 | update_vertices<<< (mesh->num_vertices) / 256 + 1, 256 >>>( 192 | mesh, d_mesh, ALPHA_VERTEX / avg_triangle_surface_area 193 | ); 194 | 195 | update_linear_colors<<< (mesh->num_triangles) / 256 + 1, 256 >>>( 196 | mesh->num_triangles, colors, d_colors, ALPHA_COLOR / avg_total_pixel_area 197 | ); 198 | 199 | cudaDeviceSynchronize(); 200 | 201 | // Render triangles to image. 202 | linear_integral_kernel<<<(num_jobs / 256) + 1, 256>>>( 203 | tids, 204 | pids, 205 | num_jobs, 206 | mesh, 207 | colors, 208 | triangle_image, 209 | image.rows, image.cols); 210 | 211 | cudaDeviceSynchronize(); 212 | 213 | for(int idx = 0; idx < image_pcs; idx ++){ 214 | int _val = (int)(triangle_image[idx] * 256); 215 | triangle_bimage[idx] = (char) ((_val < 0) ? 0 : (_val > 255 ? 255 : _val)); 216 | } 217 | 218 | float total_loss = 0.f; 219 | for(int idx = 0; idx < image.rows * image.cols; idx ++){ 220 | int _val = (int)(loss_image[idx] * 256); 221 | total_loss += loss_image[idx]; 222 | loss_bimage[idx] = (char) ((_val < 0) ? 0 : (_val > 255 ? 255 : _val)); 223 | } 224 | 225 | loss_string << total_loss << std::endl; 226 | std::cout << "Loss: " << total_loss << std::endl; 227 | 228 | std::stringstream ss; 229 | ss << "iter-" << iter << ".png"; 230 | cv::imwrite(ss.str(), cv::Mat(image.rows, image.cols, CV_8UC3, triangle_bimage)); 231 | std::stringstream ss_loss; 232 | ss_loss << "loss-" << iter << ".png"; 233 | cv::imwrite(ss_loss.str(), cv::Mat(image.rows, image.cols, CV_8UC1, loss_bimage)); 234 | } 235 | 236 | std::ofstream outfile("out.loss"); 237 | outfile << loss_string.str(); 238 | outfile.close(); 239 | 240 | 241 | /*for (int i = 0; i < 50; i++) 242 | for (int j = 0; j < 50; j++){ 243 | float f0 = d_tcolors[(i * 50 + j) * 3 + 0]; 244 | float f1 = d_tcolors[(i * 50 + j) * 3 + 1]; 245 | float f2 = d_tcolors[(i * 50 + j) * 3 + 2]; 246 | if (f0 != 0 || f1 != 0 || f2 != 0) 247 | std::cout << f0 << ", " << f1 << ", " << f2 << std::endl; 248 | } 249 | 250 | for (int i = 0; i < 50; i++) 251 | for (int j = 0; j < 50; j++){ 252 | float f0 = d_vertices[(i * 50 + j) * 2 + 0]; 253 | float f1 = d_vertices[(i * 50 + j) * 2 + 1]; 254 | if (f0 != 0 || f1 != 0) 255 | std::cout << f0 << ", " << f1 << std::endl; 256 | }*/ 257 | 258 | cudaFree(triangle_image); 259 | cudaFree(tids); 260 | cudaFree(pids); 261 | 262 | } -------------------------------------------------------------------------------- /graphics/triangulation/triangulate_quadratic.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include "math.h" 3 | #include 4 | 5 | // Image IO 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "common.cuh" 13 | #include "triangle.cuh" 14 | // Output generated from Teg 15 | #include "quadratic.cuh" 16 | 17 | 18 | // End Temporary placeholder. 19 | #define ALPHA_COLOR 0.5 20 | #define ALPHA_VERTEX 3000 21 | 22 | int main(int argc, char** argv) 23 | { 24 | if (argc != 5) { 25 | std::cout << "Usage: ./triangulate_quadratic " << std::endl; 26 | exit(1); 27 | } 28 | 29 | std::stringstream ss_nx(argv[2]); 30 | std::stringstream ss_ny(argv[3]); 31 | std::stringstream ss_delta(argv[4]); 32 | 33 | int nx; 34 | int ny; 35 | ss_nx >> nx; 36 | ss_ny >> ny; 37 | 38 | char c_use_deltas; 39 | ss_delta >> c_use_deltas; 40 | if (c_use_deltas != 'y' && c_use_deltas != 'n') { 41 | std::cout << "Please specify y/n for 4th argument" << std::endl; 42 | return -1; 43 | } 44 | bool use_deltas = c_use_deltas == 'y'; 45 | 46 | // Load an image. 47 | cv::Mat image; 48 | image = cv::imread(argv[1], cv::IMREAD_COLOR); 49 | 50 | if( !image.data ) { 51 | std::cout << "Could not open or find the image" << std::endl; 52 | return -1; 53 | } 54 | 55 | std::cout << "Fitting " << image.rows << "x" << image.cols << " image" << std::endl; 56 | 57 | auto pcolor_num = image.rows * image.cols; 58 | auto pcolor_sz = pcolor_num * sizeof(float) * 3; 59 | 60 | auto tcolor_num = nx * ny * 2; 61 | auto tcolor_sz = tcolor_num * sizeof(float) * 3; 62 | 63 | auto vertices_num = (nx + 1) * (ny + 1); 64 | auto vertices_sz = vertices_num * sizeof(float) * 2; 65 | 66 | auto indices_num = nx * ny * 2; 67 | auto indices_sz = indices_num * sizeof(int) * 3; 68 | 69 | auto image_pcs = image.rows * image.cols * 3; 70 | auto image_sz = image_pcs * sizeof(float); 71 | 72 | Image* tri_image; 73 | QuadraticFragment* colors; 74 | DQuadraticFragment* d_colors; 75 | TriMesh* mesh; 76 | DTriMesh* d_mesh; 77 | 78 | cudaMallocManaged(&tri_image, sizeof(Image)); 79 | cudaMallocManaged(&mesh, sizeof(TriMesh)); 80 | 81 | build_initial_triangles(mesh, nx, ny, image.rows, image.cols); 82 | build_d_mesh(mesh, &d_mesh); 83 | 84 | std::cout << "Build meshes" << std::endl; 85 | // Const fragments. 86 | build_quadratic_colors(mesh, &colors); 87 | build_d_quadratic_colors(mesh, &d_colors); 88 | 89 | std::cout << "Build colors" << std::endl; 90 | 91 | float* triangle_image; 92 | char* triangle_bimage = (char*) malloc(image_pcs * 1); 93 | cudaMallocManaged(&triangle_image, image_sz); 94 | 95 | float* loss_image; 96 | char* loss_bimage = (char*) malloc(image.rows * image.cols * 1); 97 | cudaMallocManaged(&loss_image, sizeof(float) * image.rows * image.cols); 98 | 99 | int max_jobs = image.rows * image.cols * 10 * sizeof(int); 100 | int* tids; 101 | int* pids; 102 | 103 | cudaMallocManaged(&tids, max_jobs * sizeof(int)); 104 | cudaMallocManaged(&pids, max_jobs * sizeof(int)); 105 | 106 | std::cout << type2str(image.type()) << std::endl; 107 | 108 | tri_image->rows = image.rows; 109 | tri_image->cols = image.cols; 110 | cudaMallocManaged(&(tri_image->colors), sizeof(Color) * image.rows * image.cols); 111 | // Load image data. 112 | for(int i = 0; i < image.rows; i++) 113 | for(int j = 0; j < image.cols; j++){ 114 | cv::Vec3b v = image.at(i, j); 115 | tri_image->colors[(image.cols * i + j)].r = ((float)v[0]) / 255.0;//*(image.data + idx + 0); 116 | tri_image->colors[(image.cols * i + j)].g = ((float)v[1]) / 255.0;//*(image.data + idx + 1); 117 | tri_image->colors[(image.cols * i + j)].b = ((float)v[2]) / 255.0;//*(image.data + idx + 2); 118 | } 119 | 120 | //x = (float*) malloc(N*sizeof(float)); 121 | //y = (float*) malloc(N*sizeof(float)); 122 | 123 | int num_jobs = 0; 124 | 125 | std::stringstream loss_string; 126 | for (int iter = 0; iter < 150; iter ++){ 127 | printf("Iteration %d", iter); 128 | 129 | // Zero buffers. 130 | // set_zero<<<((tcolor_num * 3) / 256), 256>>>(d_tcolors); 131 | // set_zero<<<((vertices_num * 2) / 256), 256>>>(d_vertices); 132 | set_zero<<<((mesh->num_triangles) / 256 + 1), 256>>>(d_colors, mesh->num_triangles); 133 | set_zero<<<((mesh->num_vertices) / 256 + 1), 256>>>(d_mesh->d_vertices, mesh->num_triangles); 134 | set_zero<<<(image_pcs / 256) + 1, 256>>>(triangle_image, image_pcs); 135 | set_zero<<<(image.rows * image.cols / 256) + 1, 256>>>(loss_image, image.rows * image.cols); 136 | 137 | num_jobs = generate_jobs(image.rows, image.cols, mesh, tids, pids); 138 | printf("jobs: %d\n", num_jobs); 139 | assert(num_jobs <= max_jobs); 140 | 141 | cudaDeviceSynchronize(); 142 | 143 | // Compute derivatives. 144 | if (use_deltas) { 145 | quadratic_deriv_kernel<<<(num_jobs / 256) + 1, 256>>>( 146 | tids, 147 | pids, 148 | num_jobs, 149 | tri_image, 150 | mesh, 151 | d_mesh, 152 | colors, 153 | d_colors); 154 | } else { 155 | quadratic_deriv_kernel_nodelta<<<(num_jobs / 256) + 1, 256>>>( 156 | tids, 157 | pids, 158 | num_jobs, 159 | tri_image, 160 | mesh, 161 | d_mesh, 162 | colors, 163 | d_colors); 164 | } 165 | 166 | cudaDeviceSynchronize(); 167 | 168 | quadratic_loss_kernel<<<(num_jobs / 256) + 1, 256>>>( 169 | tids, 170 | pids, 171 | num_jobs, 172 | tri_image, 173 | mesh, 174 | colors, 175 | loss_image); 176 | 177 | cudaDeviceSynchronize(); 178 | // TODO: temp disable regularization 179 | // compute_triangle_regularization(mesh, d_mesh); 180 | // Update values. 181 | /*update_values<<< (nx * ny) / 256 + 1, 256 >>>( 182 | nx, ny, vertices, tcolors, d_vertices, d_tcolors, ALPHA 183 | );*/ 184 | 185 | compute_triangle_regularization(mesh, d_mesh, 5); 186 | 187 | float avg_total_pixel_area = image.rows * image.cols / (nx * ny); 188 | float avg_triangle_surface_area = image.rows * image.cols / (sqrt(nx * ny)); 189 | update_vertices<<< (mesh->num_vertices) / 256 + 1, 256 >>>( 190 | mesh, d_mesh, ALPHA_VERTEX / avg_triangle_surface_area 191 | ); 192 | 193 | update_quadratic_colors<<< (mesh->num_triangles) / 256 + 1, 256 >>>( 194 | mesh->num_triangles, colors, d_colors, ALPHA_COLOR / avg_total_pixel_area 195 | ); 196 | 197 | cudaDeviceSynchronize(); 198 | 199 | // Render triangles to image. 200 | quadratic_integral_kernel<<<(num_jobs / 256) + 1, 256>>>( 201 | tids, 202 | pids, 203 | num_jobs, 204 | mesh, 205 | colors, 206 | triangle_image, 207 | image.rows, image.cols); 208 | 209 | cudaDeviceSynchronize(); 210 | 211 | for(int idx = 0; idx < image_pcs; idx ++){ 212 | int _val = (int)(triangle_image[idx] * 256); 213 | triangle_bimage[idx] = (char) ((_val < 0) ? 0 : (_val > 255 ? 255 : _val)); 214 | } 215 | 216 | float total_loss = 0.f; 217 | for(int idx = 0; idx < image.rows * image.cols; idx ++){ 218 | int _val = (int)(loss_image[idx] * 256); 219 | total_loss += loss_image[idx]; 220 | loss_bimage[idx] = (char) ((_val < 0) ? 0 : (_val > 255 ? 255 : _val)); 221 | } 222 | 223 | std::cout << "Loss: " << total_loss << std::endl; 224 | loss_string << total_loss << std::endl; 225 | 226 | std::stringstream ss; 227 | ss << "iter-" << iter << ".png"; 228 | cv::imwrite(ss.str(), cv::Mat(image.rows, image.cols, CV_8UC3, triangle_bimage)); 229 | std::stringstream ss_loss; 230 | ss_loss << "loss-" << iter << ".png"; 231 | cv::imwrite(ss_loss.str(), cv::Mat(image.rows, image.cols, CV_8UC1, loss_bimage)); 232 | } 233 | 234 | std::ofstream outfile("out.loss"); 235 | outfile << loss_string.str(); 236 | outfile.close(); 237 | 238 | /*for (int i = 0; i < 50; i++) 239 | for (int j = 0; j < 50; j++){ 240 | float f0 = d_tcolors[(i * 50 + j) * 3 + 0]; 241 | float f1 = d_tcolors[(i * 50 + j) * 3 + 1]; 242 | float f2 = d_tcolors[(i * 50 + j) * 3 + 2]; 243 | if (f0 != 0 || f1 != 0 || f2 != 0) 244 | std::cout << f0 << ", " << f1 << ", " << f2 << std::endl; 245 | } 246 | 247 | for (int i = 0; i < 50; i++) 248 | for (int j = 0; j < 50; j++){ 249 | float f0 = d_vertices[(i * 50 + j) * 2 + 0]; 250 | float f1 = d_vertices[(i * 50 + j) * 2 + 1]; 251 | if (f0 != 0 || f1 != 0) 252 | std::cout << f0 << ", " << f1 << std::endl; 253 | }*/ 254 | 255 | cudaFree(triangle_image); 256 | cudaFree(tids); 257 | cudaFree(pids); 258 | 259 | } -------------------------------------------------------------------------------- /physics/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChezJrk/teg_applications/21fd77891a17af0d42abc3425abb734592b03c89/physics/__init__.py -------------------------------------------------------------------------------- /physics/billiards_constraints.py: -------------------------------------------------------------------------------- 1 | from typing import Union, Optional 2 | import collections 3 | import numpy as np 4 | import pprint 5 | import textwrap 6 | 7 | 8 | # inputs 9 | 10 | class Wall(object): 11 | def __init__(self, x0, y0, x1, y1, normalx=None, normaly=None): 12 | super().__init__() 13 | self.x0 = x0 14 | self.y0 = y0 15 | self.x1 = x1 16 | self.y1 = y1 17 | self.normalx = normalx if normalx is not None else -(y1 - y0) 18 | self.normaly = normaly if normalx is not None else x1 - x0 19 | 20 | def __repr__(self): 21 | return f'{self.__class__.__name__}(x0={self.x0!r}, y0={self.y0!r}, x1={self.x1!r}, y1={self.y1!r})' 22 | 23 | 24 | class Tee(object): 25 | def __init__(self, x, y, t=0): 26 | super().__init__() 27 | self.x = x 28 | self.y = y 29 | self.t = t 30 | 31 | def __repr__(self): 32 | return f'{self.__class__.__name__}(x={self.x!r}, y={self.y!r}, t={self.t!r})' 33 | 34 | 35 | class Pocket(object): 36 | def __init__(self, x, y, t=1): 37 | super().__init__() 38 | self.x = x 39 | self.y = y 40 | self.t = t 41 | 42 | def __repr__(self): 43 | return f'{self.__class__.__name__}(x={self.x!r}, y={self.y!r}, t={self.t!r})' 44 | 45 | 46 | class BilliardsProblem(object): 47 | def __init__(self, tee: Tee, walls: [Wall], pocket: Pocket): 48 | super().__init__() 49 | self.tee = tee 50 | self.walls = walls 51 | self.pocket = pocket 52 | 53 | def __repr__(self): 54 | return ( 55 | f'{self.__class__.__name__}(\n' 56 | f' tee={self.tee!r},\n' 57 | f' walls={self.walls!r},\n' 58 | f' pocket={self.pocket!r},\n' 59 | f')' 60 | ) 61 | 62 | 63 | # outputs 64 | 65 | class Path(object): 66 | def __init__(self): 67 | super().__init__() 68 | 69 | def interpolate(self, t): 70 | raise NotImplementedError 71 | 72 | 73 | class LinearPath(Path): 74 | def __init__(self, ts, xs): 75 | super().__init__() 76 | assert len(ts) > 0 77 | assert len(ts) == len(xs) 78 | self.ts = ts 79 | self.xs = xs 80 | 81 | def interpolate(self, t): 82 | if t < self.ts[0]: 83 | return self.xs[0] 84 | for t0, t1, x0, x1 in zip(self.ts, self.ts[1:], self.xs, self.xs[1:]): 85 | if t <= t1: 86 | return remap(t, t0, t1, x0, x1) 87 | return self.xs[-1] 88 | 89 | def __str__(self): 90 | return f'LinearPath: ts={self.ts}, xs={self.xs}' 91 | 92 | 93 | # helpers 94 | 95 | def remap(t, t0, t1, x0, x1): 96 | s = (t - t0) / (t1 - t0) 97 | return x0 + s*(x1 - x0) 98 | 99 | 100 | # solvers 101 | 102 | def solve_analytic(prob: BilliardsProblem) -> Optional[Path]: 103 | start = prob.tee 104 | w0 = prob.walls[0] 105 | end = prob.pocket 106 | 107 | def flip_over_wall(p, w: Wall): 108 | a = np.array([w.x0, w.y0]) 109 | b = np.array([w.x1, w.y1]) 110 | t = np.dot(p - a, b - a) / np.dot(b - a, b - a) 111 | proj_p_on_wall = a + t * (b - a) 112 | return 2 * proj_p_on_wall - p 113 | 114 | def on_correct_side(p, w: Wall): 115 | n = np.array([w.normalx, w.normaly]) 116 | a = np.array([w.x0, w.y0]) 117 | return np.dot(p - a, n) > 0 118 | 119 | p0 = np.array([start.x, start.y]) 120 | p1 = np.array([end.x, end.y]) 121 | 122 | if not on_correct_side(p0, w0) or not on_correct_side(p1, w0): 123 | return None 124 | 125 | a = np.array([w0.x0, w0.y0]) 126 | b = np.array([w0.x1, w0.y1]) 127 | 128 | def intersect_line_segments(a0, b0, a1, b1): 129 | d0 = b0 - a0 130 | d1 = b1 - a1 131 | denom = np.cross(d0, d1) 132 | if denom == 0: 133 | return None 134 | factor = (a1 - a0) / denom 135 | t = np.cross(factor, d0) 136 | s = np.cross(factor, d1) 137 | if 0 <= t <= 1 and 0 <= s <= 1: 138 | return a0 + t * d0, t 139 | return None 140 | 141 | isect_result = intersect_line_segments(a, b, p0, flip_over_wall(p1, w0)) 142 | if not isect_result: 143 | return None 144 | isect, isect_t = isect_result 145 | 146 | return LinearPath(ts=[0, isect_t, 1], xs=[p0, isect, p1]) 147 | 148 | 149 | def main(): 150 | start = Tee(0, 0) 151 | w0 = Wall(-1, 1, 9, 11, 1, -1) 152 | walls = [w0] 153 | end = Pocket(10, 10) 154 | prob = BilliardsProblem(start, walls, end) 155 | ans = solve_analytic(prob) 156 | print(ans) 157 | 158 | 159 | if __name__ == '__main__': 160 | main() 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /physics/billiards_technical_test.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple 2 | import time 3 | import collections 4 | import itertools 5 | import math 6 | import numpy as np 7 | import scipy as sp 8 | import scipy.optimize as spop 9 | import matplotlib.pyplot as plt 10 | 11 | from teg.lang.integrable_program import ( 12 | ITeg, 13 | Const, 14 | Var, 15 | IfElse, 16 | Teg, 17 | Tup, 18 | LetIn, 19 | TegVar, 20 | And, 21 | Or, 22 | Bool, 23 | ) 24 | from teg.math.smooth import ( 25 | Sqr 26 | ) 27 | from teg.lang.integrable_program import false as TegFalse 28 | from teg.derivs import FwdDeriv, RevDeriv 29 | from teg.eval import numpy_eval as evaluate_numpy 30 | from teg.passes import simplify 31 | from teg.passes import substitute 32 | from teg.ir import emit 33 | from tests.c_utils import runProgram, compileProgram 34 | from tap import Tap 35 | 36 | 37 | def remap(t, t0, t1, x0, x1): 38 | s = (t - t0) * (1 / (t1 - t0)) 39 | return x0 + s*(x1 - x0) 40 | 41 | 42 | # linear spline expression through xs; linear runtime 43 | def linspline(t: ITeg, ts: List[ITeg], xs: List[ITeg]): 44 | # assert len(ts) == len(xs) 45 | # assert len(ts) > 0 46 | # 47 | # f = xs[0] 48 | # for pt, nt, px, nx in zip(ts, ts[1:], xs, xs[1:]): 49 | # m = (px - nx) / (pt - nt) 50 | # b = px - m * pt 51 | # ramp = m * t + b 52 | # f = IfElse(t < pt, f, ramp) 53 | # f = IfElse(t < ts[-1], f, xs[-1]) 54 | # return f 55 | assert len(ts) == len(xs) 56 | assert len(ts) > 0 57 | 58 | f = Const(0) 59 | for idx, (t0, t1, x0, x1) in enumerate(zip(ts, ts[1:], xs, xs[1:])): 60 | indicator = t < t1 if idx == 0 else t0 <= t if idx == (len(ts) - 2) else And(t0 <= t, t < t1) 61 | lerp01 = remap(t, t0, t1, x0, x1) 62 | f += IfElse(indicator, lerp01, Const(0)) 63 | return f 64 | 65 | 66 | # linear spline expression through xs; linear runtime 67 | def condition_linspline(t: ITeg, ts: List[ITeg], xs: List[ITeg], bool_func): 68 | assert len(ts) == len(xs) 69 | assert len(ts) > 0 70 | 71 | f = TegFalse 72 | for idx, (t0, t1, x0, x1) in enumerate(zip(ts, ts[1:], xs, xs[1:])): 73 | indicator = t < t1 if idx == 0 else t0 <= t if idx == (len(ts) - 2) else And(t0 <= t, t < t1) 74 | lerp01 = remap(t, t0, t1, x0, x1) 75 | f = Or(f, And(indicator, bool_func(lerp01))) 76 | 77 | return f 78 | 79 | 80 | # cubic hermite spline expression through xs; linear runtime 81 | def cubic_hermite_spline(t: ITeg, ts: List[ITeg], xs: List[ITeg], dxs:List[ITeg]): 82 | assert len(ts) == len(xs) 83 | assert len(ts) == len(dxs) 84 | assert len(ts) > 0 85 | 86 | f = xs[0] 87 | for idx, (pt, nt, px, nx, pdx, ndx), in enumerate(zip(ts, ts[1:], xs, xs[1:], dxs, dxs[1:])): 88 | u = (t - pt) / (nt - pt) # == t normalized to [0, 1] 89 | u2 = u * u 90 | u3 = u * u2 91 | ramp = (2 * u3 - 3 * u2 + 1) * px + (u3 - 2 * u2 + u) * pdx + (-2 * u3 + 3 * u2) * nx + (u3 - u2) * ndx 92 | f = ramp if idx == 0 else IfElse(t < pt, f, ramp) 93 | return f 94 | 95 | 96 | def catmull_spline(t: ITeg, ts: List[ITeg], xs: List[ITeg]): 97 | assert len(ts) == len(xs) 98 | assert len(ts) > 0 99 | 100 | dxs = [] 101 | ts_ = [ts[0], *ts, ts[-1]] 102 | xs_ = [xs[0], *xs, xs[-1]] 103 | for idx in range(1, len(ts) + 1): 104 | pt = ts_[idx - 1] 105 | nt = ts_[idx + 1] 106 | px = xs_[idx - 1] 107 | nx = xs_[idx + 1] 108 | dxs.append((nx - px) / (nt - pt)) 109 | 110 | return cubic_hermite_spline(t, ts, xs, dxs) 111 | 112 | 113 | def test_func(t, a, m): 114 | args = Args() 115 | t_ = TegVar('t_') 116 | 117 | # a_ = a 118 | # a = t 119 | params = [a] 120 | 121 | ts = [0, 1, 2] 122 | xs = [0, a, 0] 123 | x = linspline(t_, ts, xs) 124 | x_cond = condition_linspline(t_, ts, xs, lambda expr: (1 < expr)) 125 | k = 10000 126 | potential = k * IfElse(x_cond, Sqr(x - 1), 0) 127 | # potential = k * IfElse(x_cond, 1, 0) 128 | 129 | v = FwdDeriv(x, [(t_, 1), *[(_, 0) for _ in params]]).deriv_expr 130 | kinetic = 1/2*m*v*v 131 | lagrangian = kinetic - potential 132 | action = Teg(0, 2, lagrangian, t_) 133 | dSda = RevDeriv(action, Tup(Const(1))) 134 | dels = dSda.variables 135 | print(dels) 136 | 137 | def bind_param(expr, vs): 138 | for param, v in zip(params, vs): 139 | expr.bind_variable(param, v) 140 | 141 | def action_func(vs): 142 | bind_param(action, vs) 143 | return evaluate_numpy(-action, num_samples=args.num_samples, ignore_cache=True) 144 | 145 | def d_action_func(vs): 146 | bind_param(dSda, vs) 147 | k = evaluate_numpy(dSda, num_samples=args.num_samples, ignore_cache=True) 148 | return k[0] 149 | 150 | init_guess = [2.0] 151 | # init_guess = [1.03571428] 152 | print(d_action_func(init_guess)) 153 | print(action_func(init_guess)) 154 | # res = spop.root_scalar(d_action_func, bracket=[0.1, 2.0], method='bisect') 155 | res = spop.root(d_action_func, x0=init_guess, method='hybr', tol=1e-8) 156 | # res = spop.minimize(action_func, init_guess, method='Nelder-Mead', tol=1e-12) 157 | # res = spop.minimize(action_func, init_guess, method='CG', tol=1e-6, jac=loss_grad) 158 | 159 | print(res.x) 160 | print(d_action_func(res.x)) 161 | x.bind_variable(a, res.x) 162 | return substitute.substitute(x, t_, t) 163 | # return action 164 | # return dSda 165 | 166 | 167 | class Args(Tap): 168 | pixel_width: int = 30 169 | pixel_height: int = 30 170 | num_samples: int = 30 171 | t_samples: int = 2000 172 | 173 | 174 | def main(): 175 | args = Args() 176 | fig, axes = plt.subplots(nrows=1, ncols=2) 177 | 178 | a0 = 1.5 179 | m0 = 1 180 | t = Var('t') 181 | a = Var('a', a0) 182 | m = Var('m', m0) 183 | param_vars = [ 184 | a, 185 | m, 186 | ] 187 | differential_vals = collections.defaultdict(int, { 188 | 'a': 1, 189 | 'm': 0, 190 | }) 191 | 192 | teg_func = test_func 193 | 194 | def sample_expr(expr, ts): 195 | for t_ in ts: 196 | print(t_) 197 | expr.bind_variable(t, t_) 198 | f = evaluate_numpy(expr, num_samples=args.num_samples, ignore_cache=True) 199 | # print(t_, f) 200 | yield f 201 | 202 | t_samples = 40 203 | def map_sample_func(f, ts): 204 | return Tup(*[ 205 | f(Const(t), a, m) 206 | for t in ts 207 | ]) 208 | 209 | ts = [(2*i)/args.t_samples for i in range(args.t_samples + 1)] 210 | fexpr = teg_func(t, a, m) 211 | xs = list(sample_expr(fexpr, ts)) 212 | 213 | axes[0].plot(ts, xs) 214 | # axes[1].plot(ts, dxs) 215 | 216 | 217 | 218 | 219 | plt.show() 220 | 221 | 222 | 223 | if __name__ == '__main__': 224 | main() 225 | -------------------------------------------------------------------------------- /physics/gaussian_rasterize.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple 2 | import time 3 | import collections 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | 7 | from teg.lang.integrable_program import ( 8 | ITeg, 9 | Const, 10 | Var, 11 | IfElse, 12 | Teg, 13 | Tup, 14 | LetIn, 15 | TegVar, 16 | ) 17 | from teg.math.smooth import ( 18 | Sqr 19 | ) 20 | from util.smooth import ( 21 | Exp 22 | ) 23 | from teg.derivs import FwdDeriv 24 | from teg.eval import numpy_eval as evaluate_numpy 25 | from teg.passes.simplify import simplify 26 | from teg.ir import emit 27 | from tests.c_utils import runProgram, compileProgram 28 | from tap import Tap 29 | 30 | 31 | class Args(Tap): 32 | pixel_width: int = 10 33 | pixel_height: int = 10 34 | num_samples: int = 30 35 | 36 | 37 | def evaluate_c(expr: ITeg, num_samples=5000, ignore_cache=False, silent=False): 38 | pcount_before = time.perf_counter() 39 | c_code = emit(expr, target='C', num_samples=num_samples) 40 | pcount_after = time.perf_counter() 41 | if not silent: 42 | print(f'Teg-to-C emit time: {pcount_after - pcount_before:.3f}s') 43 | 44 | pcount_before = time.perf_counter() 45 | binary = compileProgram(c_code) 46 | pcount_after = time.perf_counter() 47 | if not silent: 48 | print(f'C compile time: {pcount_after - pcount_before:.3f}s') 49 | 50 | pcount_before = time.perf_counter() 51 | value = runProgram(binary) 52 | pcount_after = time.perf_counter() 53 | if not silent: 54 | print(f'C exec time: {pcount_after - pcount_before:.3f}s') 55 | 56 | return value 57 | 58 | 59 | def evaluate(*args, **kwargs): 60 | fast_eval = kwargs.pop('fast_eval', False) 61 | if fast_eval: 62 | if not kwargs.get('silent', True): 63 | print('Evaluating in fast-mode: C') 64 | return evaluate_c(*args, **kwargs) 65 | else: 66 | if not kwargs.get('silent', True): 67 | print('Evaluating using numpy/python') 68 | # kwargs['ignore_cache'] = True 69 | return evaluate_numpy(*args, **kwargs) 70 | 71 | 72 | def rasterize_triangles(): 73 | x, y = TegVar('x'), TegVar('y') 74 | theta = Var('theta', 1) 75 | A = Var('a', 1) 76 | mux = Var('mx', 0.5) 77 | muy = Var('mx', 0.5) 78 | sigmax = Var('sx', 0.15) 79 | sigmay = Var('sy', 0.15) 80 | 81 | param_vars = [ 82 | A, 83 | mux, 84 | muy, 85 | sigmax, 86 | sigmay, 87 | ] 88 | 89 | def right_triangle(x0, y0): 90 | """ ◥ with upper right corner at (x0, y0) """ 91 | return (y < y0) & (x < x0 + theta) & (x - x0 + y - y0 + 0.75 + theta > 0) 92 | 93 | inside_front_cond = right_triangle(0.7, 0.7) 94 | 95 | # body = IfElse(inside_front_cond, 1, 0) 96 | # body = IfElse((y < .7 + theta) & (x < .7 + theta) & (.65 + theta < x + y), 1, 0) 97 | 98 | def gaussian(x_, y_, a, mx, my, sx, sy): 99 | # return a * Exp(-0.5 * Sqr((y_ - my) / sy)) / (sy * 2.5066) \ 100 | # * Exp(-0.5 * Sqr((x_ - mx) / sx)) / (sx * 2.5066) 101 | return a * Exp(-0.5 * (Sqr((x_ - mx) / sx) + Sqr((y_ - my) / sy))) / (sx * sy * 2 * np.pi) 102 | 103 | 104 | body = gaussian(x, y, A, mux, muy, sigmax, sigmay) 105 | # body = Sqr(x - mux) 106 | # body = (x - mux) * (x - mux) 107 | 108 | w, h = args.pixel_width, args.pixel_height 109 | inv_area = w * h 110 | pixel_expr = Tup(*[ 111 | Teg(i / w, (i + 1) / w, Teg(j / h, (j + 1) / h, body, x), y) * inv_area 112 | for i in range(w) 113 | for j in range(h) 114 | ]) 115 | return pixel_expr, param_vars 116 | 117 | 118 | if __name__ == '__main__': 119 | args = Args().parse_args() 120 | 121 | fig, axes = plt.subplots(nrows=1, ncols=2) 122 | pixel_expr, param_vars = rasterize_triangles() 123 | 124 | pcount_before = time.perf_counter() 125 | 126 | w, h = args.pixel_width, args.pixel_height 127 | res = evaluate(pixel_expr, num_samples=args.num_samples) 128 | pixel_grid = np.array(res).reshape((w, h)) 129 | # axes[0].imshow(pixel_grid[::-1, :], vmin=-1/(w * h), vmax=1/(w * h)) 130 | axes[0].imshow(pixel_grid, origin='lower', extent=(0, 1, 0, 1)) 131 | 132 | import math 133 | differential_vals = collections.defaultdict(int, { 134 | 'a': 0, 135 | 'mx': 0, 136 | 'my': 0, 137 | 'sx': 1, 138 | 'sy': 0, 139 | }) 140 | deriv_expr = FwdDeriv(pixel_expr, [(theta, differential_vals[theta.name]) for theta in param_vars]) 141 | 142 | res = evaluate(deriv_expr, num_samples=args.num_samples) 143 | pixel_grid = np.array(res).reshape((w, h)) 144 | # axes[1].imshow(pixel_grid[::-1, :], vmin=-0.05, vmax=0.05) 145 | axes[1].imshow(pixel_grid, origin='lower', extent=(0, 1, 0, 1)) 146 | pcount_after = time.perf_counter() 147 | print(f'total:\t{pcount_after - pcount_before}') 148 | plt.show() 149 | 150 | -------------------------------------------------------------------------------- /physics/smooth.py: -------------------------------------------------------------------------------- 1 | from teg import ( 2 | ITeg, 3 | Const, 4 | Var, 5 | SmoothFunc, 6 | ) 7 | 8 | import numpy as np 9 | from teg.ir.passes.c_math import SimpleCMath 10 | 11 | 12 | class InvertSqrt(SmoothFunc): 13 | """y = x^(-0.5) with suppressed errors """ 14 | def __init__(self, expr: ITeg, name: str = "InvertSqrt"): 15 | super(InvertSqrt, self).__init__(expr=expr, name=name) 16 | self.blow_up = False 17 | 18 | def fwd_deriv(self, in_deriv_expr: ITeg): 19 | return Const(-1/2) * InvertSqrt(self.expr)**3 * in_deriv_expr 20 | 21 | def rev_deriv(self, out_deriv_expr: ITeg): 22 | return out_deriv_expr * Const(-1/2) * InvertSqrt(self.expr)**3 23 | 24 | def operation(self, in_value): 25 | if (np.array(in_value) > 0).all(): 26 | return 1 / np.sqrt(in_value) 27 | self.blow_up = True 28 | return np.zeros_like(in_value) 29 | 30 | def output_size(input_size): 31 | return input_size 32 | 33 | 34 | class IsNotNan(SmoothFunc): 35 | """y = x^(-0.5) with suppressed errors """ 36 | def __init__(self, expr: ITeg, name: str = "Sqrt"): 37 | super(IsNotNan, self).__init__(expr=expr, name=name) 38 | self.blew_up = Var('blow_up', 1) 39 | self.errored = False 40 | 41 | def fwd_deriv(self, in_deriv_expr: ITeg): 42 | return self.blew_up * in_deriv_expr 43 | 44 | def rev_deriv(self, out_deriv_expr: ITeg): 45 | return out_deriv_expr * self.blew_up 46 | 47 | def operation(self, in_value): 48 | if np.isnan(in_value): 49 | self.errored = True 50 | return 0 51 | return 1 52 | 53 | def output_size(input_size): 54 | return input_size 55 | 56 | 57 | class Exp(SmoothFunc): 58 | """exp(x)""" 59 | def __init__(self, expr: ITeg, name: str = "Exp"): 60 | super(Exp, self).__init__(expr=expr, name=name) 61 | 62 | def fwd_deriv(self, in_deriv_expr: ITeg): 63 | return Exp(self.expr) * in_deriv_expr 64 | 65 | def rev_deriv(self, out_deriv_expr: ITeg): 66 | return out_deriv_expr * Exp(self.expr) 67 | 68 | def operation(self, in_value): 69 | return np.exp(in_value) 70 | 71 | def to_c(input_symbol, output_symbol, **kwargs): 72 | return SimpleCMath.simple_c(input_symbol, output_symbol, lambda x: f'exp({x})', **kwargs) 73 | 74 | -------------------------------------------------------------------------------- /physics/springs.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from scipy.optimize import minimize 3 | import numpy as np 4 | import os 5 | import pickle 6 | 7 | from teg import ( 8 | ITeg, 9 | Const, 10 | Var, 11 | IfElse, 12 | Teg, 13 | Tup, 14 | TegVar, 15 | ) 16 | from teg.derivs.reverse_deriv import reverse_deriv 17 | from teg.math.smooth import Sqrt, Sqr 18 | from teg.eval import evaluate 19 | from teg.passes.simplify import simplify 20 | from teg.passes.reduce import reduce_to_base 21 | 22 | from tap import Tap 23 | 24 | 25 | class Args(Tap): 26 | k1: float = 1 27 | k2: float = 10 28 | l1: float = 2 29 | l2: float = 10 30 | 31 | nadir: float = 1e-5 32 | apex: float = 5.0 33 | plastic_weakening: float = 0.2 34 | 35 | mass: float = 1 36 | gravity: float = 10 37 | 38 | num_samples: int = 200 39 | maxiter: int = 1000 40 | tol: int = 1e-8 41 | 42 | finite_diff: bool = False 43 | ignore_deltas: bool = False 44 | 45 | backend: str = 'C' 46 | 47 | def process_args(self): 48 | self.thresholds = [Var('threshold1', self.l1), Var('threshold2', self.l2)] 49 | self.scales = [Var('scale1', self.k1), Var('scale2', self.k2)] 50 | 51 | 52 | def stress(strain: ITeg, args: Args) -> ITeg: 53 | """Stress curve given the strain for a string-bungee system. 54 | 55 | :strain: is downward displacement 56 | :threshold: is the string length s - the bungee rest length b 57 | :scale: is the elastic modulus of the bungee 58 | 59 | stress = (k1 x1 + k2 x2) H(l1 - x1) H(l2 - x2) + 60 | (k1 l1 alpha + k2 (x - l1)) H(x1 - l1) H(l2 - x2) + 61 | (k2 l2 alpha + k1 (x - l1)) H(l1 - x1) H(x2 - l2) + 62 | g H(x1 - l1) H(x2 - l2) 63 | x1 = k2 x/(k1 + k2) 64 | x2 = k1 x/(k1 + k2) 65 | """ 66 | scale1, scale2 = args.scales 67 | threshold1, threshold2 = args.thresholds 68 | g = args.gravity 69 | delta_x = strain 70 | delta_x1 = delta_x * scale2 / (scale1 + scale2) 71 | delta_x2 = delta_x * scale1 / (scale1 + scale2) 72 | 73 | delta_x1_raw = delta_x * scale2 74 | delta_x2_raw = delta_x * scale1 75 | scaled_thresh1 = (scale1 + scale2) * threshold1 76 | scaled_thresh2 = (scale1 + scale2) * threshold2 77 | 78 | lock1 = scale1 * threshold1 * args.plastic_weakening + scale2 * (delta_x - threshold1) 79 | lock2 = scale2 * threshold2 * args.plastic_weakening + scale1 * (delta_x - threshold2) 80 | 81 | neither_lock = IfElse((delta_x1_raw <= scaled_thresh1) & (delta_x2_raw <= scaled_thresh2), scale1 * delta_x1 + scale2 * delta_x2, 0) 82 | spring1_lock = IfElse((delta_x1_raw > scaled_thresh1) & (delta_x2_raw < scaled_thresh2), lock1, 0) 83 | spring2_lock = IfElse((delta_x1_raw < scaled_thresh1) & (delta_x2_raw > scaled_thresh2), lock2, 0) 84 | both_lock = IfElse((delta_x1_raw >= scaled_thresh1) & (delta_x2_raw >= scaled_thresh2), g, 0) 85 | 86 | e = neither_lock + spring1_lock + spring2_lock + both_lock 87 | 88 | return e 89 | 90 | 91 | def optimize(args: Args): 92 | """Optimizing both yield strength and scale for springiness. """ 93 | g = args.gravity 94 | m = args.mass 95 | num_samples = args.num_samples 96 | nadir, apex = args.nadir, args.apex 97 | 98 | def generate_loss(): 99 | def acc(): 100 | return g - stress(apex, args) / m 101 | def t_from_pos(): 102 | xhat = TegVar('xhat') 103 | disp = TegVar('disp') 104 | inner_integrand = g - stress(disp, args) / m 105 | hvs = Teg(0, xhat, inner_integrand, disp) 106 | inv_v = 1 / Sqrt(Sqrt(Sqr(hvs * 2))) 107 | t_of_apex = Teg(nadir, apex, inv_v, xhat) 108 | return t_of_apex 109 | 110 | out_list = [*args.scales, *args.thresholds] 111 | loss_expr = Sqr(acc() - 0.0) + t_from_pos() 112 | 113 | deriv_args = {'ignore_deltas': True} if args.ignore_deltas else {} 114 | 115 | loss_jac_list = reverse_deriv(loss_expr, Tup(Const(1)), output_list=out_list, args=deriv_args)[1] 116 | loss_jac_expr = simplify(reduce_to_base(loss_jac_list)) 117 | 118 | def loss_f(values): 119 | param_assigns = dict(zip(args.scales + args.thresholds, values)) 120 | loss = evaluate(loss_expr, param_assigns, num_samples=num_samples, backend=args.backend) 121 | return loss 122 | 123 | def loss_jac(values): 124 | param_assigns = dict(zip(args.scales + args.thresholds, values)) 125 | grad = evaluate(loss_jac_expr, param_assigns, num_samples=num_samples, backend=args.backend) 126 | return grad 127 | 128 | return loss_f, loss_jac 129 | 130 | def generate_displacement_is_constrained(): 131 | # x'' = f(x), x(0) = 0, x'(0) = 0 132 | # x' = ±sqrt(2(F(x) - F(0))) 133 | # x' = 0 when F(x) - F(0) = 0 134 | # max displacement occurs at position s when int_0^s f(z) dz = 0 135 | 136 | def half_vel_squared(): 137 | disp = TegVar('disp') 138 | inner_integrand = g - stress(disp, args) / m 139 | half_velocity_squared = Teg(args.nadir, args.apex, inner_integrand, disp) 140 | return half_velocity_squared 141 | 142 | out_list = [*args.scales, *args.thresholds] 143 | deriv_args = {'ignore_deltas': True} if args.ignore_deltas else {} 144 | expr = half_vel_squared() 145 | expr_grad = reverse_deriv(expr, Tup(Const(1)), output_list=out_list, args=deriv_args)[1] 146 | expr_grad = simplify(reduce_to_base(expr_grad)) 147 | 148 | def displacement_is_constrained(values): 149 | param_assigns = dict(zip(args.scales + args.thresholds, values)) 150 | velocity_proxy = evaluate(expr, {**param_assigns}, num_samples=num_samples, backend=args.backend) 151 | return velocity_proxy 152 | 153 | def displacement_is_constrained_gradient(values): 154 | param_assigns = dict(zip(args.scales + args.thresholds, values)) 155 | grad = evaluate(expr_grad, {**param_assigns}, num_samples=num_samples, backend=args.backend) 156 | return grad 157 | return displacement_is_constrained, displacement_is_constrained_gradient 158 | 159 | loss_f, loss_jac = generate_loss() 160 | disp_f, disp_jac = generate_displacement_is_constrained() 161 | cons = [ 162 | {'type': 'eq', 'fun': disp_f} if args.finite_diff else {'type': 'eq', 'fun': disp_f, 'jac': disp_jac}, 163 | ] 164 | 165 | print('Starting minimization') 166 | 167 | options = {'maxiter': args.maxiter, 'verbose': 2} 168 | init = [var.value for var in (args.scales + args.thresholds)] 169 | print(f'init loss : {loss_f(init)}') 170 | method = 'trust-constr' 171 | bounds = ((0, 1000), (0, 1000), (0, 1000), (0, 1000)) 172 | if args.finite_diff: 173 | res = minimize(loss_f, init, method=method, constraints=cons, bounds=bounds, options=options) 174 | else: 175 | res = minimize(loss_f, init, jac=loss_jac, method=method, constraints=cons, bounds=bounds, options=options) 176 | 177 | print('The final parameter values are', res.x) 178 | print('Command line args') 179 | k1, k2, l1, l2 = res.x 180 | print(f'--k1 {k1} --k2 {k2} --l1 {l1} --l2 {l2}') 181 | print(f'end loss : {loss_f(res.x)}') 182 | print('Ending minimization') 183 | return res.x 184 | 185 | 186 | def main(): 187 | args = Args().parse_args() 188 | scales_init = [scale.value for scale in args.scales] 189 | thresholds_init = [threshold.value for threshold in args.thresholds] 190 | final_param_vals = optimize(args) 191 | num_samples = args.num_samples 192 | backend = args.backend 193 | 194 | strains = np.arange(0, args.apex+1, step=0.01) 195 | param_assigns = dict(zip(args.scales + args.thresholds, scales_init + thresholds_init)) 196 | 197 | strain = Var('strain') 198 | stress_expr = stress(strain, args) 199 | stresses_before = [evaluate(stress_expr, {**param_assigns, strain: val}, num_samples=num_samples, backend=backend) 200 | for val in strains] 201 | param_assigns = dict(zip(args.scales + args.thresholds, final_param_vals)) 202 | stresses_after = [evaluate(stress_expr, {**param_assigns, strain: val}, num_samples=num_samples, backend=backend) 203 | for val in strains] 204 | 205 | plt.plot(strains, stresses_before, label='Before') 206 | plt.plot(strains, stresses_after, label='After') 207 | plt.xlabel('Strain') 208 | plt.ylabel('Stress') 209 | plt.legend() 210 | plt.show() 211 | 212 | 213 | if __name__ == "__main__": 214 | main() 215 | -------------------------------------------------------------------------------- /physics/stress_strain.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | import numpy as np 3 | from scipy.interpolate import UnivariateSpline 4 | from scipy.integrate import odeint 5 | from scipy import integrate 6 | import matplotlib.pyplot as plt 7 | from matplotlib.widgets import Slider 8 | from functools import partial 9 | 10 | from tap import Tap 11 | 12 | 13 | class Args(Tap): 14 | k1: float = 3 15 | k2: float = 3 16 | t1: float = 3 17 | t2: float = 3 18 | 19 | nadir: float = 1e-5 20 | apex: float = 5 21 | 22 | mass: float = 1 23 | gravity: float = 10 24 | 25 | 26 | args = Args().parse_args() 27 | k1_init = args.k1 28 | k2_init = args.k2 29 | t1_init = args.t1 30 | t2_init = args.t2 31 | mass = args.mass 32 | gravity = args.gravity 33 | nadir = args.nadir 34 | apex = args.apex 35 | 36 | 37 | class Params(object): 38 | def __init__(self, ks, ts): 39 | k1, k2 = ks 40 | t1, t2 = ts 41 | self.k1 = k1 42 | self.k2 = k2 43 | self.t1 = t1 44 | self.t2 = t2 45 | 46 | def update(self, ps: Params): 47 | self.k1 = ps.k1 48 | self.k2 = ps.k2 49 | self.t1 = ps.t1 50 | self.t2 = ps.t2 51 | 52 | 53 | params = Params([k1_init, k2_init], [t1_init, t2_init]) 54 | 55 | def stress_func(params, x): 56 | def UStep(t): 57 | return 1 if t > 0 else 0 58 | k1 = params.k1 59 | k2 = params.k2 60 | t1 = params.t1 61 | t2 = params.t2 62 | gravity = 10 63 | 64 | x1 = k2 * x / (k1 + k2) 65 | x2 = k1 * x / (k1 + k2) 66 | neither_lock = (k1 * x1 + k2 * x2) * (UStep(t1 - x1) * UStep(t2 - x2)) 67 | spring1_lock = (k1 * t1 + k2 * (x - t1)) * (UStep(x1 - t1) * UStep(t2 - x2)) 68 | spring2_lock = (k2 * t2 + k1 * (x - t2)) * (UStep(t1 - x1) * UStep(x2 - t2)) 69 | both_lock = gravity * (UStep(x1 - t1) * UStep(x2 - t2)) 70 | ret = neither_lock + spring1_lock + spring2_lock + both_lock 71 | return ret 72 | 73 | 74 | def spring_acc(disp): 75 | return gravity - stress_func(params, disp) / mass 76 | 77 | def dposvel_dt(U, t): 78 | # Here U is a vector such that y=U[0] and z=U[1]. This function should return [y', z'] 79 | return [U[1], spring_acc(U[0])] 80 | 81 | 82 | def forward_sim(ts): 83 | posvel0 = [0, 0] 84 | posvel = odeint(dposvel_dt, posvel0, ts) 85 | poss = posvel[:, 0] 86 | first_osilation = poss[0: int(num_increments * 0.3)] 87 | vels = posvel[:, 1] 88 | accs = np.array(list(map(spring_acc, poss))) 89 | tmaxp = ts[list(poss).index(max(first_osilation))] 90 | maxabsa = max(list(map(abs, accs))) 91 | print(f'At time {tmaxp}, the position is maximal, reaching {max(first_osilation)}; max abs acceleration is {maxabsa}') 92 | return np.array([poss, vels, accs]) 93 | 94 | 95 | # Initial x and y arrays 96 | xs = np.linspace(0, 10, 1000) 97 | y = np.array(list(map(partial(stress_func, params), xs))) 98 | # y = np.sin(0.5 * x) * np.sin(x * np.random.randn(30)) 99 | # Spline interpolation 100 | spline = UnivariateSpline(xs, y, s=6) 101 | x_spline = np.linspace(0, 10, 1000) 102 | y_spline = np.array(list(map(partial(stress_func, params), x_spline))) 103 | # Plotting 104 | fig = plt.figure() 105 | plt.subplots_adjust(bottom=0.25) 106 | (ax1, ax2) = fig.subplots(nrows=2, ncols=1) 107 | stress_strain_plot = ax1.plot(xs, y) 108 | stress_strain_plot, = ax1.plot(x_spline, y_spline, 'g') 109 | 110 | num_increments = 200 111 | ts = np.linspace(0, 10, num_increments) 112 | init_sim = forward_sim(ts) 113 | pos_plot, = ax2.plot(ts, init_sim[0], label='pos') 114 | vel_plot, = ax2.plot(ts, init_sim[1], label='vel') 115 | acc_plot, = ax2.plot(ts, init_sim[2], label='acc') 116 | ax2.legend() 117 | 118 | 119 | # Defining the Slider button 120 | # xposition, yposition, width and height 121 | k1_ax = plt.axes([0.25, 0.16, 0.65, 0.03]) 122 | k1_slider = Slider(k1_ax, 'k1', 0.1, 10, valinit=params.k1, valstep=0.1) 123 | 124 | k2_ax = plt.axes([0.25, 0.11, 0.65, 0.03]) 125 | k2_slider = Slider(k2_ax, 'k2', 0.1, 10, valinit=params.k2, valstep=0.1) 126 | 127 | t1_ax = plt.axes([0.25, 0.06, 0.65, 0.03]) 128 | t1_slider = Slider(t1_ax, 't1', 0.1, 10, valinit=params.t1, valstep=0.1) 129 | 130 | t2_ax = plt.axes([0.25, 0.01, 0.65, 0.03]) 131 | t2_slider = Slider(t2_ax, 't2', 0.1, 10, valinit=params.t2, valstep=0.1) 132 | 133 | 134 | # Updating the plot 135 | def k1_update(val): 136 | new_param_update(Params([val, params.k2], [params.t1, params.t2])) 137 | def k2_update(val): 138 | new_param_update(Params([params.k1, val], [params.t1, params.t2])) 139 | def t1_update(val): 140 | new_param_update(Params([params.k1, params.k2], [val, params.t2])) 141 | def t2_update(val): 142 | new_param_update(Params([params.k1, params.k2], [params.t1, val])) 143 | def new_param_update(ps): 144 | params.update(ps) 145 | new_ys = np.array(list(map(partial(stress_func, params), x_spline))) 146 | # spline = UnivariateSpline(xs, new_ys, s=1) 147 | stress_strain_plot.set_ydata(new_ys) 148 | new_simdata = forward_sim(ts) 149 | pos_plot.set_ydata(new_simdata[0]) 150 | vel_plot.set_ydata(new_simdata[1]) 151 | acc_plot.set_ydata(new_simdata[2]) 152 | # redrawing the figure 153 | ax1.relim() 154 | ax1.autoscale_view(True, True, True) 155 | ax2.relim() 156 | ax2.autoscale_view(True, True, True) 157 | fig.canvas.draw() 158 | 159 | 160 | # Calling the function "update" when the value of the slider is changed 161 | k1_slider.on_changed(k1_update) 162 | k2_slider.on_changed(k2_update) 163 | t1_slider.on_changed(t1_update) 164 | t2_slider.on_changed(t2_update) 165 | plt.show() 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /physics/test.py: -------------------------------------------------------------------------------- 1 | import open3d as o3d 2 | 3 | if __name__ == '__main__': 4 | o3d.utility.set_verbosity_level(o3d.utility.VerbosityLevel.Debug) 5 | mesh_frame = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.6) 6 | o3d.visualization.draw_geometries([mesh_frame]) 7 | 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scipy 3 | matplotlib 4 | torch 5 | typed-argument-parser 6 | -e ./Teg 7 | 8 | -------------------------------------------------------------------------------- /util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChezJrk/teg_applications/21fd77891a17af0d42abc3425abb734592b03c89/util/__init__.py -------------------------------------------------------------------------------- /util/smooth.py: -------------------------------------------------------------------------------- 1 | """ 2 | Custom SmoothFunc class demonstration 3 | 4 | TODO: Add emit_c function mapppings 5 | """ 6 | 7 | from teg import ( 8 | ITeg, 9 | Const, 10 | SmoothFunc, 11 | Invert, 12 | ) 13 | 14 | import numpy as np 15 | 16 | 17 | class Exp(SmoothFunc): 18 | """ 19 | y = e^x 20 | """ 21 | def __init__(self, expr: ITeg, name: str = "Exp"): 22 | super(Exp, self).__init__(expr=expr, name=name) 23 | 24 | def fwd_deriv(self, in_deriv_expr: ITeg): 25 | return Exp(self.expr) * in_deriv_expr 26 | 27 | def rev_deriv(self, out_deriv_expr: ITeg): 28 | return out_deriv_expr * Exp(self.expr) 29 | 30 | def operation(self, in_value): 31 | return np.exp(in_value) 32 | 33 | 34 | class PowN(SmoothFunc): 35 | """ 36 | y = x^1000 37 | """ 38 | def __init__(self, expr: ITeg, n=2, name: str = "PowN"): 39 | super(PowN, self).__init__(expr=expr, name=name) 40 | self.n = n 41 | 42 | def fwd_deriv(self, in_deriv_expr: ITeg): 43 | if self.n == 0: 44 | return 0 45 | else: 46 | return self.n * PowN(self.expr, self.n - 1) * in_deriv_expr 47 | 48 | def rev_deriv(self, out_deriv_expr: ITeg): 49 | if self.n == 0: 50 | return 0 51 | else: 52 | return out_deriv_expr * self.n * PowN(self.expr, self.n - 1) 53 | 54 | def operation(self, in_value): 55 | return in_value**self.n 56 | 57 | 58 | class Sin(SmoothFunc): 59 | """ 60 | y = sin(x) 61 | """ 62 | def __init__(self, expr: ITeg, name: str = "Sin"): 63 | super(Sin, self).__init__(expr=expr, name=name) 64 | 65 | def fwd_deriv(self, in_deriv_expr: ITeg): 66 | return Cos(self.expr) * in_deriv_expr 67 | 68 | def rev_deriv(self, out_deriv_expr: ITeg): 69 | return out_deriv_expr * Cos(self.expr) 70 | 71 | def operation(self, in_value): 72 | return np.sin(in_value) 73 | 74 | 75 | class Cos(SmoothFunc): 76 | """ 77 | y = cos(x) 78 | """ 79 | def __init__(self, expr: ITeg, name: str = "Cos"): 80 | super(Cos, self).__init__(expr=expr, name=name) 81 | 82 | def fwd_deriv(self, in_deriv_expr: ITeg): 83 | return -Sin(self.expr) * in_deriv_expr 84 | 85 | def rev_deriv(self, out_deriv_expr: ITeg): 86 | return out_deriv_expr * -Sin(self.expr) 87 | 88 | def operation(self, in_value): 89 | return np.cos(in_value) 90 | 91 | 92 | 93 | 94 | 95 | --------------------------------------------------------------------------------