V-Ray SDK BitmapInterface getting color crashes V-ray & Maya

Hey Guys,

Somehow I’m unable to use the SDK forum so I’m quickly putting it here in public. :wink: Probably picked up the wrong account or something.
Anyway…

I’m trying to create my own shader that samples an image at a specified UV point and figured I needed to use the bitmap interface.
But it keeps on crashing on me and I don’t really understand why. I took most of the source code from the bitmap example and the checker.

Here’s my code:

//**************************************************
// File: tex_AColor.cpp
// Description: this file is an implementation of a simple AColor texture for VRay
// Notes: used when exporting data - to do a conversion from AColor to Texture.
//        it can also work with textures as input and will leave them unchanged.
//        (file created from tex_invert.cpp)
//**************************************************

#include "vrayplugins.h"
#include "vrayinterface.h"
#include "vrayrenderer.h"
#include "vraytexutils.h"
#include <math.h>

#include "globalnewdelete.cpp"

using namespace VR;

// Parameters
struct SphereMapTex_Params: VRayParameterListDesc {
	SphereMapTex_Params(void) {
		// Add the parameters
		addParamPlugin("uvwgen", EXT_UVWGEN);
		//addParamTexture("texture");
		addParamTexture("bitmap", EXT_BITMAP);
	}
};

struct SphereMapTex: VRayTexture, RTTexInterface {
	SphereMapTex(VRayPluginDesc *pluginDesc):VRayTexture(pluginDesc) {
		// Set parameter caches
		paramList->setParamCache("uvwgen", &uvwgen_plugin);
		paramList->setParamCache("bitmap", &bitmap_plugin);
		//paramList->setParamCache("texture", &texture);
	}

	void renderBegin(VR::VRayRenderer *vray);
	void renderEnd(VR::VRayRenderer *vray);
	void frameBegin(VR::VRayRenderer *vray);
	void frameEnd(VR::VRayRenderer *vray);

	AColor getTexColor(const VRayContext &rc);
	void getTexColorBounds(AColor &cmin, AColor &cmax);
	Vector getColorBumpGradient(const VRayContext &rc);
private:
	// Cached parameters
	PluginBase* uvwgen_plugin;
	UVWGenInterface* uvwgen;
	//TextureInterface *texture;
	PluginBase* bitmap_plugin;
	BitmapInterface *bitmap;
	BitmapInterface2 *bitmap2;

	// The color cache
	ShadeCache<AColor, true, false> shadeCache;
public:
	// From RTTexInterface
	PluginBase* getPlugin(void) { return this; }
	int getDataSize(void) { return 0; }
	void getData(float *fdata) { }

	PluginInterface *newInterface( InterfaceID id ) {
		if (EXT_RTTEX==id) return static_cast<PluginInterface*>( (RTTexInterface*)this );
		return VRayTexture::newInterface(id);
	}

	virtual int getSource(const char *part,const char *outParam,const char *lang,VUtils::ShaderSource &shaderSrc, OCLData &mtlData)
	{
		return 0;
	}
};

#define SphereMapTex_PluginID PluginID(LARGE_CONST(20141228000))
SIMPLE_PLUGIN_LIBRARY(SphereMapTex_PluginID, EXT_TEXTURE, "SphereMapTex", "SphereMap texture for VRay", SphereMapTex, SphereMapTex_Params);

void SphereMapTex::renderBegin(VR::VRayRenderer *vray) {
	VRayTexture::renderBegin(vray);
	shadeCache.renderBegin(vray);
}

void SphereMapTex::renderEnd(VR::VRayRenderer *vray) {
	VRayTexture::renderEnd(vray);
	shadeCache.renderEnd(vray);
}

void SphereMapTex::frameBegin(VR::VRayRenderer *vray) {
	// Call the base class to update the parameter caches
	VRayTexture::frameBegin(vray);

	// Call frameBegin on the shade cache
	shadeCache.frameBegin(vray);

	// Get the uvw gen
	uvwgen=(UVWGenInterface*) GET_INTERFACE(uvwgen_plugin, EXT_UVWGEN);

	// Get bitmap data
	bitmap=(BitmapInterface*) GET_INTERFACE(bitmap_plugin, EXT_BITMAP);
	bitmap2=static_cast<BitmapInterface2*>(GET_INTERFACE(bitmap_plugin, EXT_BITMAP2));
	const VRaySequenceData &sdata=vray->getSequenceData();
	if (!bitmap && sdata.progress) sdata.progress->warning("[TexBitmap] No bitmap buffer specified.\n");
}

void SphereMapTex::frameEnd(VR::VRayRenderer *vray) {
	VRayTexture::frameEnd(vray);
	shadeCache.frameEnd(vray);
}

AColor SphereMapTex::getTexColor(const VRayContext &rc) {
	if (!bitmap) return AColor(0.5, 0.5, 0.5, 1.0);

	double u = 0.5;
	double v = 0.5;

	//return AColor(1.0, 0.0, 0.0, 1.0); // test with red (keeping this avoids the crash and render it red as expected)
	// !!!!!!!!!!!!!!!!!!!!!CRASH!!!!!!!!!!!!!!!!!!
	bitmap->getInterpolatedColor(Vector2(u, v), 1); // THIS LINE CRASHES MAYA & RENDERER

}

void SphereMapTex::getTexColorBounds(AColor &cmin, AColor &cmax) {
	//if (texture==NULL) cmin=cmax=AColor(0.5f, 0.5f, 0.5f, 1.0f); 
	//else texture->getTexColorBounds(cmin, cmax);
	if (!bitmap) return;
	bitmap->getColorBounds(cmin, cmax);
}

Vector SphereMapTex::getColorBumpGradient(const VRayContext &rc) {
	return Vector(0.0f, 0.0f, 0.0f);
	//if (texture==NULL) return Vector(0.0f, 0.0f, 0.0f);
	//return texture->getColorBumpGradient(rc);
}

Any help is greatly appreciated! :slight_smile:

Cheers,
Roy


bitmap->getInterpolatedColor(Vector2(u, v), 1); // THIS LINE CRASHES MAYA & RENDERER

You’re missing a return statement at the beginning of this line.
Increase the warning level of you compiler and you’ll see a warning about this same line.

This probably has nothing to do with the crash though…

Best regards,
Vlado

Can you post the call stack at the time of the crash?

Best regards,
Vlado

The missing return statement was indeed a copy/paste and clean-up thing that I removed. I definitely had it in there the whole time for the crashes (otherwise the compiler wouldn’t even compile) just pasted it over to the forum without it. Woops! :slight_smile:

I’ve written many plug-ins for different software applications (learned by myself) but never got any grip on how to handle the beast of an IDE like Visual Studio. :smile:
To get to the call stack at the time of the crash I need to compile in debug mode right? And then connect the debugger to the running app and make the crash happen?
Any tips for this?
I’ll have a go at this tomorrow and see if I can get some nice debugging output either way.

Thanks for the amazingly quick replies Vlado and t.petrov.

Cheers,
Roy

Though technically it’s not needed to compile in debug mode, it helps to make more sense of the code. When it crashes, in Visual Studio, go to Debug > Windows > Call stack, make sure you scroll to the top, and send me a screengrab to vlado@chaosgroup.com

Best regards,
Vlado

Hey Vlado,

Maya crashes with the line giving the error on Create Texture from Plugin when I create the node.
All I can see in the call stack for Maya is a single line saying:
> 0000000000000000()

So I’m probably doing something wrong with debugging this.

By the way could it be that the crash is related to not inheriting from a MappedTexture like the bitmap example?
Basically I don’t need the object’s UV but want to sample an image with my own algorithm at a calculated point U and V so I assumed I didn’t need the MappedTexture.
I so hope to nail this bug today, hehe. :wink: Any pointers are welcome.

Thanks.

-Roy

No, this should not matter. It would be best if we can reproduce this here. Is that the entire source code above? Can you also get me a simple Maya scene with this set up?

Best regards,
Vlado

Hey Vlado,

I e-mailed you the files. :slight_smile:
The code above should work (incl. crash) if you add the missing return statement as mentioned above.
I can’t really make a Maya scene with the set-up because it crashes even on creating the node with the getInterpolatedColor() line enabled.

-Roy

Which email did you use?

Best regards,
Vlado

I used vlado@chaosgroup.com, but it was blocking my mail with the .dll (compiled plug-in) both separately attached or in a .zip file.
So now I’ve just sent a new one with only the .cpp file. :wink: Hope this comes through.

- Roy

It crashes because you declared the parameter with addParamTexture(), but you are using it as a bitmap. You will either have to use addParamPlugin() instead, or else use a regular texture parameter.

I don’t know how you intend to use the plugin, but within the Maya UI, there is no way to handle pure bitmap buffer parameters, only textures. Might be something to keep in mind…

Best regards,
Vlado

Vlado, it’s crazy that I missed that the whole time when looking over the differences with the bitmap example!
Thank you so very much.

Basically to work around that texture issue not popping up in the Maya interface is by writing a Maya node equivalent with a corresponding shader description file, correct?

-Roy

It is actually showing the bitmap attribute, but during my first test it seemed it didn’t work to actually sample the file that I connected to it.
Probably that’s what you meant with it not working? Can I workaround this at all with the bitmap parameter? I think it should be because it’s also used for the bitmap example. (Or I misunderstood the concept of that example).

The reason I chose for a bitmap parameter is because I could sample that at an arbitrary UV point, which I was unable to do with a texture parameter.

This can actually be done, although it is not obvious how. I will rework your example a bit to show you.

Best regards,
Vlado

Thanks, looking forward to it! :smile:

I tried using the context and changing the sample point with setRay() or spawnNewContext from the context and setting the ray on that, but it never seemed to give the results of actually sampling the UV point specified.
So I wonder what the correct workaround is.

Here is the modified code. Here I removed the “uvwgen” parameter as I assume you don’t need it.


#include "vrayplugins.h"
#include "vrayinterface.h"
#include "vrayrenderer.h"
#include "vraytexutils.h"
#include <math.h>

#include "globalnewdelete.cpp"

using namespace VR;

// Parameters
struct SphereMapTex_Params: VRayParameterListDesc {
	SphereMapTex_Params(void) {
		// Add the parameters
		addParamTexture("texture");
	}
};

struct SphereMapTex: VRayTexture {
	SphereMapTex(VRayPluginDesc *pluginDesc):VRayTexture(pluginDesc) {
		// Set parameter caches
		paramList->setParamCache("texture", &texture);
	}

	void renderBegin(VR::VRayRenderer *vray);
	void renderEnd(VR::VRayRenderer *vray);
	void frameBegin(VR::VRayRenderer *vray);
	void frameEnd(VR::VRayRenderer *vray);

	AColor getTexColor(const VRayContext &rc);
	void getTexColorBounds(AColor &cmin, AColor &cmax);
	Vector getColorBumpGradient(const VRayContext &rc);
private:
	// Cached parameters
	TextureInterface *texture;

	// The color cache
	ShadeCache<AColor, true, false> shadeCache;
};

#define SphereMapTex_PluginID PluginID(LARGE_CONST(20141228000))
SIMPLE_PLUGIN_LIBRARY(SphereMapTex_PluginID, EXT_TEXTURE, "SphereMapTex", "SphereMap texture for VRay", SphereMapTex, SphereMapTex_Params);

void SphereMapTex::renderBegin(VR::VRayRenderer *vray) {
	VRayTexture::renderBegin(vray);
	shadeCache.renderBegin(vray);
}

void SphereMapTex::renderEnd(VR::VRayRenderer *vray) {
	VRayTexture::renderEnd(vray);
	shadeCache.renderEnd(vray);
}

void SphereMapTex::frameBegin(VR::VRayRenderer *vray) {
	// Call the base class to update the parameter caches
	VRayTexture::frameBegin(vray);

	// Call frameBegin on the shade cache
	shadeCache.frameBegin(vray);

	const VRaySequenceData &sdata=vray->getSequenceData();
	if (!texture && sdata.progress) sdata.progress->warning("[SphereMapTex] No texture specified.");
}

void SphereMapTex::frameEnd(VR::VRayRenderer *vray) {
	VRayTexture::frameEnd(vray);
	shadeCache.frameEnd(vray);
}

// A structure that replaces the normal shade data in the ray context so
// that we can evaluate textures at arbitrary UVs.
struct UVSurface: public MappedSurface, public VRayShadeData {
public:
    UVSurface(float u, float v, const VRayContext& rc):uvCoords(u,v) {
        oldShadeData=rc.rayresult.sd;
        rcc=const_cast<VRayContext*>( &rc );
        rcc->rayresult.sd=static_cast<VRayShadeData*>(this);
    }

    ~UVSurface() {
        rcc->rayresult.sd=oldShadeData;
    }

    PluginBase *getPlugin(void) {
        return static_cast<PluginBase*>(this);
    }

    PluginInterface *newInterface(InterfaceID id) {
        if (id==EXT_MAPPED_SURFACE) {
            return static_cast<MappedSurface*>(this);
        }
        return NULL;
    }

	// From MappedSurface
    virtual Transform getLocalUVWTransform(const VRayContext& rc, int channel) {
        Transform t;

        // Matrix that describes how a change in the shading point, in world coordinates,
        // is converted to a change in UV coordinates. This is used for texture filtering.
        // If you do not know how to compute this matrix analytically, you can set it
        // to zero, but this will remove any filtering from the sampled texture. For
        // bitmap textures, this will cause the most detailed mip-map level to be always
        // loaded. It is a good idea to spend some time and compute the correct matrix here.
        t.m.makeZero();

        // Replace the UVs with our own
        t.offs.set(uvCoords.x, uvCoords.y, 0.0f);
        return t;
    }

private:
    VRayContext* rcc;
    VRayShadeData* oldShadeData;

    Vector2 uvCoords;
};

AColor SphereMapTex::getTexColor(const VRayContext &rc) {
	if (!texture) return AColor(0.5, 0.5, 0.5, 1.0);

	// Compute some UVs
	float u=(float) rc.rayresult.wpoint.x*0.1f, v=(float) rc.rayresult.wpoint.y*0.1f;

	//return AColor(1.0, 0.0, 0.0, 1.0); // test with red (keeping this avoids the crash and render it red as expected)
	UVSurface uvSurface(u, v, rc);
	return texture->getTexColor(rc);

}

void SphereMapTex::getTexColorBounds(AColor &cmin, AColor &cmax) {
	if (texture==NULL) cmin=cmax=AColor(0.5f, 0.5f, 0.5f, 1.0f); 
	else texture->getTexColorBounds(cmin, cmax);
}

Vector SphereMapTex::getColorBumpGradient(const VRayContext &rc) {
	return Vector(0.0f, 0.0f, 0.0f);
	//if (texture==NULL) return Vector(0.0f, 0.0f, 0.0f);
	//return texture->getColorBumpGradient(rc);
}

Let me know if you have any questions.

Best regards,
Vlado

Thanks Vlado!

I’ll definitely start working with this. So what exactly is the need of the BitmapInterface and why doesn’t that work with Maya’s UI connected textures? :wink: At least it didn’t seem to work.
The workaround you provided here seems a bit odd. You’re overriding the sample point in the context to sample a different UV point.
Does that mean that if I would have multiple texture slots that I want to sample at a different UV I just need to change the context with the surface class after each other?

Also I saw this topic:
http://forums.chaosgroup.com/showthread.php?77370-Vray-texture-lookup-equivalent

Looking at this it seemed that he was able to connect the LUT texture somehow and have it render correctly.
Does that mean he connected it outside of Maya’s UI? :wink: Or what is exactly the reason we need this workaround with the texture parameters?

Thanks for all the information! :slight_smile: This really helps to understand more about the V-ray SDK!

Cheers,
Roy

It is an internal interface that V-Ray uses to represent bitmap buffers. Those may come from bitmap files on the disk, but we also have a bitmap buffer that can specify the raw pixel data directly. We have never meant for BitmapInterface plugins to be directly accessible to the user inside Maya.

The workaround you provided here seems a bit odd. You’re overriding the sample point in the context to sample a different UV point.Yes. What is odd about that?

Does that mean that if I would have multiple texture slots that I want to sample at a different UV I just need to change the context with the surface class after each other?Yes, just be careful to restore the original shade data pointer in the context on exit.

Also I saw this topic: http://forums.chaosgroup.com/showthread.php?77370-Vray-texture-lookup-equivalent Looking at this it seemed that he was able to connect the LUT texture somehow and have it render correctly. Does that mean he connected it outside of Maya’s UI? ;)Yes, the BitmapBuffer plugin is created internally by the V-Ray plugin so it does not appear directly in the Maya UI. Perhaps in Maya the user just put a string parameter to specify the file name.

Or what is exactly the reason we need this workaround with the texture parameters?Well, I don’t know what you really want to do, so I’m just giving you the simplest something that I know will work. It is of course possible to use a BitmapBuffer plugin, but you will most likely have to create it yourself based on a user-supplied string, or something else.

Best regards,
Vlado

Thanks for the explanation, makes perfect sense.
Not sure how to calculate a matrix for the subsampling, but I don’t think I need that in this particular case.

Basically what I’m doing is sample a spherical map based on the surface normal.
So I ended up doing:


	Vector nrm = rc.rayresult.normal;
	float u = 1- (0.5 + (atan2(nrm.z, nrm.x) / (2*pi())));
	float v = 1 - (0.5 - (asin(nrm.y) / pi()));

With the current code it seems to be working nicely. :wink:
Now all that’s left is create a Maya node equivalent so I can handle it nicely in Maya, write a shader relation file and figure out how to nicely distribute this on the server. :wink:
We were unable to figure out how to do the above with built-in nodes in Maya/V-ray.

Cheers,
Roy