在HL引擎中制作自定义高清贴花
你是不是想过要做自定义的子弹孔、喷漆或者一些自定义的痕迹呢?
如果按照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引擎中制作自定义高清贴花的更多相关文章
- Android中制作自定义dialog对话框的实例
http://www.jb51.net/article/83319.htm 这篇文章主要介绍了Android中制作自定义dialog对话框的实例分享,安卓自带的Dialog显然不够用,因而我们要继 ...
- Cocos2D iOS之旅:如何写一个敲地鼠游戏(二):Cocos2D中的高清支持
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- 如何在Google上下载高清原图
在我们学习和生活中常常一些高清图片作为相关的素材,比如制作PPT.写博文.制作视频都需要大量图片.我们常常会在百度上下载一些图片,但是百度上提供的图片存在很多问题:存在水印.清晰度不够等.而Googl ...
- cocos2d-x 2.0.3 设置高清模式注意事项(已移除-hd方式)
猴子原创,欢迎转载.转载请注明: 转载自Cocos2D开发网–Cocos2Dev.com,谢谢! 原文地址: http://www.cocos2dev.com/?p=304 在cocos2d-x 2. ...
- 故障解决 | win10没声音及找不到Realtek高清音频管理器
重装 win10 系统后,电脑没声音,更新驱动以及万不得已下载驱动精灵都没有解决. 后来发现在“硬件和声音”中没有Realtek高清音频管理器,之后找到解决办法如下: 1. 找到Realtek高清音频 ...
- 面包板入门电子制作(class1)视频 全套30集高清
面包板入门电子制作(class1)套件(30集高清) 本套件以电子制作中最基础的元器件在面包板上搭建电路,用启发性的视频教学方式,使学习者熟悉电子电路基础.发挥想像力.在创新设计和制作中学会独立设计和 ...
- cocos2D v3.4 在TileMap中开启高清显示
在Tiled中制作一幅地图,用的图片砖块分辨率为32x32. iOS设备为iPhone 4s. 在未打开高清屏支持的cocos2d v2.x版本中,运行log显示480x320.遂启用高清屏支持: [ ...
- 第二十八篇、自定义的UITableViewCell上有图片需要显示,要求网络网络状态为WiFi时,显示图片高清图;网络状态为蜂窝移动网络时,显示图片缩略图
1)SDWebImage会自动帮助开发者缓存图片(包括内存缓存,沙盒缓存),所以我们需要设置用户在WiFi环境下下载的高清图,下次在蜂窝网络状态下打开应用也应显示高清图,而不是去下载缩略图. 2)许多 ...
- 高清语音技术(WBS)及其在手机和蓝牙耳机中的实现
高清语音也被称为宽带语音,是一种能为蜂窝网络.移动电话和无线耳机传输高清.自然语音质量的音频技术.与传统的窄带电话相比,高清语音很大程度上提高了语音质量,减少了听觉负担. 通信产业链上的所有网络和设备 ...
随机推荐
- tikz中谐振子(弹簧)的绘制,以及声子色散关系的绘制
今天整理了简正模导出声子的内容,其中用tikz画了两张图.一张是整个问题的物理模型,效果如下 这幅图的绘制参考了https://tex.stackexchange.com/questions/4160 ...
- [Java] Design Pattern:Code Shape - manage your code shape
[Java] Design Pattern:Code Shape - manage your code shape Code Shape Design Pattern Here I will intr ...
- Jmeter接口测试(六)关联&正则匹配
问题思考 接口测试过程中经常需要接口之间关联调用,比如获取上一个接口的返回值,作为另一个接口的请求参数,那么该如何从处理呢? 这里需要使用 Jmeter 的正则表达式提取器,通过对响应的数据来提取指定 ...
- 402. Remove K Digits/738.Monotone Increasing Digits/321. Create Maximum Number
Given a non-negative integer num represented as a string, remove k digits from the number so that th ...
- linux下实现压测-html报表生成-控制台参数优化【jmeter】
jmeter - 单机压测 - 命令行模式-html报表生成-控制台参数优化 一/ 准备工作 1.压力机安装并配置好 jdk 2.调试好程序脚本 再上传到 linux下 3.进入jmeter bin ...
- Harbor 学习分享系列4 - Harbor常用功能实验
前言 本文为Harbor技术分享系列的第4部分也是初级部分的完结篇,下个阶段作者将会进阶分享,更多详细的内容将会将会在文中介绍. 云盘链接 链接:https://pan.baidu.com/s/1PT ...
- HPUX系统启动后主机名为unknown的解决办法
HPUX系统启动完成后,主机名为unknown,查看/etc/rc.log出现如下报错: unknown:[/]grep -i error /etc/rc.log /sbin/rc1.d/S320 ...
- ubuntu下import matplotlib错误解决办法
环境:ubuntu16.04,python2.7,tensorflow1.4.0 问题: ImportError: No moudule named _tkinter, please install ...
- Alpha版会议总结
目前的进度: 实现了文字备忘的录入: 实现了提醒功能: 实现了可视化界面: 语音录入功能还没有完成: 界面相当粗糙: 遇到的问题: 语音录入按钮按下后没有反应,目前没有解决思路和方法. 原本的解屏功能 ...
- 求int型数组和最大子数组 续
之前的博文里已经实现过该程序的构思.编译.运行,本次就不再重复与之相雷同的内容. 题目:与别人借组,借助求int型数组最大和子数组的问题,考虑大数溢出和int取值范围的问题 要求: 调试程序 当子数 ...