summaryrefslogtreecommitdiff
path: root/Runtime/Camera/RenderLoops/ReplacementRenderLoop.cpp
blob: fcba391a8e8f02b58baf55385e0c0b162f89f521 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#include "UnityPrefix.h"
#include "ReplacementRenderLoop.h"
#include "Runtime/Camera/Renderqueue.h"
#include "Runtime/Shaders/Material.h"
#include "Runtime/Camera/BaseRenderer.h"
#include "Runtime/Graphics/Transform.h"
#include "Runtime/Camera/Camera.h"
#include "External/shaderlab/Library/intshader.h"
#include "External/shaderlab/Library/shaderlab.h"
#include "Runtime/Shaders/Shader.h"
#include "Runtime/Camera/RenderManager.h"
#include "Runtime/Camera/UnityScene.h"
#include "Runtime/GfxDevice/GfxDevice.h"


struct RODataReplacement {
	float				distance;
	int					subshaderIndex;
	Material*			material;
	const VisibleNode*  visibleNode;
	Shader*				shader;
	int					materialIndex;
	GlobalLayeringData  globalLayeringData;
};

typedef UNITY_TEMP_VECTOR(RODataReplacement) RenderObjects;

struct ROSorterReplacement {
	bool operator()( const RODataReplacement& ra, const RODataReplacement& rb ) const;
};


bool ROSorterReplacement::operator()( const RODataReplacement& ra, const RODataReplacement& rb ) const
{
	// Sort by layering depth. //@TODO:should this be here?
	bool globalLayeringResult;
	if (CompareGlobalLayeringData(ra.globalLayeringData, rb.globalLayeringData, globalLayeringResult))
		return globalLayeringResult;
	
	// Sort by subshader index used
	if (ra.subshaderIndex != rb.subshaderIndex)
		return ra.subshaderIndex < rb.subshaderIndex;
	
	// Sort front to back
	return ra.distance > rb.distance;
}


static inline float EvaluateObjectDepth (const Matrix4x4f& cameraMatrix, const TransformInfo& info)
{
	Vector3f center = info.worldAABB.GetCenter();
	float d = cameraMatrix.MultiplyPoint3( center ).z;
	Assert(IsFinite(d));
	return d;
}


static void PerformRenderingReplacement (Camera& camera, const Matrix4x4f& curCameraMatrix, RenderObjects& renderData)
{
	// Sort
	std::sort (renderData.begin(), renderData.end(), ROSorterReplacement());
	
	
	GfxDevice& device = GetGfxDevice();
	size_t ndata = renderData.size();
	device.SetViewMatrix (curCameraMatrix.GetPtr());

	for( size_t i = 0; i < ndata; ++i )
	{
		const RODataReplacement& roData = renderData[i];
		
		const VisibleNode* node = roData.visibleNode;
		Assert (node);
		BaseRenderer* renderer = node->renderer;
		Assert (renderer);
		Shader* shader = roData.shader;
		
		device.SetInverseScale(1.0f);

		//@TODO: if this returns true and we have any sort of batching, we'd have to break batches here
		renderer->ApplyCustomProperties(*roData.material, shader, roData.subshaderIndex);

		ShaderLab::SubShader& subshader = roData.shader->GetShaderLabShader()->GetSubShader (roData.subshaderIndex);
		int shaderPassCount = subshader.GetValidPassCount();
		for (int p = 0; p < shaderPassCount; ++p)
		{	
			const ChannelAssigns* channels = roData.material->SetPassWithShader(p, shader, roData.subshaderIndex);
			if (channels)
			{
				SetupObjectMatrix (node->worldMatrix, node->transformType);
				renderer->Render( renderer->GetSubsetIndex(roData.materialIndex), *channels );
			}
		}
	}
}

static void AddReplacementObject (
								  RenderObjects& renderObjects,
								  Material* mat,
								  Shader* replacementShader,
								  bool noReplacementTag,
								  int replacementTagID,
								  const VisibleNode* visibleNode,
								  float distanceForSort,
								  int materialIndex,
								  GlobalLayeringData globalLayeringData

								  )
{
	if( mat == NULL )
		mat = Material::GetDefault();
	Shader *shader = mat->GetShader();
	
	// Note: do not check whether object is in geometry queue range,
	// let shader replacement handle that. E.g. terrain billboard shaders are actually
	// beyond geometry queue, but still can output meaningful depth/normals information.
	
	// Handle shader replacement
	// Given a replacement shader and tag name:
	// 1. if tag name is empty, then all objects are just rendered with replacement shader's first subshader
	// 2. if tag name is given:
	//    * real object's subshader is queried for tag value.
	//    * if it does not have that tag, the object is not rendered.
	//    * subshader is found in the replacement shader, that has given tag with the given value. If no subshader found, object is not rendered.
	//    * that subshader is used instead to render the object.
	int usedSubshaderIndex;
	if (noReplacementTag)
	{
		usedSubshaderIndex = 0;
	}
	else
	{
		int subshaderTypeID = shader->GetShaderLabShader()->GetTag (replacementTagID, true);
		if (subshaderTypeID < 0)
			return; // skip rendering
		usedSubshaderIndex = replacementShader->GetSubShaderWithTagValue (replacementTagID, subshaderTypeID);
		if (usedSubshaderIndex == -1)
			return; // skip rendering
	}
	
	renderObjects.push_back(RODataReplacement());
	RODataReplacement& roData = renderObjects.back();
	roData.visibleNode = visibleNode;
	roData.distance = distanceForSort;
	
	DebugAssertIf( !mat );
	roData.material = mat;
	roData.materialIndex = materialIndex;
	
	roData.shader = replacementShader;
	roData.subshaderIndex = usedSubshaderIndex;
	
	roData.globalLayeringData = globalLayeringData;
}

void RenderSceneShaderReplacement (const VisibleNodes& contents, Shader* shader, const std::string& shaderReplaceTag)
{
	ShaderReplaceData replaceData;
	replaceData.replacementShader = shader;
	replaceData.replacementTagSet = !shaderReplaceTag.empty();
	replaceData.replacementTagID = ShaderLab::GetShaderTagID(shaderReplaceTag);
	
	RenderSceneShaderReplacement(contents, replaceData);
}

	
void RenderSceneShaderReplacement (const VisibleNodes& contents, const ShaderReplaceData& shaderReplace)
{
	Assert (shaderReplace.replacementShader != NULL);

	const bool noReplacementTag = !shaderReplace.replacementTagSet;
	const int replacementTagID = shaderReplace.replacementTagID;
	Shader* replacementShader = shaderReplace.replacementShader;
	Camera& camera = GetRenderManager().GetCurrentCamera();
	Matrix4x4f curCameraMatrix = camera.GetWorldToCameraMatrix();	
	
	RenderObjects renderObjects;
	renderObjects.reserve (contents.size()/4);

	// Go over the objects
	for( VisibleNodes::const_iterator i = contents.begin(); i != contents.end(); ++i )
	{
		float distanceForSort = EvaluateObjectDepth (curCameraMatrix, *i);
		
		const BaseRenderer* renderer = i->renderer;
		
		int matCount = renderer->GetMaterialCount();
		for (int mi = 0; mi < matCount; ++mi)
		{
			Material* mat = renderer->GetMaterial(mi);
			AddReplacementObject (
								  renderObjects,
								  mat,
								  replacementShader,
								  noReplacementTag,
								  replacementTagID,
								  &*i,
								  distanceForSort,
								  mi,
								  renderer->GetGlobalLayeringData()
								  );
		}
	}
	
	// Render
	PerformRenderingReplacement (camera, curCameraMatrix, renderObjects);
}

void RenderSceneShaderReplacement (const RenderObjectDataContainer& contents, Shader* replacementShader, const std::string& replacementTag)
{
	Assert (replacementShader);

	const bool noReplacementTag = replacementTag.empty();
	const int replacementTagID = ShaderLab::GetShaderTagID(replacementTag);

	Camera& camera = GetRenderManager().GetCurrentCamera();
	Matrix4x4f curCameraMatrix = camera.GetWorldToCameraMatrix();	

	RenderObjects renderObjects;
	renderObjects.reserve (contents.size()/4);

	// Go over the objects
	for (RenderObjectDataContainer::const_iterator i = contents.begin(); i != contents.end(); ++i)
	{
		const RenderObjectData& ro = *i;
		const BaseRenderer* renderer = ro.visibleNode->renderer;
		Assert (renderer);
		Material* mat = renderer->GetMaterial(ro.sourceMaterialIndex);
		AddReplacementObject (
			renderObjects,
			mat,
			replacementShader,
			noReplacementTag,
			replacementTagID,
			ro.visibleNode,
			ro.distance,
			ro.sourceMaterialIndex,
			renderer->GetGlobalLayeringData()
			);
	}

	// Render
	PerformRenderingReplacement (camera, curCameraMatrix, renderObjects);
}