- 텍스쳐를 받을 수 있는 Cubemap생성하기 :
Create > Legacy > Cubemap
TEXTURECUBE(_CubeMap); SAMPLER(sampler_CubeMap);
half3 reflectVN = reflect(-V, N);
half4 cubeReflect = SAMPLE_TEXTURECUBE_LOD(_CubeMap, sampler_CubeMap, reflectVN, 0);
half3 refractVN = refract(-V, N, 1 / _RefractiveIndex);
half4 cubeRefract = SAMPLE_TEXTURECUBE_LOD(_CubeMap, sampler_CubeMap, refractVN, 0);
// | AMD CubeMapGen | Unity |
// | -------------- | ----- |
// | X+ | -X |
// | X- | +X |
// | Y+ | +Y |
// | Y- | -Y |
// | Z+ | +Z |
// | Z- | -Z |
using System.IO;
using UnityEditor;
using UnityEngine;
public class BakeStaticCubemap : ScriptableWizard
{
static string imageDirectory = "Assets/CubemapImages";
static string[] cubemapImage = new string[6] {
"top+Y", "bottom-Y",
"left-X", "right+X",
"front+Z","back-Z",
};
static Vector3[] eulerAngles = new Vector3[6] {
new Vector3(-90.0f, 0.0f, 0.0f), new Vector3(90.0f, 0.0f, 0.0f),
new Vector3(0.0f, 90.0f, 0.0f), new Vector3(0.0f, -90.0f, 0.0f),
new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 180.0f, 0.0f),
};
public Transform renderPosition;
public Cubemap cubemap;
// Camera settings.
public int cameraDepth = 24;
public LayerMask cameraLayerMask = -1;
public Color cameraBackgroundColor;
public float cameraNearPlane = 0.1f;
public float cameraFarPlane = 2500.0f;
public bool cameraUseOcclusion = true;
// Cubemap settings.
public FilterMode cubemapFilterMode = FilterMode.Trilinear;
// Quality settings.
public int antiAliasing = 4;
public bool IsCreateIndividualImages = false;
[MenuItem("GameObject/Bake Cubemap")]
static void RenderCubemap()
{
DisplayWizard("Bake CubeMap", typeof(BakeStaticCubemap), "Bake!");
}
void OnWizardUpdate()
{
helpString = "Set the position to render from and the cubemap to bake.";
if (renderPosition != null && cubemap != null)
{
isValid = true;
}
else
{
isValid = false;
}
}
void OnWizardCreate()
{
QualitySettings.antiAliasing = antiAliasing;
cubemap.filterMode = cubemapFilterMode;
GameObject go = new GameObject("CubemapCam", typeof(Camera));
go.transform.position = renderPosition.position;
go.transform.rotation = Quaternion.identity;
Camera camera = go.GetComponent<Camera>();
camera.depth = cameraDepth;
camera.backgroundColor = cameraBackgroundColor;
camera.cullingMask = cameraLayerMask;
camera.nearClipPlane = cameraNearPlane;
camera.farClipPlane = cameraFarPlane;
camera.useOcclusionCulling = cameraUseOcclusion;
camera.RenderToCubemap(cubemap);
if (IsCreateIndividualImages)
{
if (!Directory.Exists(imageDirectory))
{
Directory.CreateDirectory(imageDirectory);
}
RenderIndividualCubemapImages(camera);
}
DestroyImmediate(go);
}
void RenderIndividualCubemapImages(Camera camera)
{
camera.backgroundColor = Color.black;
camera.clearFlags = CameraClearFlags.Skybox;
camera.fieldOfView = 90;
camera.aspect = 1.0f;
camera.transform.rotation = Quaternion.identity;
for (int camOrientation = 0; camOrientation < eulerAngles.Length; camOrientation++)
{
string imageName = Path.Combine(imageDirectory, cubemap.name + "_" + cubemapImage[camOrientation] + ".png");
camera.transform.eulerAngles = eulerAngles[camOrientation];
RenderTexture renderTex = new RenderTexture(cubemap.height, cubemap.height, cameraDepth);
camera.targetTexture = renderTex;
camera.Render();
RenderTexture.active = renderTex;
Texture2D img = new Texture2D(cubemap.height, cubemap.height, TextureFormat.RGB24, false);
img.ReadPixels(new Rect(0, 0, cubemap.height, cubemap.height), 0, 0);
RenderTexture.active = null;
DestroyImmediate(renderTex);
byte[] imgBytes = img.EncodeToPNG();
File.WriteAllBytes(imageName, imgBytes);
AssetDatabase.ImportAsset(imageName, ImportAssetOptions.ForceUpdate);
}
AssetDatabase.Refresh();
}
}
- 좋은 큐브맵
- https://youtu.be/mnuKwAV-MBA?si=g-NaYv2cyln2jQes&t=239
- 밝고 어둠/ 중간명도 /반사광이 충분히 포함
- GI가 표현될 수 있는 밝음
- 태양 반대편에 빛을 받는 물체가 있어야 함
- 라이팅셋팅
- https://youtu.be/mnuKwAV-MBA?si=HZsut7AbGQ0C-OPE&t=576
- albedo 명도 벨런스 필수
- 색온도 조절이 편함
- 하지만, 노을질때든지 라이트가 너무 진하면
- directional light색온도 대신 postprocess 색온도 활용
- 대기
- https://youtu.be/mnuKwAV-MBA?si=JGrQpz3kCFf7M3i1&t=747
- atmospheric fog - 하늘,대기
- exponential