[TUTORIAL] – Automatically Create Light Probes
Ok, so I ended up tweaking and bug fixing this script a bit more, but I feel it is ready to post. Please keep in mind this isn’t thoroughly tested so there might still be bugs in it.
How to use:
- First and foremost this script assumes that you have an empty gameobject in your scene named “_LightProbes”, and that it has a light probe group component attached to it. If you do not, then either make an empty game object called “_LightProbes” and attach a light probe component, or edit the script to point to your game object where your lightprobes are attached.
- Save this code in a file called “CreateLightProbes.cs”. Place this file in your projects Editor folder. If you do not have one, create a folder called “Editor”. A “Custom” menu tab will appear at the top of Unity once you place this script in the Editor folder.
- Select meshes that you would like light probes to appear on. In our setup we have flat ground planes, as this works the best. This will not work for caves or enclosed areas!
- Make sure that the meshes have a collider attached to them. Mesh colliders work the best!
- Set the spacing and secondary height values in the UI. The spacing is how far apart on the X and Z axis the probes will be. After it places a 2d grid of probes it will duplicate those and move them upwards to form a volume. The secondary spacing is how high up to move them.
- Select the objects you want to generate light probes for and click Create Light Probes on Selected Objects and you’re done! Rebuild the probe lighting from the Lightmapping tab to see the new probes.
Code:
// -------------------------------------------------- // Copyright (C) 2013 Ghost Mantis Games LLC // This software is provided "as is", withouth warranty of any kind. // This software is provided exclusively to you free of charge. // Ghost Mantis Games LLC does not make and hereby disclaims any warranties // of any kind. By using this software you agree to these terms. // -------------------------------------------------- using UnityEngine; using UnityEditor; using System.Collections.Generic; public class CreateLightProbes : EditorWindow { float Spacing = 2.0f; float SecondHeight = 4.0f; [MenuItem("Custom/Create Light Probes")] static void Init(){ // Get existing open window or if none, make a new one: CreateLightProbes window = (CreateLightProbes)EditorWindow.GetWindow(typeof(CreateLightProbes), true, "Create Light Probes"); window.position = new Rect((Screen.width / 2) - 125, Screen.height / 2 + 85, 300, 80); window.Show(); } void OnGUI(){ GUILayout.Label ("Creation:", EditorStyles.boldLabel); Spacing = EditorGUILayout.FloatField("Spacing:", Spacing); SecondHeight = EditorGUILayout.FloatField("Secondary Height:", SecondHeight); // Clamp values if(Spacing < 0.1f) Spacing = 0.1f; if(SecondHeight < 0.1f) SecondHeight = 0.1f; if(GUILayout.Button("Create Light Probes On Selected Objects")){ Bounds(); } } void Bounds(){ // Get selection GameObject[] Select = Selection.gameObjects; if(Select.Length < 1) return; // Get total bounds for selected objects float minX = 0.0f; float minY = 0.0f; float minZ = 0.0f; float maxX = 0.0f; float maxY = 0.0f; float maxZ = 0.0f; for(int i=0; i<Select.Length; i++){ // First check that mesh has a collider attached to it // if it doesn't then we can't raycast so we should ignore this object Collider col = Select[i].GetComponent(); if(col == null) continue; // Get renderer component attached to object // If there is no renderer attached then we ignore this object Renderer renderer = Select[i].GetComponent(); if(renderer == null) continue; // Get the renderer bounds Bounds bbox = renderer.bounds; // Update total bounds if(bbox.min.x < minX) minX = bbox.min.x; if(bbox.min.y < minY) minY = bbox.min.y; if(bbox.min.z < minZ) minZ = bbox.min.z; if(bbox.max.x > maxX) maxX = bbox.max.x; if(bbox.max.y > maxY) maxY = bbox.max.y; if(bbox.max.z > maxZ) maxZ = bbox.max.z; } // Now go through in a grid and attempt to place a light probe using raycasting float xCount = minX; float zCount = minZ; List VertPositions = new List(); for(int z=0; z<maxZ; z++){ for(int x=0; x<maxX; x++){ // Raycast downwards through each selected object and // attempt to find one that we are over for(int j=0; j<Select.Length; j++){ Collider col = Select[j].GetComponent(); RaycastHit hit; Ray ray = new Ray(); ray.origin = new Vector3(xCount, maxY, zCount); ray.direction = -Vector3.up; if(col.Raycast(ray, out hit, (maxY-minY)*2)){ VertPositions.Add(hit.point + new Vector3(0, 0.07f, 0)); VertPositions.Add(hit.point + new Vector3(0, SecondHeight, 0)); } } xCount += Spacing; } // Reset X Counter xCount = minX; zCount += Spacing; } // Check if we have any hits if(VertPositions.Count < 1) return; // Get _LightProbes game object GameObject LightProbeGameObj = GameObject.Find("_LightProbes"); if(LightProbeGameObj == null) return; // Get light probe group component LightProbeGroup LPGroup = LightProbeGameObj.GetComponent("LightProbeGroup") as LightProbeGroup; if(LPGroup == null) return; // Create lightprobe positions Vector3[] ProbePos = new Vector3[VertPositions.Count]; for(int i=0; i<VertPositions.Count; i++){ ProbePos[i] = VertPositions[i]; } // Set new light probes LPGroup.probePositions = ProbePos; Debug.Log("Finished Probe Calculations with: " + ProbePos.Length + "Probes."); } }
Excellent!
Hi when i insert your code into unity i receive this error.
Please get back to me on this as i have copied the code perfectly.
Assets/Editor/CreateLightProbes.cs(70,17): error CS0246: The type or namespace name `List’ could not be found. Are you missing a using directive or an assembly reference?
I get this error:
“Assets/Editor/CreateLightProbes.cs(78,17): error CS0246: The type or namespace name `List’ could not be found. Are you missing a using directive or an assembly reference?”
I am using Unity 4.3.4f1.
I have System.Collections.Generic in the script, but I still receive this error…
To the people having issues, it appears things have changed in the latest version of Unity. I will work on getting it converted and updated to the latest Unity release, and I will update the blog accordingly.
for those who have error on compilate it
// ————————————————–
// Copyright (C) 2013 Ghost Mantis Games LLC
// This software is provided “as is”, withouth warranty of any kind.
// This software is provided exclusively to you free of charge.
// Ghost Mantis Games LLC does not make and hereby disclaims any warranties
// of any kind. By using this software you agree to these terms.
//
// Fixed by xalsVR 08/2014
// ————————————————–
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
public class CreateLightProbes : EditorWindow {
float Spacing = 2.0f;
float SecondHeight = 4.0f;
[MenuItem("Custom/Create Light Probes")]
static void Init(){
// Get existing open window or if none, make a new one:
CreateLightProbes window = (CreateLightProbes)EditorWindow.GetWindow(typeof(CreateLightProbes), true, “Create Light Probes”);
window.position = new Rect((Screen.width / 2) – 125, Screen.height / 2 + 85, 300, 80);
window.Show();
}
void OnGUI(){
GUILayout.Label (“Creation:”, EditorStyles.boldLabel);
Spacing = EditorGUILayout.FloatField(“Spacing:”, Spacing);
SecondHeight = EditorGUILayout.FloatField(“Secondary Height:”, SecondHeight);
// Clamp values
if(Spacing < 0.1f) Spacing = 0.1f;
if(SecondHeight < 0.1f) SecondHeight = 0.1f;
if(GUILayout.Button("Create Light Probes On Selected Objects")){
Bounds();
}
}
void Bounds(){
// Get selection
GameObject[] Select = Selection.gameObjects;
if(Select.Length < 1) return;
// Get total bounds for selected objects
float minX = 0.0f;
float minY = 0.0f;
float minZ = 0.0f;
float maxX = 0.0f;
float maxY = 0.0f;
float maxZ = 0.0f;
for(int i=0; i<Select.Length; i++){
// First check that mesh has a collider attached to it
// if it doesn't then we can't raycast so we should ignore this object
Collider col = Select[i].GetComponent();
if(col == null) continue;
// Get renderer component attached to object
// If there is no renderer attached then we ignore this object
Renderer renderer = Select[i].GetComponent();
if(renderer == null) continue;
// Get the renderer bounds
Bounds bbox = renderer.bounds;
// Update total bounds
if(bbox.min.x < minX) minX = bbox.min.x;
if(bbox.min.y < minY) minY = bbox.min.y;
if(bbox.min.z maxX) maxX = bbox.max.x;
if(bbox.max.y > maxY) maxY = bbox.max.y;
if(bbox.max.z > maxZ) maxZ = bbox.max.z;
}
// Now go through in a grid and attempt to place a light probe using raycasting
float xCount = minX;
float zCount = minZ;
List VertPositions = new List();
for(int z=0; z<maxZ; z++){
for(int x=0; x<maxX; x++){
// Raycast downwards through each selected object and
// attempt to find one that we are over
for(int j=0; j<Select.Length; j++){
Collider col = Select[j].GetComponent();
RaycastHit hit;
Ray ray = new Ray();
ray.origin = new Vector3(xCount, maxY, zCount);
ray.direction = -Vector3.up;
if(col.Raycast(ray, out hit, (maxY-minY)*2)){
VertPositions.Add(hit.point + new Vector3(0, 0.07f, 0));
VertPositions.Add(hit.point + new Vector3(0, SecondHeight, 0));
}
}
xCount += Spacing;
}
// Reset X Counter
xCount = minX;
zCount += Spacing;
}
// Check if we have any hits
if(VertPositions.Count < 1) return;
// Get _LightProbes game object
GameObject LightProbeGameObj = GameObject.Find("_LightProbes");
if(LightProbeGameObj == null) return;
// Get light probe group component
LightProbeGroup LPGroup = LightProbeGameObj.GetComponent("LightProbeGroup") as LightProbeGroup;
if(LPGroup == null) return;
// Create lightprobe positions
Vector3[] ProbePos = new Vector3[VertPositions.Count];
for(int i=0; i<VertPositions.Count; i++){
ProbePos[i] = VertPositions[i];
}
// Set new light probes
LPGroup.probePositions = ProbePos;
Debug.Log("Finished Probe Calculations with: " + ProbePos.Length + "Probes.");
}
}
I fixed the script
// ————————————————–
// Copyright (C) 2013 Ghost Mantis Games LLC
// This software is provided “as is”, withouth warranty of any kind.
// This software is provided exclusively to you free of charge.
// Ghost Mantis Games LLC does not make and hereby disclaims any warranties
// of any kind. By using this software you agree to these terms.
//
// Fixed by xalsVR 08/2014
// ————————————————–
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
public class CreateLightProbes : EditorWindow {
float Spacing = 2.0f;
float SecondHeight = 4.0f;
[MenuItem("Custom/Create Light Probes")]
static void Init(){
// Get existing open window or if none, make a new one:
CreateLightProbes window = (CreateLightProbes)EditorWindow.GetWindow(typeof(CreateLightProbes), true, “Create Light Probes”);
window.position = new Rect((Screen.width / 2) – 125, Screen.height / 2 + 85, 300, 80);
window.Show();
}
void OnGUI(){
GUILayout.Label (“Creation:”, EditorStyles.boldLabel);
Spacing = EditorGUILayout.FloatField(“Spacing:”, Spacing);
SecondHeight = EditorGUILayout.FloatField(“Secondary Height:”, SecondHeight);
// Clamp values
if(Spacing < 0.1f) Spacing = 0.1f;
if(SecondHeight < 0.1f) SecondHeight = 0.1f;
if(GUILayout.Button("Create Light Probes On Selected Objects")){
Bounds();
}
}
void Bounds(){
// Get selection
GameObject[] Select = Selection.gameObjects;
if(Select.Length < 1) return;
// Get total bounds for selected objects
float minX = 0.0f;
float minY = 0.0f;
float minZ = 0.0f;
float maxX = 0.0f;
float maxY = 0.0f;
float maxZ = 0.0f;
for(int i=0; i<Select.Length; i++){
// First check that mesh has a collider attached to it
// if it doesn't then we can't raycast so we should ignore this object
Collider col = Select[i].GetComponent();
if(col == null) continue;
// Get renderer component attached to object
// If there is no renderer attached then we ignore this object
Renderer renderer = Select[i].GetComponent();
if(renderer == null) continue;
// Get the renderer bounds
Bounds bbox = renderer.bounds;
// Update total bounds
if(bbox.min.x < minX) minX = bbox.min.x;
if(bbox.min.y < minY) minY = bbox.min.y;
if(bbox.min.z maxX) maxX = bbox.max.x;
if(bbox.max.y > maxY) maxY = bbox.max.y;
if(bbox.max.z > maxZ) maxZ = bbox.max.z;
}
// Now go through in a grid and attempt to place a light probe using raycasting
float xCount = minX;
float zCount = minZ;
List VertPositions = new List();
for(int z=0; z<maxZ; z++){
for(int x=0; x<maxX; x++){
// Raycast downwards through each selected object and
// attempt to find one that we are over
for(int j=0; j<Select.Length; j++){
Collider col = Select[j].GetComponent();
RaycastHit hit;
Ray ray = new Ray();
ray.origin = new Vector3(xCount, maxY, zCount);
ray.direction = -Vector3.up;
if(col.Raycast(ray, out hit, (maxY-minY)*2)){
VertPositions.Add(hit.point + new Vector3(0, 0.07f, 0));
VertPositions.Add(hit.point + new Vector3(0, SecondHeight, 0));
}
}
xCount += Spacing;
}
// Reset X Counter
xCount = minX;
zCount += Spacing;
}
// Check if we have any hits
if(VertPositions.Count < 1) return;
// Get _LightProbes game object
GameObject LightProbeGameObj = GameObject.Find("_LightProbes");
if(LightProbeGameObj == null) return;
// Get light probe group component
LightProbeGroup LPGroup = LightProbeGameObj.GetComponent("LightProbeGroup") as LightProbeGroup;
if(LPGroup == null) return;
// Create lightprobe positions
Vector3[] ProbePos = new Vector3[VertPositions.Count];
for(int i=0; i<VertPositions.Count; i++){
ProbePos[i] = VertPositions[i];
}
// Set new light probes
LPGroup.probePositions = ProbePos;
Debug.Log("Finished Probe Calculations with: " + ProbePos.Length + "Probes.");
}
}
Yeah… not working.. Please try your scripts before posting it, I already see this “if(bbox.min.z maxX) maxX = bbox.max.x;” wich obviously makes no sense and i bet more are missing seeing how much monodevelop is angry at me when i paste this.