2007/06/24 | 群聊整理之“Sprite3D”
类别(游戏开发) | 评论(1) | 阅读(201) | 发表于 13:12

石头 11:04:41
下面在这句话,大家认为对么:
Sprite3D实际上就是把一张2D的图片放在3D的空间里。sprite总是正对着Camera的,而不考虑Camera的角度和World的旋转。
另外有个问题,场景里生成了camera和sprite3D并都加入到了word中。但刚开始原地旋转camera的时候,sprite3d显示是没问题的,但一旦移动了camera后(注:camera的位移是根据先前旋转好的角度通过正余玄定理计算好的) sprite却移出到了相机视口之外了。我加了下面的语句也没用,其中 angeley是camera旋转的角度,locationx和locationz是相机旋转后,前进或后退通过计算得到的当前坐标。请帮忙看看啊
camera.setOrientation(angley, 0.0F, 1.0F, 0.0F);
camera.setTranslation(locationx, 5F, locationz);

sprite3d.setOrientation(angley, 0.0F, 1.0F, 0.0F);
sprite3d.setTranslation(locationx, 5F, locationz-5f);
实在晕了。请教各位强人啊
石头 11:06:28
刚才的问题也是水晶的问题:)
tk能说说sprite3d的使用要注意些什么问题么:)
大河马 11:11:15
我强烈建议写自己的Sprite3D。。。因为索爱的机器上Sprite3D实现有bug,只能抠电池
汤锴 11:11:19
现在认真研究一下这个问题
我不熟悉java版的sprite 3D实现,也没有用过。所以一切都是基于猜测。
Sprite3D实际上就是把一张2D的图片放在3D的空间里。这句话肯定没有问题。
但是“总是正对着Camera的”,这就不一定了。我不知道java 3D里是怎么定义Sprite 3D的,但是通常称“总是正对着Camera的”sprite是Billboard(公告牌),而普通的sprite 3D未必总是正对Camera,至少在我自己的引擎中是如此。
汤锴 11:13:51
对sprite 3D,我想实现思路从根本上,应该就分成区别很大的两种:
1 用一个质点表示sprite 3D
2 用一个quad(也就是两个三角形)表示sprite 3D
石头 11:13:56
只是想随着相机的移动,精灵能正常显示在视口范围内就可以了。要求不高啊
大河马 11:14:19
嗯,我现在用一个Quad来写了个billboard
汤锴 11:15:13
如果是前者,那么进行transform的仅仅是一个点,把这个点transform到screen之后,再根据sprite的size居中这个点来绘制sprite,那么我想基本上就不会有“近大远小”,也不会有旋转了(也就是始终正对camera)
如果是后者,那么平移了sprite它就不正对camera这是必然的,camera靠近sprite它就变大这也是必然的,如果这一点无法理解那就没什么好说的了。
在这种情况下,如果希望sprite始终正对camera并且不会出现近大远小,那就必须添加transform。
我一开始想知道java 3D的API实现内部有没有自动做这个transform,前面和水晶羽的测试结果是没有,那么必须手动加入这个transform。
 
汤锴 11:17:05
可是,水晶羽,你为什么要这么麻烦?如果仅仅是要做始终在屏幕正中的一个小人,为什么要用sprite 3D? 
你哪怕直接用2D方式直接在屏幕中间画一个图片也行啊!
汤锴 11:23:00
河马,你自己用quad实现sprite 3D,原因是什么?
为什么选择quad,而不是用一个点来表示呢?你用这个sprite3d做什么效果?
大河马 11:23:57
我其实用的一个Quad来组成一个Mesh,然后手动更新Mesh,让它始终对准Camera
用点表示的话,最后怎么渲染这个image?
汤锴 11:25:07
那为什么不用一个点?如果用第一种方式,那它肯定是正对camera了.
是不是因为需要3D透视所以才用quad?
坐标变换这个点,然后求得其屏幕坐标,比如screen_pos.
然后用2D方式画图片,
left_corner = screen_pos.x - (pic.width>>1);
up_corner = screen_pos.y - (pic.height>>1);
不就行了
大河马 11:26:44
哦,我知道了!
汤锴 11:26:49
当然了,java中可能没有这样的自由度
大河马 11:27:19
你说的方法就不能实现billboard的近大远小吧?
汤锴 11:27:36
也可以实现
近大远小不过就是一些数学计算,你自己重现这个计算就是了

大河马 11:28:43
快速缩放image有好算法吗?
汤锴 11:29:29
一般2D API总会提供拉伸draw吧,这一步我想应该不需要自己实现
conan 11:29:43
有些没有
大河马 11:29:44
你一般都是用的什么快速图像放缩算法啊?
j2me里没有native的拉伸算法。。
汤锴 11:30:31
啊,这么凄凉 
 
汤锴 11:31:19
2D缩放算法很简单,和3D贴图映射算法类似.
//--------------------------------------------------------------------------------------------------------
/// draw stretch, no color key, no blend
void  Draw2D::DrawOL_Stretch_NoKey_NoBlend()
{
 s32 destWidth  = m_DestRect.right - m_DestRect.left;
 s32 destHeight = m_DestRect.bottom - m_DestRect.top;
 f32 u = I2FP( 0 );
 f32 v = I2FP( m_SrcRect.top );

 for( s32 j = 0; j < destHeight; ++j ) {
  for( s32 i = 0; i < destWidth; ++i ) {
   m_pDstOverlay[i] = m_pSrcOverlay[FP2I(u)];
   u += m_fScaleX;
  }
  m_pDstOverlay  += SCREEN_WIDTH;

  v += m_fScaleY;
  m_pSrcOverlay = (Pixel*)m_pTexture->GetPtr() + ( FP2I( v ) * m_pTexture->GetWidth() + m_SrcRect.left );
  u = I2FP( 0 );
 }
}
大河马 11:32:52
我找了很多 什么二次线性插值,卷积插值之类的,不过不知道效率高不高
汤锴 11:32:58
哪有这么烦
极其简单
二次线性插值...卷积插值...
这样做效率不可能顶得住
直接最近点采样就行了
KEN 11:35:39
EXPORT_C void Raster2d::blit_RGB565_RGB565_MaskAlpha(RGB565::IPixelFilter& F,
  RGB565::IPixelBlend& B,
  RGB565::IBufferLocalizer& L,
  HIMAGE tImg,
  HIMAGE sImg,
  CLIPPER& clipper)
 {
  XsAssertM(tImg && sImg,text("Invalid target image or invalid source image"));

  if(!clipper.isOutOfScreen())
  {
   UINT16* tBuffer = (UINT16*)XsImage::getBuffer(tImg,clipper.targetRect.Top);
   tBuffer += clipper.targetRect.Left;

   INT32 sPitchX,sPitchY;
   UINT16* sBuffer = L(sImg,clipper.sourceRect,sPitchX,sPitchY);

   UINT16 width  = clipper.targetRect.getWidth();
   UINT16 height = clipper.targetRect.getHeight();

   while(height--)
   {
    RGB565::Raster<RGB565::FilterMaskColor,RGB565::BlendPixelAlpha>::processLine((RGB565::FilterMaskColor&) F,
     (RGB565::BlendPixelAlpha&) B,
     tBuffer,
     sBuffer,
     sPitchX,
     width);
    tBuffer += XsImage::getWidth(tImg);
    sBuffer += sPitchY;
   }
  }
 }

KEN 11:36:16
void Raster2d::stretch_RGB565_RGB565_MaskAlpha(RGB565::IPixelFilter& F,
  RGB565::IPixelBlend& B,
  RGB565::IBufferLocalizer& L,
  HIMAGE tImg,
  HIMAGE sImg,
  STRETCHEDCLIPPER& clipper)
 {
  XsAssertM(tImg && sImg,text("Invalid target image or invalid source image"));
  
  if(!clipper.isOutOfScreen())
  {
   UINT16* tBuffer = (UINT16*)XsImage::getBuffer(tImg,clipper.targetRect.Top);
   tBuffer += clipper.targetRect.Left;

   INT32 sPitchX,sPitchY;
   UINT16* sBuffer = L(sImg,clipper.sourceRect,sPitchX,sPitchY);

   UINT16 width  = clipper.targetRect.getWidth();
   UINT16 height = clipper.targetRect.getHeight();

   INT32 prevY = clipper.stretchTable.vertArray.getAt(0);
   for(INT32 loop = 0; loop < height; ++loop)
   {
    if(prevY != clipper.stretchTable.vertArray.getAt(loop))
    {
     // Add the source buffer
     sBuffer += sPitchY * (clipper.stretchTable.vertArray.getAt(loop) - prevY);
     prevY = clipper.stretchTable.vertArray.getAt(loop);
    }
    RGB565::Raster<RGB565::FilterMaskColor,RGB565::BlendPixelAlpha>::stretchLine((RGB565::FilterMaskColor&) F,
     (RGB565::BlendPixelAlpha&) B,
     tBuffer,
     sBuffer,
     sPitchX,
     width,
     clipper.stretchTable.horzArray.getElements());
    tBuffer += XsImage::getWidth(tImg);
   }
  
  }  
 }
汤锴 11:37:14
stretchTable 看到一个有意思的东西
stretch查表做了?
这个表有多大?
KEN 11:41:20
很小
最多也就是屏幕大小
屏幕高和宽
176个UInt16 + 208个UInt16
汤锴 11:43:15
先抛开stretch表不谈.
KEN这段代码实现2D渲染的思路,和我最后用的思路,有很大区别.
这两个接口可以概括基本上所有的2D渲染,除了混合比例是固定的(我猜是50%混合?)
我最后用了一组函数来实现,目的是为了效率.
比如对于没有blend,也没有color key的方式,上面接口中很多东西是不必要的
KEN 11:43:57
那个是函数指针处理的 
 /*!
   * \brief 压入一个Blend Mode并且将这个blend mode作为当前的模式
   * \param blend:混合模式
   */
  IMPORT_C void pushBlendMode(BLENDMODE blend);

  /*!
   * \brief 弹出一个blend mode并且将前一个blend mode当作当前的模式
   */
  IMPORT_C void popBlendMode();
  
  /*!
   * \brief 设置翻转模式
   * \param flip:翻转模式
   */
  IMPORT_C void setFlipMode(FLIPMODE flip);

  /*!
   * \brief 获得当前的翻转模式
   * \return 当前的翻转模式
   */
  IMPORT_C FLIPMODE getFlipMode() const;

KEN 11:45:06
全部是状态
包括像素混合
所以最后这个.cpp搞到5000多行...为了效率又不想搞虚函数
汤锴 11:45:52
原来如此.
那么,在最内层循环反复调用
RGB565::Raster<RGB565::FilterMaskColor,RGB565::BlendPixelAlpha>::processLine
构造函数,
并且始终传递6个参数,是不是对效率有影响?
KEN 11:46:09
这个Inline了
汤锴 11:46:10
对,为了效率,就会导致代码膨胀
KEN 11:46:23
恩,很头疼
代码过大会导致cpu buffer命中率降低
汤锴 11:47:31
我这里最夸张的一个cpp有1万多行,就是带perspective correction的texture mapping...
改起来也很不方便
KEN 11:47:50
不过这样做的好处就是对于使用引擎的人来说,绘制图只有2个函数,drawImagehe 
drawImage和stretchImage
汤锴 11:48:09
对,这确实是好处,所以当时我也犹豫了很久.
KEN 11:48:28
以前老的引擎2D支持脏矩形,结果发现用的人基本上都不会关心这个,直接InvalidateAll了
所以后来就放弃这个想法了...
汤锴 11:49:10
不过我这里最上层接口也DrawOverlay和DrawStretchOverlay两个,只是内部实现分支很多,代码维护起来不方便
stretch table是个好东西,我收下了,呵呵。
我用了那么多查找表,居然这里忘了用。

0

评论Comments

日志分类
首页[118]
游戏开发[40]
绝命都市[6]
文章[47]
朝花夕拾[10]
诗歌[6]
相簿[9]