Single computing/rendering for complex Skybox shader.

I have a fairly complex procedural space skybox shader. It uses multiple passes with perlin noise algorithms to generate nebula. On lower end machines it’s quite taxing on the frame rate because of the amount of calculations.

Is there a way to run a shader once and then never again? The skybox doesn’t need to be dynamic, it needs to be computed once and then never again. Is this possible?

The skybox must be rendered every frame - it usually clears the screen before the new frame is rendered. What you could do is to start with your complex skybox shader, render its faces on RenderTextures only once (requires Pro), then assign them to the faces of a regular skybox material and assign it to RenderSettings.skybox - after that your skybox will be rendered at lower cost.

The code could be something like this, attached to an empty game object:

private var cam: Camera;
private var skyMat: Material;

function Start(){
  // create a regular skybox material:
  skyMat = new Material(Shader.Find("RenderFX/Skybox"));
  // create a temporary camera:
  cam = gameObject.AddComponent(Camera);
  cam.clearFlags = CameraClearFlags.Skybox; // clear with current skybox
  cam.cullingMask = 0; // draw nothing but the current skybox
  cam.fieldOfView = 90; // adjust view to exactly one face
  cam.aspect = 1;
  // render the faces and assign them to the new skybox material:
  RenderFace("_FrontTex", 0, 0);
  RenderFace("_BackTex", 0, 180);
  RenderFace("_LeftTex", 0, 90);
  RenderFace("_RightTex", 0, -90);
  RenderFace("_UpTex", -90, 0);
  RenderFace("_DownTex", 90, 0);
  // assign the new skybox material to RenderSettings.skybox:
  RenderSettings.skybox = skyMat;
  DestroyImmediate(cam); // camera not needed anymore
}

// rotate the camera according to angX, angY and render a face,
// then assign it to the texName texture in skyMat

function RenderFace(texName: String, angX, angY){
  cam.transform.eulerAngles = Vector3(angX, angY, 0); // look at the desired face
  var face: Texture2D = new Texture2D(512, 512); // create the face texture
  cam.targetTexture = face;
  cam.Render(); // take a snapshot of the face
  skyMat.SetTexture(texName, face); // assign it to the correct face in the shader
}

NOTE: The purpose of this code is just to show you the path. It wasn’t tested, and may fail miserably - but the basic idea will probably work with a few adjustments.