自己学习写的第一个shader,画个圆


学习到如果需要显示一个圆型的图片,需要自己来写shader,这里是我学习写的第一个shader。

以后会边学习边将写的shader记录下来,也可以不断补充自己学习能力。

Shader "Custom/Circle2" {
	Properties{
		_Color("Color", Color) = (1,0,0,0)
	}
	SubShader{
 
		Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True" }
		Pass{
			ZWrite Off
			Blend SrcAlpha OneMinusSrcAlpha

			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			fixed4 _Color; // low precision type is usually enough for colors

			struct fragmentInput {
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
			};

			fragmentInput vert(appdata_base v)
			{
				fragmentInput o;

				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = v.texcoord.xy - fixed2(0.5,0.5);
 
				return o;
			}

			fixed4 frag(fragmentInput i) : SV_Target{
				float distance = sqrt(pow(i.uv.x, 2) + pow(i.uv.y,2));
		
				if (distance > 0.5f) {
					if (distance < 0.51f) {
						return fixed4(_Color.r* distance, _Color.g* distance, _Color.b* distance, 0.6f);
					}
					else {
						return fixed4(0, 0, 0, 0);
					}
				}
				else {
					return fixed4(_Color.r * distance, _Color.g * distance, _Color.b * distance,1);
				}
			}
			ENDCG
		}
	}
}

开源java recast navmesh寻路库

自己之前写的在java服务器上使用导航网格寻路的库。

底层使用c++提供接口,java层通过jni调用c++接口。

https://github.com/zhukunqian/unity_navmesh_for_java

更多信息直接在github上交流吧。

unity官方出的内存查看工具

https://bitbucket.org/Unity-Technologies/memoryprofiler

Cannot open Eclipse Marketplace 错误

国内网络环境果真复杂。

今天使用eclipse遇到这个问题,推测这个问题只出现在国内。

http://blog.csdn.net/cashcat2004/article/details/43819517

按国内同僚的解决方法:

在eclipse.ini中添加

找来找去没找到解决办法,在stackoverflow中终于看到描述,在eclipse.ini中增加
 -Djava.NET.preferIPv4Stack=true

重启eclipse后顺利连上。

c/c++ 与 lua之前互调的性能测试

完整测试代码如下:

测试目标主要是看看c与lua之前互调的性能如何。

测试结论:c调用lua与lua调用c基本只有一个数量级的性能损失。

从c中调用lua,使用缓存ref的方式,可以提升30%的性能。

#include <lua.h>
#include <lauxlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include "skynet.h"

// 取当前毫秒值
static int
ltime(lua_State *L) {
	struct timeval tv;
	gettimeofday(&tv,NULL);
	lua_pushinteger(L,tv.tv_sec*1000+tv.tv_usec/1000);
	return 1;
}

// 供lua调用,内部无业务逻辑
static int
ltest1(lua_State *L) {
        return 0;
}

// 供lua调用, 内部int相加并返回
static int
ltest2(lua_State *L) {
	int a1=luaL_checkinteger(L,1);
	int a2=luaL_checkinteger(L,2);
	lua_pushinteger(L,a1+a2);
	return 1;
}
// 内部调用lua中方法
static int
ltest3(lua_State *L) {
	lua_getglobal(L,"global_test_func1");
	lua_call(L,0,0);
	return 0;
}
// 内部调用lua中方法,并取得lua中返回值
static int
ltest4(lua_State *L) {
	lua_getglobal(L,"global_test_func2");
	lua_pushinteger(L,1);
	lua_pushinteger(L,2);
	lua_call(L,2,1);
	int sum = (int)lua_tointeger(L, -1); 
	lua_pop(L, 1); 
	lua_pushinteger(L,sum);
	return 1;
}
// 内部调用lua方法10000次
static int
ltest5(lua_State *L) {
	int sum=0;	

	for(int m=0;m<10000000;m++){
        	lua_getglobal(L,"global_test_func2");
        	lua_pushinteger(L,1);
        	lua_pushinteger(L,2);
        	lua_call(L,2,1);
        	sum=(int)lua_tointeger(L, -1);
		lua_pop(L, 1); 
	}

        lua_pushinteger(L,sum);
        return 1;
}
// 和test5一起对比
static int
ltest6(lua_State *L) {
        for(int m=0;m<10000000;m++){
                lua_getglobal(L,"global_test_func2");
                lua_pushinteger(L,1);
                lua_pushinteger(L,2);
                lua_call(L,2,1);
                lua_pop(L, 1);
        }
        lua_pushinteger(L,3);
        return 1;
}
// 和test5一起做对比
static int
ltest7(lua_State *L) {
	int func2_handler;
	lua_getglobal(L,"global_test_func2");
	func2_handler=luaL_ref(L,LUA_REGISTRYINDEX);

	for(int m=0;m<10000000;m++){
		lua_rawgeti(L,LUA_REGISTRYINDEX,func2_handler);
		lua_pushinteger(L,1);
		lua_pushinteger(L,2);
		lua_call(L,2,1);
		lua_pop(L,1);
	}
	
	//luaL_unref(L,LUA_REGISTRYINDEX);
	lua_pushinteger(L,3);
	return 1;
}

// 和test5一起做对比一下
int add(int a,int b){
	return a+b;
}
static int
ltest8(lua_State *L) {
	for(int m=0;m<10000000;m++){
		add(1,2);
	}
	return 0;
}


// full userdata

// light userdata

int
luaopen_perf(lua_State *L) {
        luaL_checkversion(L);
        luaL_Reg l[] = {
		{ "time",  ltime  },
                { "test1", ltest1 }, // 从lua中直接调用c,内部无逻辑
                { "test2", ltest2 },
		{ "test3", ltest3 },
		{ "test4", ltest4 },
		{ "test5", ltest5 },
		{ "test6", ltest6 },
		{ "test7", ltest7 },
		{ "test8", ltest8 },
                { NULL, NULL}
        };
        luaL_newlib(L,l);

        return 1;
}

lua代码:

require "common"

local perf = require "perf"


function global_test_func1()
--	print("global_test_func1")
end
function global_test_func2(a,b)
	return a+b
end
local t1
local t2

t1=perf.time()
for i=1,10000000 do
	perf.test1()
end
t2=perf.time()
print("test1:"..(t2-t1))

t1=perf.time()
for i=1,10000000 do
	perf.test2(1,2)
end
t2=perf.time()
print("test2:"..(t2-t1))

t1=perf.time()
for i=1,10000000 do
	perf.test3()
end
t2=perf.time()
print("test3:"..(t2-t1))

t1=perf.time()
for i=1,10000000 do
	perf.test4()
end
t2=perf.time()
print("test4:"..(t2-t1))

t1=perf.time()
perf.test5()
t2=perf.time()
print("test5:"..(t2-t1))

t1=perf.time()
perf.test6()
t2=perf.time()
print("test6:"..(t2-t1))

t1=perf.time()
perf.test7()
t2=perf.time()
print("test7:"..(t2-t1))

t1=perf.time()
perf.test8()
t2=perf.time()
print("test8:"..(t2-t1))

运行结果:

test1:470
test2:777
test3:1619
test4:1941
test5:1490
test6:1437
test7:675
test8:40

jni错误 UnsatisfiedLinkError

很久没写过jni了。这次项目中用到,准备使用vs2015生成dll,供java调用。我用premake5生成了vs2015项目,但生成出来的dll,无法在java中调用,报以下错误:

Exception in thread "main" java.lang.UnsatisfiedLinkError: RecastLib.hello()V
    at RecastLib.hello(Native Method)
    at RecastLib.main(RecastLib.java:22)

使用vs2015中的工具 dumpbin 查看dll中的方法:

          1    0 00001200 ?Java_RecastLib_hello@@YAXPEAUJNIEnv_@@PEAV_jobject@@@
Z = ?Java_RecastLib_hello@@YAXPEAUJNIEnv_@@PEAV_jobject@@@Z (void __cdecl Java_R
ecastLib_hello(struct JNIEnv_ *,class _jobject *))
          2    1 00001220 ?_Java_RecastLib_hello@@YAXPEAUJNIEnv_@@PEAV_jobject@@
@Z = ?_Java_RecastLib_hello@@YAXPEAUJNIEnv_@@PEAV_jobject@@@Z (void __cdecl _Jav
a_RecastLib_hello(struct JNIEnv_ *,class _jobject *))

发现 vs2015 编译的方法名全部被添加上了@后缀。

正确的应该是:

    ordinal hint RVA      name

          1    0 00011091 Java_RecastLib_hello = @ILT+140(Java_RecastLib_hello)

这是因为 vc++中的 Name Mangling:

	JNIEXPORT void JNICALL Java_RecastLib_hello
		(JNIEnv *, jobject);

如果要导出的cpp中使用了c++特性,即使指定为 extern “C” 也受Name Mangling的影响。

这里可以定义一个  java.def 文件也解决。定义如下:

LIBRARY recastDll
EXPORTS
  Java_RecastLib_hello

然后在vs2015的链接器中定义:

这样导出的函数即不会受name mangling 的影响。

除此之外,还可以使用  RegisterNatives 的方式将函数入口注入java vm(两种试并无性能差异)。

如下:

static JNINativeMethod s_methods[] = {
	{ "jniHello", "()V", (void*)Java_RecastLib_hello },
	{ "jniLoad",  "(Ljava/lang/String;)I", (void*)Java_RecastLib_load },
	{ "jniFind",  "(FFFFFF)Ljava/util/List;", (void*)Java_RecastLib_find }
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved)
{
	JNIEnv* env = NULL;
	if (vm->GetEnv((void**)&env, JNI_VERSION_1_8) != JNI_OK)
	{
		return JNI_ERR;
	}
	jclass cls = env->FindClass("LRecastLib;");
	if (cls == NULL)
	{
		return JNI_ERR;
	}
	int len = sizeof(s_methods) / sizeof(s_methods[0]);
	if (env->RegisterNatives(cls, s_methods, len) < 0)
	{
		return JNI_ERR;
	}
	return JNI_VERSION_1_8;
}

一个hashmap算法

阅读云风开源的AOI实现时,看到里面有一个hashmap算法实现。

https://github.com/cloudwu/aoi

这里记录下分享下其实现

map内部存储是使用数组实现即  map_slot,初始分配16个。容量不足时,以翻倍容量增加,并将对象重新进行分配至新的内存空间。

这里画图举例时以初始容量为8进行原理说明:

1、初始状态,所有slot处于未分配

2、插入A,使用hash算法计算出应该分配在哪个slot上(注:可以考虑添加扰动函数避免比较差的hash算法,这里针对aoi的情况,直接使用了对size取模)

假设对A取模后将其放入第三个slot

3、继续插入B和C,其中B和A取模后 不在相同的slot中。

然后是取模后分配到相同的slot的情况:

实际上两个对象不会存在相同的slot中。

这里如果出现分配的slot中已经存在对象了,比如此时,C分配的第三个slot已经存在A了。

则从数组最尾部向前查找第一个为空的slot,将C放入,并将A.next指向C所在的slot

 

4、继续插入一个和A相同slot的对象时,继续从尾部向前查找一个空的slot,并将A.next指向新分配的slot,新分配的slot.next指向原A.next ( 即C)

5、如果遇到分配的slot被其它slot的对象占用如何处理。

比如,我这里想分配E,取模后应该分配在第七个格子,但第七个格子已经被D占用。

这里采用的方式,是将D取出( 因为D取模不应该分配在第七个格子,只是因为第三个格子被占用了,所以才从尾部查找的一个空闲的格子放D),取出D后将E放后,如下图:

 

这里D被取出应该如何处理,再执行一个第1步,将D放hashmap即可。

 

安利一下云风写的公式计算器

安利一下云风写的公式计算器

http://blog.codingnow.com/2012/10/dev_note_27.html

方便简单,超级好用。

 

 

apk逆向

现在apk加固越来越强了,

除了dex进行加固,连so也一直进行加固,防动态调试及静态分析。

有位大神自己编译了libdvm.so,理论上应该可以将所有的dex进行dump,因为无论在如何加固,最终都会生成完整的dex供系统使用。

https://github.com/zhukunqian/DexExtractor

学习导航网格

现在开发游戏,基本上不存在解决不了的技术难点了,所有的难点都有成熟的解决方案了。

寻路解决方案:导航网格,虽然unity自带导航网格解决方案,但还是希望自己能多学习些知识。

先解决第一步,如何生成导航网格:

这里先从开源的解决方案些开始学习:https://github.com/luzexi/Unity3DNavMesh.

看起来,应该有算法,可以直接生成,还没找到生成算法。如果是三角形,应该可以合并为多边凸边形。