Skip to content

Commit

Permalink
Merge pull request #677 from crest-ocean/feature/view-camera-property
Browse files Browse the repository at this point in the history
Add camera property to ocean renderer
  • Loading branch information
daleeidd committed Nov 12, 2020
2 parents 83e2e6b + d14e800 commit 42da938
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 68 deletions.
49 changes: 49 additions & 0 deletions crest/Assets/Crest/Crest/Scripts/Helpers/Editor/EditorHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Crest Ocean System

// This file is subject to the MIT License as seen in the root of this folder structure (LICENSE)

#if UNITY_EDITOR

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace Crest
{
/// <summary>
/// Provides general helper functions for the editor.
/// </summary>
public static class EditorHelpers
{
static EditorWindow _lastGameOrSceneEditorWindow = null;

/// <summary>
/// Returns the scene view camera if the scene view is focused.
/// </summary>
public static Camera GetActiveSceneViewCamera()
{
Camera sceneCamera = null;

if (EditorWindow.focusedWindow != null && (EditorWindow.focusedWindow.titleContent.text == "Scene" ||
EditorWindow.focusedWindow.titleContent.text == "Game"))
{
_lastGameOrSceneEditorWindow = EditorWindow.focusedWindow;
}

// If scene view is focused, use its camera. This code is slightly ropey but seems to work ok enough.
if (_lastGameOrSceneEditorWindow != null && _lastGameOrSceneEditorWindow.titleContent.text == "Scene")
{
var sceneView = SceneView.lastActiveSceneView;
if (sceneView != null && !EditorApplication.isPlaying)
{
sceneCamera = sceneView.camera;
}
}

return sceneCamera;
}
}
}

#endif

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public class LodDataMgrShadow : LodDataMgr
public static bool s_processData = true;

Light _mainLight;
Camera _cameraMain;

// SRP version needs access to this externally, hence public get
public CommandBuffer BufCopyShadowMap { get; private set; }
Expand Down Expand Up @@ -90,9 +89,6 @@ public override void Start()
return;
}

// Setup the camera.
UpdateCameraMain();

#if UNITY_EDITOR
if (!OceanRenderer.Instance.OceanMaterial.IsKeywordEnabled("_SHADOWS_ON"))
{
Expand Down Expand Up @@ -188,12 +184,6 @@ public override void UpdateLodData()
return;
}

// Update the camera if it has changed.
if (_cameraMain.transform != OceanRenderer.Instance.Viewpoint)
{
UpdateCameraMain();
}

Swap(ref _sources, ref _targets);

BufCopyShadowMap.Clear();
Expand All @@ -210,6 +200,14 @@ public override void UpdateLodData()
TextureArrayHelpers.ClearToBlack(_targets);
}

// Cache the camera for further down.
var camera = OceanRenderer.Instance.ViewCamera;
if (camera == null)
{
// We want to return early after clear.
return;
}

{
// Run shadow update

Expand All @@ -218,14 +216,11 @@ public override void UpdateLodData()

_renderProperties.Initialise(BufCopyShadowMap, _updateShadowShader, krnl_UpdateShadow);

if (OceanRenderer.Instance.Viewpoint != null)
{
_renderProperties.SetVector(sp_CamPos, OceanRenderer.Instance.Viewpoint.position);
_renderProperties.SetVector(sp_CamForward, OceanRenderer.Instance.Viewpoint.forward);
}
_renderProperties.SetVector(sp_CamPos, camera.transform.position);
_renderProperties.SetVector(sp_CamForward, camera.transform.forward);

_renderProperties.SetVector(sp_JitterDiameters_CurrentFrameWeights, new Vector4(Settings._jitterDiameterSoft, Settings._jitterDiameterHard, Settings._currentFrameWeightSoft, Settings._currentFrameWeightHard));
_renderProperties.SetMatrix(sp_MainCameraProjectionMatrix, _cameraMain.projectionMatrix * _cameraMain.worldToCameraMatrix);
_renderProperties.SetMatrix(sp_MainCameraProjectionMatrix, camera.projectionMatrix * camera.worldToCameraMatrix);
_renderProperties.SetFloat(sp_SimDeltaTime, OceanRenderer.Instance.DeltaTimeDynamics);

_renderProperties.SetTexture(GetParamIdSampler(true), (Texture)_sources);
Expand Down Expand Up @@ -260,7 +255,7 @@ public override void UpdateLodData()
// Disable single pass double-wide stereo rendering for these commands since we are rendering to
// rendering texture. Otherwise, it will render double. Single pass instanced is broken here, but that
// appears to be a Unity bug only for the legacy VR system.
if (_cameraMain.stereoEnabled && XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.SinglePass)
if (camera.stereoEnabled && XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.SinglePass)
{
BufCopyShadowMap.SetSinglePassStereo(SinglePassStereoMode.None);
BufCopyShadowMap.DisableShaderKeyword("UNITY_SINGLE_PASS_STEREO");
Expand All @@ -274,7 +269,7 @@ public override void UpdateLodData()
}

// Restore single pass double-wide as we cannot rely on remaining pipeline to do it for us.
if (_cameraMain.stereoEnabled && XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.SinglePass)
if (camera.stereoEnabled && XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.SinglePass)
{
BufCopyShadowMap.SetSinglePassStereo(SinglePassStereoMode.SideBySide);
BufCopyShadowMap.EnableShaderKeyword("UNITY_SINGLE_PASS_STEREO");
Expand All @@ -285,19 +280,6 @@ public override void UpdateLodData()
Shader.SetGlobalTexture(GetParamIdSampler(), _targets);
}

void UpdateCameraMain()
{
var viewpoint = OceanRenderer.Instance.Viewpoint;
_cameraMain = viewpoint != null ? viewpoint.GetComponent<Camera>() : null;

if (_cameraMain == null)
{
Debug.LogError("Could not find main camera, disabling shadow data", _ocean);
enabled = false;
return;
}
}

public void ValidateSourceData()
{
#if UNITY_EDITOR
Expand Down
97 changes: 60 additions & 37 deletions crest/Assets/Crest/Crest/Scripts/OceanRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace Crest
[ExecuteAlways, SelectionBase]
public partial class OceanRenderer : MonoBehaviour
{
[Tooltip("The viewpoint which drives the ocean detail. Defaults to main camera."), SerializeField]
[Tooltip("The viewpoint which drives the ocean detail. Defaults to the camera."), SerializeField]
Transform _viewpoint;
public Transform Viewpoint
{
Expand All @@ -33,20 +33,10 @@ public Transform Viewpoint
#if UNITY_EDITOR
if (_followSceneCamera)
{
if (EditorWindow.focusedWindow != null &&
(EditorWindow.focusedWindow.titleContent.text == "Scene" || EditorWindow.focusedWindow.titleContent.text == "Game"))
var sceneViewCamera = EditorHelpers.GetActiveSceneViewCamera();
if (sceneViewCamera != null)
{
_lastGameOrSceneEditorWindow = EditorWindow.focusedWindow;
}

// If scene view is focused, use its camera. This code is slightly ropey but seems to work ok enough.
if (_lastGameOrSceneEditorWindow != null && _lastGameOrSceneEditorWindow.titleContent.text == "Scene")
{
var sv = SceneView.lastActiveSceneView;
if (sv != null && !EditorApplication.isPlaying && sv.camera != null)
{
return sv.camera.transform;
}
return sceneViewCamera.transform;
}
}
#endif
Expand All @@ -55,9 +45,12 @@ public Transform Viewpoint
return _viewpoint;
}

if (Camera.main != null)
// Even with performance improvements, it is still good to cache whenever possible.
var camera = ViewCamera;

if (camera != null)
{
return Camera.main.transform;
return camera.transform;
}

return null;
Expand All @@ -68,12 +61,39 @@ public Transform Viewpoint
}
}

public Transform Root { get; private set; }

[Tooltip("The camera which drives the ocean data. Defaults to main camera."), SerializeField]
Camera _camera;
public Camera ViewCamera
{
get
{
#if UNITY_EDITOR
static EditorWindow _lastGameOrSceneEditorWindow = null;
if (_followSceneCamera)
{
var sceneViewCamera = EditorHelpers.GetActiveSceneViewCamera();
if (sceneViewCamera != null)
{
return sceneViewCamera;
}
}
#endif

if (_camera != null)
{
return _camera;
}

// Unity has greatly improved performance of this operation in 2019.4.9.
return Camera.main;
}
set
{
_camera = value;
}
}

public Transform Root { get; private set; }

[Tooltip("Optional provider for time, can be used to hard-code time for automation, or provide server time. Defaults to local Unity time."), SerializeField]
TimeProviderBase _timeProvider = null;
TimeProviderDefault _timeProviderDefault = new TimeProviderDefault();
Expand Down Expand Up @@ -252,7 +272,7 @@ public enum DefaultClippingState
public int CurrentLodCount { get { return _lodTransform != null ? _lodTransform.LodCount : 0; } }

/// <summary>
/// Vertical offset of viewer vs water surface
/// Vertical offset of camera vs water surface.
/// </summary>
public float ViewerHeightAboveWater { get; private set; }

Expand Down Expand Up @@ -388,7 +408,7 @@ void OnEnable()

_commandbufferBuilder = new BuildCommandBuffer();

InitViewpoint();
ValidateViewpoint();

if (_attachDebugGUI && GetComponent<OceanDebugGUI>() == null)
{
Expand Down Expand Up @@ -634,19 +654,11 @@ bool VerifyRequirements()
return true;
}

void InitViewpoint()
void ValidateViewpoint()
{
if (Viewpoint == null)
{
var camMain = Camera.main;
if (camMain != null)
{
Viewpoint = camMain.transform;
}
else
{
Debug.LogError("Crest needs to know where to focus the ocean detail. Please set the Viewpoint property of the OceanRenderer component to the transform of the viewpoint/camera that the ocean should follow, or tag the primary camera as MainCamera.", this);
}
Debug.LogError("Crest needs to know where to focus the ocean detail. Please set the <i>ViewCamera</i> or the <i>Viewpoint</i> property that will render the ocean, or tag the primary camera as <i>MainCamera</i>.", this);
}
}

Expand Down Expand Up @@ -703,10 +715,7 @@ void RunUpdate()
var meshScaleLerp = needToBlendOutShape ? ViewerAltitudeLevelAlpha : 0f;
Shader.SetGlobalFloat(sp_meshScaleLerp, meshScaleLerp);

if (Viewpoint == null && Application.isPlaying)
{
Debug.LogError("Viewpoint is null, ocean update will fail.", this);
}
ValidateViewpoint();

if (_followViewpoint && Viewpoint != null)
{
Expand Down Expand Up @@ -832,11 +841,13 @@ void LateUpdateScale()

void LateUpdateViewerHeight()
{
_sampleHeightHelper.Init(Viewpoint.position, 0f, true);
var camera = ViewCamera;

_sampleHeightHelper.Init(camera.transform.position, 0f, true);

_sampleHeightHelper.Sample(out var waterHeight);

ViewerHeightAboveWater = Viewpoint.position.y - waterHeight;
ViewerHeightAboveWater = camera.transform.position.y - waterHeight;
}

void LateUpdateLods()
Expand Down Expand Up @@ -1102,6 +1113,18 @@ public bool Validate(OceanRenderer ocean, ValidatedHelper.ShowMessage showMessag
{
var isValid = true;

#if !UNITY_2019_4_9_OR_NEWER
if (_camera == null)
{
showMessage
(
"Not setting the camera property will result in using Camera.main which has a significant " +
"performance cost. This is improved in Unity 2019.4.9 and above.",
ValidatedHelper.MessageType.Warning, ocean
);
}
#endif

if (_material == null)
{
showMessage
Expand Down

0 comments on commit 42da938

Please sign in to comment.