Is it possible to sample lightmap colors from a script? If so, what’s the standard technique?
Here’s the use case: I’m writing a script to copy lightmap colors to mesh vertices. I’m able to access all the relevant data, but when I try to sample the lightmap texture (via LightmapData.lightmapColor), I get this error:
“UnityException: Texture is not readable, the texture memory can not be accessed from scripts. You can make the texture readable in the Texture Import Settings.”
Problem is, there are no Texture Import Settings to set: I’m just looking at the texture generated by light baking.
Is there any way to programmatically duplicate and/or re-import the lightmap texture so I can set the isReadable flag? Or, is there some other way to do this?
@ Interesting… I guess if you can get the lightmap texture reference out of the material that the original object uses, and assign that texture as the primary albedo in an unlit material on a quad, then point a camera at the quad, then use a RenderTexture to strike it to a texture, then use getpixel on that texture to read the resulting pixel…
Yeah, I tried that, but the texture formats are different. The lightmap is a DXT5 format compressed file. Not sure how to convert that into a format you can blit into the RenderTexture.
Okay, I know that you know this, but I will make myself a little bit more precise for the visitors:
So, you have reference to the lightmap Texture2Ds through the LightmapData. These textures aren’t readable from C# code since they are uploaded to the graphics card.
RenderTexture in reality isn’t just a C# object, if we want to simplify, it is a command sent to the graphics card to render something. The Rendertexture then read back to the CPU so you can access it from C# code (this is the reason it is slow as hell).
Unfortunately, Texture2D and RenderTexture use a different set of formats. GraphicsFormat.RGBA_DXT5_SRGB isn’t necessarily the same as TextureFormat.DXT5 (which is what Texture2D uses). Also, there might be some native platform dependencies, there… not sure.
Trying to write a reliable tool, so I can’t just guess.
Seems like there should be a method to make a CPU-accessible copy of a texture. Hmm…
using UnityEditor;
class MyTexturePostprocessor : AssetPostprocessor
{
void OnPreprocessTexture()
{
if (assetPath.Contains("<Path_to_your_lightmaps>"))
{
TextureImporter textureImporter = (TextureImporter)assetImporter;
var tis = new TextureImporterSettings();
textureImporter.ReadTextureSettings(tis);
tis.readable = true;
textureImporter.SetTextureSettings(tis);
}
}
}
I have tried on a dummy project, it is setting the readable to true. Although I haven’t tried to actually read the textures, that’s up to you.
Also you can choose anything to identify your textures, you don’t have to use the path. I advise to do that since usually the reflection data goes into the same folder too and you don’t want everything to be readable, that significantly raise the memory consumption and slow down your application.
That might sorta work, but… lightmaps are very strange. If you are using iterative/auto-generated lightmaps, the textures are never written out as assets. So, you can’t import them. Ugh.
But, they do get written out as .exr’s if you’re in manual mode. That’ll sorta work. Thanks!
Hmph. Guess Unity really doesn’t want anyone messing with lightmaps!
Ninja! You brilliant lurking-around tied-scarf-wearin’ game controller eyeglass genius!!!
OP, I had to bake maps explicitly, didn’t try auto-baking, and I also did NOT try it from a build, which also might fail.
But in any case, used Ninja’s importer, added this script, and I am reading pixels from the lightmap:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Ninja : MonoBehaviour
{
public Texture2D tx;
void Start ()
{
for (int i = 0; i < 10; i++)
{
var x = Random.Range(0, tx.width);
var y = Random.Range(0, tx.height);
var c = tx.GetPixel(x, y);
Debug.LogFormat("{0},{1} -> {2}", x, y, c);
}
}
}
Well, I think they don’t store the lightmap as an asset because you’d hit race conditions with the live updates.
But a lightmap texture is a just a texture. Plenty of reasons to access it. I get how they’re trying to keep data structures transferable to the GPU; but you can’t even make a duplicate of that texture. Bit heavy-handed in my opinion. It’s frustrating when people design SDK’s for the lowest common denominator, or whatever it is they’re doing.
I don’t render to screen, I render using a custom camera, I use screen coordinate as in, the camera parameter in the shader, if you render to texture resolution it’s the same minus padding.
Argh, tried RGBA_DXT5_SRGB just for fun, and got:
“ArgumentException: RenderTextureDesc graphicsFormat must be a supported GraphicsFormat. RGBA_DXT5_SRGB is not supported.”