Texture Publishing to mental ray

Nailing down a good texture pipeline can be confusing!  Hopefully this clears up some of the whys and hows for efficiently handling texture of images with mental ray, providing a straightforward solution to a complicated problem.

[You can also find a test example on the ARC forum here: https://forum.nvidia-arc.com/showthread.php?13316-Maya-and-mental-ray-texture-caching ]

Texture Filtering

Non-filtered images may result in artifacts such as moire patterns (click to view full size).

When sampling a textured object, color information is lost between sampling points.  This is because a single sample only calls a single texture pixel (texel).  Information for texels that don’t get sampled is lost – which can be a real problem if that information was important.  For highly detailed textures or for textures with regular patterns this sampling limitation may manifest itself as an artifact such as a moiré pattern.

Aliasing-free texture sampling is restricted by a mathematical limitation known as the Nyquist rate which states that the number of samples required to adequately estimate a signal must be at least twice the noise frequency.  This means there are only two options to remove rendering artifacts caused by noisy textures: sample more or filter the texture.

Filtering a texture removes high frequency noise from images making them easier to sample.  While this does away with many potential aliasing artifacts, it also removes detail leaving your textures looking fuzzy.  This is not a problem for textures that occupy limited screen space because that is detail that would have been lost anyways.  However it is a problem for textures that occupy lots of screen space because that detail might have been visually important.  Luckily for us, texture mipmapping provides a convenient solution for both situations.

Mipmapping

Mipmapped images reduce texture artifacts by filtering (click to view full size).

Mipmapping (from the Latin phrase multum in parvo meaning “much in little”) is the process of pre-filtering one large image into many smaller images of progressively decreasing resolutions. The largest images retain detail that the smallest images lose to filtering.  These mipmap images are generally organized into a multi-resolution file sometimes known as a pyramid image.

Mipmapped “Pyramid Image”

The advantage of multi-resolution images is that they provide mental ray with the ability to read from appropriately sized pre-filtered images based on the amount of screen space that the textured object occupies.  This allows superior anti-aliasing performance while using less samples.

For the above renders, mental ray read from higher and higher mipmap levels as the checkered texture receded into the background.  The highest mipmap levels have lost virtually all detail and appear as a middle grey.  As a result of filtering, mipmapping reduced the total number of eye rays from 5552111 to 5144177!

It is advisable to use mipmapped textures.  Generally, mipmapped textures should be used with the filter declaration (see miFilter attribute below).  The purpose of the filter declaration is two fold:

  1. filter tells mental ray to mipmap images on demand if they are not already so.  When computed on demand, full upper pyramid layers are computed and kept in memory, totaling 1/3 of the base (largest resolution) image.
  2. You can control how selective mental ray is when choosing mipmap levels (and thus the blur of the textures) by setting filter size (see miFilterSize attribute below).  A filter size above 1.0 increases the texture blur by reading from a higher level (lower resolution) mipmap.  A filter size below 1.0 reduces texture blur by reading from a lower (higher resolution) mipmap.  Generally filter size should correspond to the number of times a texture repeats itself in UV space, i.e. an image that repeats itself 10 times should use a filter size value of 10.0.

Elliptical Lookup

Elliptical lookup has removed practically all texture artifacts (click to view full size).

Texels are square when viewed with photoshop or some other 2D application, but this is not always the case when rendering in a 3D environment.  When textures are rendered at glancing angles, the screen space each texel occupies become distorted – i.e. more texels may fit into a screen pixel in one direction than another.

To avoid artifacts caused by symmetric filtering for textures viewed non-symmetrically, some textures require an additional elliptical lookup on top of mipmapping.  Elliptical lookup works by projecting the circular area surrounding a sample onto the texture image, resulting in an ellipse.  The texels within the ellipse are then averaged resulting in a more accurate return value.

The above render shows the artifact-free result elliptical lookups provide.  Not only is the strange middle grey circle gone, but the number of eye rays has been further reduced to 4705444!

While elliptical lookup is relatively fast, not every textured object requires it.  To avoid unnecessary render time, elliptical lookup should be enabled on a per-texture basis.  The default lookup size of 8.0 is generally a good starting point for most situations.  Reducing this value will speed up render times, but may reintroduce artifacts.

Note: mental ray will mipmap on demand if elliptical filtering is specified for non-pyramidal images.

Tiled and Cached Textures

Keeping all texture information in memory can become quite expensive for large scene, especially when using pyramid images.  mental ray supports texture caching for certain tiled texture formats.  When texture caching, only certain tiles of a texture are loaded into memory.  These tiles are automatically removed or replaced by recently accessed ones, dramatically reducing the memory consumption during rendering.

Starting with mental ray 3.9, texture caching can be specified globally using the “{_MI_REG_TEXTURE_CACHE}” registry variable set to “on” / “off” / “local”.  The defualt “local” means that only local textures are cached (see miLocal attribute below).  Native .map files are always considered local.  It is important that local textures be saved locally or on a caching file server where images can be shared across multiple machines (on a render farm) to avoid network overhead.

Another registry variable, “{_MI_REG_TEXTURE_CACHE_SIZE}”, exists to set a maximum size for the texture cache in megabytes (e.g. “512” corresponds to 512MB).  mental ray will dynamically determine the cache size for the default value of “0”.

It is advisable to use tiled/cacheable textures to reduce memory consumption.

Image Formats and Conversion

  • OpenEXR (.exr)
    • Can be saved as mipmap pyramid
    • Can be tiled/cached
    • Personally recommended by me!
  • mental ray’s native memory-mapped image (.map)
    • Can be saved as mipmap pyramid
    • Can be tiled/cached
  • TIFF (.tif)
    • Can be saved as mipmap pyramid
    • Can be tiled/cached
    • note: Photoshop has been known to do some odd things to tifs (like layering)
  • Bitmap Image File (.bmp, .dib)
    • Can be tiled/cached
  • Maya IFF (.iff)
    • Can be tiled/cached

imf_copy (which ships with mental ray and Maya) is a convenient command-line tool that can be used to create mipmapped-tiled images. For example, I could run this command if I wanted to publish my working TIFF texture to an mipmapped-tiled zip-compressed OpenEXR texture:

imf_copy -p -r -k zip working_texture.tif published_texture.exr

Alternatively, exrmaketiled and/or the openimageIO toolkit can provide increased flexibility for publishing textures.

Setting up the Maya file node for mental ray

Maya file node set up for elliptical lookup

If using a pre-mipmapped image (which you should be):

  1. File Attributes > Filter Type → Mipmap (This enables the miFilter option)
  2. File Attributes > Pre Filter → off (we are using mipmapping with the option of elliptical lookup instead)
  3. mental ray > Override Global Auto-Conversion Settings → on (I don’t trust any global Maya auto settings)
  4. mental ray > Convert File To Optimized Format → off (texture has been already mipmapped!)
  5. mental ray > Advanced Elliptical Filtering → generally off, on if this texture is producing rendering artefacts
  6. Extra Attributes > Mi Local → preferably on for texture caching, otherwise off.
  7. Extra Attributes > Mi Filter Size → generally 1.0, higher for repeated textures.
Note: The last two are dynamic attributes so they might not be present on all file nodes.  See below on how to add them.

Python script to add texture attributes to all Maya file nodes in a scene:

import pymel.core as pm

# Add Extension Attributes to all file nodes.
pm.addExtension(nt="file", ln="miLocal", at="bool")
pm.addExtension(nt="file", ln="miFilterSize", at="float", dv=1.0)

# Delete Extension Attributes from all file nodes.
pm.deleteExtension(nt="file", at="miLocal", fd=True)
pm.deleteExtension(nt="file", at="miFilterSize", fd=True)

Last Notes

As a rule-of-thumb, I recommend using mipmapped-tiled OpenEXRs for all textures and to declare them local.  The one exception is the environment map which will only benefit from tiling, not mipmapping.  To pre-blur the environment, try using the mia_envblur shader combined with “Single Env Sample” on material shaders.

A formalized texture publishing step between texture creation and rendering provides an excellent opportunity to both optimize image formats and linearize data.  For more information on colorspaces and linear color workflow, see Linear Color Workflow(s) in Maya.

About bnrayner

I am a VFX developer specializing in 3d rendering. With a background in Physics and Digital Art, I enjoying using math to explain how light interacts with materials and to creating pretty pictures along the way.

Posted on April 17, 2012, in maya, Optimization, scripts and tagged , , , , . Bookmark the permalink. 66 Comments.

  1. Great article, as always. In maya 2012 and up, there is a simple way to add the dynamics attributes to all node types with the addExtension command:

    import pymel.core as pm
    pm.addExtension( nt= "file",longName="miFilterSize", attributeType="float",defaultValue=1.0)
    
    • Quite true! I updated the script to take advantage of extension attributes.

      • I found I had to run the “import pymel.core as pm” command before I could run the other commands. Maybe that’s how you intended it be run anyway.

        Piecing together information on other sites I have a batch process that I drop one or more non-mapped textures onto – giving me the tiled, mapped, zipped, EXR texture files. Copy the text into a text file and save as .bat file (you’ll notice I have a hard link to imf_copy.exe because it was just easier at the time):

        :convertfile
        @IF %1 == “” GOTO end
        “C:\Program Files\Autodesk\mentalrayForMaya2015\bin\imf_copy.exe” -p -r -k zip -v %1 “%~d1%~p1%~n1_mapped.exr”
        @SHIFT
        @GOTO convertfile
        :end
        @ECHO.
        @ECHO Done!
        @pause

        Great blog. I really appreciate the help.

  2. You sir, are a gentleman and a scholar. This has to be one of the most useful blogs I have ever found. A little hard to wrap my head around some of the technical stuff here, but extremely useful information nonetheless. Thank you.

  3. Hi there,

    Using “imf_copy -p -r -k zip” command for exr creation, I get two messages in the cmd saying: tiles and pyramid levels can only be created for .map files, “ignoring”. Does this matter? Is the memory mapped tiled exr still created correctly? Or is this where exrmaketiled should be used…

    Great blog by the way 🙂

    Thanks

    James

    • Great question. If you are using the imf_copy from Maya 2012 then I think you can ignore that warning. Exr support was integrated with that version. It does not warn with the Maya 2013 imf_copy.

      exrmaketiled and the openimageIO toolkit provide similar functionality for doing the same thing, so you could always just use those if you want.

      Brenton

    • I found that when simply typing imf_copy in the command line it opted to use my Maya 2011 version and gave those errors, but when I specifically called the 2012 version there was no error!

      • If you’re using Windows, sometimes the Path environment variable needs updated or reordered. Less often it’s a registry change.

      • Great thanks – I will investigate….

        James

      • It was the windows environment variable – looking for the Maya 2011 bin. I changed it to 2012, should have known really!

        Thanks again.

  4. Thanks for all this interesting posts. Thanks for sharing all what you know!

    About exr. Is it possible to use a compressed (ZIP, ZIPS, PIZ) tiled and mipmapped exr with mental ray? It will use it as it should (no conversion)?

    Where can I check mental ray use an exr file as it should?

    Thanks in advance and keep the good work! 🙂

    • mental ray 3.10 now outputs EXRs as non-tiled (scanline). You can use zip compression from Maya now. zips (single scanline) has been added but not made it to Maya yet.

      Generally speaking, mental ray will use file types that it can output. For memory/caching purposes, tiled is required. The above script in the post applies zip compression. I haven’t found a problem with this. It also displays in the Maya Viewport correctly (although it may be heavy and difficult to navigate the scene this way.)

      • Thanks. You was talking about imf_copy command line?

        On Maya station they said -r was not working with exr files…

        http://mayastation.typepad.com/maya-station/2009/07/imf_copy-and-exr-format.html

        And:

        imf_copy -p cylindre009.png cylindre009.exr
        imf_copy -r cylindre009.png cylindre009.exr
        imf_copy -p -r cylindre009.png cylindre009.exr

        This three lines doesn’t work with imf_copy from Maya2012 sp1.

        This line work:

        imf_copy -k zip cylindre009.png cylindre009.exr

        Maybe it’s just Maya2012 problem and the imf_copy of 2013 work well…

        Anyway, I always wonder how mental ray use exr I give to him. How can I check this myself… A kind of verbose mode for texture loading, just to be sure…

        For now, I don’t know how see how mr use exr, I can just suppose…

        Thanks anyway! 😉

      • The “-r” remap (tiled) flag is ignored/always on when used in conjunction with the “-p” pyramid flag.

        The command imf_copy -p -k zip working_texture.png published_texture.exr should be sufficient for most textures. For environment maps use imf_copy -r -k zip working_texture.png published_texture.exr.

        The exrheader tool allows you to check the mipmap, compression, and tile status of any OpenEXR image, I highly recommend using it.

        It is generally favorable to use zip compressed images for textures and zips compression for renderd images going into nuke.

      • Thanks for all of this! 🙂

  5. Two questions:

    1.) Is the above mipmap image correctly linearized, i.e. with gamma correction? The part furthest away looks a lot darker than the rest.

    2.) What is your recommendation for extremely large images (4 GB and up)? In the past, I had problems using imf_copy on such large images as it ran out of memory.

    Thanks!

    • 2) Even with imf_copy 64bits? 😦 What is your hardware memory?

    • 4GB is fairly huge. I have dealt with textures in the few hundred megabyte range for film (multiple textures at that size) but never 4GB. Was this for some sort of zoom from space? I would swap out the texture using a script instead.

      The texture above is gamma correct. However, remember that gamma doesn’t affect the black or white ends of the curve. So gamma correcting a checkerboard won’t really make much visual difference (Same with pure red, green, and blue. Only shades/tints are affected.)

    • Wow, I never thought about the colorspace implications of texture filtering. The most obvious two workflows are:

      A)
      Step 1: Generate texture image (typically sRGB)
      Step 2: Linearize (sRGB to Linear)
      Step 3: Filter image (i.e. mipmap)
      Step 4: Render

      For a black and white checker board the image will remain the same during linearization. That is, white remains (0.0, 0.0, 0.0) and black remains (1.0, 1.0, 1.0). These colors are then filtered to middle grey for the highest mipmap levels. Highest level result: (0.5, 0.5, 0.5)

      B)
      Step 1: Generate texture image (typically sRGB)
      Step 2: Filter image (i.e. mipmap)
      Step 3: Linearize (sRGB to Linear)
      Step 4: Render

      For a black and white checker board the image will be first filtered to middle grey (0.5, 0.5, 0.5) for the highest mipmap levels. This middle grey will then be linearized to (0.73, 0.73, 0.73). Highest level result: (0.73, 0.73, 0.73)

      I guess the real question is if you filter in linear (similar to a compositing operation) or if you filter in sRGB. There is an interesting paper “Color Space Considerations for Linear Image Filtering” by W. Burger describing this exact issue. Surprisingly his findings are neither.

      In any case, option A is the easiest workflow and the one I presented for this post.

      Hope this helps!

  6. Hello.. really like the post here.. I wanted to know is using imf copy script the same as going to settings/preferences/rendering and and clicking update optimized cache textures now and changing the conversion mode to all textures..

    also under the mental ray tab in the file node.. does checking the convert file to optimized format convert your textures .map on local basis instead of doing it from the preferences..
    and one more thing.. ( this is a question for and exr btw) also do you change the filter type to mipmap after clicking the convert file to optimized format .. also would you change it to mip map if you was to convert all textures from the preferences/rendering area..
    Sorry if it this question seems redundant.. seems like quick a few spots to do the same thing either globally or locally..

    and one more thing.. if you click mi local.. is that corresponding with the custom location folder in the prefs/rendering if i was to set one.. and i guess if i didnt set a custom folder.. it would cache the texture in a default folder..Really nice help on this post!

    • Using the “optimized” format in the Maya menus are all the same thing in different locations.

      We change it to mipmap to also allow the use of elliptical filtering; elliptical filtering requires mipmapped textures.

      miLocal specifies the path is local to the rendering machine and not networked.

  7. Following this process in Maya 2013 sp1 works great for me with exrs in terms of memory usage going down and also render time.

    But I don’t notice any difference when adjusting Mi Filter size? I added the attributes to the file nodes with attributes > add attributes

    Long name: miFilterSize
    Type: Float
    Default: 1.0

    I set the filter type to mipmap. Override gloabal conversion – but no noticeable change at any value. Anybody else notice any effect? Am i missing something here?

    On another note, useful imf_copy batch file link:

    http://forums.cgsociety.org/archive/index.php/t-480443.html

    Scroll down for drag and drop, automated batch conversion in windows, just change path and options!

    james

    • After a little more investigation. With “override Global auto conversion settings” off. Setting miFilterSize to 0 turns off texturing filtering? Sharper texture. But no other values have an effect?

      I could be wrong here, but that’s what I’m getting…

    • We think miFilterSize is broken in Maya, we’ve been trying to come up with a fix but there’s not one unless you use the mib texture nodes. Mental Core has his own where this works as well so it seems just the Maya File Node isn’t working correctly.

  8. Fair enough, thanks for the clarification

  9. here’s a script that will batch convert all your textures .map and more and allows u to add flags to them as well.. http://www.creativecrash.com/maya/downloads/scripts-plugins/utility-external/misc/c/batch-image-converter-imf_copy–2

  10. Hello.. for some reason im getting errors in my file..Error: line 0: The file ‘file17’ has no ‘miLocal’ attribute.
    so basically i gotta run the script again.. i plan on batch rendering the file.. any way to remedy the the error

    • Not sure, we have our own script here for those attributes above. We just make it a shelf button.

      • yea man.. not sure if im doing something wrong.. i copied the script in the script editor and it works.. but if i close my scene and re open.. the attributes are no longer present.. i wonder if their is a certain way i need to apply the script

  11. How do I use exrheader?

  12. I used your python script to add the extra attributes but mine look like this:

    http://imageshack.us/photo/my-images/837/fotografiadelloschermo0.jpg/

    is it right?

    • exrheader is a command line tool that is part of the OpenEXR distribution.
      usage: exrheader imagefile [imagefile ...]

      You definitly want miLocal checked, however miFilterSize might be overridden by the Maya file node’s internal lookup.

      • “You definitly want miLocal checked, however miFilterSize might be overridden by the Maya file node’s internal lookup.”
        Even with a .map file? .map files ares supposed to “be miLocal” in anyway no? Just to be sure. 🙂

      • Thanks! Anyway I still get problem… I mean… I published my texture from tiff to exr with imf_copy, but in Maya I still have to set them as RGB otherwise I will see them “very bright”.

        My linear worklow setup is correct: so I don’t understand why I have this problem..

      • I suppose your tiff is linear and imf_copy think it’s sRGB and set it to linear a second time while it is converting to exr.

        Maybe…

      • I just checked, my tiff is an RGB 8bit image…

  13. OpenEXR files I don’t have to concern myself with the conversion process. I can load my OpenEXR files and they are automatically mipmapped, that is what I’m ‘pulling’ from this article as the best suggestion.

    • They should also be “tiled” or cached. A utility like imf_copy or exrmaketiled will do that for you as well. This is where the added memory performance comes into play and can result in better render times for texture heavy scenes.

  14. thanx for a great article! speaking about exr – doesnt it make rendering more expensive to have all the textures in 16 bits? also, most painting apps are not even able to fully use the advantage of larger bit depth and most photographic sources are 8-bit too. so basically you end up with 8-bit content stored as 16-bit image (with exception of rendered textures and displacements). when dealing with texture heavy scenes, this might be a problem (or at least it would make the rendering workflow less straightforward) with no real advantage, right?

  15. yeap. i know. its not matter of render times. but input bit depth does matter in terms of memory. it runs out much more quickly when using 16 bits. very interested about this bsc we are currently establishing new workflow for texturing and exr seems to be one of options (using tiffs so far).

    • For example: a scene with 8.5 GBs in .tif textures fails to render on a machine with 8 GB of RAM. Geometry + Texture memory exceeds the machine’s capacity.

      When replaced with tiled/mipmapped EXRs, the scene renders quickly without failure or flushing. In fact it renders more quickly than the machine with more memory using the .tif files. So no, the higher bit depth doesn’t impact the render with this mechanism.

  16. Thanks for the info. I’m doing tests with a character (a lot of different maps like disp/bump/color/spec, no env maps) in 3.11 and they show that exr zip compression slows down rendering considerably. As soon as these exrs (p/r/k zip) become local, mem usage decreases, but render time increases – from 17min to 37min. If I use them uncompressed (p/r/k none) as local – I get the same result in 18min. If I use .map (p/r) I get the same mem usage improvements keeping render time in 17min. So, .map seems to be the fastest approach for me. Or maybe I’m missing something important?

    • What is your texture cache statistics at the end of the render?

    • Also, .map might always be considered local while .exr is not. Check the rest of the post about miLocal.

      • Sure, by “as soon as these exrs become local” I actually meant that I’m adding and enabling ‘miLocal’ attribute (along with miFilter/miFilterSize) and they get “opening local texture …” in log.

        I’m getting this from .map:
        IMG 0.2 3130 MB info : total for cached textures and framebuffers:
        IMG 0.2 3130 MB info : 936475550 pixel block accesses
        IMG 0.2 3130 MB info : 4889118 pages loaded/saved, 0.522076% image cache failures
        IMG 0.2 3130 MB info : maximal texture cache size: 4953 pages, 87.682 MBytes
        IMG 0.2 3130 MB info : uncompressed cached texture I/O: 77362.864 MB

        this from .exr (with miLocal on):
        IMG 0.2 3131 MB info : total for cached textures and framebuffers:
        IMG 0.2 3131 MB info : 1120429496 pixel block accesses
        IMG 0.2 3131 MB info : 1917548 pages loaded/saved, 0.171144% image cache failures
        IMG 0.2 3131 MB info : maximal texture cache size: 2872 pages, 448.688 MBytes
        IMG 0.2 3131 MB info : uncompressed cached texture I/O: 236212.188 MB

        and this one from .exr (with miLocal off):
        IMG 0.2 10234 MB info : total for cached textures and framebuffers:
        IMG 0.2 10234 MB info : 134209536 pixel block accesses
        IMG 0.2 10234 MB info : 46884 pages loaded/saved, 0.0349334% image cache failures
        IMG 0.2 10234 MB info : maximal texture cache size: 560 pages, 22.250 MBytes
        IMG 0.2 10234 MB info : uncompressed cached texture I/O: 632.594 MB

      • Render times of these three tests are as follows:

        .map: 17min
        .exr miLocal on: 37min
        .exr miLocal off: 16.5min

      • The local off thing lost me, do you have a caching setting in the rayrc file? The 16.5 minutes is expected. Notice the cache failures were lowest with fewer pages:

        IMG 0.2 10234 MB info : 46884 pages loaded/saved, 0.0349334% image cache failures

      • No special cache settings in rayrc. I have a pretty long lightmap+fg phase for misss (a lot of hair), but as well as I’ve noticed, textures and even displacement maps start to load after in the beginning of fg (strange, shouldn’t displacement affect lightmaps?) – so, I’m not sure where the time gets lost (still no duration for lightmap phase in mental ray).

      • Everything is loaded on demand for mental ray. (Part of why tiling helps) You may not hit anything initially when it starts to render. The layering library will skip the lightmap phase in 2015 and do that on the fly.

      • I tried mila_fastsss from 3.11.1.13 package before. Is there a way to store solution somehow for reusing? One of my methods is to bake misss lightmaps once and then reuse them for shading tweaks – saves a lot of time. Found no such option with mila though.

        What concerns sss and hair – that would be great to be able to skip hair completely from sss calculation – too much time for effect that could be faked.

      • MILA is multi threaded and during the render phase. It’s fast. Baking would complicate things and possibly slow you down. There’s a new basic hair shader in 2015 but MILA hair will look better.

  17. David, your last reply from April 1, 2014 you make it sound as though when using the MILA shaders you don’t need to create mip-mapped textures ?

    • I think David was saying that pre-baking light maps wasn’t necessary. Texture images still need some preprocessing for an efficient workflow.

  18. All textures including bump and displacement should be mip-mapped ?

    • It’s a good habit except mipmapping an environment may not make sense. Displacement actually happens before a render so mipmapping won’t help because it doesn’t really know how to choose the right mipmap level.

  19. #Sets Texture Caching for mapped files
    #registry “{_MI_REG_TEXTURE_CACHE}” value “on”

    #Sets Texture Cache size
    #registry “{_MI_REG_TEXTURE_CACHE_SIZE}” value “0”

    Is there a command I can check to verify that texture caching & texture cache size is working ? I want to know whether the command I put in the rayrc file listed above is correct ?

    • You’ll get a readout in the Output window about cache performance. The # means commented out. You should publish textures as tiled/mipmapped EXRs or let Maya do the auto-MAP conversion. The Cache value should be reasonable for your machine RAM. Or maybe greatly reduced (for a penalty) if you’re running out of memory.

  1. Pingback: Linear Color Workflow(s) in Maya – Part 2: The Preferred Method « elemental ray

  2. Pingback: “My render times are high? How do I fix that?” « elemental ray

  3. Pingback: Maya 2015 – mental ray changes | elemental ray

  4. Pingback: Maya 2016, new features and integration | elemental ray

  5. Pingback: rickeytone » Blog Archive » Tiled EXR

Leave a reply to Ark Cancel reply