解决模型半透明时看到内部结构的问题

  大家好,我是阿赵。
  之前在做钢铁侠线框效果的时候,说到过一种技术,这里单独拿出来再说明一下。
  我们经常要做一些模型半透明效果,比如这个钢铁侠的模型,我做了一个Rim边缘光的效果,边缘的地方亮一点,中间的地方暗一点,然后整个模型呈现半透明的状态。
  在想象中,这个效果只需要计算一个NdotV,然后赋给alpha通道,应该就可以了吧?然后就应该出现了这样的效果??
在这里插入图片描述

  但实际上,如果只是单纯的把alpha通道设置为半透明,是会出现这样的效果的:
在这里插入图片描述

  这是因为,模型内部也是有结构的,当半透明整个模型的时候,这些内部的结构也参与计算,原来由于不透明而被遮挡的部分,也会被看到。
为了解决这个问题,可以加多一个Pass:

Pass
{
Cull off
ZWrite on
ColorMask 0
	CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
			struct appdata
	{
		float4 pos:POSITION;
};
	struct v2f
	{
		float4 pos:SV_POSITION;
	};
	v2f vert(appdata i)
	{
		v2f o;
		o.pos = UnityObjectToClipPos(i.pos);
		return o;
	}
	float4 frag(v2f o):SV_Target
	{
		return float4(0,0,0,0);
	}
		ENDCG
}

这个Pass很简单,主要的部分是:

Cull off
ZWrite on
ColorMask 0

  开启了ZWrite,让它有一个前后遮挡关系,那么内部的东西就被挡住了。然后ColorMask 0是为了让这个挡住内部的部分,是看不见的。
  加完这个Pass之后,就能出现正确的效果了:
在这里插入图片描述

加上了Rim边缘光的完整Shader:

Shader "Rim"
{
	Properties
	{
		_color("颜色",Color) = (1,1,1,1)
		_emiss("增幅",Float) = 1
		_rimPow("边缘强度",Range(0,5)) = 1
		_alpha("alpha",Range(0,1)) = 1
	}

	SubShader
	{
		Pass
		{

		Cull off
			ZWrite on
			ColorMask 0
	CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
			struct appdata
	{
		float4 pos:POSITION;
};
	struct v2f
	{
		float4 pos:SV_POSITION;
	};
	v2f vert(appdata i)
	{
		v2f o;
		o.pos = UnityObjectToClipPos(i.pos);
		return o;
	}
	float4 frag(v2f o):SV_Target
	{
		return float4(0,0,0,0);
	}
		ENDCG
		}

		Pass
		{
		Blend SrcAlpha OneMinusSrcAlpha
	Tags{"Queue" = "Transparent"}
		ZWrite off
		CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
		struct appdata
	{
		float4 pos:POSITION;		
		float4 normal:NORMAL;
};
	struct v2f
	{
		float4 pos:SV_POSITION;
		float3 normal_world:TEXCOORD0;
		float3 view_world:TEXCOORD1;
	};
	float4 _color;
	float _emiss;
	float _rimPow;
	float _alpha;
	v2f vert(appdata i)
	{
		v2f o;
		o.pos = UnityObjectToClipPos(i.pos);
		float3 normalWorld = mul(i.normal, unity_WorldToObject).xyz;
		o.normal_world = normalize(normalWorld);
		float4 worldPos = mul(unity_ObjectToWorld, i.pos);
		float3 viewWorld = _WorldSpaceCameraPos.xyz - worldPos.xyz;
		o.view_world = normalize(viewWorld);
		return o;
	}

	float4 frag(v2f o):SV_Target
	{
		float NdotV = dot(o.normal_world,o.view_world);
		float4 col = _color*_emiss;
		float rim = 1-saturate(NdotV);
		rim = pow(rim, _rimPow);
		col.a = rim*_emiss*_alpha;
		return col;
	}
		ENDCG
		}
	}
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在osgEarth中解决模型透明问题,可以采用以下两种方式: 1. 使用深度排序 深度排序是一种常用的解决模型透明问题的方法。在渲染透明模型,需要按照模型的深度从后往前渲染,这样才能保证前面的模型不会遮挡后面的模型。osgEarth中提供了DepthOffsetNode这个节点,可以用于设置渲染的深度偏移量,从而实现深度排序。 例如,可以将需要渲染的节点加入到DepthOffsetNode中,然后设置合适的深度偏移量,即可实现深度排序。示例代码如下: ``` osg::ref_ptr<osgEarth::Util::DepthOffsetNode> depthOffsetNode = new osgEarth::Util::DepthOffsetNode; depthOffsetNode->addChild(model); depthOffsetNode->setDepthOffset(-1.0f, -1.0f); root->addChild(depthOffsetNode); ``` 在上述代码中,我们创建了一个DepthOffsetNode节点,并将需要渲染的模型节点model添加到其中。然后,我们设置了深度偏移量为(-1.0f, -1.0f),表示在渲染透明模型,深度值需要减去一个较小的偏移量,以保证透明模型能够正确地进行深度排序。最后,我们将DepthOffsetNode节点添加到场景根节点root中即可。 2. 使用Alpha测试 另一种解决模型透明问题的方法是使用Alpha测试。Alpha测试是一种在渲染透明模型,根据像素的Alpha值来决定是否进行绘制的方法。在osgEarth中,可以使用StateSet来设置Alpha测试相关的状态,例如设置Alpha测试函数和Alpha测试值等。 示例代码如下: ``` osg::ref_ptr<osg::StateSet> stateSet = model->getOrCreateStateSet(); stateSet->setAttributeAndModes(new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.5f), osg::StateAttribute::ON); stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); ``` 在上述代码中,我们首先获取或创建模型的StateSet,然后设置Alpha测试函数为GREATER,Alpha测试值为0.5f。这表示只有像素的Alpha值大于0.5f,才会进行绘制。最后,我们使用setMode()函数将混合模式设置为ON,表示需要进行混合处理。 总之,这两种方法都可以解决模型透明问题,在具体应用中可以根据情况选择。需要注意的是,深度排序需要考虑场景中所有透明物体的深度关系,而Alpha测试只是根据像素的Alpha值进行判断,因此在场景比较复杂的情况下,深度排序可能更加合适。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值