1######################################################################## 2## 3## Copyright (C) 2016-2021 The Octave Project Developers 4## 5## See the file COPYRIGHT.md in the top-level directory of this 6## distribution or <https://octave.org/copyright/>. 7## 8## This file is part of Octave. 9## 10## Octave is free software: you can redistribute it and/or modify it 11## under the terms of the GNU General Public License as published by 12## the Free Software Foundation, either version 3 of the License, or 13## (at your option) any later version. 14## 15## Octave is distributed in the hope that it will be useful, but 16## WITHOUT ANY WARRANTY; without even the implied warranty of 17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18## GNU General Public License for more details. 19## 20## You should have received a copy of the GNU General Public License 21## along with Octave; see the file COPYING. If not, see 22## <https://www.gnu.org/licenses/>. 23## 24######################################################################## 25 26## -*- texinfo -*- 27## @deftypefn {} {} material shiny 28## @deftypefnx {} {} material dull 29## @deftypefnx {} {} material metal 30## @deftypefnx {} {} material default 31## @deftypefnx {} {} material ([@var{as}, @var{ds}, @var{ss}]) 32## @deftypefnx {} {} material ([@var{as}, @var{ds}, @var{ss}, @var{se}]) 33## @deftypefnx {} {} material ([@var{as}, @var{ds}, @var{ss}, @var{se}, @var{scr}]) 34## @deftypefnx {} {} material (@var{hlist}, @dots{}) 35## @deftypefnx {} {@var{mtypes} =} material () 36## @deftypefnx {} {@var{refl_props} =} material (@var{mtype_string}) 37## Set reflectance properties for the lighting of surfaces and patches. 38## 39## This function changes the ambient, diffuse, and specular strengths, as well 40## as the specular exponent and specular color reflectance, of all 41## @code{patch} and @code{surface} objects in the current axes. This can be 42## used to simulate, to some extent, the reflectance properties of certain 43## materials when used with @code{light}. 44## 45## When called with a string, the aforementioned properties are set 46## according to the values in the following table: 47## 48## @multitable @columnfractions .0 .2 .15 .15 .15 .15 .15 .0 49## @headitem @tab @var{mtype} @tab ambient- strength @tab diffuse- 50## strength @tab specular- strength @tab specular- exponent @tab specular- 51## color- reflectance @tab 52## @item @tab @qcode{"shiny"} @tab 0.3 @tab 0.6 @tab 0.9 @tab 20 @tab 1.0 @tab 53## @item @tab @qcode{"dull"} @tab 0.3 @tab 0.8 @tab 0.0 @tab 10 @tab 1.0 @tab 54## @item @tab @qcode{"metal"} @tab 0.3 @tab 0.3 @tab 1.0 @tab 25 @tab 0.5 @tab 55## @item @tab @qcode{"default"} @tab @qcode{"default"} @tab @qcode{"default"} @tab @qcode{"default"} @tab 56## @qcode{"default"} @tab @qcode{"default"} @tab 57## @end multitable 58## 59## When called with a vector of three elements, the ambient, diffuse, and 60## specular strengths of all @code{patch} and @code{surface} objects in the 61## current axes are updated. An optional fourth vector element updates the 62## specular exponent, and an optional fifth vector element updates the 63## specular color reflectance. 64## 65## A list of graphic handles can also be passed as the first argument. In 66## this case, the properties of these handles and all child @code{patch} and 67## @code{surface} objects will be updated. 68## 69## Additionally, @code{material} can be called with a single output argument. 70## If called without input arguments, a column cell vector @var{mtypes} with 71## the strings for all available materials is returned. If the one input 72## argument @var{mtype_string} is the name of a material, a 1x5 cell vector 73## @var{refl_props} with the reflectance properties of that material is 74## returned. In both cases, no graphic properties are changed. 75## 76## @seealso{light, fill, mesh, patch, pcolor, surf, surface} 77## @end deftypefn 78 79function retval = material (varargin) 80 81 if (! ((nargout == 0 && (nargin == 1 || nargin == 2)) 82 || (nargout == 1 && (nargin == 0 || nargin == 1)))) 83 print_usage (); 84 endif 85 86 ## resolve input 87 h = []; 88 if (nargout == 0) 89 ## Check whether first argument is list of graphics handles. 90 if (all (ishghandle (varargin{1}))) 91 h = varargin{1}; 92 varargin(1) = []; 93 endif 94 95 ## There must be one (additional) argument. 96 if (numel (varargin) != 1) 97 if (nargin == 2) 98 error (["material: When called with two arguments, the first argument " ... 99 "must be a list of handles to graphics objects."]); 100 else 101 print_usage (); 102 endif 103 endif 104 elseif (nargin == 0) 105 ## Return name of materials. 106 retval = {"shiny"; "dull"; "metal"; "default"}; 107 return; 108 endif 109 110 mtype = varargin{1}; 111 112 se = []; 113 scr = []; 114 115 ## check material type 116 if (ischar (mtype)) 117 switch (lower (mtype)) 118 case "shiny" 119 as = 0.3; 120 ds = 0.6; 121 ss = 0.9; 122 se = 20; 123 scr = 1.0; 124 125 case "dull" 126 as = 0.3; 127 ds = 0.8; 128 ss = 0.0; 129 se = 10; 130 scr = 1.0; 131 132 case "metal" 133 as = 0.3; 134 ds = 0.3; 135 ss = 1.0; 136 se = 25; 137 scr = .5; 138 139 case "default" 140 as = "default"; 141 ds = "default"; 142 ss = "default"; 143 se = "default"; 144 scr = "default"; 145 146 otherwise 147 error ("material: unknown material type '%s'", mtype); 148 149 endswitch 150 151 if (nargout == 1) 152 ## Return 1x5 cell vector with reflectance properties. 153 retval = {as, ds, ss, se, scr}; 154 return; 155 endif 156 157 elseif (nargout == 1) 158 ## If we reach here with one output argument, the input was wrong. 159 print_usage (); 160 161 elseif (isvector (mtype)) 162 num_mtype = numel (mtype); 163 if (num_mtype < 3 || num_mtype > 5) 164 error ("material: incorrect number of elements in material vector"); 165 endif 166 as = mtype(1); 167 ds = mtype(2); 168 ss = mtype(3); 169 if (num_mtype >= 4) 170 se = mtype(4); 171 if (num_mtype == 5) 172 scr = mtype(5); 173 endif 174 endif 175 176 else 177 error ("material: MTYPE must be a named material or a vector"); 178 endif 179 180 if (isempty (h)) 181 h = gca (); 182 endif 183 ## find all patch and surface objects in current axes 184 hps = findobj (h, "Type", "patch", "-or", "Type", "surface"); 185 186 ## set properties 187 set (hps, 188 "ambientstrength", as, "diffusestrength", ds, "specularstrength", ss); 189 190 if (! isempty (se)) 191 set (hps, "specularexponent", se); 192 if (! isempty (scr)) 193 set (hps, "specularcolorreflectance", scr); 194 endif 195 endif 196 197endfunction 198 199 200%!demo 201%! clf; 202%! ## patch 203%! [x,y,z] = meshgrid (-2:0.2:2, -2:0.2:2, -2:0.2:2); 204%! val = x.^2 + y.^2 + z.^2; 205%! fv1 = isosurface (x, y, z, val, 1); 206%! h_patch = patch (fv1, "FaceColor", "r", "EdgeColor", "none", ... 207%! "FaceLighting", "Gouraud"); 208%! isonormals (x, y, z, val, h_patch); 209%! axis equal; axis tight; 210%! view (3); 211%! box off; 212%! drawnow (); 213%! light (); 214%! material ([0 0.5 1 10 .5]); 215%! title ("material() with numeric input"); 216 217%!demo 218%! clf; 219%! ## surface 220%! hax = axes (); 221%! surf (hax, peaks, "LineStyle", "none", "FaceLighting", "Gouraud"); 222%! view (3); 223%! light (); 224%! material metal; 225%! title ("material metal"); 226 227%!test 228%! hf = figure ("Visible", "off"); 229%! unwind_protect 230%! hp = patch; 231%! hs = surface; 232%! material dull 233%! assert (get (hp, "ambientstrength"), 0.3); 234%! assert (get (hs, "ambientstrength"), 0.3); 235%! assert (get (hp, "diffusestrength"), 0.8); 236%! assert (get (hs, "diffusestrength"), 0.8); 237%! assert (get (hp, "specularstrength"), 0.0); 238%! assert (get (hs, "specularstrength"), 0.0); 239%! assert (get (hp, "specularexponent"), 10); 240%! assert (get (hs, "specularexponent"), 10); 241%! assert (get (hp, "specularcolorreflectance"), 1.0); 242%! assert (get (hs, "specularcolorreflectance"), 1.0); 243%! material default 244%! assert (get (hp, "ambientstrength"), get (0, "defaultpatchambientstrength")); 245%! assert (get (hs, "ambientstrength"), get (0, "defaultsurfaceambientstrength")); 246%! assert (get (hp, "diffusestrength"), get (0, "defaultpatchdiffusestrength")); 247%! assert (get (hs, "diffusestrength"), get (0, "defaultsurfacediffusestrength")); 248%! assert (get (hp, "specularstrength"), get (0, "defaultpatchspecularstrength")); 249%! assert (get (hs, "specularstrength"), get (0, "defaultsurfacespecularstrength")); 250%! assert (get (hp, "specularexponent"), get (0, "defaultpatchspecularexponent")); 251%! assert (get (hs, "specularexponent"), get (0, "defaultsurfacespecularexponent")); 252%! assert (get (hp, "specularcolorreflectance"), get (0, "defaultpatchspecularcolorreflectance")); 253%! assert (get (hs, "specularcolorreflectance"), get (0, "defaultsurfacespecularcolorreflectance")); 254%! material ([0.5 0.6 0.7 20 0.8]) 255%! assert (get (hp, "ambientstrength"), 0.5); 256%! assert (get (hs, "ambientstrength"), 0.5); 257%! assert (get (hp, "diffusestrength"), 0.6); 258%! assert (get (hs, "diffusestrength"), 0.6); 259%! assert (get (hp, "specularstrength"), 0.7); 260%! assert (get (hs, "specularstrength"), 0.7); 261%! assert (get (hp, "specularexponent"), 20); 262%! assert (get (hs, "specularexponent"), 20); 263%! assert (get (hp, "specularcolorreflectance"), 0.8); 264%! assert (get (hs, "specularcolorreflectance"), 0.8); 265%! material (hp, "shiny") 266%! assert (get (hp, "ambientstrength"), 0.3); 267%! assert (get (hs, "ambientstrength"), 0.5); 268%! assert (get (hp, "diffusestrength"), 0.6); 269%! assert (get (hs, "diffusestrength"), 0.6); 270%! assert (get (hp, "specularstrength"), 0.9); 271%! assert (get (hs, "specularstrength"), 0.7); 272%! assert (get (hp, "specularexponent"), 20); 273%! assert (get (hs, "specularexponent"), 20); 274%! assert (get (hp, "specularcolorreflectance"), 1.0); 275%! assert (get (hs, "specularcolorreflectance"), 0.8); 276%! material (hf, "metal") 277%! assert (get (hp, "ambientstrength"), 0.3); 278%! assert (get (hs, "ambientstrength"), 0.3); 279%! assert (get (hp, "diffusestrength"), 0.3); 280%! assert (get (hs, "diffusestrength"), 0.3); 281%! assert (get (hp, "specularstrength"), 1.0); 282%! assert (get (hs, "specularstrength"), 1.0); 283%! assert (get (hp, "specularexponent"), 25); 284%! assert (get (hs, "specularexponent"), 25); 285%! assert (get (hp, "specularcolorreflectance"), 0.5); 286%! assert (get (hs, "specularcolorreflectance"), 0.5); 287%! unwind_protect_cleanup 288%! close (hf); 289%! end_unwind_protect 290 291%!test 292%! mtypes = material (); 293%! assert (iscell (mtypes)); 294%! assert (size (mtypes, 2), 1); 295%! assert (all (cellfun (@ischar, mtypes))); 296 297%!test 298%! refl_props = material ("metal"); 299%! assert (refl_props, {0.3, 0.3, 1, 25, 0.5}) 300 301## Test input validation 302%!error <Invalid call to material> material () 303%!error <Invalid call to material> material (-1, 2, 3) 304%!error <Invalid call to material> a = material (-1) 305%!error <Invalid call to material> a = material (-1, 2) 306%!error <Invalid call to material> a = material ({}) 307%!error <Invalid call to material> a = material ([.3 .4 .5]) 308%!error <Invalid call to material> [a, b] = material () 309%!error <first argument must be a list of handles> material (-1, "metal") 310%!error <unknown material type 'foo'> material foo 311%!error <incorrect number of elements in material vector> material (-1) 312%!error <incorrect number of elements in material vector> material ([1 2 3 4 5 6]) 313%!error <MTYPE must be a named material or a vector> material ({}) 314 315%!error <Invalid call to material.> 316%! hf = figure ("visible", "off"); 317%! unwind_protect 318%! material (hf); 319%! unwind_protect_cleanup 320%! close (hf); 321%! end_unwind_protect 322