├── img ├── 2d.jpg ├── vft.jpg ├── fmx_18.jpg ├── fmx_19.jpg ├── sig_19.jpg ├── volumes.jpg ├── particles.jpg ├── vft_cover.jpg └── comparison │ ├── grid_hd.jpg │ ├── a_fog_9min.jpg │ ├── a_poly_2min.jpg │ ├── a_pts_4min.jpg │ ├── a_sdf_3min.jpg │ ├── frustum_hd.jpg │ ├── m_fog_8min.jpg │ ├── m_pts_11min.jpg │ ├── m_sdf_16min.jpg │ ├── rs_fog_1min.jpg │ ├── rs_pts_4min.jpg │ ├── a_pts_cam_1min.jpg │ ├── frustum_hd_25.jpg │ ├── frustum_hd_5.jpg │ ├── frustum_hd_75.jpg │ ├── m_poly_10min.jpg │ ├── m_pts_cam_8min.jpg │ ├── rs_poly_1min.jpg │ ├── a_pts_spec_1min.jpg │ ├── m_fog_spec_13min.jpg │ ├── m_pts_spec_3min.jpg │ ├── rs_pts_cam_2min.jpg │ ├── a_pts_cam_2spp_1min.jpg │ ├── a_pts_cam_3spp_1min.jpg │ ├── a_pts_spec_too_long.jpg │ ├── a_pts_cam_1_5spp_1min.jpg │ └── rs_pts_spec_spheres_incorrect.jpg ├── web ├── README.md ├── style.css ├── mandelbrot.html └── mandelbrot.js ├── blender ├── primitives.blend ├── volume_test.blend ├── stripes_test.blend ├── README.md └── osl │ ├── primitive_test.osl │ └── stripes_test.osl ├── houdini ├── scenes │ ├── pts.hipnc │ ├── subd.hipnc │ ├── osl_scene.hipnc │ ├── camera_fly.hipnc │ ├── testing_scene.hipnc │ ├── rs_resolution_test.hipnc │ ├── htoa_resolution_test.hipnc │ ├── testing_scene_mantra_only.hipnc │ └── run.sh ├── otls │ ├── vft_points.hdanc │ ├── vft_benesiIter.hdanc │ ├── vft_curlNoise.hdanc │ ├── vft_fog_volume.hdanc │ ├── vft_ides2Iter.hdanc │ ├── vft_idesIter.hdanc │ ├── vft_iqBulbIter.hdanc │ ├── vft_scaleIter.hdanc │ ├── vft_sdf_volume.hdanc │ ├── vft_boxFoldIter.hdanc │ ├── vft_fabsFoldIter.hdanc │ ├── vft_preScaleIter.hdanc │ ├── vft_rotationIter.hdanc │ ├── vft_addCOffsetIter.hdanc │ ├── vft_amazingSurfIter.hdanc │ ├── vft_bristorbrotIter.hdanc │ ├── vft_compress_colors.hdanc │ ├── vft_josKleinianIter.hdanc │ ├── vft_mandelboxIter.hdanc │ ├── vft_mandelbulb2Iter.hdanc │ ├── vft_mandelbulb3Iter.hdanc │ ├── vft_mandelbulb4Iter.hdanc │ ├── vft_mandelbulbIter.hdanc │ ├── vft_raymarch_points.hdanc │ ├── vft_tgladFoldIter.hdanc │ ├── vft_translateIter.hdanc │ ├── vft_mengerSmoothIter.hdanc │ ├── vft_mengerSpongeIter.hdanc │ ├── vft_quaternion3dIter.hdanc │ ├── vft_sierpinski3dIter.hdanc │ ├── vft_xenodreambuieIter.hdanc │ ├── vft_fog_volume_combined.hdanc │ ├── vft_mandelbulbPower2Iter.hdanc │ ├── vft_raymarch_perspective.hdanc │ ├── vft_generate_points_camera.hdanc │ ├── vft_generate_points_sphere.hdanc │ └── vft_fog_volume_combined_frustum.hdanc ├── toolbar │ └── dev.shelf ├── ocl │ ├── vft_attractor_kernels.cl │ ├── include │ │ ├── vft_defines.h │ │ ├── vft_utils.h │ │ ├── vft_shading.h │ │ ├── vft_math.h │ │ └── vft_fractals.h │ └── vft_kernels.cl ├── vex │ └── include │ │ ├── vft_particles.h │ │ ├── vft_fractals.h │ │ └── vft_subd.h └── python2.7libs │ └── vft_hou.py ├── .gitignore ├── nuke ├── scenes │ └── run.sh └── blink │ ├── test_param_var.blink │ ├── root.blink │ ├── modulo.blink │ ├── test_kernel.blink │ ├── complex_plane.blink │ ├── include │ └── vft_blink.h │ └── mandelbrot.blink ├── osl ├── vft_get_matrix_element.osl ├── vft_primitive.osl ├── vft_mandelbulb.osl ├── vft_ides.osl ├── vft_benesi.osl └── include │ ├── vft_osl.h │ └── vft_fractals_osl.h ├── LICENSE ├── python └── m3fanalyze.py ├── comparison.md └── README.md /img/2d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/2d.jpg -------------------------------------------------------------------------------- /img/vft.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/vft.jpg -------------------------------------------------------------------------------- /img/fmx_18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/fmx_18.jpg -------------------------------------------------------------------------------- /img/fmx_19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/fmx_19.jpg -------------------------------------------------------------------------------- /img/sig_19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/sig_19.jpg -------------------------------------------------------------------------------- /img/volumes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/volumes.jpg -------------------------------------------------------------------------------- /img/particles.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/particles.jpg -------------------------------------------------------------------------------- /img/vft_cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/vft_cover.jpg -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | Work was moved [here](https://github.com/jtomori/web_experiments). -------------------------------------------------------------------------------- /blender/primitives.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/blender/primitives.blend -------------------------------------------------------------------------------- /blender/volume_test.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/blender/volume_test.blend -------------------------------------------------------------------------------- /houdini/scenes/pts.hipnc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/scenes/pts.hipnc -------------------------------------------------------------------------------- /houdini/scenes/subd.hipnc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/scenes/subd.hipnc -------------------------------------------------------------------------------- /blender/stripes_test.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/blender/stripes_test.blend -------------------------------------------------------------------------------- /img/comparison/grid_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/grid_hd.jpg -------------------------------------------------------------------------------- /houdini/otls/vft_points.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_points.hdanc -------------------------------------------------------------------------------- /houdini/scenes/osl_scene.hipnc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/scenes/osl_scene.hipnc -------------------------------------------------------------------------------- /img/comparison/a_fog_9min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/a_fog_9min.jpg -------------------------------------------------------------------------------- /img/comparison/a_poly_2min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/a_poly_2min.jpg -------------------------------------------------------------------------------- /img/comparison/a_pts_4min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/a_pts_4min.jpg -------------------------------------------------------------------------------- /img/comparison/a_sdf_3min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/a_sdf_3min.jpg -------------------------------------------------------------------------------- /img/comparison/frustum_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/frustum_hd.jpg -------------------------------------------------------------------------------- /img/comparison/m_fog_8min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/m_fog_8min.jpg -------------------------------------------------------------------------------- /img/comparison/m_pts_11min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/m_pts_11min.jpg -------------------------------------------------------------------------------- /img/comparison/m_sdf_16min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/m_sdf_16min.jpg -------------------------------------------------------------------------------- /img/comparison/rs_fog_1min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/rs_fog_1min.jpg -------------------------------------------------------------------------------- /img/comparison/rs_pts_4min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/rs_pts_4min.jpg -------------------------------------------------------------------------------- /houdini/otls/vft_benesiIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_benesiIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_curlNoise.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_curlNoise.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_fog_volume.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_fog_volume.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_ides2Iter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_ides2Iter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_idesIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_idesIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_iqBulbIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_iqBulbIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_scaleIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_scaleIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_sdf_volume.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_sdf_volume.hdanc -------------------------------------------------------------------------------- /houdini/scenes/camera_fly.hipnc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/scenes/camera_fly.hipnc -------------------------------------------------------------------------------- /img/comparison/a_pts_cam_1min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/a_pts_cam_1min.jpg -------------------------------------------------------------------------------- /img/comparison/frustum_hd_25.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/frustum_hd_25.jpg -------------------------------------------------------------------------------- /img/comparison/frustum_hd_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/frustum_hd_5.jpg -------------------------------------------------------------------------------- /img/comparison/frustum_hd_75.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/frustum_hd_75.jpg -------------------------------------------------------------------------------- /img/comparison/m_poly_10min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/m_poly_10min.jpg -------------------------------------------------------------------------------- /img/comparison/m_pts_cam_8min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/m_pts_cam_8min.jpg -------------------------------------------------------------------------------- /img/comparison/rs_poly_1min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/rs_poly_1min.jpg -------------------------------------------------------------------------------- /houdini/otls/vft_boxFoldIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_boxFoldIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_fabsFoldIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_fabsFoldIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_preScaleIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_preScaleIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_rotationIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_rotationIter.hdanc -------------------------------------------------------------------------------- /houdini/scenes/testing_scene.hipnc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/scenes/testing_scene.hipnc -------------------------------------------------------------------------------- /img/comparison/a_pts_spec_1min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/a_pts_spec_1min.jpg -------------------------------------------------------------------------------- /img/comparison/m_fog_spec_13min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/m_fog_spec_13min.jpg -------------------------------------------------------------------------------- /img/comparison/m_pts_spec_3min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/m_pts_spec_3min.jpg -------------------------------------------------------------------------------- /img/comparison/rs_pts_cam_2min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/rs_pts_cam_2min.jpg -------------------------------------------------------------------------------- /houdini/otls/vft_addCOffsetIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_addCOffsetIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_amazingSurfIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_amazingSurfIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_bristorbrotIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_bristorbrotIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_compress_colors.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_compress_colors.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_josKleinianIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_josKleinianIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_mandelboxIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_mandelboxIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_mandelbulb2Iter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_mandelbulb2Iter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_mandelbulb3Iter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_mandelbulb3Iter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_mandelbulb4Iter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_mandelbulb4Iter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_mandelbulbIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_mandelbulbIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_raymarch_points.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_raymarch_points.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_tgladFoldIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_tgladFoldIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_translateIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_translateIter.hdanc -------------------------------------------------------------------------------- /img/comparison/a_pts_cam_2spp_1min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/a_pts_cam_2spp_1min.jpg -------------------------------------------------------------------------------- /img/comparison/a_pts_cam_3spp_1min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/a_pts_cam_3spp_1min.jpg -------------------------------------------------------------------------------- /img/comparison/a_pts_spec_too_long.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/a_pts_spec_too_long.jpg -------------------------------------------------------------------------------- /houdini/otls/vft_mengerSmoothIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_mengerSmoothIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_mengerSpongeIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_mengerSpongeIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_quaternion3dIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_quaternion3dIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_sierpinski3dIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_sierpinski3dIter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_xenodreambuieIter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_xenodreambuieIter.hdanc -------------------------------------------------------------------------------- /houdini/scenes/rs_resolution_test.hipnc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/scenes/rs_resolution_test.hipnc -------------------------------------------------------------------------------- /img/comparison/a_pts_cam_1_5spp_1min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/a_pts_cam_1_5spp_1min.jpg -------------------------------------------------------------------------------- /houdini/otls/vft_fog_volume_combined.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_fog_volume_combined.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_mandelbulbPower2Iter.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_mandelbulbPower2Iter.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_raymarch_perspective.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_raymarch_perspective.hdanc -------------------------------------------------------------------------------- /houdini/scenes/htoa_resolution_test.hipnc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/scenes/htoa_resolution_test.hipnc -------------------------------------------------------------------------------- /houdini/otls/vft_generate_points_camera.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_generate_points_camera.hdanc -------------------------------------------------------------------------------- /houdini/otls/vft_generate_points_sphere.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_generate_points_sphere.hdanc -------------------------------------------------------------------------------- /houdini/scenes/testing_scene_mantra_only.hipnc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/scenes/testing_scene_mantra_only.hipnc -------------------------------------------------------------------------------- /img/comparison/rs_pts_spec_spheres_incorrect.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/img/comparison/rs_pts_spec_spheres_incorrect.jpg -------------------------------------------------------------------------------- /houdini/otls/vft_fog_volume_combined_frustum.hdanc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtomori/vft/HEAD/houdini/otls/vft_fog_volume_combined_frustum.hdanc -------------------------------------------------------------------------------- /web/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | } 4 | 5 | canvas { 6 | width: 100vw; 7 | height: 100vh; 8 | display: block; 9 | } -------------------------------------------------------------------------------- /blender/README.md: -------------------------------------------------------------------------------- 1 | Blender integration is being developed in [blender](/../../tree/blender) branch, because it requires some changes in OSL shaders, which were initially created for Arnold. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.pyc 3 | backup 4 | bak 5 | presets 6 | geo 7 | *.autosave 8 | *.nk~ 9 | node_modules 10 | npm-debug.log 11 | *.oso 12 | /houdini/scenes/caches 13 | *.blend? -------------------------------------------------------------------------------- /web/mandelbrot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | VFT | Mandelbrot 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /nuke/scenes/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # usage 4 | 5 | # find location of this script and move to blink dir 6 | ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd ../blink && pwd )" 7 | 8 | # set needed paths 9 | export BLINK_PATH="${ROOT_DIR}" 10 | export FN_BLINK_INCLUDE_PATHS="${ROOT_DIR}" 11 | 12 | # run the scene, expects an "nuke_launcher" environment variable pointing to binary of Nuke (e.g. /usr/local/Nuke11.1v4/Nuke11.1) 13 | ${nuke_launcher} test_scene.nk 14 | -------------------------------------------------------------------------------- /houdini/toolbar/dev.shelf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /osl/vft_get_matrix_element.osl: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | shader vft_get_matrix_element( 13 | matrix mat = 1, 14 | int row = 0, 15 | int column = 0, 16 | 17 | output float element_out = 0.0 18 | ) 19 | { 20 | element_out = mat[row][column]; 21 | } -------------------------------------------------------------------------------- /houdini/scenes/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # usage 4 | printf "Usage:./run.sh scene_file.hip (-cpu)\n -cpu: optional argument to run OpenCL code on a CPU device (default: GPU)\n\n\n" 5 | 6 | # find location of this script 7 | ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd ../.. && pwd )" 8 | 9 | # include this project in HOUDINI_PATH 10 | export HOUDINI_PATH="${ROOT_DIR}/houdini:${HOUDINI_PATH}" 11 | 12 | # setup OSL 13 | export ARNOLD_PLUGIN_PATH="${ARNOLD_PLUGIN_PATH}:${ROOT_DIR}/osl:${ROOT_DIR}/houdini/ocl/include" 14 | export OSL_OPTIONS="range_checking=1,max_warnings_per_thread=100,compile_report=1" # debug_nan=1,debug_uninit=1 15 | 16 | # use a cpu mode 17 | if [[ $2 == "-cpu" ]] 18 | then 19 | export HOUDINI_OCL_DEVICETYPE="CPU" 20 | printf "CPU mode set\n" 21 | fi 22 | 23 | # run the scene 24 | houdini $1 -foreground -------------------------------------------------------------------------------- /nuke/blink/test_param_var.blink: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #include "include/vft_blink.h" 13 | 14 | /* 15 | First testing kernel, just to try out things 16 | */ 17 | 18 | kernel testParamVar : ImageComputationKernel 19 | { 20 | Image dst; 21 | 22 | param: 23 | float4 color; 24 | 25 | void define() { 26 | defineParam(color, "Color", float4(1.0f)); 27 | } 28 | 29 | void init() { 30 | } 31 | 32 | void process() 33 | { 34 | color *= 0.99f; 35 | 36 | dst() = color; 37 | } 38 | }; -------------------------------------------------------------------------------- /nuke/blink/root.blink: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #include "include/vft_blink.h" 13 | 14 | /* 15 | Root input image 16 | */ 17 | 18 | kernel rootKernel : ImageComputationKernel 19 | { 20 | Image src; 21 | Image dst; 22 | 23 | param: 24 | float root; 25 | 26 | void define() { 27 | defineParam(root, "root", 2.0f); 28 | } 29 | 30 | void init() { 31 | 32 | } 33 | 34 | void process() 35 | { 36 | float4 img_src = float4(src(0), src(1), src(2), src(3)); 37 | dst() = pow(img_src, float4(1.0f/root)); 38 | } 39 | }; -------------------------------------------------------------------------------- /houdini/ocl/vft_attractor_kernels.cl: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | kernel void lorenzAttractor( 13 | int P_length, 14 | global float* P, 15 | int k_length, 16 | global int* k_index, 17 | global float* k 18 | ) 19 | { 20 | int idx = get_global_id(0); 21 | if (idx >= P_length) 22 | return; 23 | 24 | float3 p = vload3(idx, P); 25 | float a = k[0]; 26 | float b = k[1]; 27 | float c = k[2]; 28 | float dt = 0.0005; 29 | 30 | float3 d; 31 | d.x = a * (p.y - p.x); 32 | d.y = p.x * (b - p.z) - p.y; 33 | d.z = p.x * p.y - c * p.z; 34 | 35 | p += d * dt; 36 | vstore3(p, idx, P); 37 | } 38 | -------------------------------------------------------------------------------- /nuke/blink/modulo.blink: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #include "include/vft_blink.h" 13 | 14 | /* 15 | Modulo input image 16 | */ 17 | 18 | kernel moduloKernel : ImageComputationKernel 19 | { 20 | Image src; 21 | Image dst; 22 | 23 | param: 24 | float4 modulo; 25 | 26 | void define() { 27 | defineParam(modulo, "modulo", float4(1.0f, 1.0f, 1.0f, 1.0f)); 28 | } 29 | 30 | void init() { 31 | 32 | } 33 | 34 | void process() 35 | { 36 | dst() = float4(fmod(src(0), modulo.x), fmod(src(1), modulo.y), fmod(src(2), modulo.z), fmod(src(3), modulo.w)); 37 | } 38 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /houdini/ocl/include/vft_defines.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #ifndef VFT_DEFINES 13 | #define VFT_DEFINES 14 | 15 | // constants 16 | 17 | #define NULL 0 18 | 19 | #define LARGE_NUMBER 10e10 20 | #define ORBITS_OFFSET 0.006f // is used to hide colored seams in sdf subtracting 21 | 22 | #define ORBITS_ARRAY_LENGTH 9 23 | #define ENABLE_DELTA_DE 0 24 | 25 | // functions 26 | 27 | #define SIN(x) native_sin(x) 28 | #define COS(x) native_cos(x) 29 | #define TAN(x) native_tan(x) 30 | #define POWR(x, y) native_powr((x), (y)) 31 | #define SQRT(x) native_sqrt(x) 32 | #define LOG(x) native_log(x) 33 | #define EXP(x) native_exp(x) 34 | #define DIV(x, y) native_divide((x), (y)) 35 | #define NORMALIZE(x) fast_normalize(x) 36 | #define LENGTH(x) fast_length(x) 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /blender/osl/primitive_test.osl: -------------------------------------------------------------------------------- 1 | // sphere: position, radius 2 | float sphere( vector P, float rad ) 3 | { 4 | float dist = length(P) - rad; 5 | return dist; 6 | } 7 | 8 | shader vft_mandelbulb( 9 | int primitive = 0 [[ string widget = "popup", string options = "Sphere|Box|Rounded Box|Torus|Cone" ]], 10 | float sphere_size = 1.0, 11 | vector box_size_vec = vector(1, 2, 3), 12 | float box_roundness = 1.0, 13 | float torus_radius = 1.0, 14 | float torus_thickness = 1.0, 15 | float cone_radius_x = 1.0, 16 | float cone_radius_y = 1.0, 17 | 18 | output float dist = 0.0 19 | ) 20 | { 21 | vector Z = P; 22 | 23 | if (primitive == 0) 24 | dist = sphere(Z, sphere_size); 25 | // else if (primitive == 1) 26 | // dist = box(Z, float3(box_size_vec[0], box_size_vec[1], box_size_vec[2])); 27 | // else if (primitive == 2) 28 | // dist = roundBox(Z, float3(box_size_vec[0], box_size_vec[1], box_size_vec[2]), box_roundness); 29 | // else if (primitive == 3) 30 | // dist = torus(Z, float2(torus_radius, torus_thickness)); 31 | // else if (primitive == 4) 32 | // dist = cone(Z, float2(cone_radius_x, cone_radius_y)); 33 | 34 | dist = dist < 1.0 ? 1.0 : 0.0; 35 | } -------------------------------------------------------------------------------- /nuke/blink/test_kernel.blink: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #include "include/vft_blink.h" 13 | 14 | /* 15 | First testing kernel, just to try out things 16 | */ 17 | 18 | kernel testKernel : ImageComputationKernel 19 | { 20 | Image dst; 21 | 22 | param: 23 | float2 center; 24 | float radius; 25 | float falloff; 26 | 27 | void define() { 28 | defineParam(center, "Center", float2(960.0f, 540.0f)); 29 | defineParam(radius, "Radius (px)", 200.0f); 30 | defineParam(falloff, "Falloff", 1.0f); 31 | } 32 | 33 | void init() { 34 | 35 | } 36 | 37 | void process(int2 pos) 38 | { 39 | float dist = length( float2(pos.x, pos.y) - center ); 40 | //dist = sqrt( dot(float2(pos.x, pos.y) - center, float2(pos.x, pos.y) - center) ); 41 | dist = fit(dist, 0.0f, radius, 1.0f, 0.0f); 42 | dist = pow(dist, falloff); 43 | 44 | dst() = float4(dist, dist, dist, 1); 45 | } 46 | }; -------------------------------------------------------------------------------- /nuke/blink/complex_plane.blink: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #include "include/vft_blink.h" 13 | 14 | /* 15 | Generates a complex plane which has positions of X and Y axes in R and G channels, 16 | it is meant to be used with fractal kernels, which use complex plane image as an input 17 | */ 18 | 19 | kernel complexPlane : ImageComputationKernel 20 | { 21 | Image dst; 22 | 23 | param: 24 | int2 img_res; 25 | float zoom; 26 | float exp_zoom; 27 | float2 offset; 28 | 29 | void define() { 30 | defineParam(img_res, "resolution", int2(1920, 1080)); 31 | defineParam(zoom, "initial_zoom", 1.0f); 32 | defineParam(exp_zoom, "exponential_zoom", 0.0f); 33 | defineParam(offset, "offset", float2(0.0f, 0.0f)); 34 | } 35 | 36 | void init() { 37 | } 38 | 39 | void process(int2 pos) 40 | { 41 | float2 c = float2(pos.x, pos.y) - float2(img_res.x, img_res.y)/2; 42 | c = zoomComplexPlane(c, zoom, exp_zoom, offset); 43 | 44 | dst() = float4(c.x, c.y, 0, 0); 45 | } 46 | }; -------------------------------------------------------------------------------- /osl/vft_primitive.osl: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #include "include/vft_osl.h" 13 | #include "include/vft_fractals_osl.h" 14 | 15 | shader vft_mandelbulb( 16 | int primitive = 0 [[ string widget = "popup", string options = "Sphere|Box|Rounded Box|Torus|Cone" ]], 17 | float sphere_size = 1.0, 18 | vector box_size_vec = vector(1, 2, 3), 19 | float box_roundness = 1.0, 20 | float torus_radius = 1.0, 21 | float torus_thickness = 1.0, 22 | float cone_radius_x = 1.0, 23 | float cone_radius_y = 1.0, 24 | 25 | output float dist = 0.0 26 | ) 27 | { 28 | float3 Z = float3(P[0], P[1], P[2]); 29 | 30 | if (primitive == 0) 31 | dist = sphere(Z, sphere_size); 32 | else if (primitive == 1) 33 | dist = box(Z, float3(box_size_vec[0], box_size_vec[1], box_size_vec[2])); 34 | else if (primitive == 2) 35 | dist = roundBox(Z, float3(box_size_vec[0], box_size_vec[1], box_size_vec[2]), box_roundness); 36 | else if (primitive == 3) 37 | dist = torus(Z, float2(torus_radius, torus_thickness)); 38 | else if (primitive == 4) 39 | dist = cone(Z, float2(cone_radius_x, cone_radius_y)); 40 | } -------------------------------------------------------------------------------- /houdini/vex/include/vft_particles.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #ifndef VFT_PARTICLES 13 | #define VFT_PARTICLES 14 | 15 | function vector transform_right(vector vx; int i) { 16 | int i_mod = i % 3; 17 | 18 | if (i_mod == 0) return vx; 19 | if (i_mod == 1) return set(vx.z,vx.x,vx.y); 20 | if (i_mod == 2) return set(vx.y,vx.z,vx.x); 21 | else return vx; 22 | } 23 | 24 | function vector transform_left(vector vx; int i) { 25 | int i_mod = i % 3; 26 | 27 | if (i_mod == 0) return vx; 28 | if (i_mod == 1) return set(vx.y,vx.z,vx.x); 29 | if (i_mod == 2) return set(vx.z,vx.x,vx.y); 30 | else return vx; 31 | } 32 | 33 | function vector transform_full(vector vx; int i) { 34 | int i_mod = i % 6; 35 | 36 | if (i_mod == 0) return vx; 37 | if (i_mod == 1) return set(vx.y,vx.z,vx.x); 38 | if (i_mod == 2) return set(vx.z,vx.x,vx.y); 39 | if (i_mod == 3) return set(vx.x,vx.z,vx.y); 40 | if (i_mod == 4) return set(vx.z,vx.y,vx.x); 41 | if (i_mod == 5) return set(vx.y,vx.x,vx.z); 42 | 43 | else return vx; 44 | } 45 | 46 | function vector transform_straight(vector vx; int i) { 47 | return vx; 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /houdini/vex/include/vft_fractals.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #ifndef VFT_FRACTALS 13 | #define VFT_FRACTALS 14 | 15 | struct computeFogParms 16 | { 17 | vector pos = {0.0, 0.0, 0.0}; 18 | int max_iter = 20; 19 | float max_dist = 2; 20 | float power = 8; 21 | float orbit_volume_scale = 1.0; 22 | vector orbit_volume_offset = {0.0, 0.0, 0.0}; 23 | } 24 | 25 | function float computeFog(computeFogParms parms; vector colors) 26 | { 27 | vector z = parms.pos; 28 | int i = 0; 29 | 30 | float dr = 1.0; 31 | float r = 0.0; 32 | float orbit_volume = 10000000000000000000; 33 | 34 | for (; i < parms.max_iter; i++) { 35 | // convert to polar coordinates 36 | float theta = acos(z.z/r); 37 | float phi = atan(z.y, z.x); 38 | dr = pow(r, parms.power-1.0) * parms.power * dr + 1.0; 39 | 40 | // scale and rotate the point 41 | float zr = pow(r, parms.power); 42 | theta = theta * parms.power; 43 | phi = phi * parms.power; 44 | 45 | // convert back to cartesian coordinates 46 | z = zr * set(sin(theta)*cos(phi), sin(phi)*sin(theta), cos(theta)); 47 | z += parms.pos; 48 | 49 | // check for exit 50 | r = length(z); 51 | orbit_volume = min(orbit_volume, volumesample(1, 0, (z + parms.orbit_volume_offset) * parms.orbit_volume_scale)); 52 | 53 | if (r > parms.max_dist) 54 | break; 55 | } 56 | 57 | colors.x = orbit_volume; 58 | return i == parms.max_iter ? 1.0 : 0.0; 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /python/m3fanalyze.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | ----------------------------------------------------------------------------- 5 | This source file has been developed within the scope of the 6 | Technical Director course at Filmakademie Baden-Wuerttemberg. 7 | http://technicaldirector.de 8 | 9 | Written by Juraj Tomori. 10 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 11 | ----------------------------------------------------------------------------- 12 | """ 13 | 14 | import os 15 | import fnmatch 16 | 17 | def countInstructions(filePath): 18 | with open(filePath) as file: 19 | lines = file.readlines() 20 | lines = [n.replace(" ","") for n in lines] # kill spaces for finding exact line 21 | 22 | # find start and ending lines of code section 23 | start = lines.index("[CODE]\n") 24 | end = lines.index("[END]\n") 25 | length = end-start-1 26 | 27 | # create a list with lines containing instructions 28 | code = [] 29 | 30 | for i in range(length): 31 | code.append( lines[start + i + 1].replace("\n", "") ) 32 | 33 | # concat the list and divide by 2 (hexadecimal instrcutions) 34 | return len( "".join(code) )/2 35 | 36 | # path to the formulas folder 37 | path = "/home/jtomori/Downloads/mb3d-master/M3Formulas" 38 | 39 | # find files only 40 | files = [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))] 41 | 42 | # keep only .m3f files, but not JIT 43 | files = fnmatch.filter(files, "*.m3f") 44 | files = [n for n in files if not fnmatch.fnmatch(n.lower(), "*jit*")] 45 | 46 | # a list containing amount of instructions per file 47 | instructions = [] 48 | 49 | for file in files: 50 | instructions.append( countInstructions( os.path.join(path, file) ) ) 51 | 52 | # generate an index list 53 | sortedIndices = sorted(range(len(instructions)), key=lambda k: instructions[k]) 54 | 55 | # print from longest to shortest code formulas 56 | for index in sortedIndices[::-1]: 57 | print files[index] + " (" + str(instructions[index]) + " instructions)" -------------------------------------------------------------------------------- /nuke/blink/include/vft_blink.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #ifndef VFT_BLINK_FUNCS 13 | #define VFT_BLINK_FUNCS 14 | 15 | // constants 16 | #define LARGE_NUMBER 10e10 17 | 18 | 19 | // functions 20 | static float fit(float value, float src_min, float src_max, float dst_min, float dst_max) { 21 | return dst_min + (dst_max - dst_min) * (value - src_min) / (src_max - src_min); 22 | } 23 | 24 | static float distPtLine(float2 pt, float2 line_pt_1, float2 line_pt_2) 25 | { 26 | float numerator = fabs( pt.x*( line_pt_2.y - line_pt_1.y ) - pt.y*( line_pt_2.x - line_pt_1.x ) + line_pt_2.x*line_pt_1.y - line_pt_2.y * line_pt_1.x ); 27 | float denominator = sqrt( pow( line_pt_2.y - line_pt_1.y , 2.0f) + pow( line_pt_2.x - line_pt_1.x , 2.0f) ); 28 | return numerator / denominator; 29 | } 30 | 31 | static float distPtCircle(float2 pt, float2 center, float radius) 32 | { 33 | return length(pt - center) - radius; 34 | } 35 | 36 | static float2 zoomComplexPlane(float2 pos, float zoom, float exp_zoom, float2 offset) 37 | { 38 | pos /= zoom; 39 | pos /= exp(exp_zoom); 40 | pos += offset; 41 | 42 | return pos; 43 | } 44 | 45 | // complex number functions 46 | typedef float2 complex; 47 | 48 | static complex complex_add(complex a, complex b) 49 | { 50 | return complex(a.x + b.x, a.y + b.y); 51 | } 52 | 53 | static complex complex_mult(complex a, complex b) 54 | { 55 | return complex(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); 56 | } 57 | 58 | static float complex_abs(complex a) 59 | { 60 | return dot(float2(a), float2(a)); 61 | } 62 | 63 | static complex complex_pow(complex a, int n) 64 | { 65 | complex result = a; 66 | 67 | for (int i = 0; i < (n-1); i++) 68 | { 69 | result = complex_mult(result, a); 70 | } 71 | 72 | return result; 73 | } 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /osl/vft_mandelbulb.osl: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #include "include/vft_osl.h" 13 | #include "include/vft_fractals_osl.h" 14 | 15 | shader vft_mandelbulb( 16 | float power = 8.0, 17 | int julia_enable = 0 [[ string widget = "boolean" ]], 18 | vector julia_coord = vector(0, 0, 0), 19 | int max_iterations = 100, 20 | float max_distance = 250.0, 21 | 22 | output matrix out = 0 23 | ) 24 | { 25 | point P_w = P; 26 | point P_o = transform("object", P_w); 27 | 28 | point P_in = P_o; 29 | point Z = P_in; 30 | float4 julia = float4( julia_enable, julia_coord[0], julia_coord[1], julia_coord[2] ); 31 | int i = 0; 32 | float z_dist = LENGTH(Z); 33 | 34 | float orbit_coord_dist = LARGE_NUMBER; 35 | float orbit_sphere_dist = LARGE_NUMBER; 36 | point orbit_plane_origin = point(0.0); 37 | vector orbit_plane_dist = vector(LARGE_NUMBER); 38 | 39 | for (; i < max_iterations; i++) 40 | { 41 | z_dist = LENGTH(Z); 42 | if (z_dist > max_distance) break; 43 | 44 | //mandelbulbIter(Z, P_in, 1.0, julia, power); 45 | //mandelboxIter(Z, P_in, 0.1, julia, -1.5); 46 | //mandelbulbPower2Iter(Z, P_in, 1.0, julia); 47 | //bristorbrotIter(Z, P_in, 1.0, julia); 48 | //xenodreambuieIter(Z, P_in, 1.0, julia, power, 0.0, 0.0); 49 | //benesiIter(Z, P_in, 1.0, julia); 50 | //idesIter(Z, P_in, 1.0, julia, point(1.0, 2.0, 1.0), float2(0.5, 0.5)); 51 | iqBulbIter(Z, P_in, 1.0, julia, power, power+2.0); 52 | 53 | // orbit traps 54 | orbit_coord_dist = min(orbit_coord_dist, fabs( length2(Z - P_in) )); 55 | orbit_sphere_dist = min( orbit_sphere_dist, fabs( length2(Z - point(0)) - 2.0) ); 56 | orbit_plane_dist[0] = min( orbit_plane_dist[0], distPointPlane(Z, vector(1.0, 0.0, 0.0), orbit_plane_origin) ); 57 | orbit_plane_dist[1] = min( orbit_plane_dist[1], distPointPlane(Z, vector(0.0, 1.0, 0.0), orbit_plane_origin) ); 58 | orbit_plane_dist[2] = min( orbit_plane_dist[2], distPointPlane(Z, vector(0.0, 0.0, 1.0), orbit_plane_origin) ); 59 | } 60 | 61 | orbit_coord_dist = sqrt(orbit_coord_dist); 62 | orbit_sphere_dist = sqrt(orbit_sphere_dist); 63 | 64 | float mask = i == max_iterations ? 1 : 0; 65 | 66 | out[0][0] = mask; 67 | out[0][1] = orbit_coord_dist; 68 | out[0][2] = orbit_sphere_dist; 69 | out[0][3] = orbit_plane_dist[0]; 70 | out[1][0] = orbit_plane_dist[1]; 71 | out[1][1] = orbit_plane_dist[2]; 72 | } -------------------------------------------------------------------------------- /osl/vft_ides.osl: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #include "include/vft_osl.h" 13 | #include "include/vft_fractals_osl.h" 14 | 15 | shader vft_mandelbulb( 16 | float power = 8.0, 17 | int julia_enable = 0 [[ string widget = "boolean" ]], 18 | vector julia_coord = vector(0, 0, 0), 19 | vector multiplier = vector(1, 2, 1), 20 | vector sub_multiplier = vector(0.5, 0.5, -99999), 21 | int max_iterations = 100, 22 | float max_distance = 250.0, 23 | 24 | output matrix out = 0 25 | ) 26 | { 27 | point P_w = P; 28 | point P_o = transform("object", P_w); 29 | 30 | point P_in = P_o; 31 | point Z = P_in; 32 | float4 julia = float4( julia_enable, julia_coord[0], julia_coord[1], julia_coord[2] ); 33 | int i = 0; 34 | float z_dist = LENGTH(Z); 35 | 36 | float orbit_coord_dist = LARGE_NUMBER; 37 | float orbit_sphere_dist = LARGE_NUMBER; 38 | point orbit_plane_origin = point(0.0); 39 | vector orbit_plane_dist = vector(LARGE_NUMBER); 40 | 41 | for (; i < max_iterations; i++) 42 | { 43 | z_dist = LENGTH(Z); 44 | if (z_dist > max_distance) break; 45 | 46 | //mandelbulbIter(Z, P_in, 1.0, julia, power); 47 | //mandelboxIter(Z, P_in, 0.1, julia, -1.5); 48 | //mandelbulbPower2Iter(Z, P_in, 1.0, julia); 49 | //bristorbrotIter(Z, P_in, 1.0, julia); 50 | //xenodreambuieIter(Z, P_in, 1.0, julia, power, 0.0, 0.0); 51 | //benesiIter(Z, P_in, 1.0, julia); 52 | idesIter(Z, P_in, 1.0, julia, multiplier, float2(sub_multiplier[0], sub_multiplier[1])); 53 | //iqBulbIter(Z, P_in, 1.0, julia, power, power); 54 | 55 | // orbit traps 56 | orbit_coord_dist = min(orbit_coord_dist, fabs( length2(Z - P_in) )); 57 | orbit_sphere_dist = min( orbit_sphere_dist, fabs( length2(Z - point(0)) - 2.0) ); 58 | orbit_plane_dist[0] = min( orbit_plane_dist[0], distPointPlane(Z, vector(1.0, 0.0, 0.0), orbit_plane_origin) ); 59 | orbit_plane_dist[1] = min( orbit_plane_dist[1], distPointPlane(Z, vector(0.0, 1.0, 0.0), orbit_plane_origin) ); 60 | orbit_plane_dist[2] = min( orbit_plane_dist[2], distPointPlane(Z, vector(0.0, 0.0, 1.0), orbit_plane_origin) ); 61 | } 62 | 63 | orbit_coord_dist = sqrt(orbit_coord_dist); 64 | orbit_sphere_dist = sqrt(orbit_sphere_dist); 65 | 66 | float mask = i == max_iterations ? 1 : 0; 67 | 68 | out[0][0] = mask; 69 | out[0][1] = orbit_coord_dist; 70 | out[0][2] = orbit_sphere_dist; 71 | out[0][3] = orbit_plane_dist[0]; 72 | out[1][0] = orbit_plane_dist[1]; 73 | out[1][1] = orbit_plane_dist[2]; 74 | } -------------------------------------------------------------------------------- /osl/vft_benesi.osl: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #include "include/vft_osl.h" 13 | #include "include/vft_fractals_osl.h" 14 | 15 | shader vft_mandelbulb( 16 | vector translate = vector(0, 0, 0), 17 | vector euluer_rotate = vector(0, 0, 0), 18 | int julia_enable = 0 [[ string widget = "boolean" ]], 19 | vector julia_coord = vector(0, 0, 0), 20 | int max_iterations = 100, 21 | float max_distance = 250.0, 22 | 23 | output matrix out = 0 24 | ) 25 | { 26 | point P_w = P; 27 | point P_o = transform("object", P_w); 28 | 29 | point P_in = P_o; 30 | point Z = P_in; 31 | float4 julia = float4( julia_enable, julia_coord[0], julia_coord[1], julia_coord[2] ); 32 | int i = 0; 33 | float z_dist = LENGTH(Z); 34 | 35 | float orbit_coord_dist = LARGE_NUMBER; 36 | float orbit_sphere_dist = LARGE_NUMBER; 37 | point orbit_plane_origin = point(0.0); 38 | vector orbit_plane_dist = vector(LARGE_NUMBER); 39 | 40 | for (; i < max_iterations; i++) 41 | { 42 | z_dist = LENGTH(Z); 43 | if (z_dist > max_distance) break; 44 | 45 | //mandelbulbIter(Z, P_in, 1.0, julia, power); 46 | //mandelboxIter(Z, P_in, 0.1, julia, -1.5); 47 | //mandelbulbPower2Iter(Z, P_in, 1.0, julia); 48 | //bristorbrotIter(Z, P_in, 1.0, julia); 49 | //xenodreambuieIter(Z, P_in, 1.0, julia, power, 0.0, 0.0); 50 | benesiIter(Z, P_in, 1.0, julia); 51 | Z += translate; 52 | Z = transform(euler_rotation(euluer_rotate), Z); 53 | //idesIter(Z, P_in, 1.0, julia, point(1.0, 2.0, 1.0), float2(0.5, 0.5)); 54 | //iqBulbIter(Z, P_in, 1.0, julia, power, power+2.0); 55 | 56 | // orbit traps 57 | orbit_coord_dist = min(orbit_coord_dist, fabs( length2(Z - P_in) )); 58 | orbit_sphere_dist = min( orbit_sphere_dist, fabs( length2(Z - point(0)) - 2.0) ); 59 | orbit_plane_dist[0] = min( orbit_plane_dist[0], distPointPlane(Z, vector(1.0, 0.0, 0.0), orbit_plane_origin) ); 60 | orbit_plane_dist[1] = min( orbit_plane_dist[1], distPointPlane(Z, vector(0.0, 1.0, 0.0), orbit_plane_origin) ); 61 | orbit_plane_dist[2] = min( orbit_plane_dist[2], distPointPlane(Z, vector(0.0, 0.0, 1.0), orbit_plane_origin) ); 62 | } 63 | 64 | orbit_coord_dist = sqrt(orbit_coord_dist); 65 | orbit_sphere_dist = sqrt(orbit_sphere_dist); 66 | 67 | float mask = i == max_iterations ? 1 : 0; 68 | 69 | out[0][0] = mask; 70 | out[0][1] = orbit_coord_dist; 71 | out[0][2] = orbit_sphere_dist; 72 | out[0][3] = orbit_plane_dist[0]; 73 | out[1][0] = orbit_plane_dist[1]; 74 | out[1][1] = orbit_plane_dist[2]; 75 | } -------------------------------------------------------------------------------- /blender/osl/stripes_test.osl: -------------------------------------------------------------------------------- 1 | // a cell noise function that takes two parameters 2 | float cnoise(float a, float b){ 3 | return noise("cell",vector(a,b,0)); 4 | } 5 | 6 | // return the relative position of a value in a slot given the upper 7 | // boundary an the slot number. 8 | // m : the upper boundary 9 | // i : the slot number 10 | // n : the number of slots 11 | // value: the value 12 | // offset: the offset of the lower boundary of the slot with index 0 13 | // width: the width of each slot 14 | // varw: the variance of the width 15 | // seed: a random seed 16 | 17 | float relvalue(float m, float i, float n, float value, 18 | float offset, float width, float varw, float seed){ 19 | 20 | float mp=0; 21 | float ri = i; // parameters are passed by reference so if we alter them it has effect outside 22 | float val = value; 23 | float last = m; 24 | ri -= 1; 25 | if( ri < 0 ){ 26 | ri = n - 1; 27 | last += 1; 28 | val += 1; 29 | } 30 | mp = offset + ri * width + (cnoise(ri,seed)-0.5)*varw; 31 | return (val - mp)/(last - mp); 32 | } 33 | 34 | // return the slot that a value belongs to and its 35 | // relative position within the slot 36 | // value : a value between [0,1] 37 | // n : the number of slots 38 | // var : the variance of the position of the slot boundaries 39 | // seed : a random seed, allows you to pick a pattern 40 | // rel : will recive the relative position of the value within 41 | // a slot 42 | 43 | float slot(float value, float n, float var, float seed, 44 | output float rel){ 45 | 46 | float dw = 1.0/n; 47 | float dw2 = dw/2; 48 | float varw = dw * var; 49 | float i; 50 | 51 | float m,mn; 52 | 53 | for(i=0; i 8 | 9 | Mantra ~ 10 min, Arnold ~ 2 min, Redshift ~ 1 min 10 | 11 |
12 | 13 | ### B) Points (sphere trace), ~ 50.6 M 14 | 15 | 16 | Mantra ~ 11 min, Arnold ~ 4 min, Redshift ~ 4 min 17 | 18 |
19 | 20 | ### C) Points (perspective camera trace), ~ 10.3 M (4 samples/pixel) 21 | 22 | 23 | Mantra ~ 8 min, Arnold ~ 1 min, Redshift ~ 2 min 24 | 25 |
26 | 27 | ### D) Volume, ~ 90 M voxels 28 | 29 | 30 | Mantra (with GGX) ~ 13 min, Mantra ~ 8 min, Arnold ~ 9 min, Redshift ~ 1 min 31 | 32 |
33 | 34 | ### E) SDF, ~ 70 M voxels 35 | 36 | 37 | Mantra ~ 16 min, Arnold ~ 3 min 38 | 39 |
40 | 41 | ## Mantra sdf vs polygons vs points (sphere traced) vs points (camera traced) vs fog vs fog (with GGX) 42 | 43 | 44 |
45 | 46 | ## Arnold points (camera traced), ~ 1 min 47 | 48 | 49 | 4 spp (~ 10.3 M points), 3 spp (~ 5.8 M points), 2 spp (~ 2.5 M points), 1.5 spp (~ 1.5 M points) 50 | 51 |
52 | 53 | ## Points (sphere traced) with GGX speculars, ~ 87 M points 54 | 55 | 56 | Mantra ~ 3 min, Arnold ~ 1 min (particles as discs with correct normals), Arnold (using instancing, too slow), Redshift ~ 3 min (as spheres - incorrect speculars, instancing not possible because of VRAM) 57 | 58 |
59 | 60 | ## Grid vs Frustum volumes comparison of volume size and render time 61 | 62 | 63 | Grid volume (~ 800MB, 272M voxels) - 3:30s, frustum volume 1.0 z (~ 800MB, 272M voxels) - 5:20s, frustum volume 0.75 z (~ 600MB, 204M voxels) - 5:21s, frustum volume 0.5 z (~ 400MB, 136M voxels) - 5:27s, frustum volume 0.25 z (~ 200MB, 68M voxels) - 5:42s 64 | 65 | **1.0 z** means scaling of resolution along Z axis (inside of the image) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | VFX Fractal Toolkit 2 | ========================== 3 | ![VFX Fractal Toolkit banner image](img/vft_cover.jpg) 4 | *Set of tools for generating fractal and generative art.* 5 | 6 |
7 | 8 | ## About 9 | This is my graduation project: **VFX Fractal Toolkit** (VFT), which I developed at *Filmakademie Baden-Württemberg* while studying [Technical Directing](https://animationsinstitut.de/de/studium/animation/technical-director/informationen/). 10 | 11 | It contains tools written in *OpenCL, OSL, Blink, Python, VEX and JavaScript* intended to be used in *Houdini, Arnold, Nuke or a web browser*. 12 | 13 | The code is in prototyping stage and many features are experimental. It is **not production ready** and most parts of it need refactoring. 14 | 15 | Here are some animations produced with it: 16 | 17 | * [![Volumetric fractals](img/volumes.jpg)](https://www.youtube.com/watch?v=E8n6chN2Txw) 18 | * [![Dynamical systems](img/particles.jpg)](https://www.youtube.com/watch?v=_gdApm_QPjs) 19 | * [![2D fractals](img/2d.jpg)](https://www.youtube.com/watch?v=__8gaEv5GAs) 20 | 21 | I had a chance to present progress of VFT at two **FMX** conferences (2018, 2019), you can find the recordings here: 22 | 23 | * [![FMX 2019 recording](img/fmx_19.jpg)](https://youtu.be/n-m00N7TYYM?t=2452) 24 | * [![FMX 2018 recording](img/fmx_18.jpg)](https://youtu.be/SNa18n5d8UY?t=1m26s) 25 | 26 | It was also featured in **Posters Preview: SIGGRAPH 2019** video: 27 | * [![Siggraph 2019 posters preview](img/sig_19.jpg)](https://youtu.be/aRmfaEBLNmw) 28 | 29 | This project was presented at **The 15th ACM SIGGRAPH European Conference on Visual Media Production** [(CVMP 2018)](https://www.cvmp-conference.org/2018/programme/) conference: [fast-forward](https://www.youtube.com/watch?v=_CI8GFDmKZQ), [paper](https://animationsinstitut.de/fileadmin/user_upload/files_forschung/pdf/Publications/18_cvmp_vft_juraj_tomori_paper.pdf), [poster](https://animationsinstitut.de/fileadmin/user_upload/files_forschung/pdf/Publications/18_cvmp_vft_juraj_tomori_poster.png). 30 | 31 | It was also presented in [posters session](https://s2019.siggraph.org/presentation/?sess=sess175&id=pos_114#038;id=pos_114) at **SIGGRAPH 2019** in Los Angeles. You can find the abstract [here](https://dl.acm.org/citation.cfm?id=3306214.3338543). 32 | 33 | You can also cite my work: 34 | ``` 35 | @inproceedings{Tomori:2019:VFT:3306214.3338543, 36 | author = {Tomori, Juraj}, 37 | title = {VFX Fractal Toolkit: Integrating Fractals into VFX Pipeline}, 38 | booktitle = {ACM SIGGRAPH 2019 Posters}, 39 | series = {SIGGRAPH '19}, 40 | year = {2019}, 41 | isbn = {978-1-4503-6314-3}, 42 | location = {Los Angeles, California}, 43 | pages = {97:1--97:2}, 44 | articleno = {97}, 45 | numpages = {2}, 46 | url = {http://doi.acm.org/10.1145/3306214.3338543}, 47 | doi = {10.1145/3306214.3338543}, 48 | acmid = {3338543}, 49 | publisher = {ACM}, 50 | address = {New York, NY, USA}, 51 | keywords = {distance fields, fractals, pipeline, ray marching, vfx}, 52 | } 53 | ``` 54 | 55 | You can find **comparison of various techniques** (visual quality vs performance) [here](comparison.md). 56 | 57 |
58 | 59 | ## Resources 60 | * [Mandelbulber2 source code repository](https://github.com/buddhi1980/mandelbulber2/) 61 | * [Mandelbulb3D source code repository](https://github.com/thargor6/mb3d) 62 | * [Capturing the infinite universe in "Lucy": fractal rendering in film production](https://dl.acm.org/citation.cfm?id=2614166) 63 | * [The fractal nature of Guardians of the Galaxy Vol. 2](https://www.fxguide.com/featured/the-fractal-nature-of-guardians-of-the-galaxy-vol-2/) 64 | 65 |
66 | 67 | ## Thanks 68 | * [Íñigo Quílez](http://www.iquilezles.org/www/index.htm) - great articles on raymarching, fractals, orbit traps, SDFs... 69 | * Krzysztof Marczak - lead Mandelbulber2 developer, supporting via emails 70 | * [Mikael Hvidtfeldt Christensen](http://blog.hvidtfeldts.net/) - great articles on raymarching, fractals, generative art 71 | * [Dom Penfold](http://woo4.me/) - blog with useful articles -------------------------------------------------------------------------------- /web/mandelbrot.js: -------------------------------------------------------------------------------- 1 | const glsl = x => x; 2 | 3 | 4 | // init 5 | var canvas = document.getElementById("main"); 6 | var gl = canvas.getContext('webgl'); 7 | 8 | // canvas size 9 | // Lookup the size the browser is displaying the canvas. 10 | var displayWidth = canvas.clientWidth; 11 | var displayHeight = canvas.clientHeight; 12 | 13 | // Check if the canvas is not the same size. 14 | if (canvas.width != displayWidth || canvas.height != displayHeight) { 15 | // Make the canvas the same size 16 | canvas.width = displayWidth; 17 | canvas.height = displayHeight; 18 | } 19 | 20 | /** 21 | * Shaders 22 | */ 23 | 24 | // Utility to fail loudly on shader compilation failure 25 | function compileShader(shaderSource, shaderType) { 26 | var shader = gl.createShader(shaderType); 27 | gl.shaderSource(shader, shaderSource); 28 | gl.compileShader(shader); 29 | 30 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { 31 | throw "Shader compile failed with: " + gl.getShaderInfoLog(shader); 32 | } 33 | 34 | return shader; 35 | } 36 | 37 | var vertexShader = compileShader(glsl` 38 | attribute vec2 position; 39 | 40 | void main() { 41 | // position specifies only x and y. 42 | // We set z to be 0.0, and w to be 1.0 43 | gl_Position = vec4(position, 0.0, 1.0); 44 | } 45 | `, gl.VERTEX_SHADER); 46 | 47 | var fragmentShader = compileShader(glsl` 48 | precision highp float; 49 | uniform vec2 res; 50 | 51 | void main(){ 52 | // Draw every pixel red 53 | gl_FragColor = vec4(gl_FragCoord.x/res.x, gl_FragCoord.y/res.y, 0.0, 1.0); 54 | } 55 | `, gl.FRAGMENT_SHADER); 56 | 57 | var program = gl.createProgram(); 58 | gl.attachShader(program, vertexShader); 59 | gl.attachShader(program, fragmentShader); 60 | gl.linkProgram(program); 61 | gl.useProgram(program); 62 | 63 | // setup uniforms 64 | var resLocation = gl.getUniformLocation(program, "res"); 65 | gl.uniform2f(resLocation, displayWidth, displayHeight); 66 | 67 | /** 68 | * Geometry setup 69 | */ 70 | 71 | // Set up 4 vertices, which we'll draw as a rectangle 72 | // via 2 triangles 73 | // 74 | // A---C 75 | // | /| 76 | // | / | 77 | // |/ | 78 | // B---D 79 | // 80 | // We order them like so, so that when we draw with 81 | // gl.TRIANGLE_STRIP, we draw triangle ABC and BCD. 82 | var vertexData = new Float32Array([ 83 | -1.0, 1.0, // top left 84 | -1.0, -1.0, // bottom left 85 | 1.0, 1.0, // top right 86 | 1.0, -1.0, // bottom right 87 | ]); 88 | var vertexDataBuffer = gl.createBuffer(); 89 | gl.bindBuffer(gl.ARRAY_BUFFER, vertexDataBuffer); 90 | gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW); 91 | 92 | /** 93 | * Attribute setup 94 | */ 95 | 96 | // Utility to complain loudly if we fail to find the attribute 97 | 98 | function getAttribLocation(program, name) { 99 | var attributeLocation = gl.getAttribLocation(program, name); 100 | if (attributeLocation === -1) { 101 | throw 'Can not find attribute ' + name + '.'; 102 | } 103 | return attributeLocation; 104 | } 105 | 106 | // To make the geometry information available in the shader as attributes, we 107 | // need to tell WebGL what the layout of our data in the vertex buffer is. 108 | var positionHandle = getAttribLocation(program, 'position'); 109 | gl.enableVertexAttribArray(positionHandle); 110 | gl.vertexAttribPointer(positionHandle, 111 | 2, // position is a vec2 112 | gl.FLOAT, // each component is a float 113 | gl.FALSE, // don't normalize values 114 | 2 * 4, // two 4 byte float components per vertex 115 | 0 // offset into each span of vertex data 116 | ); 117 | 118 | /** 119 | * Draw 120 | */ 121 | 122 | // Render the 4 vertices specified above (starting at index 0) 123 | // in TRIANGLE_STRIP mode. 124 | gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); 125 | -------------------------------------------------------------------------------- /houdini/ocl/include/vft_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #ifndef VFT_UTILS 13 | #define VFT_UTILS 14 | 15 | // some of the functions here are ported/derived from those sources: 16 | // http://iquilezles.org/www/ 17 | // http://woo4.me/woofractal/ 18 | 19 | ////////////// helper funcs 20 | 21 | 22 | // export float attrib 23 | static void vstore1(float dataIn, long i, global float* dataOut) 24 | { 25 | dataOut[i] = dataIn; 26 | } 27 | 28 | 29 | ////////////// sdf operations 30 | 31 | 32 | // polynomial smooth min 33 | static float sminPoly( float a, float b, float k ) 34 | { 35 | float h = clamp( 0.5f + 0.5f * DIV((b - a), k), 0.0f, 1.0f ); 36 | return mix( b, a, h ) - k * h * (1.0f - h); 37 | } 38 | 39 | // exponential smooth min 40 | static float sminExp( float a, float b, float k ) 41 | { 42 | float res = EXP( -k * a ) + EXP( -k * b ); 43 | return -DIV(LOG(res), k); 44 | } 45 | 46 | // union 47 | static float sdfUnion( float a, float b ) 48 | { 49 | return min(a, b); 50 | } 51 | 52 | // smooth union 53 | static float sdfUnionSmooth( float a, float b, float k ) 54 | { 55 | return sminPoly(a, b, k); 56 | } 57 | 58 | // subtraction 59 | static float sdfSubtract( float b, float a ) 60 | { 61 | return max(-a, b); 62 | } 63 | 64 | // intersection 65 | static float sdfIntersect( float a, float b ) 66 | { 67 | return max(a, b); 68 | } 69 | 70 | // blend 71 | static float sdfBlend(float d1, float d2, float a) 72 | { 73 | return (1 - a) * d1 + a * d2; 74 | } 75 | 76 | // infinitely repeat by a distance (c) 77 | static float3 spaceRep( float3 p, float3 c ) 78 | { 79 | p = fmod(p,c) - 0.5f*c ; 80 | return p; 81 | 82 | } 83 | 84 | // repeat by a distance (c) and by a fixed number of copies (limit) 85 | static float3 spaceRepFixed(float3 p, float3 c, float3 limit) 86 | { 87 | limit *= c-1; 88 | p = min(-limit, p) + limit 89 | + fmod(max(min(p, limit), -limit), c) - 0.5f*c 90 | + max(p, limit) - limit; 91 | return p; 92 | } 93 | 94 | // [M2] wrap 95 | static float3 wrap(float3 x, float3 a, float3 s) 96 | { 97 | x -= s; 98 | return (float3)(x.x - a.x * floor(DIV(x.x, a.x)) + s.x, x.y - a.y * floor(DIV(x.y, a.y)) + s.y, x.z - a.z * floor(DIV(x.z, a.z)) + s.z); 99 | } 100 | 101 | ////////////// debug 102 | 103 | 104 | // print a mtx 105 | static void printMtx(float16 m) 106 | { 107 | int idx = get_global_id(0); 108 | if (idx == 0) { 109 | printf( "\n" ); 110 | printf( "%2.2v4hlf\n", m.s0123 ); 111 | printf( "%2.2v4hlf\n", m.s4567 ); 112 | printf( "%2.2v4hlf\n", m.s89ab ); 113 | printf( "%2.2v4hlf\n", m.scdef ); 114 | printf( "\n" ); 115 | } 116 | } 117 | 118 | // print a mtx 119 | static void printMtxVol(float16 m) 120 | { 121 | int gidx = get_global_id(0); 122 | int gidy = get_global_id(1); 123 | int gidz = get_global_id(2); 124 | 125 | if (gidx == 0 && gidy == 0 && gidz == 0) { 126 | printf( "\n" ); 127 | printf( "%2.2v4hlf\n", m.s0123 ); 128 | printf( "%2.2v4hlf\n", m.s4567 ); 129 | printf( "%2.2v4hlf\n", m.s89ab ); 130 | printf( "%2.2v4hlf\n", m.scdef ); 131 | printf( "\n" ); 132 | } 133 | } 134 | 135 | // print a vector 136 | static void printVec(float3 a) 137 | { 138 | int idx = get_global_id(0); 139 | if (idx == 0) { 140 | printf( "%2.2v3hlf\n", a ); 141 | } 142 | } 143 | 144 | // print a float 145 | static void printFloat(float a) 146 | { 147 | int idx = get_global_id(0); 148 | if (idx == 0) { 149 | printf( "%2.15f\n", a ); 150 | } 151 | } 152 | 153 | // print n new lines 154 | static void printNewLines(int n) 155 | { 156 | int idx = get_global_id(0); 157 | if (idx == 0) { 158 | for (int i = 0; i < n; i++) 159 | printf( "\n" ); 160 | } 161 | } 162 | 163 | #endif 164 | -------------------------------------------------------------------------------- /osl/include/vft_osl.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #ifndef VFT_OSL 13 | #define VFT_OSL 14 | 15 | // Trying to make OSL more compatible with OpenCL syntax 16 | // Some features like vector swizzling are not supported in OSL, so they won't be fully compatible with the current code, 17 | // but I am at least creating some helper macros and structs to speed up porting my OpenCL code 18 | // Note that list of types and functions here is not complete, I implemented only those which were required by OpenCL functions 19 | 20 | // functions 21 | 22 | #define SIN(x) sin(x) 23 | #define COS(x) cos(x) 24 | #define POWR(x, y) pow((x), (y)) 25 | #define SQRT(x) sqrt(x) 26 | #define LOG(x) log(x) 27 | #define EXP(x) exp(x) 28 | #define DIV(x, y) ((x) / (y)) 29 | #define NORMALIZE(x) normalize(x) 30 | #define LENGTH(x) length(x) 31 | 32 | #define M_PI_F 3.14159265358979323846 33 | #define LARGE_NUMBER 10e10 34 | 35 | // float3 36 | 37 | struct float3 38 | { 39 | float x, y, z; 40 | }; 41 | 42 | float length(float3 vec) 43 | { 44 | return length( vector(vec.x, vec.y, vec.z) ); 45 | } 46 | 47 | float3 fabs(float3 a) 48 | { 49 | vector vec = fabs( vector(a.x, a.y, a.z) ); 50 | return float3(vec[0], vec[1], vec[2]); 51 | } 52 | 53 | float3 max(float3 a, float3 b) 54 | { 55 | vector vec = max( vector(a.x, a.y, a.z), vector(b.x, b.y, b.z) ); 56 | return float3(vec[0], vec[1], vec[2]); 57 | } 58 | 59 | float3 max(float3 a, float b) 60 | { 61 | vector vec = max( vector(a.x, a.y, a.z), vector(b) ); 62 | return float3(vec[0], vec[1], vec[2]); 63 | } 64 | 65 | float3 mix(float3 a, float3 b, float t) 66 | { 67 | vector vec = mix( vector(a.x, a.y, a.z), vector(b.x, b.y, b.z), t ); 68 | return float3(vec[0], vec[1], vec[2]); 69 | } 70 | 71 | float3 __operator__neg__ (float3 a) 72 | { 73 | return float3(-a.x, -a.y, -a.z); 74 | } 75 | 76 | float3 __operator__add__ (float3 a, float3 b) 77 | { 78 | return float3(a.x+b.x, a.y+b.y, a.z+b.z); 79 | } 80 | 81 | float3 __operator__sub__ (float3 a, float3 b) 82 | { 83 | return float3(a.x-b.x, a.y-b.y, a.z-b.z); 84 | } 85 | 86 | float3 __operator__mul__ (float3 a, float3 b) 87 | { 88 | return float3(a.x*b.x, a.y*b.y, a.z*b.z); 89 | } 90 | 91 | float3 __operator__mul__ (float a, float3 b) 92 | { 93 | return float3(a*b.x, a*b.y, a*b.z); 94 | } 95 | 96 | float3 __operator__div__ (float3 a, float3 b) 97 | { 98 | return float3(a.x/b.x, a.y/b.y, a.z/b.z); 99 | } 100 | 101 | float3 __operator__mod__ (float3 a, float3 b) 102 | { 103 | return float3(fmod(a.x, b.x), fmod(a.y, b.y), fmod(a.z, b.z)); 104 | } 105 | 106 | int __operator__eq__ (float3 a, float3 b) 107 | { 108 | if (a.x == b.x && a.y == b.y && a.z == b.z) 109 | return 1; 110 | else 111 | return 0; 112 | } 113 | 114 | int __operator__ne__ (float3 a, float3 b) 115 | { 116 | return 1 - (a == b); 117 | } 118 | 119 | // float2 120 | 121 | struct float2 122 | { 123 | float x, y; 124 | }; 125 | 126 | float length(float2 vec) 127 | { 128 | return length( vector(vec.x, vec.y, 0) ); 129 | } 130 | 131 | float2 normalize(float2 a) 132 | { 133 | vector vec = normalize( vector(a.x, a.y, 0) ); 134 | return float2(vec[0], vec[1]); 135 | } 136 | 137 | float dot(float2 a, float2 b) 138 | { 139 | return dot( vector(a.x, a.y, 0), vector(b.x, b.y, 0) ); 140 | } 141 | 142 | // float4 143 | 144 | struct float4 145 | { 146 | float x, y, z, w; 147 | }; 148 | 149 | 150 | // functions 151 | 152 | float length2(vector vec) 153 | { 154 | return dot(vec, vec); 155 | } 156 | 157 | // point to plane distance 158 | float distPointPlane(vector pt, vector plane_n, vector plane_point) 159 | { 160 | float sb, sn, sd; 161 | vector point_proj; 162 | 163 | sn = -dot( plane_n, (pt - plane_point)); 164 | sd = dot(plane_n, plane_n); 165 | sb = DIV(sn, sd); 166 | 167 | point_proj = pt + sb * plane_n; 168 | 169 | return LENGTH(pt - point_proj); 170 | } 171 | 172 | // returns rotation matrix specified by euler rotations in rot vector in degrees 173 | matrix euler_rotation(vector rot) 174 | { 175 | vector rot_rad = radians(-rot); 176 | 177 | float cosx = COS(rot_rad[0]); 178 | float sinx = SIN(rot_rad[0]); 179 | matrix x = matrix(1, 0, 0, 0, 180 | 0, cosx, -sinx, 0, 181 | 0, sinx, cosx, 0, 182 | 0, 0, 0, 1 ); 183 | 184 | float cosy = COS(rot_rad[1]); 185 | float siny = SIN(rot_rad[1]); 186 | matrix y = matrix(cosy, 0, siny, 0, 187 | 0, 1, 0, 0, 188 | -siny, 0, cosy, 0, 189 | 0, 0, 0, 1 ); 190 | 191 | float cosz = COS(rot_rad[2]); 192 | float sinz = SIN(rot_rad[2]); 193 | matrix z = matrix(cosz, -sinz, 0, 0, 194 | sinz, cosz, 0, 0, 195 | 0, 0, 1, 0, 196 | 0, 0, 0, 1 ); 197 | 198 | matrix xform = 1; 199 | xform *= x; 200 | xform *= y; 201 | xform *= z; 202 | 203 | return xform; 204 | } 205 | 206 | #endif 207 | -------------------------------------------------------------------------------- /nuke/blink/mandelbrot.blink: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #include "include/vft_blink.h" 13 | 14 | /* 15 | Mandelbort set visualizer, it takes complex image plane as an input (e.g. generated by complex_plane.blink) 16 | 17 | complex numbers are stored in vec2(X, Y) type, where X is real and Y is imaginary part 18 | */ 19 | 20 | kernel mandelbrotKernel : ImageComputationKernel 21 | { 22 | Image c_src; 23 | Image c_trap; 24 | 25 | Image dst; 26 | 27 | param: 28 | int max_iter; 29 | int mandelbrot_power; 30 | 31 | int julia_mode; 32 | float2 julia_coord_parm; 33 | 34 | int color_mode; 35 | 36 | float2 orbit_pt_parm; 37 | float2 orbit_line_pt_1_parm; 38 | float2 orbit_line_pt_2_parm; 39 | float2 orbit_circle_center_parm; 40 | float orbit_circle_radius; 41 | float2 orbit_bitmap_offset; 42 | float orbit_bitmap_zoom; 43 | 44 | float zoom; 45 | float exp_zoom; 46 | float exp_zoom_anim; 47 | float2 offset; 48 | int2 img_res; 49 | 50 | local: 51 | 52 | void define() { 53 | defineParam(max_iter, "maximum_iterations", 1000); 54 | defineParam(mandelbrot_power, "mandelbrot_power", 2); 55 | 56 | defineParam(julia_mode, "julia_mode", 0); 57 | defineParam(julia_coord_parm, "julia_coordinate", float2(0.0f, 0.0f)); 58 | 59 | defineParam(color_mode, "color_mode", 1); 60 | 61 | defineParam(orbit_pt_parm, "orbit_point_coordinate", float2(0.0f, 0.0f)); 62 | defineParam(orbit_line_pt_1_parm, "orbit_line_point_1_coordinate", float2(0.0f, 0.0f)); 63 | defineParam(orbit_line_pt_2_parm, "orbit_line_point_2_coordinate", float2(1.0f, 1.0f)); 64 | defineParam(orbit_circle_center_parm, "orbit_circle_coordinate", float2(1.0f, 1.0f)); 65 | defineParam(orbit_circle_radius, "orbit_circle_radius", 2.0f); 66 | defineParam(orbit_bitmap_offset, "orbit_bitmap_offset", float2(0.0f, 0.0f)); 67 | defineParam(orbit_bitmap_zoom, "orbit_bitmap_zoom", 100.0f); 68 | 69 | defineParam(zoom, "initial_zoom", 1.0f); 70 | defineParam(exp_zoom, "exponential_zoom", 0.0f); 71 | defineParam(exp_zoom_anim, "exponential_zoom_anim", 0.0f); 72 | defineParam(offset, "offset", float2(0.0f, 0.0f)); 73 | defineParam(img_res, "resolution", int2(1920, 1080)); 74 | } 75 | 76 | void init() { 77 | } 78 | 79 | void process(int2 pos) 80 | { 81 | //float2 c_my = float2(pos.x, pos.y) - float2(img_res.x, img_res.y)/2; 82 | //c_my = zoomComplexPlane(c_my, zoom, exp_zoom_anim, offset); 83 | 84 | complex c = complex(c_src(0), c_src(1)); 85 | //c = c_my; 86 | complex z = c; 87 | complex z0 = z; 88 | complex z_next; 89 | int i = 0; 90 | 91 | float col_smooth = exp( -dot(z,z) ); 92 | 93 | float orbit_pt_dist = LARGE_NUMBER; 94 | float orbit_coord_dist = LARGE_NUMBER; 95 | float orbit_line_dist = LARGE_NUMBER; 96 | float orbit_circle_dist = LARGE_NUMBER; 97 | 98 | float2 orbit_pt = zoomComplexPlane(orbit_pt_parm - float2(img_res.x, img_res.y)/2, zoom, exp_zoom, offset) - offset; 99 | float2 orbit_line_pt_1 = zoomComplexPlane(orbit_line_pt_1_parm - float2(img_res.x, img_res.y)/2, zoom, exp_zoom, offset) - offset; 100 | float2 orbit_line_pt_2 = zoomComplexPlane(orbit_line_pt_2_parm - float2(img_res.x, img_res.y)/2, zoom, exp_zoom, offset) - offset; 101 | float2 orbit_circle_center = zoomComplexPlane(orbit_circle_center_parm - float2(img_res.x, img_res.y)/2, zoom, exp_zoom, offset) - offset; 102 | float4 orbit_bitmap_color = float4(0.0f); 103 | float2 orbit_sample_pos = float2(0.0f); 104 | 105 | float2 julia_coord = zoomComplexPlane(julia_coord_parm - float2(img_res.x, img_res.y)/2, zoom, exp_zoom, offset) - offset; 106 | 107 | if (julia_mode) 108 | c = julia_coord; 109 | 110 | for (; i < max_iter; i++) 111 | { 112 | // complex iterative function 113 | z_next = complex_add(complex_pow(z, mandelbrot_power), c); 114 | z = z_next; 115 | 116 | // colors 117 | col_smooth += exp( -dot(z,z) ); 118 | 119 | // orbit traps 120 | if (color_mode == 2) 121 | { 122 | orbit_pt_dist = min(orbit_pt_dist, fabs( dot(z - orbit_pt, z - orbit_pt) )); 123 | orbit_coord_dist = min(orbit_coord_dist, fabs( dot(z - z0, z - z0) )); 124 | orbit_line_dist = min(orbit_line_dist, fabs( distPtLine(z, orbit_line_pt_1, orbit_line_pt_2) )); 125 | orbit_circle_dist = min(orbit_circle_dist, fabs( distPtCircle(z, orbit_circle_center, orbit_circle_radius) )); 126 | } 127 | else if (color_mode == 3) 128 | { 129 | orbit_sample_pos = z * float2(orbit_bitmap_zoom) - orbit_bitmap_offset; 130 | orbit_bitmap_color = c_trap(orbit_sample_pos.x, orbit_sample_pos.y); 131 | 132 | if (orbit_bitmap_color.w > 0.05) 133 | break; 134 | } 135 | 136 | if (complex_abs(z) > 4) 137 | break; 138 | } 139 | 140 | orbit_pt_dist = sqrt(orbit_pt_dist); 141 | orbit_coord_dist = sqrt(orbit_coord_dist); 142 | 143 | float4 out_col; 144 | float col_steps; 145 | float vis_min; 146 | 147 | if (color_mode == 0) // steps shading 148 | { 149 | col_steps = float(i) / float(max_iter); 150 | if (i == max_iter) 151 | col_steps = 0.0f; 152 | 153 | out_col = float4(col_steps, col_steps, col_steps, 1.0); 154 | } 155 | 156 | else if (color_mode == 1) // smooth shading 157 | { 158 | col_smooth /= float(max_iter); 159 | 160 | out_col = float4(col_smooth, col_smooth, col_smooth, 1.0); 161 | } 162 | 163 | else if (color_mode == 2) // orbit traps 164 | { 165 | out_col = float4(orbit_pt_dist, orbit_coord_dist, orbit_line_dist, orbit_circle_dist); 166 | } 167 | 168 | else if (color_mode == 3) // bitmap orbit trap 169 | { 170 | out_col = orbit_bitmap_color; 171 | } 172 | 173 | else if (color_mode == 4) // orbit traps visualization 174 | { 175 | vis_min = min( 176 | sqrt( fabs( dot(float2(pos.x, pos.y) - orbit_pt_parm, float2(pos.x, pos.y) - orbit_pt_parm) )) * 0.0003f, 177 | fabs( distPtLine(float2(pos.x, pos.y), orbit_line_pt_1_parm, orbit_line_pt_2_parm) ) * 0.0003f 178 | ); 179 | 180 | vis_min = min( 181 | vis_min, 182 | fabs( distPtCircle(float2(pos.x, pos.y), orbit_circle_center_parm, orbit_circle_radius) ) * 0.0003f 183 | ); 184 | 185 | out_col = float4(vis_min, vis_min, vis_min, 1.0f); 186 | } 187 | 188 | dst() = float4(out_col.x, out_col.y, out_col.z, out_col.w); 189 | } 190 | }; -------------------------------------------------------------------------------- /houdini/ocl/include/vft_shading.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #ifndef VFT_SHADING 13 | #define VFT_SHADING 14 | 15 | float scene(float3, const int, float*, float3*, global const void*); 16 | static float length2(float3); 17 | static float distPointPlane(float3, float3, float3); 18 | float primitive_stack(float3, const int); 19 | void fractal_stack(float3*, float*, const float3*, int*, const int, global const void*); 20 | 21 | ////////////// shading functions 22 | 23 | // compute Normals 24 | // based on "Modeling with distance functions" article from Inigo Quilez 25 | static float3 compute_N(const float* iso_limit, const float3* ray_P_world, global const void* theXNoise) 26 | { 27 | float3 N_grad; 28 | float2 e = (float2)(1.0f, -1.0f) * (*iso_limit) * 0.01f; 29 | 30 | N_grad = NORMALIZE( e.xyy * scene( (*ray_P_world) + e.xyy, 0, NULL, NULL, theXNoise) + 31 | e.yyx * scene( (*ray_P_world) + e.yyx, 0, NULL, NULL, theXNoise) + 32 | e.yxy * scene( (*ray_P_world) + e.yxy, 0, NULL, NULL, theXNoise) + 33 | e.xxx * scene( (*ray_P_world) + e.xxx, 0, NULL, NULL, theXNoise) ); 34 | return N_grad; 35 | } 36 | 37 | // compute Ambient Occlusion 38 | // based on "Modeling with distance functions" article from Inigo Quilez 39 | static float compute_AO(const float3* N, const float3* ray_P_world, global const void* theXNoise) 40 | { 41 | float AO = 1.0f; 42 | float AO_occ = 0.0f; 43 | float AO_sca = 1.0f; 44 | 45 | #pragma unroll 46 | for(int j=0; j<5; j++) 47 | { 48 | float AO_hr = 0.01f + 0.12f * DIV((float)(j), 4.0f); 49 | float3 AO_pos = (*N) * AO_hr + (*ray_P_world); 50 | float AO_dd = scene(AO_pos, 0, NULL, NULL, theXNoise); 51 | AO_occ += -(AO_dd-AO_hr)*AO_sca; 52 | AO_sca *= 0.95f; 53 | } 54 | 55 | AO = clamp( 1.0f - 3.4f * AO_occ, 0.0f, 1.0f ); 56 | AO = POWR(AO, 1.6f); 57 | 58 | return AO; 59 | } 60 | 61 | // primitive shape function - calls respective parto of primitive_stack(), in case of DELTA DE mode also outputs N 62 | static float primitive(float3 P, const float size, const int final, float* orbit_closest, float* orbit_colors, const float3 color, float3* N, const int stack) 63 | { 64 | P = DIV(P, size); 65 | float out_distance = primitive_stack(P, stack); 66 | 67 | if (final == 1 && out_distance <= *orbit_closest - ORBITS_OFFSET) 68 | { 69 | #pragma unroll 70 | for (int i=0; i max_distance) break; 115 | 116 | fractal_stack(&Z, &de, &P_in, &log_lin, stack, theXNoise); 117 | 118 | // orbit traps calculations 119 | if (final == 1) 120 | { 121 | orbit_pt_dist = min(orbit_pt_dist, length2(Z - orbit_pt)); 122 | orbit_plane_dist.x = min( orbit_plane_dist.x, distPointPlane(Z, orbit_plane.xyy, orbit_plane_origin) ); 123 | orbit_plane_dist.y = min( orbit_plane_dist.y, distPointPlane(Z, orbit_plane.yxy, orbit_plane_origin) ); 124 | orbit_plane_dist.z = min( orbit_plane_dist.z, distPointPlane(Z, orbit_plane.yyx, orbit_plane_origin) ); 125 | orbit_coord_dist = min( orbit_coord_dist, fabs(dot(Z, P_in)) ); 126 | orbit_sphere_dist = min( orbit_sphere_dist, length2(Z - NORMALIZE(Z)*orbit_sphere_rad) ); 127 | orbit_axis_dist.x = min(orbit_axis_dist.x, Z.y*Z.y + Z.z*Z.z); 128 | orbit_axis_dist.y = min(orbit_axis_dist.y, Z.x*Z.x + Z.z*Z.z); 129 | orbit_axis_dist.z = min(orbit_axis_dist.z, Z.x*Z.x + Z.y*Z.y); 130 | } 131 | } 132 | distance = LENGTH(Z); 133 | *iterations = i; 134 | 135 | // delta DE method 136 | // based on Makin/Buddhi 4-point Delta-DE formula 137 | #if ENABLE_DELTA_DE 138 | float delta = 0.000005f; 139 | 140 | Z = P_in + (float3)(delta, 0.0f, 0.0f); 141 | #pragma unroll 142 | for (int j=0; j= 0) out_distance = 0.5f * LOG(distance) * DIV(distance, de); 177 | else out_distance = DIV(distance, fabs(de)); 178 | 179 | // outputting orbit traps (and N in case of DELTA DE mode) to the closest shape 180 | if (final == 1 && out_distance <= *orbit_closest) 181 | { 182 | orbit_colors[0] = SQRT(orbit_pt_dist); // distance to point at specified coordinates 183 | orbit_colors[1] = orbit_plane_dist.x; // distance to YZ plane 184 | orbit_colors[2] = orbit_plane_dist.y; // distance to XZ plane 185 | orbit_colors[3] = orbit_plane_dist.z; // distance to XY plane 186 | orbit_colors[4] = orbit_coord_dist; // dot(Z, world coords) 187 | orbit_colors[5] = SQRT(orbit_sphere_dist); // distance to sphere 188 | orbit_colors[6] = SQRT(orbit_axis_dist.x); // distance to X axis 189 | orbit_colors[7] = SQRT(orbit_axis_dist.y); // distance to Y axis 190 | orbit_colors[8] = SQRT(orbit_axis_dist.z); // distance to Z axis 191 | 192 | #if ENABLE_DELTA_DE 193 | *N = dist_grad; 194 | #endif 195 | } 196 | 197 | // change orbit_closest, if the evaluated point is closer to this shape 198 | *orbit_closest = min(*orbit_closest, out_distance * size); 199 | 200 | // output distance estimate, take shape's size into consideration 201 | return out_distance * size; 202 | } 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /osl/include/vft_fractals_osl.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #ifndef VFT_FRACTALS_OSL 13 | #define VFT_FRACTALS_OSL 14 | 15 | // Porting OpenCL fractal functions from vft_fractals.h 16 | // it means removing 17 | // "static" keyword, 18 | // "f" literal, 19 | // "const" keyword, 20 | // fixing expressions with vector swizzling, 21 | // removing pointers, 22 | // removing casts 23 | // removing de, log_lin variables 24 | 25 | // sphere: position, radius 26 | float sphere( float3 P, float rad ) 27 | { 28 | float dist = LENGTH(P) - rad; 29 | return dist; 30 | } 31 | 32 | // box: position, size 33 | float box( float3 P, float3 b ) 34 | { 35 | float3 d = fabs(P) - b; 36 | return min( max( d.x, max(d.y, d.z) ), 0.0) + LENGTH( max(d, 0.0) ); 37 | } 38 | 39 | // round box: position, size, roundness 40 | float roundBox( float3 P, float3 b, float r ) 41 | { 42 | return LENGTH( max( fabs(P) - b, 0.0 ) )-r; 43 | } 44 | 45 | // torus: position, size (radius, thickness) 46 | float torus( float3 P, float2 t ) 47 | { 48 | float2 q = float2(LENGTH( float2(P.x, P.z) )-t.x,P.y); 49 | return LENGTH(q)-t.y; 50 | } 51 | 52 | // infinite cone 53 | float cone( float3 P, float2 c ) 54 | { 55 | c = NORMALIZE(c); 56 | float q = LENGTH(float2(P.x, P.y)); 57 | return dot( c, float2(q, P.z) ); 58 | } 59 | 60 | // [WEB] - http://blog.hvidtfeldts.net/index.php/2011/09/ 61 | void mandelbulbIter(point Z, point P_in, float weight, float4 julia, float power) 62 | { 63 | point Z_orig = Z; 64 | 65 | float distance = LENGTH(Z); 66 | 67 | // convert to polar coordinates 68 | float theta = acos( DIV(Z[2], distance)); 69 | float phi = atan2(Z[1], Z[0]); 70 | 71 | // scale and rotate the point 72 | float zr = POWR(distance, power); 73 | theta *= power; 74 | phi *= power; 75 | 76 | // convert back to cartesian coordinates 77 | point new_pZ = zr * point( SIN(theta)*COS(phi), SIN(phi)*SIN(theta), COS(theta) ); 78 | 79 | if (julia.x == 0.0) 80 | { 81 | Z = new_pZ + P_in; 82 | } 83 | else 84 | { 85 | Z = new_pZ + point(julia.y, julia.z, julia.w); 86 | } 87 | 88 | Z = mix(Z_orig, Z, weight); 89 | } 90 | 91 | // [WEB] - http://www.fractalforums.com/index.php?topic=2785.msg14893#msg14893 92 | void mandelboxIter(point Z, point P_in, float weight, float4 julia, float scale) 93 | { 94 | point Z_orig = Z; 95 | 96 | float fixedRadius = 1.0; 97 | float fR2 = fixedRadius * fixedRadius; 98 | float minRadius = 0.5; 99 | float mR2 = minRadius * minRadius; 100 | 101 | if (Z[0] > 1.0) Z[0] = 2.0 - Z[0]; 102 | else if (Z[0] < -1.0) Z[0] = -2.0 - Z[0]; 103 | 104 | if (Z[1] > 1.0) Z[1] = 2.0 - Z[1]; 105 | else if (Z[1] < -1.0) Z[1] = -2.0 - Z[1]; 106 | 107 | if (Z[2] > 1.0) Z[2] = 2.0 - Z[2]; 108 | else if (Z[2] < -1.0) Z[2] = -2.0 - Z[2]; 109 | 110 | float r2 = Z[0]*Z[0] + Z[1]*Z[1] + Z[2]*Z[2]; 111 | 112 | if (r2 < mR2) 113 | { 114 | Z = Z * DIV(fR2, mR2); 115 | } 116 | else if (r2 < fR2) 117 | { 118 | Z = Z * DIV(fR2, r2); 119 | } 120 | 121 | if (julia.x == 0.0) 122 | { 123 | Z = Z * scale + P_in; 124 | } 125 | else 126 | { 127 | Z = Z * scale + point(julia.y, julia.z, julia.w); 128 | } 129 | 130 | Z = mix(Z_orig, Z, weight); 131 | } 132 | 133 | // [M2] - Classic Mandelbulb Power 2 fractal - MandelbulbPower2Iteration 134 | void mandelbulbPower2Iter(point Z, point P_in, float weight, float4 julia) 135 | { 136 | point Z_orig = Z; 137 | 138 | float x2 = Z[0] * Z[0]; 139 | float y2 = Z[1] * Z[1]; 140 | float z2 = Z[2] * Z[2]; 141 | float temp = DIV(1.0 - z2, (x2 + y2)); 142 | point new_p; 143 | new_p[0] = (x2 - y2) * temp; 144 | new_p[0] = 2.0 * Z[0] * Z[1] * temp; 145 | new_p[0] = -2.0 * Z[2] * SQRT(x2 + y2); 146 | 147 | if (julia.x == 0.0) 148 | { 149 | Z = new_p + P_in; 150 | } 151 | else 152 | { 153 | Z = new_p + point(julia.y, julia.z, julia.w); 154 | } 155 | 156 | Z = mix(Z_orig, Z, weight); 157 | } 158 | 159 | // [M2] - Bristorbrot formula - BristorbrotIteration 160 | void bristorbrotIter(point Z, point P_in, float weight, float4 julia) 161 | { 162 | point Z_orig = Z; 163 | 164 | point new_p; 165 | new_p[0] = Z[0] * Z[0] - Z[1] * Z[1] - Z[2] * Z[2]; 166 | new_p[1] = Z[1] * (2.0 * Z[0] - Z[2]); 167 | new_p[2] = Z[2] * (2.0 * Z[0] + Z[1]); 168 | 169 | Z = new_p; 170 | 171 | if (julia.x == 0.0) 172 | { 173 | Z += P_in; 174 | } 175 | else 176 | { 177 | Z += point(julia.y, julia.z, julia.w); 178 | } 179 | 180 | Z = mix(Z_orig, Z, weight); 181 | } 182 | 183 | // [M2] - Xenodreambuie - XenodreambuieIteration 184 | void xenodreambuieIter(point Z, point P_in, float weight, float4 julia, float power, float alpha_parm, float beta_parm) 185 | { 186 | point Z_orig = Z; 187 | 188 | float distance = LENGTH(Z); 189 | 190 | float alpha = radians(alpha_parm); 191 | float beta = radians(beta_parm); 192 | 193 | float rp = POWR(distance, power - 1.0); 194 | rp *= distance; 195 | 196 | float th = atan2(Z[1], Z[0]) + beta; 197 | float ph = acos( DIV(Z[2], distance)) + alpha; 198 | 199 | if (fabs(ph) > 0.5 * M_PI_F) ph = sign(ph) * M_PI_F - ph; 200 | 201 | Z[0] = rp * COS(th * power) * SIN(ph * power); 202 | Z[1] = rp * SIN(th * power) * SIN(ph * power); 203 | Z[2] = rp * COS(ph * power); 204 | 205 | if (julia.x == 0.0) 206 | { 207 | Z += P_in; 208 | } 209 | else 210 | { 211 | Z += point(julia.y, julia.z, julia.w); 212 | } 213 | 214 | Z = mix(Z_orig, Z, weight); 215 | } 216 | 217 | // [M2] - Benesi formula invented by Benesi - BenesiIteration 218 | void benesiIter(point Z, point P_in, float weight, float4 julia) 219 | { 220 | point Z_orig = Z; 221 | 222 | float distance = LENGTH(Z); 223 | 224 | float r1 = Z[1] * Z[1] + Z[2] * Z[2]; 225 | float newx; 226 | if (P_in[0] < 0.0 || Z[0] < SQRT(r1)) 227 | { 228 | newx = Z[0] * Z[0] - r1; 229 | } 230 | else 231 | { 232 | newx = -Z[0] * Z[0] + r1; 233 | } 234 | r1 = DIV(-1.0, SQRT(r1)) * 2.0 * fabs(Z[0]); 235 | float newy = r1 * (Z[1] * Z[1] - Z[2] * Z[2]); 236 | float newz = r1 * 2.0 * Z[1] * Z[2]; 237 | 238 | Z = point(newx, newy, newz); 239 | 240 | if (julia.x == 0.0) 241 | { 242 | Z += P_in; 243 | } 244 | else 245 | { 246 | Z += point(julia.y, julia.z, julia.w); 247 | } 248 | 249 | Z = mix(Z_orig, Z, weight); 250 | } 251 | 252 | // [M2] - Ides formula made by Trafassel, the original Ide's Formula thread - IdesIteration 253 | void idesIter(point Z, point P_in, float weight, float4 julia, point multiplier, float2 sub_multiplier) 254 | { 255 | point Z_orig = Z; 256 | 257 | if (fabs(Z[0]) < 2.5) Z[0] = Z[0] * 0.9; 258 | if (fabs(Z[2]) < 2.5) Z[2] = Z[2] * 0.9; 259 | 260 | point z2 = Z * Z; 261 | point newZ; 262 | newZ[0] = multiplier[0] * z2[0] - sub_multiplier.x * (z2[1] + z2[2]); 263 | newZ[1] = multiplier[1] * Z[0] * Z[1] * Z[2]; 264 | newZ[2] = multiplier[2] * z2[2] - sub_multiplier.y * (z2[0] + z2[1]); 265 | Z = newZ; 266 | 267 | if (julia.x == 0.0) 268 | { 269 | Z += P_in; 270 | } 271 | else 272 | { 273 | Z += point(julia.y, julia.z, julia.w); 274 | } 275 | 276 | Z = mix(Z_orig, Z, weight); 277 | } 278 | 279 | // [M2] - IQ Bulb from Mandelbulb 3D and Inigo Quilez - IqBulbIteration 280 | void iqBulbIter(point Z, point P_in, float weight, float4 julia, float power, float zpower) 281 | { 282 | point Z_orig = Z; 283 | 284 | float distance = LENGTH(Z); 285 | 286 | // extract polar coordinates 287 | float wr = distance; 288 | float wo = acos( DIV(Z[1], wr)); 289 | float wi = atan2(Z[0], Z[2]); 290 | 291 | // scale and rotate the point 292 | wr = POWR(wr, power - 1.0); 293 | wr *= distance; 294 | wo *= power; 295 | wi *= zpower; 296 | 297 | // convert back to cartesian coordinates 298 | Z[0] = SIN(wo) * SIN(wi); 299 | Z[1] = COS(wo); 300 | Z[2] = SIN(wo) * COS(wi); 301 | 302 | Z *= wr; // then add Cpixel constant 303 | 304 | if (julia.x == 0.0) 305 | { 306 | Z += P_in; 307 | } 308 | else 309 | { 310 | Z += point(julia.y, julia.z, julia.w); 311 | } 312 | 313 | Z = mix(Z_orig, Z, weight); 314 | } 315 | 316 | #endif 317 | -------------------------------------------------------------------------------- /houdini/ocl/include/vft_math.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #ifndef VFT_MATH 13 | #define VFT_MATH 14 | 15 | // some of the functions here are ported/derived from Three.js library for WebGL: 16 | // https://github.com/mrdoob/three.js/tree/master/src/math 17 | 18 | // length2 19 | static float length2(float3 vec) 20 | { 21 | return (float)(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z); 22 | } 23 | 24 | // point to plane distance 25 | static float distPointPlane(float3 point, float3 plane_n, float3 plane_point) 26 | { 27 | float sb, sn, sd; 28 | float3 point_proj; 29 | 30 | sn = -dot( plane_n, (point - plane_point)); 31 | sd = dot(plane_n, plane_n); 32 | sb = DIV(sn, sd); 33 | 34 | point_proj = point + sb * plane_n; 35 | 36 | return LENGTH(point - point_proj); 37 | } 38 | 39 | // identity 4x4 matrix 40 | static float16 mtxIdent() 41 | { 42 | return (float16)(1,0,0,0, 43 | 0,1,0,0, 44 | 0,0,1,0, 45 | 0,0,0,1); 46 | } 47 | 48 | // transpose a 4x4 matrix 49 | static float16 mtxTranspose(float16 m) 50 | { 51 | float16 x; 52 | x = (float16)( m.s0,m.s4,m.s8,m.sc, 53 | m.s1,m.s5,m.s9,m.sd, 54 | m.s2,m.s6,m.sa,m.se, 55 | m.s3,m.s7,m.sb,m.sf); 56 | return x; 57 | } 58 | 59 | // multiplication of two 4x4 matrices 60 | static float16 mtxMult(float16 a, float16 b) 61 | { 62 | // float16 to float4 array 63 | const float4 ma[4] = { (float4)(a.s0123), 64 | (float4)(a.s4567), 65 | (float4)(a.s89ab), 66 | (float4)(a.scdef) }; 67 | 68 | const float4 mb[4] = { (float4)(b.s048c), 69 | (float4)(b.s159d), 70 | (float4)(b.s26ae), 71 | (float4)(b.s37bf) }; 72 | 73 | // compute matrix multiplication as a table of dot products 74 | float4 x[4] = { 75 | (float4)( dot(ma[0], mb[0]), dot(ma[0], mb[1]), dot(ma[0], mb[2]), dot(ma[0], mb[3]) ), 76 | (float4)( dot(ma[1], mb[0]), dot(ma[1], mb[1]), dot(ma[1], mb[2]), dot(ma[1], mb[3]) ), 77 | (float4)( dot(ma[2], mb[0]), dot(ma[2], mb[1]), dot(ma[2], mb[2]), dot(ma[2], mb[3]) ), 78 | (float4)( dot(ma[3], mb[0]), dot(ma[3], mb[1]), dot(ma[3], mb[2]), dot(ma[3], mb[3]) ) 79 | }; 80 | 81 | // float4 array to float16 82 | return (float16)(x[0].x,x[0].y,x[0].z,x[0].w, 83 | x[1].x,x[1].y,x[1].z,x[1].w, 84 | x[2].x,x[2].y,x[2].z,x[2].w, 85 | x[3].x,x[3].y,x[3].z,x[3].w ); 86 | } 87 | 88 | // generates a 4x4 scaling matrix 89 | static float16 mtxScale(float3 s) 90 | { 91 | float16 x; 92 | x = (float16)(s.x, 0, 0, 0, 93 | 0 , s.y, 0, 0, 94 | 0 , 0, s.z, 0, 95 | 0 , 0, 0, 1); 96 | return x; 97 | } 98 | 99 | // generates a 4x4 translation matrix 100 | static float16 mtxTranslate(float3 t) 101 | { 102 | float16 x; 103 | x = (float16)(1, 0, 0, 0, 104 | 0, 1, 0, 0, 105 | 0, 0, 1, 0, 106 | t.x, t.y, t.z, 1); 107 | return x; 108 | } 109 | 110 | // generates a 4x4 rotation matrix in XYZ order, in degrees 111 | static float16 mtxRotate(float3 rot) 112 | { 113 | rot = radians(-rot); 114 | 115 | const float cosx = COS(rot.x); 116 | const float sinx = SIN(rot.x); 117 | const float16 x = (float16)(1, 0, 0, 0, 118 | 0, cosx, -sinx, 0, 119 | 0, sinx, cosx, 0, 120 | 0, 0, 0, 1 ); 121 | 122 | const float cosy = COS(rot.y); 123 | const float siny = SIN(rot.y); 124 | const float16 y = (float16)(cosy, 0, siny, 0, 125 | 0, 1, 0, 0, 126 | -siny, 0, cosy, 0, 127 | 0, 0, 0, 1 ); 128 | 129 | const float cosz = COS(rot.z); 130 | const float sinz = SIN(rot.z); 131 | const float16 z = (float16)(cosz, -sinz, 0, 0, 132 | sinz, cosz, 0, 0, 133 | 0, 0, 1, 0, 134 | 0, 0, 0, 1 ); 135 | 136 | float16 xform = mtxIdent(); 137 | xform = mtxMult(xform, x); 138 | xform = mtxMult(xform, y); 139 | xform = mtxMult(xform, z); 140 | 141 | return xform; 142 | } 143 | 144 | 145 | // multiplciation of a 4x4 matrix and a position vector (homogeneous) 146 | static float3 mtxPtMult(float16 mtx, float3 vec) 147 | { 148 | const float4 m[4] = { (float4)(mtx.s048c), 149 | (float4)(mtx.s159d), 150 | (float4)(mtx.s26ae), 151 | (float4)(mtx.s37bf) }; 152 | 153 | const float4 v = (float4)(vec.x, vec.y, vec.z, 1); 154 | float4 x = (float4)( dot(v, m[0]), dot(v, m[1]), dot(v, m[2]), dot(v, m[3]) ); 155 | x = DIV(x, x.w); 156 | 157 | return (float3)(x.xyz); 158 | } 159 | 160 | // multiplciation of a 4x4 matrix and a directional vector, assumes affine matrix 161 | static float3 mtxDirMult(float16 mtx, float3 vec) 162 | { 163 | const float4 m[3] = { (float4)(mtx.s048c), 164 | (float4)(mtx.s159d), 165 | (float4)(mtx.s26ae) }; 166 | 167 | const float4 v = (float4)(vec.x, vec.y, vec.z, 1.0f); 168 | float3 x = (float3)( dot(v, m[0]), dot(v, m[1]), dot(v, m[2]) ); 169 | 170 | return x; 171 | } 172 | 173 | // inverts a 4x4 matrix 174 | static float16 mtxInvert(float16 me) 175 | { 176 | float16 te; 177 | 178 | float 179 | n11 = me.s0, n21 = me.s1, n31 = me.s2, n41 = me.s3, 180 | n12 = me.s4, n22 = me.s5, n32 = me.s6, n42 = me.s7, 181 | n13 = me.s8, n23 = me.s9, n33 = me.sa, n43 = me.sb, 182 | n14 = me.sc, n24 = me.sd, n34 = me.se, n44 = me.sf, 183 | 184 | t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, 185 | t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, 186 | t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, 187 | t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; 188 | 189 | float det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; 190 | 191 | //if ( det == 0 ) return mtxIdent(); // assuming invertible matrices only 192 | 193 | float detInv = DIV(1.0f, det); 194 | 195 | te.s0 = t11 * detInv; 196 | te.s1 = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; 197 | te.s2 = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; 198 | te.s3 = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; 199 | 200 | te.s4 = t12 * detInv; 201 | te.s5 = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; 202 | te.s6 = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; 203 | te.s7 = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; 204 | 205 | te.s8 = t13 * detInv; 206 | te.s9 = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; 207 | te.sa = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; 208 | te.sb = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; 209 | 210 | te.sc = t14 * detInv; 211 | te.sd = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; 212 | te.se = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; 213 | te.sf = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; 214 | 215 | return te; 216 | 217 | } 218 | 219 | #endif 220 | -------------------------------------------------------------------------------- /houdini/vex/include/vft_subd.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #ifndef VFT_SUBD 13 | #define VFT_SUBD 14 | 15 | // a function for constructing new primitives, to be used in subdivision functions 16 | function void construct_primitives(int prim_pts_idx[], new_edge_pts[]; int new_face_pt, ordering_mode, primnum) 17 | { 18 | removeprim(0, primnum, 0); 19 | 20 | if (ordering_mode == 0) 21 | { 22 | // uniform 23 | addprim(0, "poly", prim_pts_idx[0], new_edge_pts[0], new_face_pt, new_edge_pts[3]); 24 | addprim(0, "poly", new_edge_pts[0], prim_pts_idx[1], new_edge_pts[1], new_face_pt); 25 | addprim(0, "poly", new_face_pt, new_edge_pts[1], prim_pts_idx[2], new_edge_pts[2]); 26 | addprim(0, "poly", new_edge_pts[3], new_face_pt, new_edge_pts[2], prim_pts_idx[3]); 27 | } 28 | else if (ordering_mode == 1) 29 | { 30 | // mirror x y 31 | addprim(0, "poly", prim_pts_idx[0], new_edge_pts[0], new_face_pt, new_edge_pts[3]); 32 | addprim(0, "poly", prim_pts_idx[1], new_edge_pts[0], new_face_pt, new_edge_pts[1]); 33 | addprim(0, "poly", prim_pts_idx[2], new_edge_pts[2], new_face_pt, new_edge_pts[1]); 34 | addprim(0, "poly", prim_pts_idx[3], new_edge_pts[2], new_face_pt, new_edge_pts[3]); 35 | } 36 | else if (ordering_mode == 2) 37 | { 38 | // mirror y 39 | addprim(0, "poly", prim_pts_idx[0], new_edge_pts[0], new_face_pt, new_edge_pts[3]); 40 | addprim(0, "poly", prim_pts_idx[1], new_edge_pts[0], new_face_pt, new_edge_pts[1]); 41 | addprim(0, "poly", new_edge_pts[1], new_face_pt, new_edge_pts[2], prim_pts_idx[2]); 42 | addprim(0, "poly", new_edge_pts[3], new_face_pt, new_edge_pts[2], prim_pts_idx[3]); 43 | } 44 | else if (ordering_mode == 3) 45 | { 46 | // mirror x 47 | addprim(0, "poly", prim_pts_idx[0], new_edge_pts[0], new_face_pt, new_edge_pts[3]); 48 | addprim(0, "poly", new_edge_pts[0], prim_pts_idx[1], new_edge_pts[1], new_face_pt); 49 | addprim(0, "poly", new_edge_pts[2], prim_pts_idx[2], new_edge_pts[1], new_face_pt); 50 | addprim(0, "poly", prim_pts_idx[3], new_edge_pts[2], new_face_pt, new_edge_pts[3]); 51 | } 52 | else if (ordering_mode == 4) 53 | { 54 | // cyclic 55 | addprim(0, "poly", prim_pts_idx[0], new_edge_pts[0], new_face_pt, new_edge_pts[3]); 56 | addprim(0, "poly", prim_pts_idx[1], new_edge_pts[1], new_face_pt, new_edge_pts[0]); 57 | addprim(0, "poly", prim_pts_idx[2], new_edge_pts[2], new_face_pt, new_edge_pts[1]); 58 | addprim(0, "poly", prim_pts_idx[3], new_edge_pts[3], new_face_pt, new_edge_pts[2]); 59 | } 60 | else if (ordering_mode == 5) 61 | { 62 | // opposite 63 | addprim(0, "poly", new_edge_pts[3], new_face_pt, new_edge_pts[0], prim_pts_idx[0]); 64 | addprim(0, "poly", new_edge_pts[1], new_face_pt, new_edge_pts[0], prim_pts_idx[1]); 65 | addprim(0, "poly", new_edge_pts[1], new_face_pt, new_edge_pts[2], prim_pts_idx[2]); 66 | addprim(0, "poly", new_edge_pts[3], new_face_pt, new_edge_pts[2], prim_pts_idx[3]); 67 | } 68 | } 69 | 70 | // returns point number of a vertex in a primitive 71 | // primnum - primitive containing a vertex 72 | // vertexnum - vertex number (relative to the primitive, starting at 0) 73 | function int vertexprimpoint(int geo, primnum, vertexnum) 74 | { 75 | return vertexpoint(geo, vertexindex(geo, primnum, vertexnum) ); 76 | } 77 | 78 | // a struct containing weights and parameters - to be used for transferring all the weights into functions 79 | struct quad_face_split_parms 80 | { 81 | float face_weights[] = {1.0, 1.0, 1.0, 1.0}; 82 | float face_weight_offset = 0.0; 83 | float edge_weights[] = {1.0, 1.0}; 84 | float edge_weight_offset = 0.0; 85 | int ordering_mode = 0; 86 | } 87 | 88 | // basic quad subdivision 89 | function void quad_face_split(int primnum; quad_face_split_parms weights) 90 | { 91 | ////// face point 92 | 93 | // find pints in a primitive 94 | int prim_pts_idx[] = primpoints(0, primnum); 95 | vector new_face_P = {0, 0, 0}; 96 | 97 | // interpolate attribute 98 | for (int i = 0; i < len(prim_pts_idx); i++) 99 | { 100 | new_face_P += vector(point(0, "P", prim_pts_idx[i])) * weights.face_weights[i]; 101 | } 102 | 103 | new_face_P /= sum(weights.face_weights) + weights.face_weight_offset; 104 | 105 | // add new point 106 | int new_face_pt = addpoint(0, new_face_P); 107 | 108 | ////// edge points 109 | 110 | vector2 edge_vertices[] = array( {0, 1}, {1, 2}, {2, 3}, {3, 0} ); 111 | int new_edge_pts[]; 112 | 113 | foreach (vector2 edge; edge_vertices) 114 | { 115 | // get point numbers of vertices in the edge 116 | int pt_1 = vertexprimpoint(0, primnum, (int)edge[0]); 117 | int pt_2 = vertexprimpoint(0, primnum, (int)edge[1]); 118 | 119 | // interpolate attribute 120 | vector pt_1_P = point(0, "P", pt_1); 121 | vector pt_2_P = point(0, "P", pt_2); 122 | 123 | vector new_edge_P = pt_1_P * weights.edge_weights[0] + pt_2_P * weights.edge_weights[1]; 124 | new_edge_P /= sum(weights.edge_weights) + weights.edge_weight_offset; 125 | 126 | // add new point 127 | append(new_edge_pts, addpoint(0, new_edge_P)); 128 | } 129 | 130 | ////// construct primitives 131 | construct_primitives(prim_pts_idx, new_edge_pts, new_face_pt, weights.ordering_mode, primnum); 132 | } 133 | 134 | struct catmull_clark_quad_parms 135 | { 136 | float new_face_pt_weights[] = {1.0, 1.0, 1.0, 1.0}; 137 | float new_face_pt_weights_offset = 0.0; 138 | float new_edge_pt_weights[] = {6.0, 6.0, 1.0, 1.0, 1.0, 1.0}; 139 | float new_edge_pt_weights_offset = 0.0; 140 | float pt_3_pt_weights[] = {15.0, 6.0, 6.0, 6.0, 1.0, 1.0, 1.0}; 141 | float pt_3_pt_weights_offset = 0.0; 142 | float pt_4_pt_weights[] = {36.0, 6.0, 6.0, 6.0, 6.0, 1.0, 1.0, 1.0, 1.0}; 143 | float pt_4_pt_weights_offset = 0.0; 144 | float pt_5_pt_weights[] = {65.0, 6.0, 6.0, 6.0, 6.0, 6.0, 1.0, 1.0, 1.0, 1.0, 1.0}; 145 | float pt_5_pt_weights_offset = 0.0; 146 | 147 | int ordering_mode = 0; 148 | } 149 | 150 | // catmull clark subdivision on quad meshes 151 | function void catmull_clark_quad(int primnum; catmull_clark_quad_parms weights) 152 | { 153 | ////// face point 154 | 155 | // find pints in a primitive 156 | int prim_pts_idx[] = primpoints(0, primnum); 157 | vector new_face_P = {0, 0, 0}; 158 | 159 | // interpolate attribute 160 | for (int i = 0; i < len(prim_pts_idx); i++) 161 | { 162 | new_face_P += vector(point(0, "P", prim_pts_idx[i])) * weights.new_face_pt_weights[i]; 163 | } 164 | 165 | new_face_P /= sum(weights.new_face_pt_weights) + weights.new_face_pt_weights_offset; 166 | 167 | // add new point 168 | int new_face_pt = addpoint(0, new_face_P); 169 | 170 | ////// edge points 171 | 172 | vector2 edge_vertices[] = array( {0, 1}, {1, 2}, {2, 3}, {3, 0} ); 173 | int new_edge_pts[]; 174 | 175 | foreach (vector2 edge; edge_vertices) 176 | { 177 | // get point numbers of vertices in the edge 178 | int pt_1 = vertexprimpoint(0, primnum, (int)edge[0]); 179 | int pt_2 = vertexprimpoint(0, primnum, (int)edge[1]); 180 | 181 | // find all primitives that contain the two points 182 | int prims_1[] = pointprims(0, pt_1); 183 | int prims_2[] = pointprims(0, pt_2); 184 | int prims_shared[]; 185 | 186 | // find shared primitives 187 | foreach (int pt_prim; prims_1) 188 | { 189 | int found_idx = find(prims_2, pt_prim); 190 | if (found_idx >= 0) 191 | append(prims_shared, pt_prim); 192 | } 193 | 194 | if (len(prims_shared) > 2) 195 | warning("Edge | Found more than two shared primitives"); 196 | 197 | // if edge is shared between two primitives 198 | if (len(prims_shared) == 2) 199 | { 200 | int edge_prims_pts[]; 201 | append(edge_prims_pts, primpoints(0, prims_shared[0])); 202 | append(edge_prims_pts, primpoints(0, prims_shared[1])); 203 | 204 | removevalue(edge_prims_pts, pt_1); 205 | removevalue(edge_prims_pts, pt_1); 206 | removevalue(edge_prims_pts, pt_2); 207 | removevalue(edge_prims_pts, pt_2); 208 | edge_prims_pts = sort(edge_prims_pts); 209 | 210 | if (len(edge_prims_pts) != 4) 211 | warning("Edge | There are not 4 unshared points between two primitives"); 212 | 213 | int influence_pt_nums[]; 214 | append(influence_pt_nums, sort(array(pt_1, pt_2))); 215 | append(influence_pt_nums, edge_prims_pts); 216 | 217 | if (len(influence_pt_nums) != 6) 218 | warning("Edge | Length of array with influencing points is not 6"); 219 | 220 | vector new_edge_P = {0, 0, 0}; 221 | 222 | // interpolate attribute 223 | for (int i = 0; i < 6; i++) 224 | { 225 | new_edge_P += vector(point(0, "P", influence_pt_nums[i])) * weights.new_edge_pt_weights[i]; 226 | } 227 | 228 | new_edge_P /= sum(weights.new_edge_pt_weights) + weights.new_edge_pt_weights_offset; 229 | 230 | // add new point 231 | append(new_edge_pts, addpoint(0, new_edge_P)); 232 | } 233 | 234 | // if edge is not shared between primitives 235 | else if (len(prims_shared) == 1) 236 | { 237 | // interpolate attribute 238 | vector pt_1_P = point(0, "P", pt_1); 239 | vector pt_2_P = point(0, "P", pt_2); 240 | 241 | vector new_edge_P = pt_1_P * weights.new_edge_pt_weights[0] + pt_2_P * weights.new_edge_pt_weights[1]; 242 | new_edge_P /= weights.new_edge_pt_weights[0] + weights.new_edge_pt_weights[1] + weights.new_edge_pt_weights_offset; 243 | 244 | // add new point 245 | append(new_edge_pts, addpoint(0, new_edge_P)); 246 | } 247 | } 248 | 249 | ////// construct primitives 250 | 251 | construct_primitives(prim_pts_idx, new_edge_pts, new_face_pt, weights.ordering_mode, primnum); 252 | 253 | ////// original vertices 254 | 255 | foreach (int prim_pt; prim_pts_idx) 256 | { 257 | int prim_pt_prims[] = sort(pointprims(0, prim_pt)); 258 | 259 | // only distort vertex if the current primitive has the highest number of primitives that belong to the vertex - to avoid duplicate translations 260 | if (primnum == prim_pt_prims[-1]) 261 | { 262 | int influence_pt_nums[]; 263 | append(influence_pt_nums, prim_pt); // myself 264 | 265 | int prim_pt_neigbors[] = sort(neighbours(0, prim_pt)); 266 | append(influence_pt_nums, prim_pt_neigbors); // neighbors 267 | int prim_pt_valence = len(prim_pt_neigbors); 268 | 269 | int prim_pt_distant_neighbors[]; 270 | 271 | foreach(int prim_pt_prim; prim_pt_prims) // for each primitive that belongs to iterated point 272 | { 273 | int prim_pt_prim_pts[] = primpoints(0, prim_pt_prim); 274 | 275 | removevalue(prim_pt_prim_pts, prim_pt); // remove itself 276 | 277 | foreach (int prim_pt_neigbor; prim_pt_neigbors) 278 | { 279 | removevalue(prim_pt_prim_pts, prim_pt_neigbor); // remove neighbors 280 | } 281 | 282 | if (len(prim_pt_prim_pts) != 1) 283 | warning("Original vertex | After removing center and neighbor vertices, there is not exactly one point left"); 284 | 285 | append(influence_pt_nums, prim_pt_prim_pts[0]); // distant neighbors 286 | } 287 | 288 | vector new_orig_vertex_P = {0, 0, 0}; 289 | 290 | //if (prim_pt_valence > 5) 291 | // error("Original vertex | Subdivision is supported only for geometry with points of maximum valence 5"); 292 | 293 | // interpolate attribute 294 | int neighbor_counter = 0; 295 | foreach (int influence_pt_num; influence_pt_nums) 296 | { 297 | if (prim_pt_valence == 3) 298 | { 299 | new_orig_vertex_P += vector(point(0, "P", influence_pt_num)) * weights.pt_3_pt_weights[neighbor_counter]; 300 | } 301 | else if (prim_pt_valence == 4) 302 | { 303 | new_orig_vertex_P += vector(point(0, "P", influence_pt_num)) * weights.pt_4_pt_weights[neighbor_counter]; 304 | } 305 | else if (prim_pt_valence == 5) 306 | { 307 | new_orig_vertex_P += vector(point(0, "P", influence_pt_num)) * weights.pt_5_pt_weights[neighbor_counter]; 308 | } 309 | 310 | neighbor_counter++; 311 | } 312 | 313 | if (prim_pt_valence == 3) 314 | new_orig_vertex_P /= sum(weights.pt_3_pt_weights) + weights.pt_3_pt_weights_offset; 315 | else if (prim_pt_valence == 4) 316 | new_orig_vertex_P /= sum(weights.pt_4_pt_weights) + weights.pt_4_pt_weights_offset; 317 | else if (prim_pt_valence == 5) 318 | new_orig_vertex_P /= sum(weights.pt_5_pt_weights) + weights.pt_5_pt_weights_offset; 319 | 320 | // translate 321 | if (prim_pt_valence >= 3) 322 | setpointattrib(0, "P", prim_pt, new_orig_vertex_P, "set"); 323 | } 324 | } 325 | } 326 | 327 | #endif 328 | -------------------------------------------------------------------------------- /houdini/python2.7libs/vft_hou.py: -------------------------------------------------------------------------------- 1 | """ 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | """ 11 | 12 | import hou 13 | import toolutils 14 | import os 15 | import logging 16 | import time 17 | 18 | """ 19 | todo 20 | * pass parameters as attributes, to reduce overhead of kernel re-compilation 21 | * pass in arbitrary combination of hybrids, primitives and boolean-combine them 22 | """ 23 | 24 | # logging config 25 | logging.basicConfig(level=logging.DEBUG) # set to logging.INFO to disable DEBUG logs 26 | log = logging.getLogger(__name__) 27 | 28 | class NodeUtils(object): 29 | """ 30 | set of methods operating on Houdini nodes 31 | """ 32 | @staticmethod 33 | def getInputFractalNodes(root): 34 | """ 35 | returns list of fractal nodes that are connected (upstream) to root node 36 | """ 37 | # node type names of all fractal nodes 38 | fractals_nodes = set( ["vft_bristorbrotIter", "vft_mandelbulbPower2Iter", "vft_mengerSpongeIter"] ) 39 | 40 | all_input_nodes = root.inputAncestors() 41 | input_fractal_nodes = [] 42 | 43 | # find fractal nodes in all input nodes 44 | for node in all_input_nodes: 45 | if node.type().name() in fractals_nodes: 46 | input_fractal_nodes.append(node) 47 | 48 | return input_fractal_nodes 49 | 50 | @staticmethod 51 | def getOutputNodeByTypeName(start_node, type_name=""): 52 | """ 53 | returns a connected node (downstream) which belongs to "vft generator" list 54 | """ 55 | all_children_nodes = NodeUtils.outputChildren(start_node) 56 | out = None 57 | 58 | for node in all_children_nodes: 59 | if node.type().name() == type_name: 60 | out = node 61 | break 62 | 63 | return out 64 | 65 | @staticmethod 66 | def outputChildren(node): 67 | """ 68 | find all descending connected (downstream) nodes 69 | """ 70 | children = list( node.outputs() ) 71 | for node in children: 72 | new_children = node.outputs() 73 | if len(new_children) == 0: 74 | break 75 | else: 76 | for child in new_children: 77 | children.append( child ) 78 | NodeUtils.outputChildren(child) 79 | 80 | return children 81 | 82 | @staticmethod 83 | def fillKernelCodePythonSop(): 84 | """ 85 | this func will do all the parsing and will set up the kernel parm in descendant opencl node 86 | """ 87 | start_time = time.time() 88 | me = hou.pwd() 89 | geo = me.geometry() 90 | kernels_parm = me.parm("vft_kernels") 91 | 92 | # find a opencl downstream node 93 | cl_node = NodeUtils.getOutputNodeByTypeName(me, "opencl") 94 | 95 | # init a GenerateKernel object and init member var vft_kernels 96 | kernel = GenerateKernel() 97 | kernel.loadKernelsFileFromParm(kernels_parm) 98 | 99 | # get set of incoming fractals 100 | detail_attribs = geo.globalAttribs() 101 | 102 | # do the parsing 103 | kernel.parseKernelsFile(detail_attribs) 104 | 105 | # set vft_kernels_parsed to kernelcode parm in an opencl node if has changed 106 | cl_node_parm = cl_node.parm("kernelcode") 107 | old_cl_code = cl_node_parm.eval() 108 | 109 | if old_cl_code != kernel.vft_kernels_parsed: 110 | cl_node_parm.set(kernel.vft_kernels_parsed) 111 | log.debug("Kernel in OpenCL node updated") 112 | else: 113 | log.debug("Kernel in OpenCL is up to date") 114 | 115 | log.debug("Python SOP evaluated in {0:.8f} seconds \n\n".format( time.time() - start_time )) 116 | 117 | class GenerateKernel(object): 118 | """ 119 | class that will generate fractal generation CL code that Houdini will read from a string parameter and will execute 120 | """ 121 | def __init__(self): 122 | self.vft_root_path = self.getVftRootFromPath( hou.getenv("HOUDINI_PATH") ) 123 | self.vft_kernels_path = os.path.join(self.vft_root_path, "ocl/vft_kernels.cl") 124 | 125 | self.vft_kernels = None 126 | self.vft_kernels_parsed = None 127 | 128 | def clStatementsToString(self, statements): 129 | """ 130 | helper func 131 | """ 132 | return ";\n".join(statements) + ";\n" 133 | 134 | def getVftRootFromPath(self, path): 135 | """ 136 | this might not work on Windows 137 | extracts path to VFT from os-style paths string 138 | """ 139 | paths = path.replace(";",":").split(":") 140 | 141 | # this will need to be changed if git repository name changes 142 | pattern = os.sep + "raymarching" + os.sep + "houdini" 143 | 144 | # find pattern in list of paths 145 | vft_root = "" 146 | for path in paths: 147 | if pattern in path: 148 | vft_root = path 149 | break 150 | 151 | return vft_root 152 | 153 | def loadKernelsFileToMemberVar(self): 154 | """ 155 | loads vft_kernels.cl file into member variable 156 | """ 157 | start_time = time.time() 158 | with open(self.vft_kernels_path, 'r') as file: 159 | self.vft_kernels = file.read() 160 | 161 | 162 | log.debug("Kernels file loaded from disk in {0:.8f} seconds".format( time.time() - start_time )) 163 | 164 | def loadKernelsFileToParm(self, parm): 165 | """ 166 | loads vft_kernels.cl into specified parm object (which should be string) - this function should be called by a button for (re)loading a parm 167 | """ 168 | if self.vft_kernels == None: 169 | self.loadKernelsFileToMemberVar() 170 | 171 | parm.set(self.vft_kernels) 172 | 173 | def loadKernelsFileFromParm(self, parm): 174 | """ 175 | loads vft_kernels.cl into member var - either from disk, or parm (if it is loaded there already) 176 | """ 177 | if parm.eval() == "": 178 | log.debug("Loading member var from file") 179 | self.loadKernelsFileToMemberVar() 180 | else: 181 | log.debug("Loading member var from node parameter") 182 | self.vft_kernels = parm.eval() 183 | 184 | def parseKernelsFile(self, attribs): 185 | """ 186 | parses vft_kernels.cl file and replaces PY_* macros and saves it into member varible 187 | """ 188 | start_time = time.time() 189 | self.vft_kernels_parsed = self.vft_kernels 190 | 191 | attribs_dict = {} 192 | for attr in attribs: 193 | attribs_dict[ attr.name() ] = attr.strings() 194 | 195 | # generate fractal stack 196 | fractal_stack_token = "#define PY_FRACTAL_STACK" 197 | 198 | fractal_stack_cl_code = "" 199 | try: 200 | fractal_stack_cl_code = self.clStatementsToString( self.generateClFractalStack(attribs_dict["fractal_stack"]) ) 201 | except KeyError: 202 | pass 203 | log.error('No "fractal_stack" attribute found, probably missing input') 204 | 205 | fractal_stack_cl_code = fractal_stack_token + "\n\n" + fractal_stack_cl_code 206 | 207 | # generate pre-transform stack 208 | allowed_pre_transforms = ["curlNoise", "translateIter", "tgladFoldIter", "fabsFoldIter", "boxFoldIter", "rotationIter", "preScaleIter"] 209 | pre_transform_stack_token = "#define PY_PRE_TRANSFORM_STACK" 210 | 211 | pre_transform_stack_cl_code = "" 212 | try: 213 | pre_transform_stack_cl_code = self.clStatementsToString( self.generateClFractalStack(attribs_dict["pre-transform_stack"], valid_list=allowed_pre_transforms) ) 214 | except KeyError: 215 | pass 216 | log.debug('No "pre-transform_stack" attribute found, probably missing input') 217 | 218 | pre_transform_stack_cl_code = pre_transform_stack_token + "\n\n" + pre_transform_stack_cl_code 219 | 220 | 221 | self.vft_kernels_parsed = self.vft_kernels_parsed.replace(fractal_stack_token, fractal_stack_cl_code) 222 | self.vft_kernels_parsed = self.vft_kernels_parsed.replace(pre_transform_stack_token, pre_transform_stack_cl_code) 223 | 224 | log.debug("Kernels file parsed in {0:.8f} seconds".format( time.time() - start_time )) 225 | 226 | def generateClFractalStack(self, fractal_attribs, valid_list=None): 227 | """ 228 | returns a list of CL statements with fractal function calls from a list of fractal nodes 229 | """ 230 | 231 | # a dictionary mapping strings of arguments to OpenCL fractal function names 232 | args_dict = { 233 | "default" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f))", 234 | "mandelboxIter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), {obj.parms[scale]:.6f}f)", 235 | "mengerSpongeIter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), {obj.parms[modulus]:.0f})", 236 | "mandelbulbIter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), {obj.parms[power]:.6f}f)", 237 | "xenodreambuieIter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), {obj.parms[power]:.6f}f, {obj.parms[alpha]:.6f}f, {obj.parms[beta]:.6f}f)", 238 | "sierpinski3dIter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), {obj.parms[scale]:.6f}f, (float3)({obj.parms[offsetx]:.6f}f, {obj.parms[offsety]:.6f}f, {obj.parms[offsetz]:.6f}f), (float3)({obj.parms[rotx]:.6f}f, {obj.parms[roty]:.6f}f, {obj.parms[rotz]:.6f}f))", 239 | "mengerSmoothIter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), {obj.parms[scale]:.6f}f, {obj.parms[offset_s]:.6f}f, (float3)({obj.parms[offset_cx]:.6f}f, {obj.parms[offset_cy]:.6f}f, {obj.parms[offset_cz]:.6f}f), (float3)({obj.parms[rotx]:.6f}f, {obj.parms[roty]:.6f}f, {obj.parms[rotz]:.6f}f))", 240 | "amazingSurfIter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), {obj.parms[foldx]:.6f}f, {obj.parms[foldy]:.6f}f, {obj.parms[force_cylindrical_fold]:.0f}, {obj.parms[min_radius]:.6f}f, {obj.parms[scale]:.6f}f, {obj.parms[scale_fold_influence]:.6f}f, (float3)({obj.parms[rotx]:.6f}f, {obj.parms[roty]:.6f}f, {obj.parms[rotz]:.6f}f), {obj.parms[multiply_c]:.0f}, (float3)({obj.parms[c_multiplierx]:.6f}f, {obj.parms[c_multipliery]:.6f}f, {obj.parms[c_multiplierz]:.6f}f))", 241 | "mandelbulb4Iter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), {obj.parms[power]:.6f}f, (float3)({obj.parms[anglesx]:.6f}f, {obj.parms[anglesy]:.6f}f, {obj.parms[anglesz]:.6f}f))", 242 | "idesIter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), (float3)({obj.parms[multiplierx]:.6f}f, {obj.parms[multipliery]:.6f}f, {obj.parms[multiplierz]:.6f}f), (float2)({obj.parms[sub_multiplierx]:.6f}f, {obj.parms[sub_multipliery]:.6f}f))", 243 | "ides2Iter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), (float3)({obj.parms[multiplierx]:.6f}f, {obj.parms[multipliery]:.6f}f, {obj.parms[multiplierz]:.6f}f), (float2)({obj.parms[sub_multiplierx]:.6f}f, {obj.parms[sub_multipliery]:.6f}f))", 244 | "iqBulbIter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), {obj.parms[power]:.6f}f, {obj.parms[zpower]:.6f}f)", 245 | "quaternion3dIter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), (float3)({obj.parms[scalex]:.6f}f, {obj.parms[scaley]:.6f}f, {obj.parms[scalez]:.6f}f), (float3)({obj.parms[offsetx]:.6f}f, {obj.parms[offsety]:.6f}f, {obj.parms[offsetz]:.6f}f), (float3)({obj.parms[rotx]:.6f}f, {obj.parms[roty]:.6f}f, {obj.parms[rotz]:.6f}f), {obj.parms[de_influence]:.6f}f)", 246 | "josKleinianIter" : "{obj.cl_function_name}(Z, de, P_in, log_lin, {obj.parms[weight]:.6f}f, (float4)({obj.parms[julia_mode]:.1f}f, {obj.parms[juliax]:.6f}f, {obj.parms[juliay]:.6f}f, {obj.parms[juliaz]:.6f}f), {obj.parms[r]:.6f}f, {obj.parms[l]:.6f}f, (float3)({obj.parms[box_sizex]:.6f}f, {obj.parms[box_sizey]:.6f}f, {obj.parms[box_sizez]:.6f}f))", 247 | "rotationIter" : "{obj.cl_function_name}(Z, (float3)({obj.parms[rotx]:.6f}f, {obj.parms[roty]:.6f}f, {obj.parms[rotz]:.6f}f))", 248 | "boxFoldIter" : "{obj.cl_function_name}(Z, (int3)({obj.parms[axis_enablex]:.0f}, {obj.parms[axis_enabley]:.0f}, {obj.parms[axis_enablez]:.0f}), {obj.parms[folding_limit]:.6f}f, {obj.parms[folding_value]:.6f}f, {obj.parms[z_scale]:.6f}f)", 249 | "fabsFoldIter" : "{obj.cl_function_name}(Z, (int3)({obj.parms[axis_enablex]:.0f}, {obj.parms[axis_enabley]:.0f}, {obj.parms[axis_enablez]:.0f}), (float3)({obj.parms[offsetx]:.6f}f, {obj.parms[offsety]:.6f}f, {obj.parms[offsetz]:.6f}f))", 250 | "tgladFoldIter" : "{obj.cl_function_name}(Z, (int3)({obj.parms[axis_enablex]:.0f}, {obj.parms[axis_enabley]:.0f}, {obj.parms[axis_enablez]:.0f}), (float3)({obj.parms[offsetx]:.6f}f, {obj.parms[offsety]:.6f}f, {obj.parms[offsetz]:.6f}f))", 251 | "scaleIter" : "{obj.cl_function_name}(Z, de, (float3)({obj.parms[scalex]:.6f}f, {obj.parms[scaley]:.6f}f, {obj.parms[scalez]:.6f}f))", 252 | "translateIter" : "{obj.cl_function_name}(Z, (float3)({obj.parms[translatex]:.6f}f, {obj.parms[translatey]:.6f}f, {obj.parms[translatez]:.6f}f))", 253 | "addCOffsetIter" : "{obj.cl_function_name}(Z, P_in, (float3)({obj.parms[offsetx]:.6f}f, {obj.parms[offsety]:.6f}f, {obj.parms[offsetz]:.6f}f))", 254 | "curlNoise" : "{obj.cl_function_name}(theXNoise, Z, (float4)({obj.parms[frequencyx]:.6f}f, {obj.parms[frequencyy]:.6f}f, {obj.parms[frequencyz]:.6f}f, {obj.parms[frequencyw]:.6f}f), (float4)({obj.parms[offsetx]:.6f}f, {obj.parms[offsety]:.6f}f, {obj.parms[offsetz]:.6f}f, {obj.parms[offsetw]:.6f}f), (float3)({obj.parms[amplitudex]:.6f}f, {obj.parms[amplitudey]:.6f}f, {obj.parms[amplitudez]:.6f}f))", 255 | "preScaleIter" : "{obj.cl_function_name}(Z, (float3)({obj.parms[scalex]:.6f}f, {obj.parms[scaley]:.6f}f, {obj.parms[scalez]:.6f}f))" 256 | } 257 | 258 | def args_format(args_dict, obj): 259 | """ 260 | if a function has some custom arguments, then their formatting is specified here 261 | """ 262 | if obj.cl_function_name in args_dict: 263 | 264 | # this line is picking a string to be formatted from args_dict dictionary 265 | string = args_dict[obj.cl_function_name] 266 | string = string.format( obj=obj ) 267 | 268 | # if function has not arguments mapping in args_dict, then it is considered to use default one 269 | else: 270 | string = args_dict["default"] 271 | string = string.format( obj=obj ) 272 | 273 | return string 274 | 275 | fractal_objects = [] 276 | for attrib in fractal_attribs: 277 | obj = FractalObject() 278 | obj.attribToVars(attrib) 279 | 280 | if valid_list: 281 | if obj.cl_function_name in valid_list: 282 | fractal_objects.append(obj) 283 | else: 284 | fractal_objects.append(obj) 285 | 286 | # list which will hold CL fractal funcs calls 287 | stack = [] 288 | 289 | for obj in fractal_objects: 290 | statement = args_format(args_dict, obj) 291 | log.debug(statement) 292 | stack.append(statement) 293 | 294 | return stack 295 | 296 | class FractalObject(object): 297 | """ 298 | a class that will hold data and functionality for getting fractal data from detail attribute 299 | """ 300 | def __init__(self): 301 | # init member vars 302 | self.asset_name = None 303 | self.parent_name = None 304 | self.parent_path = None 305 | self.cl_function_name = None 306 | self.parms = { 307 | "weight" : 1.0, 308 | "julia_mode" : 0, 309 | "juliax" : 0.0, 310 | "juliay" : 0.0, 311 | "juliaz" : 0.0 312 | } 313 | 314 | def attribToVars(self, attrib): 315 | """ 316 | this will parse attribute string and will set member vars from it 317 | """ 318 | attrib_list = attrib.split("|") 319 | 320 | self.asset_name = attrib_list[0] 321 | self.parent_name = attrib_list[1] 322 | self.parent_path = attrib_list[2] 323 | 324 | self.cl_function_name = self.asset_name.split("_")[-1] 325 | 326 | parms_string = attrib_list[3] 327 | parms_list = parms_string.split(",") 328 | 329 | for item in parms_list: 330 | item_split = item.split(":") 331 | self.parms[ item_split[0] ] = float(item_split[1]) 332 | 333 | def nodeToVars(self): 334 | """ 335 | this will fill in member vars based on a node, it should be used inside of a fractal node 336 | """ 337 | node = hou.pwd() 338 | 339 | self.asset_name = node.parent().type().name() 340 | self.parent_name = node.parent().name() 341 | self.parent_path = node.parent().path() 342 | 343 | parms = node.parent().parms() 344 | for parm in parms: 345 | if parm.parmTemplate().type() != hou.parmTemplateType.Label: 346 | self.parms[ parm.name() ] = parm.eval() 347 | 348 | def varsToAttrib(self): 349 | """ 350 | this will serialize member vars into a string, which should be stored in detail attribute 351 | """ 352 | parms_string = "" 353 | 354 | for key, value in self.parms.iteritems(): 355 | parms_string += key + ":" + "{0:.6f}".format(value) + "," 356 | parms_string = parms_string[:-1] # remove the last comma 357 | 358 | attrib = "|".join( [self.asset_name, self.parent_name, self.parent_path, parms_string] ) 359 | return attrib 360 | 361 | class FpsCam(object): 362 | """ 363 | Set of functions helping with FPS/Flying camera orientation in scenes. 364 | """ 365 | pass -------------------------------------------------------------------------------- /houdini/ocl/vft_kernels.cl: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #include "xnoise.h" 13 | #include "vft_defines.h" 14 | #include "vft_utils.h" 15 | #include "vft_math.h" 16 | #include "vft_fractals.h" 17 | #include "vft_shading.h" 18 | 19 | // contains primitives 20 | float primitive_stack(float3 P, const int stack) 21 | { 22 | float out_distance; 23 | switch (stack) 24 | { 25 | case 0: 26 | { 27 | out_distance = sphere(P, 1.0f); 28 | 29 | break; 30 | } 31 | case 1: 32 | { 33 | out_distance = torus(P, (float2)(1.0f, 0.5f)); 34 | 35 | break; 36 | } 37 | } 38 | 39 | return out_distance; 40 | } 41 | 42 | void pre_transform_stack(float3* Z, global const void* theXNoise) 43 | { 44 | #define PY_PRE_TRANSFORM_STACK 45 | } 46 | 47 | // contains fractal combinations for all shapes 48 | void fractal_stack(float3* Z, float* de, const float3* P_in, int* log_lin, const int stack, global const void* theXNoise) 49 | { 50 | switch (stack) 51 | { 52 | case 0: 53 | { 54 | iqBulbIter(Z, de, P_in, log_lin, 1.0f, (float4)(0.0f, 0.0f, 0.0f, 0.0f), 8.0f, 8.0f); 55 | //idesIter(Z, de, P_in, log_lin, 1.0f, (float4)(0.0f, 0.0f, 0.0f, 0.0f), (float3)(1.0f, 2.0f, 1.0f), (float2)(0.5f, 0.5f)); 56 | //benesiIter(Z, de, P_in, log_lin, 1.0f, (float4)(0.0f, 0.0f, 0.0f, 0.0f)); 57 | //hypercomplexIter(Z, de, P_in, log_lin, 1.0f, (float4)(0.0f, 0.0f, 0.0f, 0.0f)); 58 | //josKleinianIter(Z, de, P_in, log_lin, 1.0f, (float4)(0.0f, 1.0f, 1.0f, 3.0f), 2.0f, 0.0f, (float3)(1.0f, 1.0f, 1.0f)); 59 | //amazingSurfIter(Z, de, P_in, log_lin, 1.0f, (float4)(1.0f, 0.0f, 0.0f, 0.0f), 1.0f, 1.0f, 0, 0.5f, 2.0f, 1.0f, (float3)(0.0f, 0.0f, 0.0f), 1, (float3)(1.0f, 1.0f, 1.0f)); 60 | //mandelbulbPower2Iter(Z, de, P_in, log_lin, 1.0f, (float4)(1.0f, 0.3f, 0.5f, 0.2f)); // log 61 | //bristorbrotIter(Z, de, P_in, log_lin, 1.0f, (float4)(0.0f, 1.3f, 3.3f, 0.0f)); // log 62 | //xenodreambuieIter(Z, de, P_in, log_lin, 1.0f, (float4)(1.0f, 1.0f, 0.0f, 0.0f), 9.0f, 0.0f, 0.0f); // log 63 | //mandelboxIter(Z, de, P_in, log_lin, 1.0f, (float4)(0.0f, 1.0f, 3.0f, 4.0f), 3.1f); // lin 64 | //mandelbulbIter(Z, de, P_in, log_lin, 1.0f, (float4)(0.0f, 1.0f, 0.0f, 0.0f), 8.0f); // log 65 | //mengerSpongeIter(Z, de, P_in, log_lin, 1.0f, (float4)(0.0f, 0.0f, 1.0f, 0.0f)); // lin 66 | //sierpinski3dIter(Z, de, P_in, log_lin, 1.0f, (float4)(0.0f, 0.0f, 0.0f, 0.5f), 2.0f, (float3)(1.0f, 1.0f, 1.0f), (float3)(0.0f, 0.0f, 0.0f) ); // lin 67 | 68 | break; 69 | } 70 | 71 | case 1: 72 | { 73 | sierpinski3dIter(Z, de, P_in, log_lin, 1.0f, (float4)(0.0f, 0.0f, 0.0f, 0.5f), 2.0f, (float3)(1.0f, 1.0f, 1.0f), (float3)(0.0f, 0.0f, 0.0f) ); // lin 74 | 75 | break; 76 | } 77 | 78 | case 2: 79 | { 80 | mandelbulbPower2Iter(Z, de, P_in, log_lin, 1.0f, (float4)(1.0f, 0.3f, 0.5f, 0.2f)); // log 81 | 82 | break; 83 | } 84 | case 3: 85 | { 86 | #define PY_FRACTAL_STACK 87 | 88 | break; 89 | } 90 | } 91 | } 92 | 93 | // scene setup - setting of coordinates and shapes in them 94 | 95 | // scene with multiple unions of prims and fractals 96 | /*float scene( float3 P, const int final, float* orbit_colors, float3* N ) { 97 | float dist_out; 98 | float orbit_closest = LARGE_NUMBER; 99 | 100 | float shape1 = hybrid(P, 10, 10.0f, 1.0f, final, &orbit_closest, orbit_colors, N, 0); 101 | float shape2 = hybrid(P - (float3)(2.0f), 10, 10.0f, 1.0f, final, &orbit_closest, orbit_colors, N, 1); 102 | float shape3 = hybrid(P + (float3)(2.0f), 10, 10.0f, 1.0f, final, &orbit_closest, orbit_colors, N, 2); 103 | 104 | float shape4 = primitive(P - (float3)(2.0f, 0.0f, 0.0f), 0.3f, final, &orbit_closest, orbit_colors, (float3)(1.0f,0.0f,1.0f), N, 0); 105 | float shape5 = primitive(P - (float3)(-2.0f, 0.0f, 0.0f), 0.6f, final, &orbit_closest, orbit_colors, (float3)(1.0f,1.0f,0.0f), N, 1); 106 | 107 | dist_out = sdfUnion( sdfUnion( sdfUnion( sdfUnion(shape1, shape2) , shape3 ) , shape4 ) , shape5 ); 108 | 109 | return dist_out; 110 | }*/ 111 | 112 | // scene showing unions and subtractions 113 | /*float scene( float3 P, const int final, float* orbit_colors, float3* N ) { 114 | float dist_out; 115 | float orbit_closest = LARGE_NUMBER; 116 | 117 | float shape1 = hybrid(P, 10, 10.0f, 1.0f, final, &orbit_closest, orbit_colors, N, 0); 118 | float shape2 = hybrid(P - (float3)(0.4f), 10, 10.0f, 1.0f, final, &orbit_closest, orbit_colors, N, 1); 119 | //float shape3 = hybrid(P - (float3)(-0.5f, 0.0f, 0.5f), 10, 10.0f, 1.0f, final, &orbit_closest, orbit_colors, N, 2); 120 | 121 | float shape4 = primitive(P - (float3)(0.7f, 0.0f, 0.0f), 1.0f, final, &orbit_closest, orbit_colors, (float3)(1.0f,0.0f,1.0f), N, 0); 122 | 123 | dist_out = sdfSubtract( sdfUnion(shape1, shape2) , shape4 ); 124 | 125 | return dist_out; 126 | }*/ 127 | 128 | float scene( float3 P, const int final, float* orbit_colors, float3* N, global const void* theXNoise ) { 129 | float dist_out; 130 | float orbit_closest = LARGE_NUMBER; 131 | int iterations = 0; 132 | 133 | pre_transform_stack(&P, theXNoise); 134 | 135 | float shape1 = hybrid(P, 25, 10.0f, 1.0f, final, &orbit_closest, orbit_colors, N, 3, theXNoise, &iterations); 136 | 137 | dist_out = shape1; 138 | 139 | return dist_out; 140 | } 141 | 142 | float scene_fog( float3 P, const int final, float* orbit_colors, float3* N, global const void* theXNoise, const int max_iter, const float max_dist ) { 143 | float dist_out; 144 | float orbit_closest = LARGE_NUMBER; 145 | int iterations = 0; 146 | 147 | pre_transform_stack(&P, theXNoise); 148 | 149 | float shape1 = hybrid(P, max_iter, max_dist, 1.0f, final, &orbit_closest, orbit_colors, N, 3, theXNoise, &iterations); 150 | 151 | dist_out = iterations == max_iter ? 1.0f : 0.0f; 152 | 153 | return dist_out; 154 | } 155 | 156 | kernel void marchPerspCam( 157 | global const void* theXNoise, 158 | int P_length, global float* P, 159 | int planeZ_length, global float* planeZ, 160 | int width_length, global float* width, 161 | int height_length, global float* height, 162 | int px_length, global float* px, 163 | int camXform_length, global float* camXform, 164 | int camPos_length, global float* camPos, 165 | int N_length, global float* N, 166 | int iRel_length, global float* iRel, 167 | int Cd_length, global float* Cd, 168 | int orbits_length, global int* orbits_index, global float* orbits 169 | ) 170 | { 171 | // get current point id 172 | const long idx = get_global_id(0); 173 | 174 | // if current point is not valid, then end 175 | if ( idx >= P_length ) return; 176 | 177 | // read in P attrib 178 | const float3 pixel_P_origin = vload3(idx, P); 179 | float3 pixel_P_world = pixel_P_origin; 180 | 181 | //// transforming to near img plane 182 | 183 | // move to near img plane 184 | pixel_P_world.z = planeZ[0]; 185 | 186 | // compute scale of near img plane 187 | const float16 near_plane_scale = mtxScale( (float3)(width[0]-px[0], height[0]-px[0], 1.0f) ); 188 | 189 | // read in cam world matrix 190 | const float16 cam_xform_world = (float16)(camXform[0],camXform[1],camXform[2],camXform[3], 191 | camXform[4],camXform[5],camXform[6],camXform[7], 192 | camXform[8],camXform[9],camXform[10],camXform[11], 193 | camXform[12],camXform[13],camXform[14],camXform[15] ); 194 | 195 | // create a mtx to hold transformations 196 | float16 near_plane_xform = mtxIdent(); 197 | 198 | // apply transformations, also produce alternative matrix with scaled near plane 199 | near_plane_xform = mtxMult(near_plane_xform, near_plane_scale); 200 | float16 near_plane_xform_scaled = mtxMult(near_plane_xform, mtxScale( (float3)(10000000.0f) ) ); 201 | near_plane_xform = mtxMult(near_plane_xform, cam_xform_world); 202 | near_plane_xform_scaled = mtxMult(near_plane_xform_scaled, cam_xform_world); 203 | 204 | // create a scaled near plane position for more accurate ray_dir calculation 205 | float3 pixel_P_world_scaled = mtxPtMult(near_plane_xform_scaled, pixel_P_world); 206 | 207 | // transform pixels into near img plane 208 | pixel_P_world = mtxPtMult(near_plane_xform, pixel_P_world); 209 | 210 | // get camera world space position and compute ray direction vector 211 | const float3 cam_P_world = (float3)(camPos[0], camPos[1], camPos[2]); 212 | const float3 ray_dir = NORMALIZE(pixel_P_world_scaled - cam_P_world); 213 | 214 | //// raymarching 215 | 216 | // raymarch settings, initialize variables 217 | float3 color = (float3)(0.0f); 218 | float AO = 1.0f; 219 | float orbit_colors[ORBITS_ARRAY_LENGTH]; 220 | float3 Cd_out = (float3)(1.0f); 221 | float3 N_grad; 222 | 223 | float3 ray_P_world = pixel_P_world; 224 | float cam_dist = scene(cam_P_world, 0, NULL, NULL, theXNoise); 225 | float de = 0.0f; 226 | int i = 0; 227 | 228 | // quality settings 229 | float step_size = 0.35f; 230 | float iso_limit_mult = 0.5f; 231 | float ray_dist = planeZ[0]; 232 | const int max_steps = 2500; 233 | const float max_dist = 1000.0f; 234 | 235 | float iso_limit = cam_dist * 0.0001f * iso_limit_mult; 236 | 237 | // raymarching loop 238 | #pragma unroll 239 | for (i=0; i= max_dist ) 244 | { 245 | de = scene(ray_P_world, 1, orbit_colors, &N_grad, theXNoise) * step_size; 246 | break; 247 | } 248 | 249 | ray_dist += de; 250 | ray_P_world += ray_dir * de; 251 | } 252 | 253 | // relative amount of steps 254 | float i_rel = DIV((float)(i), (float)(max_steps)); 255 | i_rel = 1.0f-POWR(i_rel, DIV(1.0f, 3.0f)); 256 | 257 | // remove missed 258 | if ( de > iso_limit ) 259 | { 260 | i_rel = -1.0f; 261 | } 262 | else 263 | { 264 | // compute N and AO only when not using DELTA DE mode 265 | #if !ENABLE_DELTA_DE 266 | N_grad = compute_N(&iso_limit, &ray_P_world, theXNoise); 267 | AO = compute_AO(&N_grad, &ray_P_world, theXNoise); 268 | #endif 269 | 270 | // output shading for viewport preview 271 | color.x = AO; 272 | color.y = orbit_colors[0]; 273 | color.z = 1.0f; 274 | 275 | Cd_out = color; 276 | } 277 | 278 | // export attribs 279 | vstore3(ray_P_world, idx, P); 280 | vstore3(N_grad, idx, N); 281 | vstore3(Cd_out, idx, Cd); 282 | vstore1(i_rel, idx, iRel); 283 | 284 | long orbits_idx_start = orbits_index[idx]; 285 | long orbits_idx_end = orbits_idx_start + ORBITS_ARRAY_LENGTH; 286 | #pragma unroll 287 | for (long j=orbits_idx_start; j= P_length ) return; 307 | 308 | // read in P, N attribs 309 | const float3 point_P_origin = vload3(idx, P); 310 | const float3 point_N = vload3(idx, N); 311 | 312 | //// raymarching 313 | 314 | // raymarch settings, initialize variables 315 | float3 color = (float3)(0.0f); 316 | float AO = 1.0f; 317 | float orbit_colors[ORBITS_ARRAY_LENGTH]; 318 | float3 Cd_out = (float3)(1.0f); 319 | float3 N_grad; 320 | 321 | float3 ray_P_world = point_P_origin; 322 | float cam_dist = scene(point_P_origin, 0, NULL, NULL, theXNoise); 323 | float de = 0.0f; 324 | int i = 0; 325 | 326 | // quality settings 327 | float step_size = 0.9f; 328 | float iso_limit_mult = 0.4f; 329 | float ray_dist = 0.0f; 330 | const int max_steps = 150; 331 | const float max_dist = 100.0f; 332 | 333 | float iso_limit = cam_dist * 0.0001f * iso_limit_mult; 334 | 335 | // raymarching loop 336 | #pragma unroll 337 | for (i=0; i= max_dist ) 342 | { 343 | de = scene(ray_P_world, 1, orbit_colors, &N_grad, theXNoise) * step_size; 344 | break; 345 | } 346 | 347 | ray_dist += de; 348 | ray_P_world += point_N * de; 349 | } 350 | 351 | // relative amount of steps 352 | float i_rel = DIV((float)(i), (float)(max_steps)); 353 | i_rel = 1.0f-POWR(i_rel, DIV(1.0f, 3.0f)); 354 | 355 | // remove missed 356 | if ( de > iso_limit ) 357 | { 358 | i_rel = -1.0f; 359 | } 360 | else 361 | { 362 | // compute N and AO only when not using DELTA DE mode 363 | #if !ENABLE_DELTA_DE 364 | N_grad = compute_N(&iso_limit, &ray_P_world, theXNoise); 365 | AO = compute_AO(&N_grad, &ray_P_world, theXNoise); 366 | #endif 367 | 368 | // output shading for viewport preview 369 | color.x = AO; 370 | color.y = orbit_colors[0]; 371 | color.z = 1.0f; 372 | 373 | Cd_out = color; 374 | } 375 | 376 | // export attribs 377 | vstore3(ray_P_world, idx, P); 378 | vstore3(N_grad, idx, N); 379 | vstore3(Cd_out, idx, Cd); 380 | vstore1(i_rel, idx, iRel); 381 | 382 | long orbits_idx_start = orbits_index[idx]; 383 | long orbits_idx_end = orbits_idx_start + ORBITS_ARRAY_LENGTH; 384 | #pragma unroll 385 | for (long j=orbits_idx_start; j 50) taper_mtx[9] *= -1; 651 | 652 | //density_xformtoworld_inverted = mtxInvert(density_xformtoworld_inverted); 653 | 654 | //float3 P_taper = mtxPtMult(density_xformtoworld_inverted, P_vol); 655 | //P_taper = mtxPtMult(density_xformtoworld, P_taper); 656 | //P_taper = mtxPtMult(density_xformtoworld, P_taper); 657 | 658 | float3 P_world = mtxPtMult(taper_mtx, P_vol); 659 | //P_world = P_vol; 660 | 661 | float fog = 0.0f; 662 | //fog = scene_fog(P_world, 0, NULL, NULL, theXNoise, max_iter, max_dist); 663 | if ( LENGTH(P_world) < 30.6f ) fog = 1.0f; 664 | 665 | printMtxVol(taper_mtx); 666 | 667 | vstore1(fog, idx, density); 668 | } 669 | 670 | kernel void computePoints( 671 | global const void* theXNoise, 672 | int P_length, 673 | global float* P, 674 | int density_length, 675 | global float* density, 676 | float max_dist, 677 | int max_iter 678 | ) 679 | { 680 | int idx = get_global_id(0); 681 | if (idx >= density_length) 682 | return; 683 | 684 | float3 P_world = vload3(idx, P); 685 | 686 | float fog = 0.0f; 687 | fog = scene_fog(P_world, 0, NULL, NULL, theXNoise, max_iter, max_dist); 688 | 689 | vstore1(fog, idx, density); 690 | } 691 | 692 | kernel void lorenzAttractor( 693 | int P_length, 694 | global float* P, 695 | int k_length, 696 | global int* k_index, 697 | global float* k 698 | ) 699 | { 700 | int idx = get_global_id(0); 701 | if (idx >= P_length) 702 | return; 703 | 704 | } 705 | -------------------------------------------------------------------------------- /houdini/ocl/include/vft_fractals.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file has been developed within the scope of the 4 | Technical Director course at Filmakademie Baden-Wuerttemberg. 5 | http://technicaldirector.de 6 | 7 | Written by Juraj Tomori. 8 | Copyright (c) 2019 Animationsinstitut of Filmakademie Baden-Wuerttemberg 9 | ----------------------------------------------------------------------------- 10 | */ 11 | 12 | #ifndef VFT_FRACTALS 13 | #define VFT_FRACTALS 14 | 15 | // mapping of variables 16 | // aux.r_dz -> de 17 | // aux.r -> distance 18 | // aux.de -> de 19 | // dr -> de 20 | // r -> distance 21 | // Bailout -> max_distance 22 | // Iterations -> max_iterations 23 | // positive log_lin -> log, negative -> lin 24 | 25 | // fractal formula sources: 26 | // [M2] - Mandelbulber v2 27 | // [M3D] - Mandelbulb 3D 28 | // [WEB] - From the web 29 | 30 | ////////////// primitives 31 | // [WEB] - http://iquilezles.org/www/articles/distfunctions/distfunctions.htm 32 | 33 | // sphere: position, radius 34 | static float sphere( float3 P, float rad ) 35 | { 36 | float dist = LENGTH(P) - rad; 37 | return dist; 38 | } 39 | 40 | // box: position, size 41 | static float box( float3 P, float3 b ) 42 | { 43 | float3 d = fabs(P) - b; 44 | return min( max( d.x, max(d.y, d.z) ), 0.0f) + LENGTH( max(d, 0.0f) ); 45 | } 46 | 47 | // round box: position, size, roundness 48 | static float roundBox( float3 P, float3 b, float r ) 49 | { 50 | return LENGTH( max( fabs(P) - b, 0.0f ) )-r; 51 | } 52 | 53 | // torus: position, size (radius, thickness) 54 | static float torus( float3 P, float2 t ) 55 | { 56 | float2 q = (float2)(LENGTH(P.xz)-t.x,P.y); 57 | return LENGTH(q)-t.y; 58 | } 59 | 60 | // infinite cone 61 | static float cone( float3 P, float2 c ) 62 | { 63 | c = NORMALIZE(c); 64 | float q = LENGTH(P.xy); 65 | return dot( c, (float2)(q, P.z) ); 66 | } 67 | 68 | 69 | ////////////// fractals 70 | 71 | // [WEB] - http://blog.hvidtfeldts.net/index.php/2011/09/ 72 | static void mandelbulbIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const float power) 73 | { 74 | float3 Z_orig = *Z; 75 | float de_orig = *de; 76 | 77 | float distance = LENGTH(*Z); 78 | 79 | // convert to polar coordinates 80 | float theta = acos( DIV((*Z).z, distance)); 81 | float phi = atan2((*Z).y, (*Z).x); 82 | 83 | *de = POWR(distance, power-1) * power * (*de) + 1.0f; 84 | 85 | // scale and rotate the point 86 | float zr = POWR(distance, power); 87 | theta *= power; 88 | phi *= power; 89 | 90 | // convert back to cartesian coordinates 91 | float3 newZ = zr * (float3)( SIN(theta)*COS(phi), SIN(phi)*SIN(theta), COS(theta) ); 92 | 93 | if (julia.x == 0.0f) 94 | { 95 | *Z = newZ + *P_in; 96 | } 97 | else { 98 | *Z = newZ + julia.yzw; 99 | } 100 | 101 | *Z = mix(Z_orig, *Z, weight); 102 | *de = mix(de_orig, *de, weight); 103 | (*log_lin)++; 104 | } 105 | 106 | // [WEB] - http://www.fractalforums.com/index.php?topic=2785.msg14893#msg14893 107 | static void mandelboxIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const float scale) 108 | { 109 | float3 Z_orig = *Z; 110 | float de_orig = *de; 111 | 112 | float fixedRadius = 1.0f; 113 | float fR2 = fixedRadius * fixedRadius; 114 | float minRadius = 0.5f; 115 | float mR2 = minRadius * minRadius; 116 | 117 | if ((*Z).x > 1.0f) (*Z).x = 2.0f - (*Z).x; 118 | else if ((*Z).x < -1.0f) (*Z).x = -2.0f - (*Z).x; 119 | 120 | if ((*Z).y > 1.0f) (*Z).y = 2.0f - (*Z).y; 121 | else if ((*Z).y < -1.0f) (*Z).y = -2.0f - (*Z).y; 122 | 123 | if ((*Z).z > 1.0f) (*Z).z = 2.0f - (*Z).z; 124 | else if ((*Z).z < -1.0f) (*Z).z = -2.0f - (*Z).z; 125 | 126 | float r2 = (*Z).x*(*Z).x + (*Z).y*(*Z).y + (*Z).z*(*Z).z; 127 | 128 | if (r2 < mR2) 129 | { 130 | *Z = *Z * DIV(fR2, mR2); 131 | *de = *de * DIV(fR2, mR2); 132 | } 133 | else if (r2 < fR2) 134 | { 135 | *Z = *Z * DIV(fR2, r2); 136 | *de *= DIV(fR2, r2); 137 | } 138 | 139 | *de *= scale; 140 | 141 | if (julia.x == 0.0f) 142 | { 143 | *Z = *Z * scale + *P_in; 144 | } 145 | else 146 | { 147 | *Z = *Z * scale + julia.yzw; 148 | } 149 | 150 | *Z = mix(Z_orig, *Z, weight); 151 | *de = mix(de_orig, *de, weight); 152 | (*log_lin)--; 153 | } 154 | 155 | // [M2] - Classic Mandelbulb Power 2 fractal - MandelbulbPower2Iteration 156 | static void mandelbulbPower2Iter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia) 157 | { 158 | float3 Z_orig = *Z; 159 | float de_orig = *de; 160 | 161 | float distance = LENGTH(*Z); 162 | 163 | *de = *de * 2.0f * distance; 164 | float x2 = (*Z).x * (*Z).x; 165 | float y2 = (*Z).y * (*Z).y; 166 | float z2 = (*Z).z * (*Z).z; 167 | float temp = DIV(1.0f - z2, (x2 + y2)); 168 | float3 new; 169 | new.x = (x2 - y2) * temp; 170 | new.y = 2.0f * (*Z).x * (*Z).y * temp; 171 | new.z = -2.0f * (*Z).z * SQRT(x2 + y2); 172 | 173 | if (julia.x == 0.0f) 174 | { 175 | *Z = new + *P_in; 176 | } 177 | else 178 | { 179 | *Z = new + julia.yzw; 180 | } 181 | 182 | *Z = mix(Z_orig, *Z, weight); 183 | *de = mix(de_orig, *de, weight); 184 | (*log_lin)++; 185 | } 186 | 187 | // [M2] - Menger Sponge formula created by Knighty, modulus modification by mancoast - MengerSpongeIteration 188 | static void mengerSpongeIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const int modulus) 189 | { 190 | float3 Z_orig = *Z; 191 | float de_orig = *de; 192 | 193 | (*Z).x = fabs((*Z).x); 194 | (*Z).y = fabs((*Z).y); 195 | (*Z).z = fabs((*Z).z); 196 | 197 | if ((*Z).x - (*Z).y < 0.0f) (*Z).xy = (*Z).yx; 198 | if ((*Z).x - (*Z).z < 0.0f) (*Z).xz = (*Z).zx; 199 | if ((*Z).y - (*Z).z < 0.0f) (*Z).yz = (*Z).zy; 200 | 201 | *Z *= 3.0f; 202 | 203 | (*Z).x -= 2.0f; 204 | (*Z).y -= 2.0f; 205 | 206 | if (modulus == 0) 207 | { 208 | if ((*Z).z > 1.0f) (*Z).z -= 2.0f; 209 | } 210 | else 211 | { 212 | if (fmod((*Z).z, M_PI_F) > 2.0f) (*Z).z -= 2.0f; 213 | } 214 | 215 | *de *= 3.0f; 216 | 217 | if (julia.x == 1.0f) 218 | { 219 | *Z += julia.yzw; 220 | } 221 | 222 | *Z = mix(Z_orig, *Z, weight); 223 | *de = mix(de_orig, *de, weight); 224 | (*log_lin)--; 225 | } 226 | 227 | // [M2] - Bristorbrot formula - BristorbrotIteration 228 | static void bristorbrotIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia) 229 | { 230 | float3 Z_orig = *Z; 231 | float de_orig = *de; 232 | 233 | float distance = LENGTH(*Z); 234 | 235 | float3 new; 236 | new.x = (*Z).x * (*Z).x - (*Z).y * (*Z).y - (*Z).z * (*Z).z; 237 | new.y = (*Z).y * (2.0f * (*Z).x - (*Z).z); 238 | new.z = (*Z).z * (2.0f * (*Z).x + (*Z).y); 239 | 240 | *de = *de * 2.0f * distance; 241 | *Z = new; 242 | 243 | if (julia.x == 0.0f) 244 | { 245 | *Z += *P_in; 246 | } 247 | else 248 | { 249 | *Z += julia.yzw; 250 | } 251 | 252 | *Z = mix(Z_orig, *Z, weight); 253 | *de = mix(de_orig, *de, weight); 254 | (*log_lin)++; 255 | } 256 | 257 | // [M2] - Xenodreambuie - XenodreambuieIteration 258 | static void xenodreambuieIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const float power, float alpha, float beta) 259 | { 260 | float3 Z_orig = *Z; 261 | float de_orig = *de; 262 | 263 | float distance = LENGTH(*Z); 264 | 265 | alpha = radians(alpha); 266 | beta = radians(beta); 267 | 268 | float rp = POWR(distance, power - 1.0f); 269 | *de = rp * (*de) * power + 1.0f; 270 | rp *= distance; 271 | 272 | float th = atan2((*Z).y, (*Z).x) + beta; 273 | float ph = acos( DIV((*Z).z, distance)) + alpha; 274 | 275 | if (fabs(ph) > 0.5f * M_PI_F) ph = sign(ph) * M_PI_F - ph; 276 | 277 | (*Z).x = rp * COS(th * power) * SIN(ph * power); 278 | (*Z).y = rp * SIN(th * power) * SIN(ph * power); 279 | (*Z).z = rp * COS(ph * power); 280 | 281 | if (julia.x == 0.0f) 282 | { 283 | *Z += *P_in; 284 | } 285 | else 286 | { 287 | *Z += julia.yzw; 288 | } 289 | 290 | *Z = mix(Z_orig, *Z, weight); 291 | *de = mix(de_orig, *de, weight); 292 | (*log_lin)++; 293 | } 294 | 295 | // [M2] - Sierpinski3D. made from Darkbeam's Sierpinski code from M3D - Sierpinski3dIteration 296 | static void sierpinski3dIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const float scale, const float3 offset, const float3 rot) 297 | { 298 | float3 Z_orig = *Z; 299 | float de_orig = *de; 300 | 301 | float3 temp = *Z; 302 | 303 | if ((*Z).x - (*Z).y < 0.0f) (*Z).xy = (*Z).yx; 304 | if ((*Z).x - (*Z).z < 0.0f) (*Z).xz = (*Z).zx; 305 | if ((*Z).y - (*Z).z < 0.0f) (*Z).yz = (*Z).zy; 306 | if ((*Z).x + (*Z).y < 0.0f) 307 | { 308 | temp.x = -(*Z).y; 309 | (*Z).y = -(*Z).x; 310 | (*Z).x = temp.x; 311 | } 312 | if ((*Z).x + (*Z).z < 0.0f) 313 | { 314 | temp.x = -(*Z).z; 315 | (*Z).z = -(*Z).x; 316 | (*Z).x = temp.x; 317 | } 318 | if ((*Z).y + (*Z).z < 0.0f) 319 | { 320 | temp.y = -(*Z).z; 321 | (*Z).z = -(*Z).y; 322 | (*Z).y = temp.y; 323 | } 324 | 325 | *Z *= scale; 326 | *de *= scale; 327 | 328 | *Z -= offset; 329 | 330 | *Z = mtxPtMult( mtxRotate(rot) , *Z ); 331 | 332 | if (julia.x == 1.0f) 333 | { 334 | *Z += julia.yzw; 335 | } 336 | 337 | *Z = mix(Z_orig, *Z, weight); 338 | *de = mix(de_orig, *de, weight); 339 | (*log_lin)--; 340 | } 341 | 342 | // [M2] - Menger Smooth - mengerSmoothIteration 343 | static void mengerSmoothIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const float scale, const float offset_s, const float3 offset_c, const float3 rot) 344 | { 345 | float3 Z_orig = *Z; 346 | float de_orig = *de; 347 | 348 | float sc1 = scale - 1.0f; 349 | float sc2 = DIV(sc1, scale); 350 | 351 | *Z = (float3)(SQRT((*Z).x * (*Z).x + offset_s), SQRT((*Z).y * (*Z).y + offset_s), SQRT((*Z).z * (*Z).z + offset_s)); 352 | 353 | float t; 354 | 355 | t = (*Z).x - (*Z).y; 356 | t = 0.5f * (t - SQRT(t * t + offset_s)); 357 | (*Z).x = (*Z).x - t; 358 | (*Z).y = (*Z).y + t; 359 | 360 | t = (*Z).x - (*Z).z; 361 | t = 0.5f * (t - SQRT(t * t + offset_s)); 362 | (*Z).x = (*Z).x - t; 363 | (*Z).z = (*Z).z + t; 364 | 365 | t = (*Z).y - (*Z).z; 366 | t = 0.5f * (t - SQRT(t * t + offset_s)); 367 | (*Z).y = (*Z).y - t; 368 | (*Z).z = (*Z).z + t; 369 | 370 | (*Z).z = (*Z).z - offset_c.z * sc2; 371 | (*Z).z = -SQRT((*Z).z * (*Z).z + offset_s); 372 | (*Z).z = (*Z).z + offset_c.z * sc2; 373 | 374 | (*Z).x = scale * (*Z).x - offset_c.x * sc1; 375 | (*Z).y = scale * (*Z).y - offset_c.y * sc1; 376 | (*Z).z = scale * (*Z).z; 377 | 378 | *de *= scale; 379 | 380 | *Z = mtxPtMult( mtxRotate(rot) , *Z ); 381 | 382 | if (julia.x == 1.0f) 383 | { 384 | *Z += *P_in; 385 | *Z += julia.yzw; 386 | } 387 | 388 | *Z = mix(Z_orig, *Z, weight); 389 | *de = mix(de_orig, *de, weight); 390 | (*log_lin)--; 391 | } 392 | 393 | // [M2] - Amazing Surf from Mandelbulber3D, formula proposed by Kali, with features added by Darkbeam - AmazingSurfIteration 394 | static void amazingSurfIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const float fold_x, const float fold_y, const int force_cylindrical_fold, const float min_radius, float scale, const float scale_fold_influence, const float3 rot, const int multiply_c, const float3 c_multiplier) 395 | { 396 | float3 Z_orig = *Z; 397 | float de_orig = *de; 398 | 399 | float actual_scale = scale; 400 | 401 | (*Z).x = fabs((*Z).x + fold_x) - fabs((*Z).x - fold_x) - (*Z).x; 402 | (*Z).y = fabs((*Z).y + fold_y) - fabs((*Z).y - fold_y) - (*Z).y; 403 | 404 | float rr = dot(*Z, *Z); 405 | 406 | // get rid of if afterwards 407 | if (force_cylindrical_fold == 1) 408 | { 409 | rr -= (*Z).z * (*Z).z; 410 | } 411 | 412 | float SQRTMinR = SQRT(min_radius); 413 | float dividend = rr < SQRTMinR ? SQRTMinR : min(rr, 1.0f); 414 | 415 | float m = DIV(actual_scale, dividend); 416 | 417 | *Z *= (m - 1.0f) * scale_fold_influence + 1.0f; 418 | *de = *de * fabs(m) + 1.0f; 419 | 420 | if (multiply_c == 1) 421 | { 422 | *Z += (float3)((*P_in).y, (*P_in).x, (*P_in).z) * c_multiplier; 423 | } 424 | 425 | *Z = mtxPtMult( mtxRotate(rot) , *Z ); 426 | 427 | if (julia.x == 0.0f) 428 | { 429 | *Z += (float3)((*P_in).y, (*P_in).x, (*P_in).z); 430 | } 431 | else 432 | { 433 | *Z += julia.yzw; 434 | } 435 | 436 | *Z = mix(Z_orig, *Z, weight); 437 | *de = mix(de_orig, *de, weight); 438 | (*log_lin)--; 439 | } 440 | 441 | // [M2] - Benesi formula invented by Benesi - BenesiIteration 442 | static void benesiIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia) 443 | { 444 | float3 Z_orig = *Z; 445 | float de_orig = *de; 446 | 447 | float distance = LENGTH(*Z); 448 | 449 | *de = *de * 2.0f * distance; 450 | float r1 = (*Z).y * (*Z).y + (*Z).z * (*Z).z; 451 | float newx; 452 | if ((*P_in).x < 0.0f || (*Z).x < SQRT(r1)) 453 | { 454 | newx = (*Z).x * (*Z).x - r1; 455 | } 456 | else 457 | { 458 | newx = -(*Z).x * (*Z).x + r1; 459 | } 460 | r1 = DIV(-1.0f, SQRT(r1)) * 2.0f * fabs((*Z).x); 461 | float newy = r1 * ((*Z).y * (*Z).y - (*Z).z * (*Z).z); 462 | float newz = r1 * 2.0f * (*Z).y * (*Z).z; 463 | 464 | *Z = (float3)(newx, newy, newz); 465 | 466 | if (julia.x == 0.0f) 467 | { 468 | *Z += *P_in; 469 | } 470 | else 471 | { 472 | *Z += julia.yzw; 473 | } 474 | 475 | *Z = mix(Z_orig, *Z, weight); 476 | *de = mix(de_orig, *de, weight); 477 | (*log_lin)++; 478 | } 479 | 480 | // [M2] - Mandelbulb 2 fractal formula created by Buddhi - Mandelbulb2Iteration 481 | static void mandelbulb2Iter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia) 482 | { 483 | float3 Z_orig = *Z; 484 | float de_orig = *de; 485 | 486 | float distance = LENGTH(*Z); 487 | 488 | *de = *de * 2.0f * distance; 489 | 490 | float tempR = SQRT((*Z).x * (*Z).x + (*Z).y * (*Z).y); //+ 1e-061 491 | *Z *= DIV(1.0f, tempR); 492 | float temp = (*Z).x * (*Z).x - (*Z).y * (*Z).y; 493 | (*Z).y = 2.0f * (*Z).x * (*Z).y; 494 | (*Z).x = temp; 495 | *Z *= tempR; 496 | 497 | tempR = SQRT((*Z).y * (*Z).y + (*Z).z * (*Z).z); //+ 1e-061 498 | *Z *= DIV(1.0f, tempR); 499 | temp = (*Z).y * (*Z).y - (*Z).z * (*Z).z; 500 | (*Z).z = 2.0f * (*Z).y * (*Z).z; 501 | (*Z).y = temp; 502 | *Z *= tempR; 503 | 504 | tempR = SQRT((*Z).x * (*Z).x + (*Z).z * (*Z).z); //+ 1e-061 505 | *Z *= DIV(1.0f, tempR); 506 | temp = (*Z).x * (*Z).x - (*Z).z * (*Z).z; 507 | (*Z).z = 2.0f * (*Z).x * (*Z).z; 508 | (*Z).x = temp; 509 | *Z *= tempR; 510 | 511 | (*Z) *= distance; 512 | 513 | if (julia.x == 0.0f) 514 | { 515 | *Z += *P_in; 516 | } 517 | else 518 | { 519 | *Z += julia.yzw; 520 | } 521 | 522 | *Z = mix(Z_orig, *Z, weight); 523 | *de = mix(de_orig, *de, weight); 524 | (*log_lin)--; 525 | } 526 | 527 | // [M2] - Mandelbulb 3 fractal formula created by Buddhi - Mandelbulb3Iteration 528 | static void mandelbulb3Iter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia) 529 | { 530 | float3 Z_orig = *Z; 531 | float de_orig = *de; 532 | 533 | float distance = LENGTH(*Z); 534 | 535 | 536 | *de = *de * 2.0f * distance; 537 | 538 | float temp, tempR; 539 | 540 | float sign = 1.0f; 541 | float sign2 = 1.0f; 542 | 543 | if ((*Z).x < 0.0f) sign2 = -1.0f; 544 | tempR = SQRT((*Z).x * (*Z).x + (*Z).y * (*Z).y); //+ 1e-061 545 | *Z *= DIV(1.0f, tempR); 546 | temp = (*Z).x * (*Z).x - (*Z).y * (*Z).y; 547 | (*Z).y = 2.0f * (*Z).x * (*Z).y; 548 | (*Z).x = temp; 549 | *Z *= tempR; 550 | 551 | if ((*Z).x < 0.0f) sign = -1.0f; 552 | tempR = SQRT((*Z).x * (*Z).x + (*Z).z * (*Z).z); //+ 1e-061 553 | *Z *= DIV(1.0f, tempR); 554 | temp = (*Z).x * (*Z).x - (*Z).z * (*Z).z; 555 | (*Z).z = 2.0f * (*Z).x * (*Z).z * sign2; 556 | (*Z).x = temp * sign; 557 | *Z *= tempR; 558 | 559 | *Z *= distance; 560 | 561 | if (julia.x == 0.0f) 562 | { 563 | *Z += *P_in; 564 | } 565 | else 566 | { 567 | *Z += julia.yzw; 568 | } 569 | 570 | *Z = mix(Z_orig, *Z, weight); 571 | *de = mix(de_orig, *de, weight); 572 | (*log_lin)++; 573 | } 574 | 575 | // [M2] - Mandelbulb 4 fractal formula created by Buddhi - Mandelbulb4Iteration 576 | static void mandelbulb4Iter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const float power, const float3 angles) 577 | { 578 | float3 Z_orig = *Z; 579 | float de_orig = *de; 580 | 581 | float distance = LENGTH(*Z); 582 | 583 | float rp = POWR(distance, power - 1.0f); 584 | *de = rp * (*de) * power + 1.0f; 585 | 586 | float angZ = degrees(atan2((*Z).y, (*Z).x)) + angles.x; 587 | float angY = degrees(atan2((*Z).z, (*Z).x)) + angles.y; 588 | float angX = degrees(atan2((*Z).z, (*Z).y)) + angles.z; 589 | 590 | float16 rotM = mtxRotate( (float3)((angX * (power - 1.0f)), (angY * (power - 1.0f)), (angZ * (power - 1.0f))) ); 591 | 592 | *Z = mtxPtMult( rotM , *Z ) * rp; 593 | 594 | if (julia.x == 0.0f) 595 | { 596 | *Z += *P_in; 597 | } 598 | else 599 | { 600 | *Z += julia.yzw; 601 | } 602 | 603 | *Z = mix(Z_orig, *Z, weight); 604 | *de = mix(de_orig, *de, weight); 605 | (*log_lin)++; 606 | } 607 | 608 | // [M2] - Ides formula made by Trafassel, the original Ide's Formula thread - IdesIteration 609 | static void idesIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const float3 multiplier, const float2 sub_multiplier) 610 | { 611 | float3 Z_orig = *Z; 612 | float de_orig = *de; 613 | 614 | if (fabs((*Z).x) < 2.5f) (*Z).x = (*Z).x * 0.9f; 615 | if (fabs((*Z).z) < 2.5f) (*Z).z = (*Z).z * 0.9f; 616 | 617 | float3 z2 = (*Z) * (*Z); 618 | float3 newZ; 619 | newZ.x = multiplier.x * z2.x - sub_multiplier.x * (z2.y + z2.z); 620 | newZ.y = multiplier.y * (*Z).x * (*Z).y * (*Z).z; 621 | newZ.z = multiplier.z * z2.z - sub_multiplier.y * (z2.x + z2.y); 622 | *Z = newZ; 623 | 624 | if (julia.x == 0.0f) 625 | { 626 | *Z += *P_in; 627 | } 628 | else 629 | { 630 | *Z += julia.yzw; 631 | } 632 | 633 | *Z = mix(Z_orig, *Z, weight); 634 | } 635 | 636 | 637 | // [M2] - Ides 2 formula made by Trafassel, the original Ide's Formula thread - Ides2Iteration 638 | static void ides2Iter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const float3 multiplier, const float2 sub_multiplier) 639 | { 640 | float3 Z_orig = *Z; 641 | float de_orig = *de; 642 | 643 | float3 z2 = (*Z) * (*Z); 644 | float3 newZ; 645 | newZ.x = multiplier.x * z2.x - sub_multiplier.x * (z2.y + z2.z); 646 | newZ.y = multiplier.y * (*Z).x * (*Z).y * (*Z).z; 647 | newZ.z = multiplier.z * z2.z - sub_multiplier.y * (z2.x + z2.y); 648 | 649 | *Z = newZ + (*Z); 650 | 651 | if (julia.x == 0.0f) 652 | { 653 | *Z += *P_in; 654 | } 655 | else 656 | { 657 | *Z += julia.yzw; 658 | } 659 | 660 | *Z = mix(Z_orig, *Z, weight); 661 | } 662 | 663 | // [M2] - IQ Bulb from Mandelbulb 3D and Inigo Quilez - IqBulbIteration 664 | static void iqBulbIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const float power, const float zpower) 665 | { 666 | float3 Z_orig = *Z; 667 | float de_orig = *de; 668 | 669 | float distance = LENGTH(*Z); 670 | 671 | // extract polar coordinates 672 | float wr = distance; 673 | float wo = acos( DIV((*Z).y, wr)); 674 | float wi = atan2((*Z).x, (*Z).z); 675 | 676 | // scale and rotate the point 677 | wr = POWR(wr, power - 1.0f); 678 | *de = wr * *de * power + 1.0f; 679 | wr *= distance; 680 | wo *= power; 681 | wi *= zpower; 682 | 683 | // convert back to cartesian coordinates 684 | (*Z).x = SIN(wo) * SIN(wi); 685 | (*Z).y = COS(wo); 686 | (*Z).z = SIN(wo) * COS(wi); 687 | 688 | *Z *= wr; // then add Cpixel constant 689 | 690 | if (julia.x == 0.0f) 691 | { 692 | *Z += *P_in; 693 | } 694 | else 695 | { 696 | *Z += julia.yzw; 697 | } 698 | 699 | *Z = mix(Z_orig, *Z, weight); 700 | *de = mix(de_orig, *de, weight); 701 | (*log_lin)++; 702 | } 703 | 704 | // [M2] - Quaternion3DE fractal with extended controls - Quaternion3dIteration 705 | static void quaternion3dIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const float3 scale, const float3 offset, const float3 rot, const float de_influence) 706 | { 707 | float3 Z_orig = *Z; 708 | float de_orig = *de; 709 | 710 | float distance = LENGTH(*Z); 711 | 712 | *de = (*de) * 2.0f * distance; 713 | *Z = (float3)((*Z).x * (*Z).x - (*Z).y * (*Z).y - (*Z).z * (*Z).z, (*Z).x * (*Z).y, (*Z).x * (*Z).z); 714 | 715 | float tempL = LENGTH(*Z); 716 | *Z *= scale; 717 | float3 tempAvgScale = (float3)((*Z).x, DIV((*Z).y, 2.0f), DIV((*Z).z, 2.0f)); 718 | float avgScale = DIV(LENGTH(tempAvgScale), tempL); 719 | float tempAux = *de * avgScale; 720 | *de = *de + (tempAux - *de) * de_influence; 721 | 722 | *Z = mtxPtMult( mtxRotate(rot) , *Z ); 723 | 724 | *Z += offset; 725 | 726 | if (julia.x == 0.0f) 727 | { 728 | *Z += *P_in; 729 | } 730 | else 731 | { 732 | *Z += julia.yzw; 733 | } 734 | 735 | *Z = mix(Z_orig, *Z, weight); 736 | *de = mix(de_orig, *de, weight); 737 | (*log_lin)++; 738 | } 739 | 740 | // [M2] - JosLeys-Kleinian - JosKleinianIteration 741 | // will not work in this case, requires different DE computation 742 | static void josKleinianIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia, const float r, const float l, const float3 box_size) 743 | { 744 | float3 Z_orig = *Z; 745 | float de_orig = *de; 746 | 747 | float a = r; 748 | float b = l; 749 | float f = sign(b); 750 | 751 | float3 box1 = (float3)(2.0f * box_size.x, a * box_size.y, 2.0 * box_size.z); 752 | float3 box2 = (float3)(-box_size.x, -box_size.y + 1.0f, -box_size.z); 753 | float3 wrapped = wrap(*Z, box1, box2); 754 | 755 | *Z = (float3)(wrapped.x, wrapped.y, wrapped.z); 756 | 757 | if ((*Z).y >= a * (0.5f + 0.2f * SIN(f * M_PI_F * DIV(((*Z).x + b * 0.5f), box_size.x)))) 758 | *Z = (float3)(-b, a, 0.0f) - *Z; 759 | 760 | float z2 = dot(*Z, *Z); 761 | 762 | float iR = DIV(1.0f, z2); 763 | *Z *= -iR; 764 | (*Z).x = -b - (*Z).x; 765 | (*Z).y = a + (*Z).y; 766 | *de *= iR; 767 | 768 | if (julia.x == 0.0f) 769 | { 770 | *Z += *P_in; 771 | } 772 | else 773 | { 774 | *Z += julia.yzw; 775 | } 776 | 777 | *Z = mix(Z_orig, *Z, weight); 778 | *de = mix(de_orig, *de, weight); 779 | (*log_lin)++; 780 | } 781 | 782 | // [M2] - T>rotation - TransfRotationIteration 783 | static void rotationIter(float3* Z, const float3 rot) 784 | { 785 | *Z = mtxPtMult( mtxRotate(rot) , *Z ); 786 | } 787 | 788 | // [M2] - T>Box Fold - TransfBoxFoldIteration 789 | static void boxFoldIter(float3* Z, const int3 axis_enable, const float folding_limit, const float folding_value, const float z_scale) 790 | { 791 | if (axis_enable.x == 1) 792 | { 793 | if (fabs((*Z).x) > folding_limit) 794 | { 795 | (*Z).x = sign((*Z).x) * folding_value - (*Z).x; 796 | } 797 | } 798 | if (axis_enable.y == 1) 799 | { 800 | if (fabs((*Z).y) > folding_limit) 801 | { 802 | (*Z).y = sign((*Z).y) * folding_value - (*Z).y; 803 | } 804 | } 805 | if (axis_enable.z == 1) 806 | { 807 | float zLimit = folding_limit * z_scale; 808 | float zValue = folding_value * z_scale; 809 | if (fabs((*Z).z) > zLimit) 810 | { 811 | (*Z).z = sign((*Z).z) * zValue - (*Z).z; 812 | } 813 | } 814 | } 815 | 816 | // [M2] - Rotation Folding: rotatedAbs & Rotated Folding transform from M3D - TransfRotationFoldingIteration 817 | static void fabsFoldIter(float3* Z, const int3 axis_enable, const float3 offset) 818 | { 819 | if (axis_enable.x == 1) 820 | { 821 | (*Z).x = fabs((*Z).x + offset.x) - offset.x; 822 | } 823 | if (axis_enable.y == 1) 824 | { 825 | (*Z).y = fabs((*Z).y + offset.y) - offset.y; 826 | } 827 | if (axis_enable.z == 1) 828 | { 829 | (*Z).z = fabs((*Z).z + offset.z) - offset.z; 830 | } 831 | } 832 | 833 | 834 | // [M2] - Rotation Folding: rotatedAbs & Rotated Folding transform from M3D - TransfRotationFoldingIteration 835 | static void tgladFoldIter(float3* Z, const int3 axis_enable, const float3 offset) 836 | { 837 | if (axis_enable.x == 1) 838 | { 839 | (*Z).x = fabs((*Z).x + offset.x) - fabs((*Z).x - offset.x) - (*Z).x; 840 | } 841 | if (axis_enable.y == 1) 842 | { 843 | (*Z).y = fabs((*Z).y + offset.y) - fabs((*Z).y - offset.y) - (*Z).y; 844 | } 845 | if (axis_enable.z == 1) 846 | { 847 | (*Z).z = fabs((*Z).z + offset.z) - fabs((*Z).z - offset.z) - (*Z).z; 848 | } 849 | } 850 | 851 | // [M2] - T>Scale - TransfScaleIteration 852 | static void scaleIter(float3* Z, float* de, const float3 scale) 853 | { 854 | float distance_init = LENGTH(*Z); 855 | 856 | *Z = mtxPtMult( mtxScale(scale) , *Z ); 857 | 858 | float distance_scaled = LENGTH(*Z); 859 | *de *= DIV(distance_scaled, distance_init); 860 | } 861 | 862 | static void preScaleIter(float3* Z, const float3 scale) 863 | { 864 | *Z = mtxPtMult( mtxScale(scale) , *Z ); 865 | } 866 | 867 | static void translateIter(float3* Z, const float3 translate) 868 | { 869 | *Z += translate; 870 | } 871 | 872 | static void addCOffsetIter(float3* Z, const float3* P_in, const float3 offset) 873 | { 874 | *Z += *P_in + offset; 875 | } 876 | 877 | static void curlNoise(global const void* theXNoise, float3* Z, const float4 frequency, const float4 offset, const float3 amplitude) 878 | { 879 | *Z += curlxnoise4(theXNoise, (float4)(*Z, 1.0f) * frequency + offset) * amplitude; 880 | } 881 | 882 | 883 | // testing new formulas 884 | /* 885 | 886 | 887 | // [M2] - Hypercomplex 3D Mandelbrot formula invented by David Makin - HypercomplexIteration 888 | static void hypercomplexIter(float3* Z, float* de, const float3* P_in, int* log_lin, const float weight, const float4 julia) 889 | { 890 | float3 Z_orig = *Z; 891 | float de_orig = *de; 892 | 893 | float distance = length(*Z); 894 | float4 Z_complex = (float4)((*Z).x, (*Z).y, (*Z).z, 1.0f); 895 | float4* Z_ = &Z_complex; 896 | 897 | *de = *de * 2.0f * distance; 898 | float newx = (*Z_).x * (*Z_).x - (*Z_).y * (*Z_).y - (*Z_).z * (*Z_).z - (*Z_).w * (*Z_).w; 899 | float newy = 2.0f * (*Z_).x * (*Z_).y - 2.0f * (*Z_).w * (*Z_).z; 900 | float newz = 2.0f * (*Z_).x * (*Z_).z - 2.0f * (*Z_).y * (*Z_).w; 901 | float neww = 2.0f * (*Z_).x * (*Z_).w - 2.0f * (*Z_).y * (*Z_).z; 902 | //(*Z).x = newx; 903 | //(*Z).y = newy; 904 | //(*Z).z = newz; 905 | //(*Z).w = neww; 906 | 907 | (*Z).x = newx * newx - newy * newy - newz * newz - neww * neww; 908 | (*Z).y = newx * newy; 909 | (*Z).z = newx * newz; 910 | 911 | if (julia.x == 0.0f) 912 | { 913 | *Z += *P_in; 914 | } 915 | else 916 | { 917 | *Z += julia.yzw; 918 | } 919 | 920 | *Z = mix(Z_orig, *Z, weight); 921 | *de = mix(de_orig, *de, weight); 922 | (*log_lin)++; 923 | } 924 | 925 | 926 | 927 | // quaternion fractals, kind of works, but not sure what to do with z.w component :) 928 | static float quaternion(float3 P, float size) 929 | { 930 | //void QuaternionIteration(CVector4 &z, const sFractal *fractal, sExtendedAux &aux) 931 | //{ 932 | // Q_UNUSED(fractal); 933 | 934 | // aux.r_dz = aux.r_dz * 2.0 * aux.r; 935 | // double newx = z.x * z.x - z.y * z.y - z.z * z.z - z.w * z.w; 936 | // double newy = 2.0 * z.x * z.y; 937 | // double newz = 2.0 * z.x * z.z; 938 | // double neww = 2.0 * z.x * z.w; 939 | // z.x = newx; 940 | // z.y = newy; 941 | // z.z = newz; 942 | // z.w = neww; 943 | //} 944 | P /= size; 945 | 946 | float4 z = (float4)(P, 1); 947 | float dr = 1.0; 948 | float r = 0.0; 949 | int Iterations = 50; 950 | int Bailout = 40; 951 | 952 | for (int i = 0; i < Iterations ; i++) 953 | { 954 | r = length(z); 955 | if (r > Bailout) break; 956 | 957 | dr = dr * 2.0f * r; 958 | float newx = z.x * z.x - z.y * z.y - z.z * z.z - z.w * z.w; 959 | float newy = 2.0f * z.x * z.y; 960 | float newz = 2.0f * z.x * z.z; 961 | float neww = 2.0f * z.x * z.w; 962 | z.x = newx; 963 | z.y = newy; 964 | z.z = newz; 965 | //z.w = neww; 966 | } 967 | 968 | float out = 0.5f * log(r) * r/dr; 969 | return out * size; 970 | } 971 | 972 | // quaternion3d 973 | // kind of works, but does not exactly match M2 visual, but parameters deform it in a similar manner, I hardcoded some of the parameters into values, there are some buggy areas, missing parts, noisy normals etc. 974 | static float quaternion3d(float3 P, float size) 975 | { 976 | //void Quaternion3dIteration(CVector4 &z, const sFractal *fractal, sExtendedAux &aux) 977 | //{ 978 | // 979 | // aux.r_dz = aux.r_dz * 2.0 * aux.r; 980 | // z = CVector4(z.x * z.x - z.y * z.y - z.z * z.z, z.x * z.y, z.x * z.z, z.w); 981 | // 982 | // double tempL = z.Length(); 983 | // z *= fractal).transformCommon.constantMultiplier122; 984 | // // if (tempL < 1e-21) tempL = 1e-21; 985 | // CVector4 tempAvgScale = CVector4(z.x, z.y / 2.0, z.z / 2.0, z.w); 986 | // double avgScale = tempAvgScale.Length() / tempL; 987 | // double tempAux = aux.r_dz * avgScale; 988 | // aux.r_dz = aux.r_dz + (tempAux - aux.r_dz) * fractal).transformCommon.scaleA1; 989 | // 990 | // if (fractal).transformCommon.rotationEnabled) 991 | // z = fractal).transformCommon.rotationMatrix.RotateVector(z); 992 | // 993 | // z += fractal).transformCommon.additionConstant000; 994 | //} 995 | P /= size; 996 | 997 | float4 z = (float4)(P, 1); 998 | float dr = 1.0; 999 | float r = 0.0; 1000 | int Iterations = 250; 1001 | int Bailout = 20; 1002 | 1003 | for (int i = 0; i < Iterations ; i++) 1004 | { 1005 | r = length(z); 1006 | if (r > Bailout) break; 1007 | 1008 | dr = dr * 2.0 * r; 1009 | z = (float4)(z.x * z.x - z.y * z.y - z.z * z.z, z.x * z.y, z.x * z.z, z.w); 1010 | 1011 | float tempL = r; 1012 | z *= (float4)(1,1,1,1); 1013 | 1014 | float4 tempAvgScale = (float4)(z.x, z.y / 2.0, z.z / 2.0, z.w); 1015 | float avgScale = length(tempAvgScale) / tempL; 1016 | float tempAux = dr * avgScale; 1017 | dr = dr + (tempAux - dr) * 1.0f; 1018 | 1019 | //if (fractal).transformCommon.rotationEnabled) 1020 | // z = fractal).transformCommon.rotationMatrix.RotateVector(z); 1021 | 1022 | z += (float4)(0,0,0,0); 1023 | } 1024 | 1025 | //float out = 0.5f * log(r) * r/dr; 1026 | float out = r / dr; 1027 | return out * size; 1028 | } 1029 | 1030 | */ 1031 | #endif 1032 | --------------------------------------------------------------------------------