2017-08-30 32 views
7

我試圖使用Android的RenderScript在圖像後面渲染半透明的圓,但從RenderScript內核返回值時事情變得非常錯誤。RenderScript錯誤地操作內核的輸出

這是我的內核:

#pragma version(1) 
#pragma rs java_package_name(be.abyx.aurora) 
// We don't need very high precision floating points 
#pragma rs_fp_relaxed 

// Center position of the circle 
int centerX = 0; 
int centerY = 0; 

// Radius of the circle 
int radius = 0; 

// Destination colour of the background can be set here. 
float destinationR; 
float destinationG; 
float destinationB; 
float destinationA; 

static int square(int input) { 
    return input * input; 
} 

uchar4 RS_KERNEL circleRender(uchar4 in, uint32_t x, uint32_t y) { 
    //Convert input uchar4 to float4 
    float4 f4 = rsUnpackColor8888(in); 

    // Check if the current coordinates fall inside the circle 
    if (square(x - centerX) + square(y - centerY) < square(radius)) { 
     // Check if current position is transparent, we then need to add the background!) 
     if (f4.a == 0) { 
      uchar4 temp = rsPackColorTo8888(0.686f, 0.686f, 0.686f, 0.561f); 
      return temp; 
     } 
    } 

    return rsPackColorTo8888(f4); 
} 

現在,rsPackColorTo8888()功能需要4個與漂浮在0.0和1.0之間的值。然後通過計算每個浮點值255次來找到生成的ARGB顏色。所以給定的浮點數對應顏色R = 0.686 * 255 = 175,G = 0.686 * 255 = 175,B = 0.686 * 255 = 175和A = 0.561 * 255 = 143。

rsPackColorTo8888()函數本身工作正常,但是當發現從內核返回的值uchar4時,會發生一些非常奇怪的事情。 R,G和B值分別變爲Red * Alpha = 56,Green * Alpha = 56和Blue * Alpha = 56,其中Alpha爲0.561。這意味着R,G和B的值不可能比A = 0.561 * 255大。

手動設置輸出,而不是使用rsPackColorTo8888()會產生完全相同的行爲。我的意思是下面的代碼產生完全相同的結果,這反過來證明,證明rsPackColorTo8888()不是問題:

if (square(x - centerX) + square(y - centerY) < square(radius)) { 
    // Check if current position is transparent, we then need to add the background!) 
    if (f4.a == 0) { 
     uchar4 temp; 
     temp[0] = 175; 
     temp[1] = 175; 
     temp[2] = 175; 
     temp[3] = 143; 
     return temp; 
    } 
} 

這是Java代碼從腳本被稱爲:

@Override 
public Bitmap renderParallel(Bitmap input, int backgroundColour, int padding) { 
    ResizeUtility resizeUtility = new ResizeUtility(); 

    // We want to end up with a square Bitmap with some padding applied to it, so we use the 
    // the length of the largest dimension (width or height) as the width of our square. 
    int dimension = resizeUtility.getLargestDimension(input.getWidth(), input.getHeight()) + 2 * padding; 

    Bitmap output = resizeUtility.createSquareBitmapWithPadding(input, padding); 
    output.setHasAlpha(true); 

    RenderScript rs = RenderScript.create(this.context); 

    Allocation inputAlloc = Allocation.createFromBitmap(rs, output); 
    Type t = inputAlloc.getType(); 

    Allocation outputAlloc = Allocation.createTyped(rs, t); 

    ScriptC_circle_render circleRenderer = new ScriptC_circle_render(rs); 

    circleRenderer.set_centerX(dimension/2); 
    circleRenderer.set_centerY(dimension/2); 
    circleRenderer.set_radius(dimension/2); 
    circleRenderer.set_destinationA(((float) Color.alpha(backgroundColour))/255.0f); 
    circleRenderer.set_destinationR(((float) Color.red(backgroundColour))/255.0f); 
    circleRenderer.set_destinationG(((float) Color.green(backgroundColour))/255.0f); 
    circleRenderer.set_destinationB(((float) Color.blue(backgroundColour))/255.0f); 

    circleRenderer.forEach_circleRender(inputAlloc, outputAlloc); 
    outputAlloc.copyTo(output); 

    inputAlloc.destroy(); 
    outputAlloc.destroy(); 
    circleRenderer.destroy(); 
    rs.destroy(); 

    return output; 
} 

當alpha設置爲255(或1.0,如float),返回的顏色值(在我的應用程序的Java代碼中)是正確的。

我做錯了什麼,或者這真的是在RenderScript實現中的某個地方?

注:我已經檢查並在萬普拉斯3T(安卓7.1.1),是Nexus 5(安卓7.1.2),Android的模擬器版本7.1.2和6.0

+0

你能分享你的java代碼和你正在測試的設備嗎? – sakridge

+0

@sakridge謝謝你的回覆!我已將用於測試的Java代碼和設備添加到我的帖子中。 –

+0

我不確定,但也許'fa.a == 0'比較結果爲false,因爲'fa.a'是浮動的。如果您更改爲'in.a == 0',它是否會產生相同的輸出? –

回答

0

而不是驗證了這一行爲將值傳遞給類型:

uchar4 temp = rsPackColorTo8888(0.686f, 0.686f, 0.686f, 0.561f); 

試着創建一個float4並傳遞它。

float4 newFloat4 = { 0.686, 0.686, 0.686, 0.561 }; 
uchar4 temp = rsPackColorTo8888(newFloat4);