AmbientShadow.cpp revision 55bfb4e728fe1db619af5d2c287f4abe711b3343
155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui/* 255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Copyright (C) 2013 The Android Open Source Project 355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * 455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Licensed under the Apache License, Version 2.0 (the "License"); 555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * you may not use this file except in compliance with the License. 655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * You may obtain a copy of the License at 755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * 855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * http://www.apache.org/licenses/LICENSE-2.0 955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * 1055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Unless required by applicable law or agreed to in writing, software 1155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * distributed under the License is distributed on an "AS IS" BASIS, 1255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * See the License for the specific language governing permissions and 1455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * limitations under the License. 1555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui */ 1655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 1755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#define LOG_TAG "OpenGLRenderer" 1855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 1955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include <math.h> 2055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include <utils/Log.h> 2155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 2255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include "AmbientShadow.h" 2355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include "Vertex.h" 2455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 2555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuinamespace android { 2655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuinamespace uirenderer { 2755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 2855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui/** 2955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Calculate the shadows as a triangle strips while alpha value as the 3055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * shadow values. 3155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * 3255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param vertices The shadow caster's polygon, which is represented in a Vector3 3355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * array. 3455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param vertexCount The length of caster's polygon in terms of number of 3555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * vertices. 3655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param rays The number of rays shooting out from the centroid. 3755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param layers The number of rings outside the polygon. 3855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param strength The darkness of the shadow, the higher, the darker. 3955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param heightFactor The factor showing the higher the object, the lighter the 4055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * shadow. 4155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param geomFactor The factor scaling the geometry expansion along the normal. 4255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * 4355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param shadowVertexBuffer Return an floating point array of (x, y, a) 4455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * triangle strips mode. 4555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui */ 4655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuivoid AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount, 4755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int rays, int layers, float strength, float heightFactor, float geomFactor, 4855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui VertexBuffer& shadowVertexBuffer) { 4955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 5055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // Validate the inputs. 5155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui if (strength <= 0 || heightFactor <= 0 || layers <= 0 || rays <= 0 5255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui || geomFactor <= 0) { 5355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#if DEBUG_SHADOW 5455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui ALOGE("Invalid input for createAmbientShadow(), early return!"); 5555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#endif 5655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui return; 5755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 5855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int rings = layers + 1; 5955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int size = rays * rings; 6055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui Vector2 centroid; 6155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui calculatePolygonCentroid(vertices, vertexCount, centroid); 6255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 6355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui Vector2 dir[rays]; 6455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float rayDist[rays]; 6555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float rayHeight[rays]; 6655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui calculateRayDirections(rays, dir); 6755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 6855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // Calculate the length and height of the points along the edge. 6955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // 7055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // The math here is: 7155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // Intersect each ray (starting from the centroid) with the polygon. 7255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui for (int i = 0; i < rays; i++) { 7355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int edgeIndex; 7455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float edgeFraction; 7555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float rayDistance; 7655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui calculateIntersection(vertices, vertexCount, centroid, dir[i], edgeIndex, 7755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui edgeFraction, rayDistance); 7855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui rayDist[i] = rayDistance; 7955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui if (edgeIndex < 0 || edgeIndex >= vertexCount) { 8055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#if DEBUG_SHADOW 8155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui ALOGE("Invalid edgeIndex!"); 8255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#endif 8355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui edgeIndex = 0; 8455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 8555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float h1 = vertices[edgeIndex].z; 8655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float h2 = vertices[((edgeIndex + 1) % vertexCount)].z; 8755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui rayHeight[i] = h1 + edgeFraction * (h2 - h1); 8855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 8955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 9055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // The output buffer length basically is roughly rays * layers, but since we 9155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // need triangle strips, so we need to duplicate vertices to accomplish that. 9255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui const int shadowVertexCount = (2 + rays + ((layers) * 2 * (rays + 1))); 9355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui AlphaVertex* shadowVertices = shadowVertexBuffer.alloc<AlphaVertex>(shadowVertexCount); 9455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 9555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // Calculate the vertex of the shadows. 9655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // 9755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // The math here is: 9855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // Along the edges of the polygon, for each intersection point P (generated above), 9955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // calculate the normal N, which should be perpendicular to the edge of the 10055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // polygon (represented by the neighbor intersection points) . 10155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // Shadow's vertices will be generated as : P + N * scale. 10255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int currentIndex = 0; 10355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui for (int r = 0; r < layers; r++) { 10455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int firstInLayer = currentIndex; 10555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui for (int i = 0; i < rays; i++) { 10655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 10755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui Vector2 normal(1.0f, 0.0f); 10855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui calculateNormal(rays, i, dir, rayDist, normal); 10955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 11055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float opacity = strength * (0.5f) / (1 + rayHeight[i] / heightFactor); 11155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 11255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // The vertex should be start from rayDist[i] then scale the 11355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // normalizeNormal! 11455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui Vector2 intersection = dir[i] * rayDist[i] + centroid; 11555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 11655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // Use 2 rings' vertices to complete one layer's strip 11755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui for (int j = r; j < (r + 2); j++) { 11855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float jf = j / (float)(rings - 1); 11955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 12055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float expansionDist = rayHeight[i] / heightFactor * geomFactor * jf; 12155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui AlphaVertex::set(&shadowVertices[currentIndex], 12255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui intersection.x + normal.x * expansionDist, 12355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui intersection.y + normal.y * expansionDist, 12455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui (1 - jf) * opacity); 12555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui currentIndex++; 12655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 12755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 12855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 12955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // From one layer to the next, we need to duplicate the vertex to 13055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // continue as a single strip. 13155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui shadowVertices[currentIndex] = shadowVertices[firstInLayer]; 13255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui currentIndex++; 13355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui shadowVertices[currentIndex] = shadowVertices[firstInLayer + 1]; 13455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui currentIndex++; 13555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 13655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 13755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // After all rings are done, we need to jump into the polygon. 13855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // In order to keep everything in a strip, we need to duplicate the last one 13955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // of the rings and the first one inside the polygon. 14055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int lastInRings = currentIndex - 1; 14155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui shadowVertices[currentIndex] = shadowVertices[lastInRings]; 14255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui currentIndex++; 14355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 14455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // We skip one and fill it back after we finish the internal triangles. 14555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui currentIndex++; 14655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int firstInternal = currentIndex; 14755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 14855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // Combine the internal area of the polygon into a triangle strip, too. 14955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // The basic idea is zig zag between the intersection points. 15055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // 0 -> (n - 1) -> 1 -> (n - 2) ... 15155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui for (int k = 0; k < rays; k++) { 15255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int i = k / 2; 15355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui if ((k & 1) == 1) { // traverse the inside in a zig zag pattern for strips 15455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui i = rays - i - 1; 15555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 15655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float cast = rayDist[i] * (1 + rayHeight[i] / heightFactor); 15755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float opacity = strength * (0.5f) / (1 + rayHeight[i] / heightFactor); 15855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float t = rayDist[i]; 15955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 16055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui AlphaVertex::set(&shadowVertices[currentIndex], dir[i].x * t + centroid.x, 16155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui dir[i].y * t + centroid.y, opacity); 16255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui currentIndex++; 16355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 16455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 16555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui currentIndex = firstInternal - 1; 16655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui shadowVertices[currentIndex] = shadowVertices[firstInternal]; 16755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui} 16855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 16955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui/** 17055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Calculate the centroid of a given polygon. 17155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * 17255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param vertices The shadow caster's polygon, which is represented in a 17355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * straight Vector3 array. 17455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param vertexCount The length of caster's polygon in terms of number of vertices. 17555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * 17655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param centroid Return the centroid of the polygon. 17755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui */ 17855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuivoid AmbientShadow::calculatePolygonCentroid(const Vector3* vertices, int vertexCount, 17955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui Vector2& centroid) { 18055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float sumx = 0; 18155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float sumy = 0; 18255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int p1 = vertexCount - 1; 18355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float area = 0; 18455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui for (int p2 = 0; p2 < vertexCount; p2++) { 18555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float x1 = vertices[p1].x; 18655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float y1 = vertices[p1].y; 18755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float x2 = vertices[p2].x; 18855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float y2 = vertices[p2].y; 18955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float a = (x1 * y2 - x2 * y1); 19055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui sumx += (x1 + x2) * a; 19155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui sumy += (y1 + y2) * a; 19255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui area += a; 19355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui p1 = p2; 19455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 19555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 19655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui if (area == 0) { 19755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#if DEBUG_SHADOW 19855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui ALOGE("Area is 0!"); 19955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#endif 20055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui centroid.x = vertices[0].x; 20155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui centroid.y = vertices[0].y; 20255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } else { 20355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui centroid.x = sumx / (3 * area); 20455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui centroid.y = sumy / (3 * area); 20555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 20655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui} 20755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 20855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui/** 20955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Generate an array of rays' direction vectors. 21055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * 21155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param rays The number of rays shooting out from the centroid. 21255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param dir Return the array of ray vectors. 21355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui */ 21455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuivoid AmbientShadow::calculateRayDirections(int rays, Vector2* dir) { 21555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float deltaAngle = 2 * M_PI / rays; 21655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 21755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui for (int i = 0; i < rays; i++) { 21855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui dir[i].x = sinf(deltaAngle * i); 21955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui dir[i].y = cosf(deltaAngle * i); 22055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 22155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui} 22255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 22355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui/** 22455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Calculate the intersection of a ray hitting the polygon. 22555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * 22655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param vertices The shadow caster's polygon, which is represented in a 22755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Vector3 array. 22855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param vertexCount The length of caster's polygon in terms of number of vertices. 22955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param start The starting point of the ray. 23055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param dir The direction vector of the ray. 23155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * 23255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param outEdgeIndex Return the index of the segment (or index of the starting 23355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * vertex) that ray intersect with. 23455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param outEdgeFraction Return the fraction offset from the segment starting 23555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * index. 23655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param outRayDist Return the ray distance from centroid to the intersection. 23755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui */ 23855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuivoid AmbientShadow::calculateIntersection(const Vector3* vertices, int vertexCount, 23955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui const Vector2& start, const Vector2& dir, int& outEdgeIndex, 24055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float& outEdgeFraction, float& outRayDist) { 24155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float startX = start.x; 24255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float startY = start.y; 24355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float dirX = dir.x; 24455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float dirY = dir.y; 24555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // Start the search from the last edge from poly[len-1] to poly[0]. 24655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int p1 = vertexCount - 1; 24755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 24855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui for (int p2 = 0; p2 < vertexCount; p2++) { 24955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float p1x = vertices[p1].x; 25055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float p1y = vertices[p1].y; 25155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float p2x = vertices[p2].x; 25255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float p2y = vertices[p2].y; 25355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 25455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // The math here is derived from: 25555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // f(t, v) = p1x * (1 - t) + p2x * t - (startX + dirX * v) = 0; 25655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // g(t, v) = p1y * (1 - t) + p2y * t - (startY + dirY * v) = 0; 25755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float div = (dirX * (p1y - p2y) + dirY * p2x - dirY * p1x); 25855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui if (div != 0) { 25955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float t = (dirX * (p1y - startY) + dirY * startX - dirY * p1x) / (div); 26055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui if (t > 0 && t <= 1) { 26155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui float t2 = (p1x * (startY - p2y) 26255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui + p2x * (p1y - startY) 26355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui + startX * (p2y - p1y)) / div; 26455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui if (t2 > 0) { 26555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui outEdgeIndex = p1; 26655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui outRayDist = t2; 26755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui outEdgeFraction = t; 26855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui return; 26955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 27055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 27155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 27255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui p1 = p2; 27355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 27455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui return; 27555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui}; 27655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 27755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui/** 27855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Calculate the normal at the intersection point between a ray and the polygon. 27955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * 28055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param rays The total number of rays. 28155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param currentRayIndex The index of the ray which the normal is based on. 28255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param dir The array of the all the rays directions. 28355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param rayDist The pre-computed ray distances array. 28455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * 28555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param normal Return the normal. 28655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui */ 28755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuivoid AmbientShadow::calculateNormal(int rays, int currentRayIndex, 28855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui const Vector2* dir, const float* rayDist, Vector2& normal) { 28955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int preIndex = (currentRayIndex - 1 + rays) % rays; 29055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui int postIndex = (currentRayIndex + 1) % rays; 29155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui Vector2 p1 = dir[preIndex] * rayDist[preIndex]; 29255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui Vector2 p2 = dir[postIndex] * rayDist[postIndex]; 29355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 29455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // Now the V (deltaX, deltaY) is the vector going CW around the poly. 29555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui Vector2 delta = p2 - p1; 29655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui if (delta.length() != 0) { 29755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui delta.normalize(); 29855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // Calculate the normal , which is CCW 90 rotate to the V. 29955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui // 90 degrees CCW about z-axis: (x, y, z) -> (-y, x, z) 30055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui normal.x = -delta.y; 30155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui normal.y = delta.x; 30255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui } 30355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui} 30455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui 30555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui}; // namespace uirenderer 30655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui}; // namespace android 307