How to get pixel color using raycast on object with Lightmap created by "Beast"?

I want to change my ship’s color depending from lightmap color (got using raycast under this ship) of object under this ship with mesh collider attached to it. Lightmap is created using “Beast” lightmapper. Simply I want to make lightmap shadows to affect my ship as if they were real time shadows. How do I do that?

Right now I’m trying to achieve that using code below but I can’t access object’s lightmap to get point color pointed with raycast:
(Note this is part of code so there might be something missing)

// Check Ground Color
				// Just in case, also make sure the collider also has a renderer material and texture. Also we should ignore primitive colliders.
				var rend : Renderer = hit.collider.renderer;
				var meshCollider = hit.collider as MeshCollider;
				if (rend == null || rend.sharedMaterial == null || rend.sharedMaterial.mainTexture == null || meshCollider == null || rend.LightmapSettings.lightmaps[rend.lightmapIndex] == null) {}
					// Get lightmap color, and apply to object 
					var tex : Texture2D = rend.LightmapSettings.lightmaps[rend.lightmapIndex];
					if (tex.format == TextureFormat.RGB24 || tex.format == TextureFormat.ARGB32) {
						var pixelUV = hit.textureCoord2;
						surfaceColor = tex.GetPixel(pixelUV.x * tex.width, pixelUV.y * tex.height);
							if (SceneLight){SceneLight.light.color = surfaceColor;}

Any ideas?

Ok, i finally had some time to create a simple test scene and baked some lightmaps. Here’s the result.

It’s quite large due to the lightmaps :wink: I change the builders color to the sampled lightmap color. The problem is that the lightmaps uses both, the rgb color and the alpha channel. At some spots it looks a bit strange, but basically it works :wink:

This is done in Unity free, so no pro features are used.

Here’s the important part of the script:

        var rend = hit.collider.renderer;
        if (rend == null || rend.lightmapIndex > 253)

        var lightMapInfo = LightmapSettings.lightmaps[rend.lightmapIndex];
        var tex = lightMapInfo.lightmapNear;
        var pixelUV = hit.lightmapCoord;
        var surfaceColor = tex.GetPixelBilinear(pixelUV.x, pixelUV.y);

Here are the major parts that you messed up or forgot:

  • First you have to make the lightmap textures readable. Just select the textures in the project view (you can select all at once) and change the texture type to “advanced”. Now you can tick the “isReadable” flag.
  • The lightmapped object has to use a MeshCollider. You only get uv information from the raycast when you use a MeshCollider which of course has to use the same Mesh as collider.
  • The lightmapIndex has to be checked against it’s special meaning. If no lightmap is available this number is either 255 or 254. In this case you can’t use it as index into the lightmaps array.
  • The LightmapSettings is a static class. You tried to use it like a member of Renderer. It holds all lightmaps for all renderers at this central point.
  • LightmapSettings.lightmaps is not an array of Texture2D. It holds LightmapData classes. Those have two textures, a near and a far texture.
  • textureCoord2 really holds the lightmap uvs, but those coordinates are scaled and offsetted by the renderers lightmapTilingOffset since each lightmap is actually atexture atlas. Unity has a special property which already does this calculation for you: lightmapCoord.
  • If you want to sample the color of an arbitary point on a texture you should use GetPixelBilinear instead of GetPixel. It takes uv coordinates instead of pixel coordinates. This even simplifies the usage. Furthermore it does a bilinear filtering which smoothes the returned color a bit.