你是不是想过要做自定义的子弹孔、喷漆或者一些自定义的痕迹呢?

如果按照HL引擎的基本FA,首先要在decals.wad里加入我们自定义的纹理,然后利用gEngfuncs.pEfxAPI->R_DecalShoot或者服务端发送TE_DECAL消息来使用。

这种方法有许多限制,首先你不能往一个WAD文件加太多纹理,其次,WAD只能保存索引色的纹理(图像质量非常LOW)。如果我们要更进一步定制,比方说做个会动的喷漆,那么WAD就不行了。

首先我要声明一下名词:

Decal 即 贴花,指贴在地图表面的图像。

这篇文章给出一种方法让你能够使用自己加载的纹理进行贴花,还可以做到实时更新贴花,做出动态效果。

首先我们认识一下引擎提供的一个贴花函数 R_DecalShoot ,它的原型如下:

void R_DecalShoot( int textureIndex, int entity, int modelIndex, vec3_t position, int flags )

第1个参数 textureIndex 通常你必须这样来获得: pEfxAPI->Draw_DecalIndex( pEfxAPI->Draw_DecalIndexFromName("{yblood6") ) ,这个名称必须是decals.wad里存在的,否则函数将会失败。

第2个参数 entity 贴花将会贴到该实体的模型上,该实体的模型必须是 mod_brush ,你必须提供这个实体,否则函数将会失败。

第3个参数 modelIndex ,如果 entity 参数提供的实体没有设置模型,将会使用此参数指定的模型 ,否则忽略此参数。

第4个参数 position 贴花的坐标。世界坐标。

第5个参数 flags 该参数可以指定为 FDECAL_ 相关的标志。

我们并不想通过这个 textureIndex 来指定纹理,我们需要自己改造一个 R_DecalShoot 。非常幸运的是,HL引擎的写法让我们可以简单地实现。

我们来看看 R_DecalShoot 内部是怎么实现的:

可以看到,它首先通过调用一个名为 Draw_DecalTexture 的函数获得一个 texture_t 的指针,然后将该指针传给一个名为 R_DecalShoot_ 的函数(注意,后面有个下划线)。

可以猜测,我们自己创建一个 texture_t 然后调用 R_DecalShoot_ 应该是没问题的。

所以我先提供这个结构体的定义:

typedef struct texture_s
{
char name[];
unsigned int width, height;
unsigned int gl_texturenum;
void *texturechain;
int anim_total;
int anim_min, anim_max;
void *anim_next;
void *alternate_anims;
unsigned int offsets[];
void *pPal;
} texture_t;

看似很复杂,其实只需要指定其中的 width、height、gl_texturenum 这3个即可,其它的全部设为0。

既然我们要调用 R_DecalShoot_ ,那么就得知道它的原型:

void R_DecalShoot_( texture_t *ptexture, int textureIndex, int entity, int modelIndex, float *position, int flags, float scale )

可以看出这个函数和 R_DecalShoot 非常像,但聪明的你可能已经发现了问题,既然都有一个 ptexture 来指定纹理了,干嘛还需要一个 textureIndex 呢,不是多此一举吗?

解释如下:引擎为了节省内存占用,时不时会将一些不经常访问的资源丢弃掉,这时 ptexture 就可能会被丢掉(释放掉),所以引擎只为贴花存储一个 textureIndex 当引擎绘制贴花时,

会使用 textureIndex 来查找一个 texture_t ,如果这个 texture_t 已经被丢弃了,那么引擎会重新载入它。

可能你还有疑问,既然传 textureIndex 一本万利,干嘛要传 ptexture 呢。那是因为 R_DecalShoot_ 需要 texture_t 里的 width 和 height 。

但是,根据上面的解释,引擎在绘制贴花时才通过 textureIndex 来查找 texture_t ,所以我们需要Hook那个查找函数,返回我们自己的 texture_t 才行。

那个函数上面已经出现过了,它就是 Draw_DecalTexture ,它的原型如下:

texture_t * Draw_DecalTexture( int textureIndex )

你可以看到它只有一个 int 参数,当引擎需要绘制一个贴花时,会调用这个函数来获取一个 texture_t ,而参数的 textureIndex 正是我们传入 R_DecalShoot 的那个。

现在尝试一下,首先我们要自己造一个 R_DecalShoot ,例如:

void R_My_DecalShoot( texture_t *ptexture, int textureIndex, int entity, int modelIndex, float *position, int flags )
{
R_DecalShoot_( ptexture, textureIndex, entity, modelIndex, position, flags, 1.0f );
}

然后还要Hook Draw_DecalTexture 函数,例如:

texture_t * Draw_DecalTexture( int textureIndex )
{
if ( textureIndex == )
{
return &g_my_texture;
} return g_callback_Draw_DecalTexture( textureIndex );
}

我这里判断 textureIndex 如果是999那么返回我们自己创建的一个 texture_t

然后调用 R_My_DecalShoot ,例如:

void Decal_Test( void )
{
R_My_DecalShoot( &g_my_texture, , ent, , tr.endpos, );
}

这里我给 textureIndex 传了 999 这个数值,如果贴花创建成功,引擎会把这个值存储到引擎内部的神秘数组里。

等到引擎需要绘制这个贴花时,便会调用 Draw_DecalTexture 来获取 texture_t 用于绘制。这时我们检查 textureIndex 是不是我们定义的,

如果是我们定义的,那就返回我们自己创建的 texture_t 给引擎绘制。

大功告成!

附上一张效果图:

附加:

你可能想立刻删掉一个贴花,那么你可以使用如下方法:

gEngfuncs.pEfxAPI->R_DecalRemoveAll( textureIndex )

注意:该方法会删除所有 textureIndex 为指定的值的贴花,所以建议给 textureIndex 再包装一层,使得每个贴花拥有独立的索引,而不是靠纹理索引来区分。

核能注意: textureIndex 是 short 型的,能存储的数值范围有限!

函数 R_DecalShoot_ 的地址:

0x01D4B530    //
0x01D49750 //

函数 Draw_DecalTexture 的地址:

0x01D321F0    //
0x01D2EB30 //

在HL引擎中制作自定义高清贴花的更多相关文章

  1. Android中制作自定义dialog对话框的实例

    http://www.jb51.net/article/83319.htm   这篇文章主要介绍了Android中制作自定义dialog对话框的实例分享,安卓自带的Dialog显然不够用,因而我们要继 ...

  2. Cocos2D iOS之旅:如何写一个敲地鼠游戏(二):Cocos2D中的高清支持

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...

  3. 如何在Google上下载高清原图

    在我们学习和生活中常常一些高清图片作为相关的素材,比如制作PPT.写博文.制作视频都需要大量图片.我们常常会在百度上下载一些图片,但是百度上提供的图片存在很多问题:存在水印.清晰度不够等.而Googl ...

  4. cocos2d-x 2.0.3 设置高清模式注意事项(已移除-hd方式)

    猴子原创,欢迎转载.转载请注明: 转载自Cocos2D开发网–Cocos2Dev.com,谢谢! 原文地址: http://www.cocos2dev.com/?p=304 在cocos2d-x 2. ...

  5. 故障解决 | win10没声音及找不到Realtek高清音频管理器

    重装 win10 系统后,电脑没声音,更新驱动以及万不得已下载驱动精灵都没有解决. 后来发现在“硬件和声音”中没有Realtek高清音频管理器,之后找到解决办法如下: 1. 找到Realtek高清音频 ...

  6. 面包板入门电子制作(class1)视频 全套30集高清

    面包板入门电子制作(class1)套件(30集高清) 本套件以电子制作中最基础的元器件在面包板上搭建电路,用启发性的视频教学方式,使学习者熟悉电子电路基础.发挥想像力.在创新设计和制作中学会独立设计和 ...

  7. cocos2D v3.4 在TileMap中开启高清显示

    在Tiled中制作一幅地图,用的图片砖块分辨率为32x32. iOS设备为iPhone 4s. 在未打开高清屏支持的cocos2d v2.x版本中,运行log显示480x320.遂启用高清屏支持: [ ...

  8. 第二十八篇、自定义的UITableViewCell上有图片需要显示,要求网络网络状态为WiFi时,显示图片高清图;网络状态为蜂窝移动网络时,显示图片缩略图

    1)SDWebImage会自动帮助开发者缓存图片(包括内存缓存,沙盒缓存),所以我们需要设置用户在WiFi环境下下载的高清图,下次在蜂窝网络状态下打开应用也应显示高清图,而不是去下载缩略图. 2)许多 ...

  9. 高清语音技术(WBS)及其在手机和蓝牙耳机中的实现

    高清语音也被称为宽带语音,是一种能为蜂窝网络.移动电话和无线耳机传输高清.自然语音质量的音频技术.与传统的窄带电话相比,高清语音很大程度上提高了语音质量,减少了听觉负担. 通信产业链上的所有网络和设备 ...

随机推荐

  1. 阿里云Linux的mysql安装,使用yum安装

    1.下载 我下载的mysql5.7 rpm格式的,在Linux的根目录下下载(防止出现安装的问题) wget https://dev.mysql.com/get/mysql57-community-r ...

  2. 将exe依赖运行的dll,合并入exe中,整个程序仅存在一个exe文件

    方法一: 使用ILMerge合并winform生成的exe和引用的dll文件 参考:https://blog.csdn.net/u010108836/article/details/76782375 ...

  3. Halcon四 双目视觉的标定

    原文作者写的一系列博客,挺不错的学习halcon:http://blog.sina.com.cn/s/blog_442bfe0e0100yjtn.html 1.get_image_pointer1(I ...

  4. anaconda+pycharm的安装和应用

    至于anaconda的安装与pycharm的安装在此不做多说,主要说下遇到的问题. 问题描述: 安装anaconda后,pip下载的第三方库调用不到. 原因分析: anaconda自带的python3 ...

  5. FFM原理及公式推导

    原文来自:博客园(华夏35度)http://www.cnblogs.com/zhangchaoyang 作者:Orisun 上一篇讲了FM(Factorization Machines),说一说FFM ...

  6. 绝对干货!初学者也能看懂的DPDK解析

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由Willko发表于云+社区专栏 一.网络IO的处境和趋势 从我们用户的使用就可以感受到网速一直在提升,而网络技术的发展也从1GE/10 ...

  7. Golang 2018.1.2激活及使用技巧

    对于做Java开发的同学使用最熟练的开发工具应该当属Eclipse了吧,但是做到后面的话一般都会转用Intellij Idea.至于转用Intellij有什么好处我就不赘述了,简言之就是功能强大,使用 ...

  8. 图片人脸检测(OpenCV版)

    图片人脸检测 人脸检测使用到的技术是OpenCV,上一节已经介绍了OpenCV的环境安装,点击查看. 功能展示 识别一种图上的所有人的脸,并且标出人脸的位置,画出人眼以及嘴的位置,展示效果图如下: 多 ...

  9. 20172325『Java程序设计』课程 结对编程练习_四则运算第二周阶段总结

    20172325『Java程序设计』课程 结对编程练习_四则运算第二周阶段总结 结对伙伴 学号:20172306 姓名:刘辰 结对伙伴博客链接 刘辰同学对编程的积极程度很高,并且在编程能力上很不错,有 ...

  10. GridView的控件说明[字典]-----方便查询

    GridView 控件以表格的形式显示数据,并提供对数据进行排序,选择,编辑,删除等功能. GridView能够完成的功能具体可以总结如下: 1,通过数据源控件将数据绑定到GridView控件 2,对 ...