Unity3D Geomerty Shader

Geomerty Shader 是 SM4.0 Directx 9.0c 中引用的新技术, 它的位置位于 Vertex Shader 和 Fragment Shader 之间, 可以对一组(多个)顶点进行编程

Geometry Shader 可以自定义输出方式
PointStream
LineStream
TriangleStream
分别是 点,线,面
这样如果想做线框模式渲染,就非常的简单

上个线框模式图
LineStream


请不要无脑复制转载本文, 由 dreamfairy 原创, 转载请注明出处 本文地址 http://www.dreamfairy.cn/blog/2016/06/05/unity3d-geomerty-shader/
一个和 Unlit Shader 一样效果的 GS Shader 如下

Shader "Aoi/GSShader"
{
	Properties
	{
		_SpriteTex("Base (RGB)", 2D) = "white" {}
		_Size("Size", Range(0, 3)) = 0.5
		_Tess("Tess", float) = 1
	}

		SubShader
	{
		Pass
	{
		Tags{ "RenderType" = "Opaque" }
		LOD 200

		CGPROGRAM
		#pragma target 5.0
		#pragma vertex VS_Main
		#pragma fragment FS_Main
		#pragma geometry GS_Main
		#include "UnityCG.cginc"

		// **************************************************************
		// Data structures                                              *
		// **************************************************************
	struct GS_INPUT
	{
		float4  pos     : POSITION;
		float3  normal  : NORMAL;
		float2  tex0    : TEXCOORD0;
	};

	struct FS_INPUT
	{
		float4  pos     : POSITION;
		float2  tex0    : TEXCOORD0;
	};


	// **************************************************************
	// Vars                                                         *
	// **************************************************************

	float _Size;
	float4x4 _VP;
	sampler2D _SpriteTex;
	float4 _SpriteTex_ST;

	// **************************************************************
	// Shader Programs                                              *
	// **************************************************************

	// Vertex Shader ------------------------------------------------
	GS_INPUT VS_Main(appdata_base v)
	{
		GS_INPUT output = (GS_INPUT)0;

		output.pos = v.vertex;
		output.normal = v.normal;
		output.tex0 = v.texcoord;

		return output;
	}



	// Geometry Shader -----------------------------------------------------
	[maxvertexcount(4)]
	void GS_Main(triangle GS_INPUT p[3], inout TriangleStream<FS_INPUT> triStream)
	{
		for (int i = 0; i < 3; i++) {
			FS_INPUT pIn;
			pIn.pos = mul(UNITY_MATRIX_MVP, p[i].pos);
			pIn.tex0 = p[i].tex0;
			triStream.Append(pIn);
		}
	}



	// Fragment Shader -----------------------------------------------
	float4 FS_Main(FS_INPUT input) : COLOR
	{
		return tex2D(_SpriteTex, input.tex0);
	}

		ENDCG
	}
	}
}

现在来介绍下GS Shader开启的方法

首先要定义2个预处理指令

#pragma target 4.0
#pragma geometry GS_Main

因为 gs shader 是在 sm 4.0 下才支持的, 如果不定义 target,可能会导致 shader.supported api 没效果, 导致部分低端设备的 fallback shader无法调用

之后就是 gs shader 的主体 gs_main 的代码

[maxvertexcount(4)] //当处理的顶点数 >= (数量) 才进行渲染

void GS_Main(triangle GS_INPUT p[3], inout TriangleStream<FS_INPUT> triStream)
//参数0 triangle GS_INPUT p[3] 表示输入数据类型转换成什么格式进行处理
//参数1 inout TriangleStream<FS_INPUT> triStream 输入输出流, 将处理的好的数据 append 到流中,完成处理
i.e 
			FS_INPUT pIn;
			//pIn.pos = mul(UNITY_MATRIX_MVP, float4(localPos, 1.0));
			pIn.pos = mul(UNITY_MATRIX_MVP, p[i].pos);
			pIn.tex0 = p[i].tex0;
			triStream.Append(pIn);

在这个 Shader 基础上,我们可以直接通过修改 inout 的输出类型,来输出不同渲染模式, 比如将
inout TriangleStream 修改为 inout PointStream
那么就可以看到 以顶点为单位, 中间没有像素插值的 皮卡丘

PointStream

GS Shader 应用的场景

1.基于模型形状,以顶点为单位的 Billboard
TriangleStream_Billboard

如图,模型本身不是 Billboard, 但是构成模型的每个 Quad 却是 Billboard

只有VS 和 GS 部分的代码和 上面的 GS Shader 有区别

	// Vertex Shader ------------------------------------------------
	GS_INPUT VS_Main(appdata_base v)
	{
		GS_INPUT output = (GS_INPUT)0;

		//output.pos = v.vertex;
		output.pos = mul(_Object2World, v.vertex);
		output.normal = v.normal;
		output.tex0 = v.texcoord;

		return output;
	}
	// Geometry Shader -----------------------------------------------------
	[maxvertexcount(4)]
	void GS_Main(point GS_INPUT p[1], inout TriangleStream<FS_INPUT> triStream)
	{
		float3 up = float3(0, 1, 0);
		float3 look = _WorldSpaceCameraPos - p[0].pos;
		look.y = 0;
		look = normalize(look);
		float3 right = (cross(up, look));

		float halfS = 0.5f * 0.1;

		float4 v[4];
		v[0] = float4(p[0].pos + halfS * right - halfS * up, 1.0f);
		v[1] = float4(p[0].pos + halfS * right + halfS * up, 1.0f);
		v[2] = float4(p[0].pos - halfS * right - halfS * up, 1.0f);
		v[3] = float4(p[0].pos - halfS * right + halfS * up, 1.0f);

		float4x4 vp = mul(UNITY_MATRIX_MVP, _World2Object);
		FS_INPUT pIn;
		pIn.pos = mul(vp, v[0]);
		pIn.tex0 = p[0].tex0;
		triStream.Append(pIn);

		pIn.pos = mul(vp, v[1]);
		pIn.tex0 = p[0].tex0;
		triStream.Append(pIn);

		pIn.pos = mul(vp, v[2]);
		pIn.tex0 = p[0].tex0;
		triStream.Append(pIn);

		pIn.pos = mul(vp, v[3]);
		pIn.tex0 = p[0].tex0;
		triStream.Append(pIn);
	}

分析这个Shader 的做法。 为了制作 Quad Billboard, 输入输出类型 肯定是 TriangleStream, 因为一个Quad 是由2个三角形组成, 也因此 [maxvertexcount(4)] 数值为4, 4个顶点构成2个三角形,处理完4个顶点就可以输出了。

因为是将每个顶点,扩展为4个顶点做Quad 所以 输入类型为 point GS_INPUT p[1] 一次处理一个顶点

		float4 v[4];
		v[0] = float4(p[0].pos + halfS * right - halfS * up, 1.0f);
		v[1] = float4(p[0].pos + halfS * right + halfS * up, 1.0f);
		v[2] = float4(p[0].pos - halfS * right - halfS * up, 1.0f);
		v[3] = float4(p[0].pos - halfS * right + halfS * up, 1.0f);

已当前顶点位置抽象为中心点,在它周围创建4个新的顶点,构成Quad.

你可能会问我,如果你想把 point GS_INPUT p[1] 改成 point GS_INPUT p[4] 行不行,已自身已有的4个顶点,来组成一个Quad. 我只能说,不行
因为 GS_INPUT p[Number] 的数量是跟 输入格式绑定的 point 格式 只能是1, line 格式 只能是2, triangle 格式只能是 3

至于用自身4个顶点来做quad 行不行呢, 当然是勉强可以,只是要换种方式做, 就是只保留一个顶点,忽略剩下的三个顶点,然后自己重建它们

添加一个结构体,用来创建Quad

	static const float4 Quad_POSITION[4] = 
	{
		float4(0, 0, 0, 0),
		float4(0, 0, -1, 0),
		float4(1, 0, 0, 0),
		float4(1, 0, -1, 0),
	};

ps:因为我的皮卡丘模型是颠倒的,所以需要 z 轴 * -1. 如果你是正常模型,把 -1 改为 1 即可

在Shader上添加

float4 _SpriteTex_ST_TexelSize;

在构建的Quad 上,也需要重建 uv, 因此需要 uv 的递进值
之后是 GS Shader

	// Geometry Shader -----------------------------------------------------
	[maxvertexcount(4)]
	void GS_Main(triangle GS_INPUT p[3], inout TriangleStream<FS_INPUT> triStream)
	{
		float4 vertex = float4(p[0].pos.x, p[0].pos.y, p[0].pos.z, 1);
		float2 uv = p[0].tex0;
		for (int i = 3; i >= 0; i--) {
			FS_INPUT pIn;
			pIn.pos = mul(UNITY_MATRIX_MVP, vertex + Quad_POSITION[i].xyzw * 0.01);
			pIn.tex0.xy = uv + Quad_POSITION[i].xy * _SpriteTex_ST_TexelSize.xy;
			triStream.Append(pIn);
		}
	}

TriangleStream1

2. 为细分曲面做一些前置计算 (这需要 SM 5.0 dx11)
3. 使用一个Pass 绘制 Cubemap

不过GS 的性能好低,到DX11 还是很低, 目前仅限做粒子和一些变形渲染上用咯
by the way 由于 unity3d 的限制 ,没有修改 PointSize, 因此使用 PointStream 输出模型后,模型像素点大小没法缩放 ╮(╯▽╰)╭

Unity3D 中的 X-Ray 透视效果

unity_xray

感觉是第三次写Xray了,最早是 stage3d, 然后是 havok, 现在是u3d… 真是闲的蛋疼。。。
不过u3d 写shader 真是比 havok 方便多了, 比如混合模式,深度检测方式都可以直接和 shader一起写,而havok 中还要去shader外部配置。。

直接上完整shader好了,渲染2次,1次深度测试以小于缓冲区的深度通过,绘制透视部分, 第二次正常渲染

请不要无脑复制转载本文, 由 dreamfairy 原创, 转载请注明出处 本文地址 http://www.dreamfairy.cn/blog/2016/05/27/unity3d-%e4%b8%ad%e7%9a%84-x-ray-%e9%80%8f%e8%a7%86%e6%95%88%e6%9e%9c/

Shader “Aoi/XRayShader”
{
Properties
{
_MainTex(“Texture”, 2D) = “white” {}
_RayColor(“RayColor”, COLOR) = (0,0,1,0)
}
SubShader
{
Pass
{
Tags{ “RenderType” = “Transparent” “Queue” = “Transparent” }
Blend One OneMinusSrcAlpha
Cull Back
ZTest Greater
ZWrite Off

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog

#include “UnityCG.cginc”
#include “Lighting.cginc”

struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 normal : NORMAL;
};

struct v2f
{
UNITY_FOG_COORDS(0)
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD1;
float4 diff : TEXCOORD2;
};

v2f vert(appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;

float3 worldNormal = normalize(mul(_Object2World, float4(v.normal.xyz,0)).xyz) * -1; //将法线转换到世界空间, * -1 是为了有外轮廓的效果,因此将法线翻转
float3 viewDirection = normalize(_WorldSpaceCameraPos); //将视野也转到相同的世界空间
o.diff = max(0, dot(viewDirection, worldNormal)); //计算视野和法线的夹角 将垂直的部分不填色

return o;
}

uniform float4 _RayColor;

fixed4 frag(v2f i) : SV_Target
{
_RayColor *= i.diff.x;
return _RayColor;
}
ENDCG
}

Pass
{
Tags{ “RenderType” = “Opaque” }
ZWrite On
ZTest LEqual

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog

#include “UnityCG.cginc”

struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};

struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};

sampler2D _MainTex;
float4 _MainTex_ST;

v2f vert(appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}

fixed4 frag(v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}

}
}

浅谈 Unity3D 的 RenderQueue

突然发现换了阿里云的空间就支持 wp的 中文链接了,好赞。。

言归正传,今天做了一个 光晕的效果, 参考的是Nehe 的Opengl教程, 以前一直没做过这个东西就有点好奇,做完后,发现效果特别赞,又简单,但是遇到了 RenderQueue 的一些bug,记录一下。

unity3d_overlay2

有人肯定会说Unity3d 自身可以创建 LensFlare 效果,为什么还要自己搞,我看了下,貌似 LensFlare必须绑定到 Light 上才有效果,而且准备素材的时候很麻烦,简单的黑白图调色都不行,还是自己写吧。

再说说 Nehe教程中判断 某点 是否在视野内, 是通过获取相机的视椎体,然后监测某点是否在视椎体的6个平面内。。。 感觉这个真麻烦,直接将 点 通过 mvp 矩阵转换到屏幕空间,然后判断该点坐标是否 x,y > 0 && x,y < 1 即可。 好吧,又跑题了。。。u3d_overlay_1

如图,编写了一个Shader, RenderQue=”Overlay” ZWrite Off ZTest Off
发现在场景有其他 GameObject 的地方,图片都能正确的挡住它们,但是当背景为天空盒的时候,确被天空盒挡住了, 根据常识理解这不应该, 天空盒应该是在实体层渲染的, 不应该会挡住, 然后在 Shader 中就算改成 Overlay+99999 也是毫无效果。。。


请不要无脑复制转载本文, 由 dreamfairy 原创, 转载请注明出处 本文地址 http://www.dreamfairy.cn/blog/2016/05/25/%e6%b5%85%e8%b0%88-unity3d-%e7%9a%84-renderqueue/
Shader就是这个咯

Shader "Unlit/Overlayer2"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_Color("Color", Color) = (1,1,1,1)
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" "Queue"="Overlay+99999"}
		//Blend SrcAlpha One
		ZWrite Off
		ZTest Off

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			// make fog work
			#pragma multi_compile_fog
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				UNITY_FOG_COORDS(1)
				float4 vertex : SV_POSITION;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			float4 _Color;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				UNITY_TRANSFER_FOG(o,o.vertex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				// sample the texture
				fixed a = tex2D(_MainTex, i.uv).r;
				fixed4 col = fixed4(_Color.rgb * a, a);
				// apply fog
				UNITY_APPLY_FOG(i.fogCoord, col);
				return col;
			}
			ENDCG
		}
	}
}

于是上 u3d 的官网论坛逛逛,发现一群老外在那边喊 ZTest Always 啊, ZWrite On 啊。。
拜托,如果开启了 ZTest Always 的话,就会影响到UI的层级关系了,因为UI总是 ZTest Always保持最上的, 一个场景特效的问题应该在场景内解决, ZWrite On 更不行了,会导致半透明部分遮挡的天空盒部分无法渲染。

然后写了个 Debug Scrpit做测试,看看RenderQueue 是多少。

using UnityEngine;
using System.Collections;

public class GetQueue : MonoBehaviour {
	public int Queue;
	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
		Renderer renderer = this.gameObject.GetComponent<Renderer> ();
		Queue = renderer.sharedMaterial.renderQueue;
	}
}

看完居然是后,发现 Queue 居然不是 4000(Overlay)+99999.. 好吧,你赢咯.
百思不得其解的情况下,我给材质重设了一次Shader, 再次启动居然ok了。。。 绕了好大一圈。。。
改了Shader居然不会刷新,必须手动设置一次, 关了Unity 重开都不会刷新。。。

在Havok Vision 中创建后期处理效果

如果有人参考了 官方手册的教程 Tutorial: Creating Custom Post-Processing Effects
然后使用 PA 的 vGameSolutionCreator 默认设置创建项目,会发现运行报错
active renderer does not provide all buffers required by the post processor.Execute

经过debug,发现默认创建的render node 实际上是 VMobileForwardRenderingSystem
它只支持一个bufferflag 就是 VBUFFERFLAG_FINALCOLOR

让我们从头开始
postprocessing
打开 VForge 编写我们的后期处理特效,这次范例就用径向模糊(Dx9,Dx11)
继续阅读在Havok Vision 中创建后期处理效果

在Havok Project Anarchy 中创建透视效果

先晒晒收到的Havok 活动抱枕

h1h2

进入正题

本人首发于http://www.anarchy.cn/ 本人博客 http://www.dreamfairy.cn 转载请著名出处
很多人都见过 RPG Sample 中的 XRay 透视效果, 像这样

h3

英雄在被铁链遮挡的部位会呈现透视的效果,而不是被遮挡。

这个效果需要2个Pass
即一个用来呈现被遮挡时的表现
一个用来呈现未被遮挡时的表现
继续阅读在Havok Project Anarchy 中创建透视效果

在Havok Vision中编写 NavMesh 寻路

这篇教程的前提是已经掌握了如何在PA中创建NavMesh,如果你还不会,请参考官方的教程
http://www.anarchy.cn/portal.php?mod=view&aid=15

首先创建我们的Hero, 寻路的主角
我选择在代码中创建的方式,而创建坐标是在PA中创建一个 名为 Spawn的模型,给它一个 key 比如 9527 . 然后我们在 Vision中通过key 找到它

1
2
3
4
5
6
7
8
9
 VisBaseEntity_cl * pPlayerSpawn = Vision::Game.SearchEntity("9527");
     if(NULL != pPlayerSpawn){
         Vision::Message.Add(1, "Try To CreatePlayer");
         hkvVec3 pos = pPlayerSpawn->GetPosition();
         hkvVec3 rot = pPlayerSpawn->GetOrientation();
         m_playerEntity = SpawnPlayer("Models/Eddy Export/Eddy.MODEL",pos, rot);
         //把出生点隐藏掉
         pPlayerSpawn->SetVisibleBitmask(0);
     }

SpawnPlayer 函数的内如

1
2
3
4
5
6
7
    VisBaseEntity_cl * tmp = Vision::Game.CreateEntity("VisBaseEntity_cl", position, prefabName);
    if(NULL != tmp){
        tmp->SetOrientation(orientation);
        m_vPos = tmp->GetPosition();
        m_vRot = tmp->GetOrientation();
    }
    return tmp;

有了Hero后,就可以开始创建寻路AI了。
这里有见基础的组件来做

1
2
3
4
5
6
7
8
9
10
11
12
    m_aiSteering = new vHavokAiSteering();
    m_aiSteering->SetRadius(40);
    m_aiSteering->SetDesiredSpeed(400);
    m_aiSteering->SetEntityPivotHeight(0);
    m_aiSteering->SetSensorSize(500);
    m_aiSteering->SetTurnRadius(40);
    m_aiSteering->SetKinematicConstraint(vHavokAiSteering::CONSTRAINT_LINEAR_AND_ANGULAR);
    m_aiSteering->SetMaximalAngularVelocity(4);
    m_aiSteering->SetMaximalAcceleration(2000);
    m_aiSteering->SetMaximalDeceleration(3000);

    m_playerEntity->AddComponent(m_aiSteering);

接下来要做的事情显而易见,就是点击屏幕,然后算出投影到NavMesh上的坐标,然后寻路过去呗
对于lua 来说有个 Sceene:PickPoint. cpp 也有可惜没有 export dll 没事,我们抄写出来就行

like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
hkvVec3 * MyGameManager::PickPoint( float x, float y, float fMaxDist )
{
    hkvVec3 *result = NULL;

    hkvVec3 traceStart = Vision::Camera.GetCurrentCameraPosition();
    hkvVec3 traceDir;
    Vision::Contexts.GetCurrentContext()->GetTraceDirFromScreenPos(x, y, traceDir, fMaxDist);
    hkvVec3 traceEnd = traceStart + traceDir;

    hkVector4 s;
    vHavokConversionUtils::VisVecToPhysVecWorld(traceStart, s);
    hkVector4 e;
    vHavokConversionUtils::VisVecToPhysVecWorld(traceEnd, e);

    hkaiNavMeshQueryMediator::RaycastInput rcInput;
    rcInput.m_from = s;
    rcInput.m_to = e;

    hkaiNavMeshQueryMediator::HitDetails hitInfo;

    const hkaiNavMeshQueryMediator* mediator = vHavokAiModule::GetInstance()->GetAiWorld()->getDynamicQueryMediator();
    hkBool didHit = mediator->castRay( rcInput, hitInfo );

    if (didHit)
    {
        hkVector4 hitPoint;
        hitPoint.setInterpolate4( s, e, hitInfo.m_hitFraction);

        result = new hkvVec3(0);
        vHavokConversionUtils::PhysVecToVisVecWorld(hitPoint, *result);
    }

    return result;
}

最后的最后,在Run函数中检测鼠标是否按下,然后做这样的事情

1
2
3
4
5
6
7
8
if(bOnMouseClick){
                    hkvVec3 * goal = PickPoint(posX, posY);
                    if(goal){
                        m_aiSteering->RequestPathTo(*goal);
                    }else{
                        m_aiSteering->CancelPath();
                    }
                }

这个时候如果你想说,我看不到鼠标咋办? 很好办,自己画一个

1
2
3
4
5
6
7
8
void MyGameManager::DrawCursor(float posX, float posY)
{
    Vision::Game.DrawSingleLine2D(posX,posY,posX + 10, posY + 5, V_RGBA_GREEN);
    Vision::Game.DrawSingleLine2D(posX,posY,posX + 5, posY + 10, V_RGBA_GREEN);
    Vision::Game.DrawSingleLine2D(posX + 10,posY + 5,posX + 5, posY + 10, V_RGBA_GREEN);

    Vision::Message.Print(1,200,500,"Mouse Pos X %f Y %f", posX, posY);
}

最后如果你又问,我的Hero在寻路的时候不会转向怎么办,也好办,写个Hkt 或者,用代码来动态算
在 Run 函数中加入如下

1
2
3
4
5
6
7
8
9
10
                if(m_aiSteering->HasPath()){
                    hkvVec3 lastPos = m_vPos;
                    hkvVec3 nowPos = m_playerEntity->GetPosition();
                    float dx = lastPos.x - nowPos.x;
                    float dy = lastPos.y - nowPos.y;
                    float degree = hkvMath::atan2Deg(dy,dx) - 90;
                    m_vRot = hkvVec3(degree,0,0);
                    m_eState = ROLE_RUN;
                }
                                m_playerEntity->SetOrientation(m_vRot);

如果你问我Hkt 怎么做转向? 改日再说吧,我要睡觉啦。

Havok Vision Project Anarchy 创建项目的二三事

最近开始深入开发C++ 的 Havok Vision, 遇到许多许多的坑,整个互联网上居然都没有前人列出来,于是我决定把遇到的坑都填上,造福你们这些看到本文章的有缘人

1.从project anarchy生成项目的时候,如果要使用ScaleForm ,请务必勾选 Enable ScaleForm Support
2.如果运行demo, 遇到无法加载 vHavokAI.Plugin 或者 vHavokBehavior.Plugin 那是因为模板文件没有把这个文件拷贝的项目的运行目录下,需要到你 vForge.exe 运行目录下找到这2个文件,然后拷贝到你项目的生成目录下
3.一旦使用了 vHavokAI 相关API 就会报错,找不到函数实现的错误, 比如使用的 vHavokAIModule 等模块, 那么需要编译一下它的依赖lib. 这个项目在类似这样的目录下 HavokVisionSDKWorkspaceWin32_VS2012_win7_DX9HavokVision_Editor_Win32_VS2012_win7_DX9.sln 找到你项目依赖的lib平台 dx9,dx11 x32 x64 等,把它们生成一下
4.如果做完第3点后,仍然报错,在使用AI相关的项目上做如下设置 项目->属性->C/C++->预处理器->预处理器定义 加上一个宏 VHAVOKAIMODULE_IMPORTS 即可 Behavior有问题的话,同理

etc…

最近无聊写了个Havok Demo,顺便发出来好了

话说Havok 自从 project anarchy 出来后,就没看到任何教程=。=, 社区也几乎没人。
切官网文档都是Lua的。 我写个C++的Demo 真是困难耶. 不过慢慢找到诀窍了。

by the way
百度BCS 貌似图标全部失效了, 之前的Flash档Demo貌似加密无法解析了, 空间貌似访问的速度好慢。。。 时候全部换掉了 =。=

然后上个截图 < 西游记之大圣归来>
monkeyking

看完表示很值票价,同时期评分最高有木有,大家快去看。

好,进入正题~
继续阅读最近无聊写了个Havok Demo,顺便发出来好了

Unity3D中使用有米广告SDK By Android Studio

最近准备对接广告SDK, 网路上搜索全是有米SDK的,fuck~ 有些还是几年前的版本
于是我决定作死,使用最新的 Android Studio 1.2.2 来打包Jar. 对接有米SDK, Unity3D 使用 5.1.2 版本,顺便试下调用Android 函数.

打开创建一个Project
create_project

这里注意下下面的包名 dreamfairy.com.adtest 之后要在Unity中填,要一模一样
点击Next

select_devices

什么都不用改,直接Next

add_activity

这里选择 Blank Activity 后点击 Finish 等 项目初始化后,开始正式工作
继续阅读Unity3D中使用有米广告SDK By Android Studio