/********************************************************************************** Persistence of Vision Ray Tracer Scene Description File File name : CF_Sub-height_fields_test.pov Version : 3.7+ Description : Christian Froeschlin wrote: "I just played a bit with adding sub-height_fields on top of a main height_field and came up with this." December 2022: Thomas de Groot incorporated CF's code into two macros, one using purely math functions (SUB_HF1) and another one based on image_map functions (SUB_HF2). With a little more work both macros could probably be merged into a single one, but... ;-) Date : 21 December 2009 Author : Christian Froeschlin (original) https://news.povray.org/povray.binaries.images/thread/%3C4b2cf3ab%40news.povray.org%3E/?mtop=335120 Copyright (C) 2009-2022. All rights reserved. This file is licensed under the terms of the CC-LGPL. Use and/or modification of this scene is free, except for commercial purposes. Commercial distribution is not allowed without written permission from the author. **********************************************************************************/ // Render settings 3.7+ (right-click on a line below): // +w840 +h440 +a0.3 +am2 +bm2 +bs8 +wt7 // for stochastic render use: // +w840 +h440 +am3 +a0.03 +ac0.90 +r3 +bm2 +bs8 +wt7 //-------------------------------------------------------------------------- #version 3.8; //or 3.7 of course global_settings { assumed_gamma 1.0 } #include "colors.inc" #include "stones.inc" #include "functions.inc" //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- // Make your choices #declare Rad = on; //radiosity switch #declare Stochastic = on; //stochastic render switch in radiosity block #declare HFres = 1024; //resolution of the heightfield function #declare Sub = 1; //1=basic function; 2=image_map function #declare Basic = off; //basic test colors //-------------------------------------------------------------------------- #switch (Sub) #case (1) //========================================================================== //--------------------------------------------- macro using "pure" functions // *** SUB_HF1 *** Add detail to part of another height_field *** // // F_BASE: Function describing the main height field // F_SUB: Structure of the overlaid subfield. // F_MERGE: Function for merging the seams. This should be smooth // and evaluate to 0 on the border of the unit square. // SUB_SCALE: Strength of overlaid substructure for convenience // SUB_?_???: Rectangle specifying the portion of the main field. #macro SUB_HF1(F_BASE, F_SUB, F_MERGE, SUB_SCALE, SUB_X_MIN, SUB_X_MAX, SUB_Z_MIN, SUB_Z_MAX) #local sub_x_min = SUB_X_MIN; #local sub_x_max = SUB_X_MAX; #local sub_z_min = 1-SUB_Z_MIN; #local sub_z_max = 1-SUB_Z_MAX; #local sub_x_ext = sub_x_max - sub_x_min; #local sub_z_ext = sub_z_max - sub_z_min; height_field { function HFres, HFres { 0.5*f1(sub_x_min + x*sub_x_ext, sub_z_min+y*sub_z_ext) + 0.5*SUB_SCALE*F_MERGE(x,y) * F_SUB(x,y) } scale translate } #end //========================================================================== #break #case (2) //========================================================================== //------------------------------------------ macro using image_map functions // *** SUB_HF2 *** Add detail to part of another height_field *** // // F_BASE: Function describing the main height field // F_SUB: Structure of the overlaid subfield. // F_MERGE: Function for merging the seams. This should be smooth // and evaluate to 0 on the border of the unit square. // SUB_SCALE: Strength of overlaid substructure for convenience // SUB_?_???: Rectangle specifying the portion of the main field. #macro SUB_HF2(F_BASE, F_SUB, F_MERGE, SUB_SCALE, SUB_X_MIN, SUB_X_MAX, SUB_Z_MIN, SUB_Z_MAX) #local sub_x_min = SUB_X_MIN; #local sub_x_max = SUB_X_MAX; #local sub_z_min = 1-SUB_Z_MIN; #local sub_z_max = 1-SUB_Z_MAX; #local sub_x_ext = sub_x_max - sub_x_min; #local sub_z_ext = sub_z_max - sub_z_min; intersection { height_field { function HFres, HFres { 0.5*f_hf(sub_x_min + x*sub_x_ext, sub_z_min+y*sub_z_ext) + 0.5*SUB_SCALE*F_MERGE(x,y) * F_SUB(x,y) } } box { <-0.5, 0.0, -0.5>, <0.5, 1.0, 0.5> scale <0.9925, 1, 0.9925> translate <0.5, 0.0, 0.5> pigment {DarkGreen} } scale <1/0.9925, 1, 1/0.9925> scale translate } #end //========================================================================== // Height_field image_map prepared as a function for SUB_HF2() macro #macro HF_warp() warp {repeat x} warp {repeat y} scale 50 warp { turbulence 0.2 octaves 1 //[6] lambda 1 //[2] omega 0.2 //[0.5] } scale 1/50 #end //----------------------------- #declare f0 = function { pigment { image_map { png "WM_HighMountainValley_01b.png" gamma 1.0 map_type 0 interpolate 2 } HF_warp() } } #declare f_hf = function(x,z) {f0(x, z, y).hf}; #declare HF = intersection { height_field { function HFres, HFres {f_hf(x,y)} #if (Basic) pigment {gradient y pigment_map {[0.0 rgb z][0.5 rgb y][1.0 rgb x+y]}} #end } box { <-0.5, 0.0, -0.5>, <0.5, 1.0, 0.5> scale <0.9925, 1, 0.9925> pigment {DarkGreen} translate <0.5, 0.0, 0.5> } scale <1/0.9925, 1, 1/0.9925> } #end //of Sub switch //========================================================================== //Examples of sample usage //------------------------ //==(1) The main height_field function #if (Sub = 1) #declare f1 = function(x,z) {f_bozo(x*10, 0, z*10) * f_spherical(1.1*(x-0.5), 0, 1.1*(z-0.5))}; #else #declare f1 = f_hf; #end //==(2) The sub-height_field functions #declare f2a = function(x,z) {f_agate(x*20, 0, z*10) * f_bozo(x*0.3, 0, z*0.4)}; #declare f2b = function(x,z) {f_granite(x*2.5, 0, z*5) * f_bozo(x*0.3, 0, z*0.4)}; //==(3) The functions used for merging the seams of the sub-heigth_fields #declare f_merge1 = function(x,z) {f_granite(2.8*(x-0.5), 0, 2.8*(z-0.5)) * f_spherical(2.1*(x-0.5), 0, 2.1*(z-0.5))}; #declare f_merge2 = function(x,z) {f_agate(2.8*(x-0.5), 0, 2.8*(z-0.5)) * f_boxed(2.1*(x-0.5), 0, 2.1*(z-0.5))}; //==(4) The generation of the heightfield and call of the sub-height_field macros union { #if (Sub = 1) height_field {function HFres, HFres {f1(x,y)} #if(Basic) pigment {gradient y pigment_map {[0.0 rgb z][1.0 rgb y]}} #end} object {SUB_HF1(f1, f2a, f_merge1, 0.2, 0.05, 0.6, 0.05, 0.95) #if(Basic) pigment {Yellow} #end} object {SUB_HF1(f1, f2b, f_merge2, 0.7, 0.4, 0.95, 0.05, 0.95) #if(Basic) pigment {Red} #end} #else object { HF } object {SUB_HF2(f1, f2a, f_merge1, 0.5, 0.02, 0.6, 0.05, 0.95) #if(Basic) pigment {Yellow} #end} object {SUB_HF2(f1, f2b, f_merge2, 0.7, 0.5, 0.95, 0.05, 0.50) #if(Basic) pigment {Red} #end} #end translate <-0.5, 0, -0.5> scale <5, 0.75, 5> texture { gradient y texture_map { [0.0 T_Stone43 normal {granite 0.1 scale 0.001} scale 0.25] [0.8 T_Stone44 normal {granite 0.1 scale 0.001} scale 0.25] } scale <1, 0.75, 1> } translate 0.001*y } //========================================================================== global_settings { #if (Rad) radiosity { pretrace_start 0.08 pretrace_end 0.01 #if (Stochastic) count 10 #else count 50, 1000 #end nearest_count 10, 5 error_bound 1 recursion_limit 2 low_error_factor 0.3 gray_threshold 0.0 minimum_reuse 0.015 maximum_reuse 0.1 brightness 1 adc_bailout 0.01/2 normal on media off always_sample off //max_sample 1.0 } #end } // camera ------------------------------------------------------------------ camera { perspective angle 75 location <0.0 , 2.0 ,-5.5> right x*image_width/image_height look_at <0.0 , 0.0 , 0.0> } // sun ---------------------------------------------------------------------- light_source{< 3000, 2000, -1500> White*1.5} // sky ---------------------------------------------------------------------- sphere {0, 10000 pigment {rgb 0.9} finish {diffuse 0 emission 0.1}} // ground ------------------------------------------------------------------- plane { <0, 1, 0>, 0 texture { pigment { checker color rgb <0.25, 0.25, 0.25>*4 color rgb <0.25, 0.25, 0.25>*3.5 } normal { granite 0.1 scale 0.0001} finish { diffuse 0.7 } translate <-0.5, 0, -0.5> } } // back wall ---------------------------------------------------------------- plane { <0, 1, 0>, 0 texture { pigment { checker color rgb <0.25, 0.25, 0.25>*3 color rgb <0.25, 0.25, 0.25>*2.5 } normal { granite 0.1 scale 0.0001} finish { diffuse 0.7 } translate <-0.5, 0, -0.5> } rotate -90*x translate <1, 0.5, 2.501> } //--------------------------------------------------------------------------- //original code by Christian (as reference) //--------------------------------------------------------------------------- /* I just played a bit with adding sub-height_fields on top of a main height_field and came up with this: // *** SUB_HF *** Add detail to part of another height_field // // F_BASE: Function describing the main height field // F_SUB: Structure of the overlaid subfield. // F_MERGE: Function for merging the seams. This should be smooth // and evaluate to 0 on the border of the unit square. // SUB_SCALE: Strength of overlaid substructure for convenience // SUB_?_???: Rectangle specifying the portion of the main field. #macro SUB_HF(F_BASE,F_SUB,F_MERGE,SUB_SCALE, SUB_X_MIN,SUB_X_MAX,SUB_Z_MIN,SUB_Z_MAX) #local sub_x_min = SUB_X_MIN; #local sub_x_max = SUB_X_MAX; #local sub_z_min = 1-SUB_Z_MIN; #local sub_z_max = 1-SUB_Z_MAX; #local sub_x_ext = sub_x_max - sub_x_min; #local sub_z_ext = sub_z_max - sub_z_min; height_field { function 512, 512 { 0.5*f1(sub_x_min + x*sub_x_ext,sub_z_min+y*sub_z_ext) + 0.5*SUB_SCALE*f_merge(x,y) * f2(x,y) } scale translate } #end Sample usage: #declare f1 = function(x,z) {f_bozo(x*10,0,z*10)}; #declare f2 = function(x,z) {f_bozo(x*50,0,z*50)}; #declare f_merge = function(x,z){f_spherical(2*(x-0.5),0,2*(z-0.5))}; union { height_field {function 512, 512 {f1(x,y)}} object {SUB_HF(f1,f2,f_merge,0.3,0.6,0.7,0.1,0.3) pigment {color Red}} object {SUB_HF(f1,f2,f_merge,0.2,0.2,0.3,0.6,0.8) pigment {color Red}} scale 0.5 * y pigment {color White} } */