Jump to content

[SOLVED] Object::setMaterialTexture with Image instance


photo

Recommended Posts

We use next code:

object.setMaterialTexture("reflection", "source/aaa.dds", i);

to dynamically change reflection texture for object's surfaces. We regenerate this texture from time to time, and hold it in Image class instance. So we need do next:

image = new Image();

// fill image

image.save("source/aaa.dds");

object.setMaterialTexture("reflection", "source/aaa.dds", i);

 

It is not convenient because we need to save image and to load it again. How we can assign Image instance to texture directly?

 

We try to use next:

Material material = object.getMaterialInherit(i);

image = new Image();

// fill image

int idTexture = material.findTexture("reflection");
material.setImageTextureImage(idTexture, image);

to get inherit instance of material and set reflection texture only for it. But this technique change used material and reflection texture changed in all objects with this material assigned.

Link to comment

to get inherit instance of material and set reflection texture only for it. But this technique change used material and reflection texture changed in all objects with this material assigned.

I think you need to get inherited material for every instance of your mesh if you want only one instance to have changed texture.

In our case similar trick didn't disabled instancing so it should not be expensive for performance.

Link to comment

Material::setImageTextureName() and Material::setImageTextureImage() implement different behaviours. setImageTextureImage() only sets image on inherited material if there has been a previous call to setImageTextureName() (causing required textures[num].override=1). If not, then parent material texture image will be changed (affecting also all other object instances)

 

render/Material.cpp

void Material::setImageTextureName(int num,const char *name) {
if(textures.size() == 0) copy_parent_textures();
int parent_num = (parent) ? parent->findTexture(textures[num].name) : -1;
if(name && (parent_num == -1 || strcmp(parent->getImageTextureName(parent_num),name))) {
	textures[num].override = 1;
	textures[num].texture_name = name;
	textures[num].ptr = engine.renders->createTexture(textures[num].texture_name,textures[num].flags);
} else {
	textures[num].override = 0;
	textures[num].texture_name.clear();
	textures[num].ptr.clear();
}
clear_parent_textures();
}

int Material::setImageTextureImage(int num,const Image ℑ) {

       // REMARK: following tests only succeed in case of previous setImageTextureName() call
if(textures.size()) {
	if(textures[num].override && textures[num].ptr.get()) {
		Image temp = image;
		textures[num].ptr->setImage(temp);
		return 1;
	}
}

       // REMARK: in your case this code path will be taken causing a texture update for all objects 
if(parent) return parent->setImageTextureImage(num,image);
return 0;
}

 

This might be a feature or BUG. On first sight I would call it a bug as I would expect same behaviour for both input formats. On the other hand the situation might not be that easy, because setting unsaved images on a material might cause problems on automatic texture unload/reload by resource manager in case of texture memory overload: reload would not be possible because of missing file backup of in-memory-only image assignment.

 

@eugene:

 

Based on current implementation a workaround for your situation could be to to call getMaterialInherit() and setImageTexturName() once on object instance creation with some kind of dummy/default texture file to force texture inheritance and then for all following dynamic updates use setImageTextureImage() with direct image assignment without file storage requirement.

Link to comment

It works, but changes in inherited material nevertheless change texture for all instances :mellow:

 

I have two functions:

	Image image = new Image(); // image instance for texture

	// this function calls only for some objects when they change their place (room)
	void updateTexture(Object object)
	{
		log.message("updateTexture\n");

		float znear = 0.1f;
		float zfar = 100.0f;

		for (int i = 0; i < object.getNumSurfaces(); i++)
		{
			float radius = object.getBoundRadius(i);

			if (radius > znear)
				znear = radius;
		}

		for (int i = 0; i < object.getNumSurfaces(); i++)
		{
			//Material material = object.getMaterialInherit(i);
			Material material = object.getMaterial(i);

			int idTexture = material.findTexture("reflection");

			if (idTexture > -1)
			{
				vec3 position = object.getPosition();
				mat4 projection = frustum(-znear, znear, -znear, znear, znear, zfar);

				engine.render.renderImageCube(
					projection,
					position,
					image,		// Texture image.
					32,		// Texture dimentions (cube map edge size).
					NULL,		// Comma-separated list of material names used for postprocessing visual effects.
					false		// HDR rendering mode flag: 1 to grab with HDR, 0 - without.
					);

				material.setImageTextureImage(idTexture, image);
			}
		}
	}

	// this function calls for all objects when game is initializing - I create inherited material and set standard texture
	void createTexture(Object object)
	{
		log.message("createTexture\n");

		for (int i = 0; i < object.getNumSurfaces(); i++)
		{
			Material material = object.getMaterialInherit(i);
			//Material material = object.getMaterial(i);

			int idTexture = material.findTexture("reflection");

			if (idTexture > -1)
			{
				material.setImageTextureName(idTexture, "core/textures/mesh_reflection_cube.dds");
				//object.setMaterialTexture("reflection", "core/textures/mesh_reflection_cube.dds", i);
			}
		}
	}

Link to comment

Texture inheritance in setTextureImageName() only happens when new texture name is different to parent texture name.

 

if(name && (parent_num == -1 || strcmp(parent->getImageTextureName(parent_num),name)))
{
   // texture inheritance
}

 

If default parent texture name is also "core/textures/mesh_reflection_cube.dds" than no inheritance will happen. Check if this is the case. A quick solution might be to make a copy of mesh_reflection_cube.dds and save it e.g. as mesh_reflection_cube_dummy.dds and set this different texture name in your createTexture(Object object) function to force texture inheritance.

 

Also use object.getMaterialInherit() in your updateTexture() function.

Link to comment

No, this is no effect.

When I call updateTexture() it's some errors occurs:

19:12:23 Direct3D9 error: invalid call
19:12:23 D3D9Texture::create(): can't update RGBA8 32x32 cube texture

Link to comment

This error message indicates DirectX9 UpdateTexture failure. Blind guess, but maybe creating image mipmaps after image rendering can solve the problem.

 

engine.render.renderImageCube(..., image,...);

image.createMipmaps();

material.setImageTextureImage(idTexture, image);

 

If not post small stand-alone test case for problem reproduction.

Link to comment

When I set "default" reflection map for create inherited material, I set

material.setImageTextureName(idTexture, "core/textures/mesh_reflection_cube.dds");

- this is created only one inherited material for all objects, and I have no desired effect, because when I update one object's material - I update all objects, and I have Direct3D9 error. Then, I use next:

material.setImageTextureName(idTexture, "source/textures/environment/mesh_" + object.getName() + ".dds");

- I set non existing texture file - this has effect - for all objects created inherited material, and when I update texture for one object - remainder objects stay without changes. Direct3D9 error not appears.

 

So I need set unique (maybe non existent texture) for all unique object, and only when for it created inherited materials.

Link to comment

material.setImageTextureName(idTexture, "source/textures/environment/mesh_" + object.getName() + ".dds");

- I set non existing texture file - this has effect - for all objects created inherited material, and when I update texture for one object - remainder objects stay without changes. Direct3D9 error not appears.

 

So I need set unique (maybe non existent texture) for all unique object, and only when for it created inherited materials.

 

So this is the working solution for your problem, right ?

Link to comment
  • 1 year later...
×
×
  • Create New...