texture lookups and extensions for AX

81 views
Skip to first unread message

Chris Allen

unread,
Nov 8, 2022, 8:08:40 PM11/8/22
to OpenVDB Forum
Hello,
We're looking to embed AX as a scripting language in a new version of an OpenVDB-making tool.  Our old tool has access to texture lookup functions, but I don't see a texture lookup function in the AX language reference:


Are there any plans to add one?

Also, a related topic, I see at the bottom of the C++ docs for AX:


there's a section header, "Extending OpenVDB AX", but the section is empty.  Are there plans for a plugin architecture for AX?  Maybe we could extend AX internally with our own texture lookup function if we need it?

Thanks...

Chris Allen

Nick Avramoussis

unread,
Nov 17, 2022, 8:55:11 AM11/17/22
to OpenVDB Forum

Hey Chris,

Sorry about those docs, they still need to be updated (it's a high priority).

You can extend AX with your own functions via the API as long as you don't mind brining in LLVM headers. You can build any function you want using the `ax::codegen::FunctionBuilder` and register it on a compiler using the `ax::codegen::FunctionRegistry` - this will allow you to call it from AX. Adding a texture lookup function makes total sense and is something we'd want to natively support as designing functions which do things like internal caching across threads isn't brilliant with the current API (and I assume your texture function will want to do something like this for, say, recently accessed arbitrary files).

Still, this is totally doable, here's an example (I have not compiled/tested this):

```c++
/// Some singleton class which handles reading and resolving textures from filenames.
/// Methods will all need to be thread safe if thread local storage isn't used
/// and recent IO should be cached, etc, etc.
struct TextureInterface
{  
    inline static auto& Get() { static TextureInterface I; return I; }

    // an actualy texture with an "eval" method on it that takes uv coords
    struct Texture2D;
    // get a texture
    const Texture2D* get(const char*);

private:
    TextureInterface() = default;
};


/// along with other standard header you need to import codegen stuff
#include <openvdb/ax/codegen/Functions.h>
#include <openvdb/ax/codegen/FunctionTypes.h>
#include <openvdb/ax/codegen/FunctionRegistry.h>


/// Function are registered with a callback that essentially only builds/compiles
/// the function if it's been used. Callbacks return FunctionGroups which represent
/// a function "myfunction" with all its possible signatures.
///
/// See PointFunctions.cc, VolumeFunctions.cc and StandatdFunctions.cc for a whole
//  lot more examples.
///
inline openvdb::ax::codegen::FunctionGroup::UniquePtr
texture_function_creator(const openvdb::ax::FunctionOptions& op)
{
    static auto tex = [](float u, float v,
        const openvdb::ax::codegen::String* texture)
    {
        // Could instead have one per thread, but this requires static
        // thread local i.e. tbb::enumerable_thread_specific. See
        // rand() implementation in StandardFunctions.cc.

        TextureInterface& interface = TextureInterface::Get(); // each thread shares the same instance
        Texture2D* tex = interface.get(texture->c_str());
        return tex ? tex->eval(u, v) : 0.0f; // tex might not exist
    }

    /// The FunctionBuilder uses the builder pattern to create a function object
    return openvdb::ax::codegen::FunctionBuilder("texture")
        .addSignature<float(float,float,openvdb::ax::codegen::String*)>
            ((float(*)(float,float,openvdb::ax::codegen::String*))(tex)) // add the function
        .setArgumentNames({"u", "v", "filename"})         // set its argument names (optional, only for used printing)
        .setDocumentation("Evaluate a 2D texture value.") // set docs (optional, only for used printing)
        .get();
}

/// When we create the compiler, we now set our own function registry:
auto compiler = openvdb::ax::Compiler::create();
auto functionRegistry = openvdb::ax::codegen::createDefaultRegistry();
functionRegistry->insert("texture", texture_function_creator);
compiler.setFunctionRegistry(std::move(functionRegistry));
   
/// do compile and execute.
```

You could then invoke this within AX, i.e:

```
float u = ...
float v = ...
float result = texture(u, v, "/path/to/a/texture.tex");
```

A native solution will probably end up with some custom framework for better internal caching. We also want to add plugin support in the future too.


Nick

Chris Allen

unread,
Nov 21, 2022, 4:20:00 PM11/21/22
to OpenVDB Forum
Hi Nick,
Thanks for the sample code for implementing a custom function.  That'll be very useful when I'm ready to implement a texture lookup!  (If I get to that before y'all do. :) )  And for other functions we'll probably want to put into our AX app.

Thanks!

Chris
Reply all
Reply to author
Forward
0 new messages