Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 512e643c authored by ztenghui's avatar ztenghui
Browse files

Re-triangulate the spot shadow.

Fix the valid umbra detection.

This looks better b/c every vertex will have one ray shooting at it, such that
we don't miss the corner.

This performs better too, due to the polygon intersection is removed and less ray
intersection. 2x performance for rect and circle for spot shadow in test app.

    b/17288227
    b/15598793
    b/16712006

Change-Id: I4a5ee397b9e192e93c8e35e6260b499e3e38a6f4
parent 9f30ce3b
Loading
Loading
Loading
Loading
+7 −30
Original line number Diff line number Diff line
@@ -91,36 +91,13 @@ inline float getTransformedAlphaFromFactoredZ(float factoredZ) {
    return getTransformedAlphaFromAlpha(getAlphaFromFactoredZ(factoredZ));
}

inline int getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2,
        float divisor) {
    // When there is no distance difference, there is no need for extra vertices.
    if (vector1.lengthSquared() == 0 || vector2.lengthSquared() == 0) {
        return 0;
    }
    // The formula is :
    // extraNumber = floor(acos(dot(n1, n2)) / (M_PI / EXTRA_VERTEX_PER_PI))
    // The value ranges for each step are:
    // dot( ) --- [-1, 1]
    // acos( )     --- [0, M_PI]
    // floor(...)  --- [0, EXTRA_VERTEX_PER_PI]
    float dotProduct = vector1.dot(vector2);
    // TODO: Use look up table for the dotProduct to extraVerticesNumber
    // computation, if needed.
    float angle = acosf(dotProduct);
    return (int) floor(angle / divisor);
}

inline void checkOverflow(int used, int total, const char* bufferName) {
    LOG_ALWAYS_FATAL_IF(used > total, "Error: %s overflow!!! used %d, total %d",
            bufferName, used, total);
}

inline int getEdgeExtraAndUpdateSpike(Vector2* currentSpike,
        const Vector3& secondVertex, const Vector3& centroid) {
    Vector2 secondSpike  = {secondVertex.x - centroid.x, secondVertex.y - centroid.y};
    secondSpike.normalize();

    int result = getExtraVertexNumber(secondSpike, *currentSpike, EDGE_RADIANS_DIVISOR);
    int result = ShadowTessellator::getExtraVertexNumber(secondSpike, *currentSpike,
            EDGE_RADIANS_DIVISOR);
    *currentSpike = secondSpike;
    return result;
}
@@ -231,8 +208,8 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
        Vector2 currentNormal = getNormalFromVertices(casterVertices, i,
                (i + 1) % casterVertexCount);

        int extraVerticesNumber = getExtraVertexNumber(currentNormal, previousNormal,
                CORNER_RADIANS_DIVISOR);
        int extraVerticesNumber = ShadowTessellator::getExtraVertexNumber(currentNormal,
                previousNormal, CORNER_RADIANS_DIVISOR);

        float expansionDist = innerVertex.z * heightFactor * geomFactor;
        const int cornerSlicesNumber = extraVerticesNumber + 1; // Minimal as 1.
@@ -349,9 +326,9 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
    shadowVertexBuffer.updateVertexCount(vertexBufferIndex);
    shadowVertexBuffer.updateIndexCount(indexBufferIndex);

    checkOverflow(vertexBufferIndex, totalVertexCount, "Vertex Buffer");
    checkOverflow(indexBufferIndex, totalIndexCount, "Index Buffer");
    checkOverflow(umbraIndex, totalUmbraCount, "Umbra Buffer");
    ShadowTessellator::checkOverflow(vertexBufferIndex, totalVertexCount, "Vertex Buffer");
    ShadowTessellator::checkOverflow(indexBufferIndex, totalIndexCount, "Index Buffer");
    ShadowTessellator::checkOverflow(umbraIndex, totalUmbraCount, "Umbra Buffer");

#if DEBUG_SHADOW
    for (int i = 0; i < vertexBufferIndex; i++) {
+24 −0
Original line number Diff line number Diff line
@@ -252,5 +252,29 @@ void ShadowTessellator::reverseVertexArray(Vertex* polygon, int len) {
    }
}

int ShadowTessellator::getExtraVertexNumber(const Vector2& vector1,
        const Vector2& vector2, float divisor) {
    // When there is no distance difference, there is no need for extra vertices.
    if (vector1.lengthSquared() == 0 || vector2.lengthSquared() == 0) {
        return 0;
    }
    // The formula is :
    // extraNumber = floor(acos(dot(n1, n2)) / (M_PI / EXTRA_VERTEX_PER_PI))
    // The value ranges for each step are:
    // dot( ) --- [-1, 1]
    // acos( )     --- [0, M_PI]
    // floor(...)  --- [0, EXTRA_VERTEX_PER_PI]
    float dotProduct = vector1.dot(vector2);
    // TODO: Use look up table for the dotProduct to extraVerticesNumber
    // computation, if needed.
    float angle = acosf(dotProduct);
    return (int) floor(angle / divisor);
}

void ShadowTessellator::checkOverflow(int used, int total, const char* bufferName) {
    LOG_ALWAYS_FATAL_IF(used > total, "Error: %s overflow!!! used %d, total %d",
            bufferName, used, total);
}

}; // namespace uirenderer
}; // namespace android
+4 −0
Original line number Diff line number Diff line
@@ -101,6 +101,10 @@ public:
     */
    static void reverseVertexArray(Vertex* polygon, int len);

    static int getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2,
            float divisor);

    static void checkOverflow(int used, int total, const char* bufferName);
}; // ShadowTessellator

}; // namespace uirenderer
+770 −264

File changed.

Preview size limit exceeded, changes collapsed.

+37 −9
Original line number Diff line number Diff line
@@ -26,22 +26,51 @@ namespace uirenderer {

class SpotShadow {
public:
    static void createSpotShadow_old(bool isCasterOpaque, const Vector3* poly,
            int polyLength, const Vector3& lightCenter, float lightSize,
            int lightVertexCount, VertexBuffer& retStrips);
    static void createSpotShadow(bool isCasterOpaque, const Vector3& lightCenter,
            float lightSize, const Vector3* poly, int polyLength,
            const Vector3& polyCentroid, VertexBuffer& retstrips);

private:
    struct VertexAngleData;

    static float projectCasterToOutline(Vector2& outline,
            const Vector3& lightCenter, const Vector3& polyVertex);
    static int calculateOccludedUmbra(const Vector2* umbra, int umbraLength,
            const Vector3* poly, int polyLength, Vector2* occludedUmbra);

    static void computeSpotShadow_old(bool isCasterOpaque, const Vector3* lightPoly,
            int lightPolyLength, const Vector3& lightCenter, const Vector3* poly,
            int polyLength, VertexBuffer& shadowTriangleStrip);
    static int setupAngleList(VertexAngleData* angleDataList,
            int polyLength, const Vector2* polygon, const Vector2& centroid,
            bool isPenumbra, const char* name);

    static int convertPolysToVerticesPerRay(
            bool hasOccludedUmbraArea, const Vector2* poly2d, int polyLength,
            const Vector2* umbra, int umbraLength, const Vector2* penumbra,
            int penumbraLength, const Vector2& centroid,
            Vector2* umbraVerticesPerRay, Vector2* penumbraVerticesPerRay,
            Vector2* occludedUmbraVerticesPerRay);

    static bool checkClockwise(int maxIndex, int listLength,
            VertexAngleData* angleList, const char* name);

    static void calculateDistanceCounter(bool needsOffsetToUmbra, int angleLength,
            const VertexAngleData* allVerticesAngleData, int* distances);

    static void mergeAngleList(int maxUmbraAngleIndex, int maxPenumbraAngleIndex,
            const VertexAngleData* umbraAngleList, int umbraLength,
            const VertexAngleData* penumbraAngleList, int penumbraLength,
            VertexAngleData* allVerticesAngleData);

    static int setupPolyAngleList(float* polyAngleList, int polyAngleLength,
        const Vector2* poly2d, const Vector2& centroid);

    static bool checkPolyClockwise(int polyAngleLength, int maxPolyAngleIndex,
        const float* polyAngleList);

    static int getEdgeStartIndex(const int* offsets, int rayIndex, int totalRayNumber,
        const VertexAngleData* allVerticesAngleData);

    static int getPolyEdgeStartIndex(int maxPolyAngleIndex, int polyLength,
        const float* polyAngleList, float rayAngle);

    static void computeLightPolygon(int points, const Vector3& lightCenter,
            float size, Vector3* ret);
@@ -67,11 +96,10 @@ private:
            double x3, double y3, double x4, double y4, Vector2& ret);

    static void generateTriangleStrip(bool isCasterOpaque, float shadowStrengthScale,
            const Vector2* penumbra, int penumbraLength, const Vector2* umbra, int umbraLength,
            const Vector3* poly, int polyLength, VertexBuffer& retstrips);
            Vector2* penumbra, int penumbraLength, Vector2* umbra, int umbraLength,
            const Vector3* poly, int polyLength, VertexBuffer& retstrips, const Vector2& centroid);

#if DEBUG_SHADOW
    // Verification utility function.
    static bool testConvex(const Vector2* polygon, int polygonLength,
            const char* name);
    static void testIntersection(const Vector2* poly1, int poly1Length,
Loading