繁体   English   中英

Scenekit:使用着色器重新着色漫反射纹理

[英]Scenekit: recolor diffuse texture with shader

我想写一些着色器(表面/片段/ ...)以一些新颜色重新着色我的漫反射纹理。 目前我有这个版本的着色器(我正在尝试实时重新着色纹理):

//sm_surf

uniform vec4 colorTarget; (used in full version)
uniform vec4 colorTint; (used in full version)

vec4 colorTexture = texture2D(u_diffuseTexture, _surface.diffuseTexcoord);
//vec4 colorTexture = _sample.diffuse;//the same result

vec4 tinted = colorTexture;
tinted.r = max(0.0, colorTexture.r - 0.2);
_surface.diffuse = tinted;

这是OpenCV中的代码(我只是事先重新着色纹理并将其用作新的漫反射纹理):

image = cv::imread([path UTF8String], cv::IMREAD_UNCHANGED);
for (int i = 0; i < image.rows; i++) {
    for (int j = 0; j < image.cols; j++) {
        cv::Vec4b pixel = image.at<cv::Vec4b>(i,j);
        pixel[2] = fmin(255, fmax(0, pixel[2] - 50));
        image.at<cv::Vec4b>(i,j) = pixel;
    }
}

cv::imwrite([newPath UTF8String], image);

对于这个测试,我只想减少颜色的R分量。 结果:

OpenCV( 正确

opencv图像

SceneKit( 不正确

SceneKit图片

漫反射纹理包含alpha通道。

(由mnuages解决)此外,似乎在重新着色着色器alpha通道被打破。 使用此着色器:

tinted.r = 1;
tinted.g = 0;
tinted.b = 0;

我的结果是: scenekit

代替: OpenCV的

原始纹理: 原版的

我怎样才能像openCV一样重新着色漫反射纹理?


更新:这是SceneKit着色器和OpenCV的结果(我已从图像中删除了所有透明像素):

OpenCV的: OPENCV

SceneKit: SceneKit

着色器:

vec4 colorTexture = _surface.diffuse;
vec3 tinted = colorTexture.a > 0.0 ? colorTexture.rgb / colorTexture.a : colorTexture.rgb;
if (colorTexture.a == 1) {
    tinted.r = max(0.0, colorTexture.r - 0.2);
} else {
    colorTexture.a = 0;
}
_surface.diffuse = vec4(tinted, 1.0) * colorTexture.a;

和OpenCV代码:

pixel[2] = fmax(0, pixel[2] - 50);//2 because it's bgr in OpenCV
if (pixel[3] != 255) {
    pixel[3] = 0;
}

一些更奇怪的事情:我已经将我的OpenCV代码更改为此以生成新纹理

pixel[0] = 255 - (j % 4) * 30;//b
pixel[1] = 0;//g
pixel[2] = 0;//r
pixel[3] = 255;

如果我像这样改变这个纹理:

if (pixel[0] == 255) {
    pixel[0] = 255;pixel[1] = 255;pixel[2] = 255;
} else {
    pixel[0] = 0;pixel[1] = 0;pixel[2] = 0;
}

我收到这样的smth:

OpenCV的

使用此SceneKit着色器,它应该是相同的:

vec4 colorTexture = _surface.diffuse;
vec3 tinted = colorTexture.rgb; // colorTexture.a == 1
if (tinted.b > 0.99) {
    tinted = vec3(0,0,0);
} else {
    tinted = vec3(1,1,1);
}
_surface.diffuse = vec4(tinted, 1.0) * colorTexture.a;

但我收到了这个:

在此输入图像描述

有一些白色条纹,但太薄了。

我可以通过将条件更改为tinted.b> 0.85来增加它们,但它已经是一个错误,因为_surface.diffuse中的颜色与纹理中的颜色不同。 看起来像SceneKit那样插入纹理或smth。


UPDATE2:

我已经添加了源代码 (1.5Mb)这个问题。 有3个领域:

1顶部)具有原始纹理

2左)纹理通过着色器重新着色(newR = r - 0.2)(浮点)

3右)OpenCV纹理重新着色(newR = r - 51)(uint8)

他们是不同的! 场景不包含任何光/环境/ ...只有3个球体。

SceneKit使用预乘alpha。 以下应该有效:

vec3 tinted = colorTexture.a > 0.f ? colorTexture.rgb / colorTexture.a : colorTexture.rgb;
tinted.r = max(0.0, tinted.r - 0.2);
_surface.diffuse = vec4(tinted, 1.f) * colorTexture.a;

编辑

此代码在您附加的示例中运行良好,但需要对两种技术进行一些更改以匹配100%。 正如在其他SO线程中所解释的,SceneKit着色器在线性颜色空间中操作。

这意味着CPU代码中的51不会映射到GPU代码中的0.2 要获得相同的结果,您需要将采样颜色(线性)转换为有色颜色(非线性),应用色调操作,然后转换回线性。


至于带条纹的示例,这是预期的行为。 Mipmapping将导致灰度值。 如果你移动到足够近的物体,以便1个纹素被投射到屏幕上的~1像素,那么你只会再次得到黑白值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM