一种Flash页游前端3D转2D显示技术——PV2D, 颠覆传统吧!

时间:2022-03-23 10:28:24

stage3D很强大,但是客户端硬件加速支持有限。

出来的图形锯齿严重,看上去和果冻一样。

Stage3d不兼容2d模式。

总的来说,3D很美好,现实很残酷。但是3D有无可比拟的优势:那就是节省90%的带宽和提升无限的显示效果。

本文根据前辈的经验,总结一种在中低模型下,3D显示为2D的技术。颠覆传统吧!

前言——为什么用3D?

在页游界,不要相信3D所谓华丽的效果。至少2014年结束,也不需要去幻想。端游就另当别论。

但是3D只需要一个模型+一个贴图,就完成了所有需要的人物显示。如果用传统序列图,8个方向,每个方向12帧,每帧15K来计算,就需要1440K,接近1.5M。但是3D不超过200K。

多么诱人的性能啊。要知道节省了10倍带宽,那就是一个服务器节省了几千块钱的带宽了。

而且,任意角度、任意视觉,不需要美术处理。

所以,3D,必须的。

3D转2D核心技术——PV2D

无论用alway3D, unity3D, stage3D,starling什么的,都不可能实现3D转2D。所以必须把老祖宗拿出来,那就是 papervision3D.

哦。原来是这个。相信很多资深前端主程已经不屑一顾了。但是,就是这个papervision3D,现在还能再一次颠覆传统。

但是pv3D有些缺陷,需要修改animationController类,添加一个帧总数和下一帧控制。

		public function get totalFrames():int{
var count:int = 0;
if(!this._channels)
return count;
for each(var _channel:Channel3D in this._channels)
{
if(_channel.output == null)
continue;
count = Math.max(_channel.output.length, count);
}
return count;
}
		/**
* 显示下一帧
*/
public function next():void{
_frameIndex++;
if(_frameIndex >= totalFrames)
{
_frameIndex = 0;
}
_currentTime = endTime / totalFrames * _frameIndex;
this._isStepping = true;
}

增加一个stepping方法

		private function stepping():void
{
var channel : Channel3D;
var et : Number = _clip ? _clip.endTime : endTime;
var clipName :String = _clip ? _clip.name : "all"; if(_currentTime > et)
{
if (_dispatchEvents)
{
dispatchEvent(new AnimationEvent(AnimationEvent.COMPLETE, et, clipName));
} if(!_loop)
{
stop();
return;
}
if(_clip)
{
_currentTimeStamp -= (_clip.startTime * 1000);
}
_currentTime = _clip ? _clip.startTime : startTime;
} for each(channel in _channels)
{
channel.update(_currentTime);
} if (_isPlaying && _dispatchEvents)
{
dispatchEvent(new AnimationEvent(AnimationEvent.NEXT_FRAME, _currentTime, clipName));
}
}

最后修改update方法:

		/**
* Update.
*/
public function update() : void
{
if(_isStepping)
{
stepping();
return;
}

 

简单说下DAE模型,他使用了时间去控制帧,因此需要计算开始时间、结束之间、总帧数,来换算控制下一帧播放。具体代码我会给出来。

然后完成我们的pv3dLoader:

package com.xtar.loader.utils
{
import com.xtar.common.FilterCoder;
import com.xtar.common.MovieClipInfo;
import com.xtar.interfaces.IDisposable; import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.filters.GlowFilter;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.utils.Dictionary;
import flash.utils.getTimer; import org.papervision3d.events.FileLoadEvent;
import org.papervision3d.objects.parsers.DAE;
import org.papervision3d.view.layer.util.ViewportLayerSortMode; //http://www.flashquake.cn/?tag=pv3d 破图的解决方法
//http://*.com/questions/549766/papervision-render-to-bitmap
public class Pv3dLoader extends EventDispatcher implements IDisposable
{
private var view:Pv3dContainer = new Pv3dContainer;
private var dae:DAE = null;
private var config:Pv3dConfig = new Pv3dConfig;
private var frames:Dictionary = new Dictionary; private var timeStart:Number = -1; public function Pv3dLoader()
{
view.viewport.containerSprite.sortMode = ViewportLayerSortMode.Z_SORT;
FilterCoder.addFilter(view, new GlowFilter(0x000000, 1, 1.5, 1.5, 2));
} public function load(config:Pv3dConfig):void{
this.config = config;
if(config.width > 0)
view.viewport.viewportWidth = config.width;
if(config.height > 0)
view.viewport.viewportHeight = config.height;
view.viewport.autoScaleToStage = false;
dae = new DAE(false);
dae.addEventListener(FileLoadEvent.LOAD_COMPLETE, daeComplete);
dae.addEventListener(IOErrorEvent.IO_ERROR, daeError);
dae.addEventListener(FileLoadEvent.ANIMATIONS_PROGRESS, daeProgress);
dae.load(config.url, null, false);
timeStart = getTimer();
} public function get content():*{
return this.frames;
} public function dispose():void{
frames = null;
view = null;
dae = null;
config = null;
} private function daeComplete(e:FileLoadEvent):void{ trace(getTimer() - timeStart);
timeStart = getTimer(); dae.stop();
view.scene.addChild(dae);
view.camera.z = -1 * (config.distance * Math.cos(Math.PI / 180 * config.angleGround));
view.camera.x = 0;
view.camera.y = config.distance * Math.sin(Math.PI / 180 * config.angleGround); var rect:Rectangle = new Rectangle(-this.view.viewport.viewportWidth / 2, -this.view.viewport.viewportHeight / 2,
this.view.viewport.viewportWidth, this.view.viewport.viewportHeight); for each(var direction:Number in config.directions)
{
dae.animation.next();
view.nextFrame();view.nextFrame(); for(var i:int = 1; i<dae.animation.totalFrames;i++)
{
dae.rotationY = direction;
dae.animation.next();
view.nextFrame();view.nextFrame();
getFrames(direction).push(transferToBitmapData(view, rect));
}
}
trace(getTimer() - timeStart);
loadComplete();
} private function transferToBitmapData(obj:DisplayObject, rect:Rectangle):MovieClipInfo{
var bitmap:BitmapData = new BitmapData(Math.ceil(rect.width), Math.ceil(rect.height), true, 0);
bitmap.draw(obj); var info:MovieClipInfo = new MovieClipInfo;
info.frameIndex = 0;
info.x = rect.x;
info.y = rect.y;
info.data = bitmap;
return info;
} private function getFrames(direction:Number):Array{
if(frames[direction])
return frames[direction];
frames[direction] = new Array;
return frames[direction];
} private function daeError(e:Event):void{
if(this.hasEventListener(IOErrorEvent.IO_ERROR))
this.dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR, e.bubbles, e.cancelable, config.url));
} private function daeProgress(e:FileLoadEvent):void{
if(this.hasEventListener(ProgressEvent.PROGRESS))
this.dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, e.bubbles, e.cancelable, e.bytesLoaded, e.bytesTotal));
} private function loadComplete():void{
this.dispatchEvent(new Event(Event.COMPLETE));
}
}
}

这样,就可以通过截图,得到了3D的序列图,最后使用一个XMovieClip显示出来:

一种Flash页游前端3D转2D显示技术——PV2D, 颠覆传统吧!

当然,为了效果更好,我使用了一点点外发光。

后续——性能与可行性分析:

如果加载1500个面的3D模型,几乎没有性能问题。也许这个就是pv3D的瓶颈。如果超过了1500面,就会出现停顿问题。

主要性能问题集中在:

DAE的XML解析、bitmapData.draw方法非常慢。

因此,一个游戏,除了BOSS、主角,基本上其他的角色都可以用这个方法进行加载。

而且是 任意尺寸、任意角度、任意动作!!!!  

 

代码下载:

pv2d,转换核心引擎

https://app.box.com/s/6pwhv6b65o9uylpzmjeo

修改的pv3d版本:

https://app.box.com/s/wayokxv5feldgjp9gexf

  

  

一种Flash页游前端3D转2D显示技术——PV2D, 颠覆传统吧!的更多相关文章

  1. IE11&sol;Flash页游白屏怎么办!立刻开启IE大地址模式!缓解浏览器白屏问题

    您是否经常发现IE白屏了,具体表现为点开新网页时无法显示,只能切换标签,用任务管理器一看,内存1.2G之多. 这是因为IE11可能有内存泄露问题,内存不断增长以至于无法申请新的内存,于是IE就完蛋了! ...

  2. 页游安全攻与防,SWF加密和隐藏密匙

    原文链接:http://netsecurity.51cto.com/art/201211/364775.htm 页游,最最核心的就是客户端(swf)与服务端的游戏通信了.游戏通信产生的封包,内容是否可 ...

  3. 基于Adobe Flash平台的3D页游技术剖析

    写在前面 从黑暗之光,佛本是道,大战神的有插件3D页游.再到如今的魔龙之戒. 足以证明,3D无插件正在引领页游技术的潮流. 目前,要做到3D引擎,有以下几个选择. 说到这里,我们发现.这些都不重要. ...

  4. 页游AS客户端架构设计历程记录

    以下是一个只用JAVA做过服务器架构的程序员做的AS客户端架构,希望大家能推荐好的框架和意见,也求AS高程们的引导,等到基本功能成形后,低调开源,框架可以支持一个中度型页游的开发,本文不断更新中... ...

  5. html5开发页游(前话)

    导师要求模仿某个页游网站开发益智小游戏.老板的要求是要跨平台,IOS,Android.PC.Mac等系统主要通过浏览器打开都能用.那个网站的页游是通过flash实现的,使用这种方法肯定不能满足老板的要 ...

  6. 一个java页游服务器框架

    一.前言 此游戏服务器架构是一个单服的形式,也就是说所有游戏逻辑在一个工程里,没有区分登陆服务器.战斗服务器.世界服务器等.此架构已成功应用在了多款页游服务器 .在此框架中没有实现相关业务逻辑,只有简 ...

  7. &lbrack;转&rsqb;页游开发中的 Python 组件与模式Presentation Transcript

    转: 页游开发中的 Python 组件与模式Presentation Transcript 1. 页游开发中的 Python 组件与模式 赖勇浩( http://laiyonghao.com ) 20 ...

  8. 【转】一个java页游服务器框架

    源地址:http://www.cnblogs.com/metoy/p/4305326.html?utm_source=tuicool&utm_medium=referral 一.前言 此游戏服 ...

  9. Android平台中的三种翻页效果机器实现原理

    本文给开发者集中展现了Android平台中的三种翻页效果机器实现原理,希望能够对开发者有实际的帮助价值! 第一种翻页效果如下:     实现原理: 当前手指触摸点为a,则 a点坐标为(ax,ay), ...

随机推荐

  1. Spring MVC返回Map格式JSON数据

    问题描述: ajax中走error : function(e) {} 问题背景: 在测试controller层时,试过了ResponseEntity<ResponseModel>这种类型返 ...

  2. 【原】iOS学习之UITabBar的隐藏

    当页面使用 UITabBarController + UINavigationController 框架的时候,当跳转到详情页面的时候,如果 UITabBar 仍然存在的话就会造成逻辑混乱,用户体验也 ...

  3. EF 5 最佳实践白皮书

    Performance Considerations for Entity Framework 5 By David Obando, Eric Dettinger and others Publish ...

  4. CIO谈:基于K2 BPM平台怎么做报销?

    即时!可视!可控!高效! 面对报销系统四大业务目标,有一个对策——用K2! 演讲人:沈明 大鹏天然气CIO 查看完章分享内容请关注K2官方微信

  5. jQuery中&period;parent和&period;parents的区别

    .parent(selector) 获得当前匹配元素集合中每个元素的父元素,由选择器筛选(可选). .parents(selector) 获得当前匹配元素集合中每个元素的祖先元素,由选择器筛选(可选) ...

  6. &period;Net程序猿玩转Android开发---&lpar;8&rpar;表格布局TableLayout

    表格布局TableLayout是Android中比較经常使用的一个布局控件,既然是表格,肯定有行和列,TableLayout中的行有TableRow组成.列依据每行控件的数量来确定 假如第一行有3个控 ...

  7. Symfony2 Doctrine从现有Database生成Entity&lpar;转载自http&colon;&sol;&sol;blog&period;it985&period;com&sol;6809&period;html&rpar;

    在我的以前一章Symfony之十分钟入门说了怎样生成数据库,然后设计实体Entity,再同步数据库的表结构,一般我们的顺序都是这样:生成数据库->设计实体Entity->同步数据库表结构. ...

  8. Python编写网页爬虫爬取oj上的代码信息

    OJ升级,代码可能会丢失. 所以要事先备份. 一開始傻傻的复制粘贴, 后来实在不能忍, 得益于大潇的启示和聪神的原始代码, 网页爬虫走起! 已经有段时间没看Python, 这次网页爬虫的原始代码是 p ...

  9. 小练习,判断X的奇偶性

    package lianxi1; public class text { public static void main(String[] args) { ; ==) { System.out.pri ...

  10. vuejs2-生命周期

    https://segmentfault.com/a/1190000008879966 1 声明周期图示 2 过渡