Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - haag.olaf

Pages: [1]
Hey Arran, have a look at this topic:,30398.0.html
But that requires that you install numpy into the python distribution of SD.

Hey there!
I just released my first Substance Designer Plugin. Sometimes I need a bit more control over the generation of MIP levels in DDS files. Since Substance Designer doesn't support exporting compressed DDS files with mipmap generation, I wrote a wrapper for binomial's crunch app.

It let's you set some advanced options.

You can get this release here:
Please note, that I haven't fully tested it, so take precautions when using it.

Unfortunately, first saving out the files and then compressing them makes the process a bit slow. I was thinking that maybe I could compile crunch as a DLL and use ctypes to compress the sdtexture binary data directly instead of intermediately writing to files. Any help on this would be highly appreciated.

I'm further planning to support customizing the mip levels, so that one could set up the outputs of the graph to be resolution dependend (see example folder in the repo), and outputs from different resolutions will be stitched together als MIP levels in the DDS file.

I know this is a niche topic, since many engines generate the mipmaps automatically. But I hope this may be useful for some who need greater control.

Since all the patents for the DXT compression expired in 2018, I wonder what's holding back the developers to support offline compression of DDS files in Substance Designer?

BTW: Does anyone know how to get the real output size of the graph when inheritance is set to be relative to parent? I mean the settings in the Parent Toolbar. I know how to get the size of the output nodes themselves, but I need that of the graph to do some optimization in the code.

Substance DesignerSubstance Designer - Scripting - Re: read buffer from memory
 on: October 20, 2019, 01:02:22 pm 
Having had a look at your output again, I think your results are actually correct. You only provided the wrong size to read from the buffer. There's a 1024² grayscale texture with 16 bits per channel (2 bytes per pixel) and you read only 1024 bytes, giving you the first 512 pixels of the first row of the node. I think you should read size of 2097152.

Substance DesignerSubstance Designer - Scripting - Re: read buffer from memory
 on: October 19, 2019, 11:34:39 pm 
Hey, were you successful with that in the meantime? I just started using the API and was looking for something similar.
The below code should work for 1 selected node. I left out all the safety checks for brevity.

I haven't tested the numpy part inside designer though, because I didn't install numpy into its python distribution, but I did check the conversions from the bytes to array in another python environment.

Basically I only used the ctypes.string_at function to read the buffer and converted using either uint8 or uint16, since the returned values can have different bits per channel (8/16).

Code: [Select]
from ctypes import string_at

import sd
from sd.api.sdproperty import SDPropertyCategory
from sd.api.sdvaluetexture import SDValueTexture

import numpy as np

def get_ui_manager():
    ctx = sd.getContext()
    app = ctx.getSDApplication()
    ui_manager = app.getUIMgr()
    return ui_manager

def get_sd_tex(node):
    prop = node.getProperties(SDPropertyCategory.Output)[0]  # Take the first output.
    value = node.getPropertyValue(prop)
    sd_texture = SDValueTexture.get(value)
    return sd_texture

def print_tex_info(sd_tex):
    dim_x, dim_y = sd_tex.getSize()
    print(f"Dimensions: {dim_x} x {dim_y}")
    print(f"Bytes per pixel: {sd_tex.getBytesPerPixel()}")
    address = sd_tex.getPixelBufferAddress()
    print(f"Buffer Address: {address}")
def get_tex_bytes(sd_tex):
    dim_x, dim_y = sd_tex.getSize()
    address = sd_tex.getPixelBufferAddress()
    tex_b = string_at(address, dim_x * dim_y * sd_tex.getBytesPerPixel())
    return tex_b

def get_dtype(bpp):
    if bpp in [1, 4]:
        return np.uint8
        return np.uint16

def get_shape(sd_tex):
    dim_x, dim_y = sd_tex.getSize()
    if sd_tex.getBytesPerPixel() == 1:
        return (dim_x, dim_y)
        return (dim_x, dim_y, 4)
def get_tex_array(sd_tex):
    tex_b = get_tex_bytes(sd_tex)
    dt = get_dtype(sd_tex.getBytesPerPixel())
    shape = get_shape(sd_tex)
    a = np.frombuffer(tex_b, dtype=dt).reshape(shape)  # row x column (x rgba)
    return a

if __name__ == '__main__':
    ui_mgr = get_ui_manager()
    node = ui_mgr.getCurrentGraphSelection()[0]  # Assume we have 1 node of interest selected.
    tex = get_sd_tex(node)
    img = get_tex_array(tex)

Pages: [1]