ImageTracking_Coloring3D

演示如何创建“AR涂涂乐”,使绘图书中的图像实时“转换”成3D

sample可以捕捉相机画面作为模型贴图,达到即画即贴的效果。

用法

../../_images/image_231.png

FindBear/Freeze/Thaw:未找到bear图像时会显示FindBear。Freeze表示点击button将会固定熊的贴图。当显示Thaw表示点击button将会固定熊的贴图恢复为动态抓取相机图像状态。

详解

映射target区域的相机图像到模型上

使用 CameraImageRenderer.RequestTargetTexture 来注册获取纹理的handler来获取camera图像的纹理并在shader中使用它。

CameraRenderer.RequestTargetTexture((camera, texture) => { renderTexture = texture; });

获取当前场景中识别图四个角点的world transform。

var halfWidth = 0.5f;
var halfHeight = 0.5f / imageTarget.Target.aspectRatio();
Matrix4x4 points = Matrix4x4.identity;
Vector3 targetAnglePoint1 = imageTarget.transform.TransformPoint(new Vector3(-halfWidth, halfHeight, 0));
Vector3 targetAnglePoint2 = imageTarget.transform.TransformPoint(new Vector3(-halfWidth, -halfHeight, 0));
Vector3 targetAnglePoint3 = imageTarget.transform.TransformPoint(new Vector3(halfWidth, halfHeight, 0));
Vector3 targetAnglePoint4 = imageTarget.transform.TransformPoint(new Vector3(halfWidth, -halfHeight, 0));
points.SetRow(0, new Vector4(targetAnglePoint1.x, targetAnglePoint1.y, targetAnglePoint1.z, 1f));
points.SetRow(1, new Vector4(targetAnglePoint2.x, targetAnglePoint2.y, targetAnglePoint2.z, 1f));
points.SetRow(2, new Vector4(targetAnglePoint3.x, targetAnglePoint3.y, targetAnglePoint3.z, 1f));
points.SetRow(3, new Vector4(targetAnglePoint4.x, targetAnglePoint4.y, targetAnglePoint4.z, 1f));
material.SetMatrix("_UvPints", points);
...

为了使用这块区域的图像作为模型贴图,需要在shader中计算像素的屏幕位置并获取纹理数值。

v2f vert (appdata_base v)
{
    v2f o;
    o.pos = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);

    float4 top = lerp(_UvPints[0], _UvPints[2], o.uv.x);
    float4 bottom = lerp(_UvPints[1], _UvPints[3], o.uv.x);
    float4 fixedPos = lerp(bottom, top, o.uv.y);
    float4x4 Rendering_Matrix_VP = mul(_RenderingProjectMatrix, _RenderingViewMatrix);
    o.fixedPos = ComputeGrabScreenPos(mul(Rendering_Matrix_VP, fixedPos));
    return o;
}

float4 frag (v2f i) : COLOR
{
    float2 coord = i.fixedPos.xy / i.fixedPos.w;
    ...
    return tex2D(_MainTex, coord);
}

这里还有一个特殊问题需要处理。Unity在使用插件创建的RenderTexture时无法隐藏不同平台的不同,因此在渲染管线中使用这个纹理时,你需要正确处理不同渲染API下 render texture坐标的不同

float4 frag (v2f i) : COLOR
{
    float2 coord = i.fixedPos.xy / i.fixedPos.w;
#if SHADER_API_METAL
#if UNITY_UV_STARTS_AT_TOP
    if (_MainTex_TexelSize.y < 0.0)
        coord.y = 1.0 - coord.y;
#endif
    coord.x = 1.0 - coord.x;
#else
#if UNITY_UV_STARTS_AT_TOP
    coord.y = 1.0 - coord.y;
#endif
#endif

    return tex2D(_MainTex, coord);
}

停止实时纹理更新

某些情况下,可能会需要使用在某些视角或特定时间点的图像作为模型贴图。

freezedTexture = new RenderTexture(renderTexture.width, renderTexture.height, 0);
Graphics.Blit(renderTexture, freezedTexture);
material.SetTexture("_MainTex", freezedTexture);