2 * Copyright (C) 2013 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * Extra vertices for the corner for smoother corner.
19 * Only for outer vertices.
20 * Note that we use such extra memory to avoid an extra loop.
22 // For half circle, we could add EXTRA_VERTEX_PER_PI vertices.
23 // Set to 1 if we don't want to have any.
24 #define EXTRA_CORNER_VERTEX_PER_PI 12
26 // For the whole polygon, the sum of all the deltas b/t normals is 2 * M_PI,
27 // therefore, the maximum number of extra vertices will be twice bigger.
28 #define MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * EXTRA_CORNER_VERTEX_PER_PI)
30 // For each RADIANS_DIVISOR, we would allocate one more vertex b/t the normals.
31 #define CORNER_RADIANS_DIVISOR (M_PI / EXTRA_CORNER_VERTEX_PER_PI)
34 * Extra vertices for the Edge for interpolation artifacts.
35 * Same value for both inner and outer vertices.
37 #define EXTRA_EDGE_VERTEX_PER_PI 50
39 #define MAX_EXTRA_EDGE_VERTEX_NUMBER (2 * EXTRA_EDGE_VERTEX_PER_PI)
41 #define EDGE_RADIANS_DIVISOR (M_PI / EXTRA_EDGE_VERTEX_PER_PI)
46 #define OUTER_ALPHA (0.0f)
48 // Once the alpha difference is greater than this threshold, we will allocate extra
50 // If this is set to negative value, then all the edge will be tessellated.
51 #define ALPHA_THRESHOLD (0.1f / 255.0f)
53 #include "AmbientShadow.h"
55 #include "ShadowTessellator.h"
57 #include "VertexBuffer.h"
60 #include <utils/Log.h>
63 namespace uirenderer {
66 * Local utility functions.
68 inline Vector2 getNormalFromVertices(const Vector3* vertices, int current, int next) {
69 // Convert from Vector3 to Vector2 first.
70 Vector2 currentVertex = { vertices[current].x, vertices[current].y };
71 Vector2 nextVertex = { vertices[next].x, vertices[next].y };
73 return ShadowTessellator::calculateNormal(currentVertex, nextVertex);
76 // The input z value will be converted to be non-negative inside.
77 // The output must be ranged from 0 to 1.
78 inline float getAlphaFromFactoredZ(float factoredZ) {
79 return 1.0 / (1 + std::max(factoredZ, 0.0f));
82 inline int getEdgeExtraAndUpdateSpike(Vector2* currentSpike,
83 const Vector3& secondVertex, const Vector3& centroid) {
84 Vector2 secondSpike = {secondVertex.x - centroid.x, secondVertex.y - centroid.y};
85 secondSpike.normalize();
87 int result = ShadowTessellator::getExtraVertexNumber(secondSpike, *currentSpike,
88 EDGE_RADIANS_DIVISOR);
89 *currentSpike = secondSpike;
93 // Given the caster's vertex count, compute all the buffers size depending on
94 // whether or not the caster is opaque.
95 inline void computeBufferSize(int* totalVertexCount, int* totalIndexCount,
96 int* totalUmbraCount, int casterVertexCount, bool isCasterOpaque) {
97 // Compute the size of the vertex buffer.
98 int outerVertexCount = casterVertexCount * 2 + MAX_EXTRA_CORNER_VERTEX_NUMBER +
99 MAX_EXTRA_EDGE_VERTEX_NUMBER;
100 int innerVertexCount = casterVertexCount + MAX_EXTRA_EDGE_VERTEX_NUMBER;
101 *totalVertexCount = outerVertexCount + innerVertexCount;
103 // Compute the size of the index buffer.
104 *totalIndexCount = 2 * outerVertexCount + 2;
106 // Compute the size of the umber buffer.
107 // For translucent object, keep track of the umbra(inner) vertex in order to draw
108 // inside. We only need to store the index information.
109 *totalUmbraCount = 0;
110 if (!isCasterOpaque) {
111 // Add the centroid if occluder is translucent.
112 (*totalVertexCount)++;
113 *totalIndexCount += 2 * innerVertexCount + 1;
114 *totalUmbraCount = innerVertexCount;
118 inline bool needsExtraForEdge(float firstAlpha, float secondAlpha) {
119 return fabsf(firstAlpha - secondAlpha) > ALPHA_THRESHOLD;
123 * Calculate the shadows as a triangle strips while alpha value as the
126 * @param isCasterOpaque Whether the caster is opaque.
127 * @param vertices The shadow caster's polygon, which is represented in a Vector3
129 * @param vertexCount The length of caster's polygon in terms of number of
131 * @param centroid3d The centroid of the shadow caster.
132 * @param heightFactor The factor showing the higher the object, the lighter the
134 * @param geomFactor The factor scaling the geometry expansion along the normal.
136 * @param shadowVertexBuffer Return an floating point array of (x, y, a)
137 * triangle strips mode.
139 * An simple illustration:
140 * For now let's mark the outer vertex as Pi, the inner as Vi, the centroid as C.
142 * First project the occluder to the Z=0 surface.
143 * Then we got all the inner vertices. And we compute the normal for each edge.
144 * According to the normal, we generate outer vertices. E.g: We generate P1 / P4
145 * as extra corner vertices to make the corner looks round and smoother.
147 * Due to the fact that the alpha is not linear interpolated along the inner
148 * edge, when the alpha is different, we may add extra vertices such as P2.1, P2.2,
149 * V0.1, V0.2 to avoid the visual artifacts.
152 * (P2) (P2.1) (P2.2) | ' (P4)
155 * (P0) ------------------------------------------------(P5)
156 * | (V0) (V0.1) (V0.2) |(V1)
164 * (V3)-----------------------------------(V2)
166 void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
167 const Vector3* casterVertices, int casterVertexCount, const Vector3& centroid3d,
168 float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) {
169 shadowVertexBuffer.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
171 // In order to computer the outer vertices in one loop, we need pre-compute
172 // the normal by the vertex (n - 1) to vertex 0, and the spike and alpha value
174 Vector2 previousNormal = getNormalFromVertices(casterVertices,
175 casterVertexCount - 1 , 0);
176 Vector2 currentSpike = {casterVertices[0].x - centroid3d.x,
177 casterVertices[0].y - centroid3d.y};
178 currentSpike.normalize();
179 float currentAlpha = getAlphaFromFactoredZ(casterVertices[0].z * heightFactor);
181 // Preparing all the output data.
182 int totalVertexCount, totalIndexCount, totalUmbraCount;
183 computeBufferSize(&totalVertexCount, &totalIndexCount, &totalUmbraCount,
184 casterVertexCount, isCasterOpaque);
185 AlphaVertex* shadowVertices =
186 shadowVertexBuffer.alloc<AlphaVertex>(totalVertexCount);
187 int vertexBufferIndex = 0;
188 uint16_t* indexBuffer = shadowVertexBuffer.allocIndices<uint16_t>(totalIndexCount);
189 int indexBufferIndex = 0;
190 uint16_t umbraVertices[totalUmbraCount];
193 for (int i = 0; i < casterVertexCount; i++) {
194 // Corner: first figure out the extra vertices we need for the corner.
195 const Vector3& innerVertex = casterVertices[i];
196 Vector2 currentNormal = getNormalFromVertices(casterVertices, i,
197 (i + 1) % casterVertexCount);
199 int extraVerticesNumber = ShadowTessellator::getExtraVertexNumber(currentNormal,
200 previousNormal, CORNER_RADIANS_DIVISOR);
202 float expansionDist = innerVertex.z * heightFactor * geomFactor;
203 const int cornerSlicesNumber = extraVerticesNumber + 1; // Minimal as 1.
205 ALOGD("cornerSlicesNumber is %d", cornerSlicesNumber);
208 // Corner: fill the corner Vertex Buffer(VB) and Index Buffer(IB).
209 // We fill the inner vertex first, such that we can fill the index buffer
211 int currentInnerVertexIndex = vertexBufferIndex;
212 if (!isCasterOpaque) {
213 umbraVertices[umbraIndex++] = vertexBufferIndex;
215 AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
216 casterVertices[i].x, casterVertices[i].y,
219 const Vector3& innerStart = casterVertices[i];
221 // outerStart is the first outer vertex for this inner vertex.
222 // outerLast is the last outer vertex for this inner vertex.
223 Vector2 outerStart = {0, 0};
224 Vector2 outerLast = {0, 0};
225 // This will create vertices from [0, cornerSlicesNumber] inclusively,
226 // which means minimally 2 vertices even without the extra ones.
227 for (int j = 0; j <= cornerSlicesNumber; j++) {
228 Vector2 averageNormal =
229 previousNormal * (cornerSlicesNumber - j) + currentNormal * j;
230 averageNormal /= cornerSlicesNumber;
231 averageNormal.normalize();
233 outerVertex.x = innerVertex.x + averageNormal.x * expansionDist;
234 outerVertex.y = innerVertex.y + averageNormal.y * expansionDist;
236 indexBuffer[indexBufferIndex++] = vertexBufferIndex;
237 indexBuffer[indexBufferIndex++] = currentInnerVertexIndex;
238 AlphaVertex::set(&shadowVertices[vertexBufferIndex++], outerVertex.x,
239 outerVertex.y, OUTER_ALPHA);
242 outerStart = outerVertex;
243 } else if (j == cornerSlicesNumber) {
244 outerLast = outerVertex;
247 previousNormal = currentNormal;
249 // Edge: first figure out the extra vertices needed for the edge.
250 const Vector3& innerNext = casterVertices[(i + 1) % casterVertexCount];
251 float nextAlpha = getAlphaFromFactoredZ(innerNext.z * heightFactor);
252 if (needsExtraForEdge(currentAlpha, nextAlpha)) {
253 // TODO: See if we can / should cache this outer vertex across the loop.
255 float expansionDist = innerNext.z * heightFactor * geomFactor;
256 outerNext.x = innerNext.x + currentNormal.x * expansionDist;
257 outerNext.y = innerNext.y + currentNormal.y * expansionDist;
259 // Compute the angle and see how many extra points we need.
260 int extraVerticesNumber = getEdgeExtraAndUpdateSpike(¤tSpike,
261 innerNext, centroid3d);
263 ALOGD("extraVerticesNumber %d for edge %d", extraVerticesNumber, i);
265 // Edge: fill the edge's VB and IB.
266 // This will create vertices pair from [1, extraVerticesNumber - 1].
267 // If there is no extra vertices created here, the edge will be drawn
268 // as just 2 triangles.
269 for (int k = 1; k < extraVerticesNumber; k++) {
270 int startWeight = extraVerticesNumber - k;
271 Vector2 currentOuter =
272 (outerLast * startWeight + outerNext * k) / extraVerticesNumber;
273 indexBuffer[indexBufferIndex++] = vertexBufferIndex;
274 AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentOuter.x,
275 currentOuter.y, OUTER_ALPHA);
277 if (!isCasterOpaque) {
278 umbraVertices[umbraIndex++] = vertexBufferIndex;
280 Vector3 currentInner =
281 (innerStart * startWeight + innerNext * k) / extraVerticesNumber;
282 indexBuffer[indexBufferIndex++] = vertexBufferIndex;
283 AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentInner.x,
285 getAlphaFromFactoredZ(currentInner.z * heightFactor));
288 currentAlpha = nextAlpha;
291 indexBuffer[indexBufferIndex++] = 1;
292 indexBuffer[indexBufferIndex++] = 0;
294 if (!isCasterOpaque) {
295 // Add the centroid as the last one in the vertex buffer.
296 float centroidOpacity =
297 getAlphaFromFactoredZ(centroid3d.z * heightFactor);
298 int centroidIndex = vertexBufferIndex;
299 AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid3d.x,
300 centroid3d.y, centroidOpacity);
302 for (int i = 0; i < umbraIndex; i++) {
303 // Note that umbraVertices[0] is always 0.
304 // So the start and the end of the umbra are using the "0".
305 // And penumbra ended with 0, so a degenerated triangle is formed b/t
306 // the umbra and penumbra.
307 indexBuffer[indexBufferIndex++] = umbraVertices[i];
308 indexBuffer[indexBufferIndex++] = centroidIndex;
310 indexBuffer[indexBufferIndex++] = 0;
313 // At the end, update the real index and vertex buffer size.
314 shadowVertexBuffer.updateVertexCount(vertexBufferIndex);
315 shadowVertexBuffer.updateIndexCount(indexBufferIndex);
316 shadowVertexBuffer.computeBounds<AlphaVertex>();
318 ShadowTessellator::checkOverflow(vertexBufferIndex, totalVertexCount, "Ambient Vertex Buffer");
319 ShadowTessellator::checkOverflow(indexBufferIndex, totalIndexCount, "Ambient Index Buffer");
320 ShadowTessellator::checkOverflow(umbraIndex, totalUmbraCount, "Ambient Umbra Buffer");
323 for (int i = 0; i < vertexBufferIndex; i++) {
324 ALOGD("vertexBuffer i %d, (%f, %f %f)", i, shadowVertices[i].x, shadowVertices[i].y,
325 shadowVertices[i].alpha);
327 for (int i = 0; i < indexBufferIndex; i++) {
328 ALOGD("indexBuffer i %d, indexBuffer[i] %d", i, indexBuffer[i]);
333 }; // namespace uirenderer
334 }; // namespace android