- Home /
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?
Answer by aldonaletto · Oct 09, 2013 at 12:59 AM
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.
There's also RenderToCubemap, but it also requires Pro - the advantage is that you can render a cubemap skybox in a single drawcall, while the conventional skybox takes six (I created a cubemap skybox shader and rendering script - let me know if you decide for this approach).
If you don't have Pro and the skybox is always the same, you may do the job by hand: adjust the main camera like above, run and take a snapshot of the screen; repeat this procedure for each face, then edit the images and assign them to a new skybox material.
Alright, thanks for the help! I'll be fine with creating the scripts myself if I ever get my hands on pro, I can't really take screenshots as it defeats the purpose of a procedural system. :P
It's only taxing on older graphics cards so unless I get pro I'll just have to reduce it's complexity for these lower end cards.
Thanks again!