如果将纹理的内存使用减半
ATF纹理能明显降低纹理的内存使用,但是有时候你可能不会用到它。如果你是动态生成纹理或者从第三方加载,那就不需要使用压缩的ATF纹理了。今天此文主要讲述如果在不使用ATF的情况下节省内存。
首先,确保你的应用时运行在Flash Player11.7或者AIR3.7下,可以通过Capabilities.version快速查看下。编译的时候也需要将Player11.7设为目标Flash player,可以用如下参数:-target-player=11.7.0,-swf-version=20.输入上面参数可以解锁郎中类型的纹理,这两种纹理都是每个像素是用16位来表示,而不是平常的24位或者32位。
当然需要将Context3DTextureFormat.BGR_PACKED或者Context3DTextureFormat.BGRA_PACKED传递给Context3D.createTexture,这样就可以获得16位/像素的纹理了。
Context3DTextureFormat.BGR_PACKED这种纹理的红色通道需要5位,绿色为6为,蓝色为5位。因为人眼睛对绿色的识别要好于红色跟蓝色。我们可以用RGB565来简化记忆。如果需要alpha值,那就使用Context3DTextureFormat.BGRA_PACKED,每个颜色都有一个4位的alpha值。虽然颜色不怎么精确,但是那就是支持alpha付出的代价。
建立纹理后,只需像以前那样调用Texture.uploadFromBitmapData,BitmapData就会自动样式化为16位/像素。这样在不需要透明度的图片上就减少了33%内存使用,需要透明度的减少了50%的内存使用。
试试这个。我只做了一个小的应用,此应用显示了一个512*512不透明土地纹理和一个128*128的带有一点透明的Flash标志。点击下面的按钮来改变不同的纹理类型。
1 package
2 {
3 import com.adobe.utils.AGALMiniAssembler;
4
5 import flash.display.Bitmap;
6 import flash.display.BitmapData;
7 import flash.display.Sprite;
8 import flash.display.Stage3D;
9 import flash.display.StageAlign;
10 import flash.display.StageScaleMode;
11 import flash.display3D.Context3D;
12 import flash.display3D.Context3DBlendFactor;
13 import flash.display3D.Context3DProgramType;
14 import flash.display3D.Context3DRenderMode;
15 import flash.display3D.Context3DTextureFormat;
16 import flash.display3D.Context3DVertexBufferFormat;
17 import flash.display3D.IndexBuffer3D;
18 import flash.display3D.Program3D;
19 import flash.display3D.VertexBuffer3D;
20 import flash.display3D.textures.Texture;
21 import flash.events.Event;
22 import flash.events.MouseEvent;
23 import flash.text.TextField;
24 import flash.text.TextFieldAutoSize;
25 import flash.text.TextFormat;
26 import flash.utils.ByteArray;
27
28 public class Texture16BPP extends Sprite
29 {
30 private static const PAD:Number = 5;
31
32 [Embed(source="earth.jpg")]
33 private static const TEXTURE_RGB:Class;
34
35 [Embed(source="flash_logo_alpha.png")]
36 private static const TEXTURE_RGBA:Class;
37
38 private var program:Program3D;
39 private var posUV:VertexBuffer3D;
40 private var tris:IndexBuffer3D;
41 private var textureRGB888:Texture;
42 private var textureRGB565:Texture;
43 private var textureRGBA8888:Texture;
44 private var textureRGBA4444:Texture;
45 private var curTexture:Texture;
46 private var context3D:Context3D;
47
48 private var modeDisplay:TextField;
49
50 public function Texture16BPP()
51 {
52 stage.align = StageAlign.TOP_LEFT;
53 stage.scaleMode = StageScaleMode.NO_SCALE;
54 stage.frameRate = 60;
55
56 var stage3D:Stage3D = stage.stage3Ds[0];
57 stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreated);
58 stage3D.requestContext3D(Context3DRenderMode.AUTO);
59 }
60
61 protected function onContextCreated(ev:Event): void
62 {
63 var stage3D:Stage3D = stage.stage3Ds[0];
64 stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreated);
65 context3D = stage3D.context3D;
66 context3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 0);
67 context3D.enableErrorChecking = true;
68
69 makeButtons("RGB888", "RGB565", "RGBA8888", "RGBA4444");
70
71 var assembler:AGALMiniAssembler = new AGALMiniAssembler();
72 assembler.assemble(
73 Context3DProgramType.VERTEX,
74 "mov op, va0\n" +
75 "mov v0, va1"
76 );
77 var vertexProgram:ByteArray = assembler.agalcode;
78
79 assembler.assemble(
80 Context3DProgramType.FRAGMENT,
81 "tex oc, v0, fs0 <2d,linear,mipnone,clamp,dxt1>"
82 );
83 var fragmentProgram:ByteArray = assembler.agalcode;
84
85 program = context3D.createProgram();
86 program.upload(vertexProgram, fragmentProgram);
87
88 posUV = context3D.createVertexBuffer(4, 5);
89 posUV.uploadFromVector(
90 new <Number>[
91 // X, Y, Z, U, V
92 -1, -1, 0, 0, 1,
93 -1, 1, 0, 0, 0,
94 1, 1, 0, 1, 0,
95 1, -1, 0, 1, 1
96 ], 0, 4
97 );
98
99 // Create the triangles index buffer
100 tris = context3D.createIndexBuffer(6);
101 tris.uploadFromVector(
102 new <uint>[
103 0, 1, 2,
104 2, 3, 0
105 ], 0, 6
106 );
107
108 var opaque:BitmapData = (new TEXTURE_RGB() as Bitmap).bitmapData;
109 var alpha:BitmapData = (new TEXTURE_RGBA() as Bitmap).bitmapData;
110
111 textureRGB888 = context3D.createTexture(
112 opaque.width,
113 opaque.height,
114 Context3DTextureFormat.BGRA,
115 false
116 );
117 textureRGB888.uploadFromBitmapData(opaque);
118
119 textureRGB565 = context3D.createTexture(
120 opaque.width,
121 opaque.height,
122 Context3DTextureFormat.BGR_PACKED,
123 false
124 );
125 textureRGB565.uploadFromBitmapData(opaque);
126
127 textureRGBA8888 = context3D.createTexture(
128 alpha.width,
129 alpha.height,
130 Context3DTextureFormat.BGRA,
131 false
132 );
133 textureRGBA8888.uploadFromBitmapData(alpha);
134
135 textureRGBA4444 = context3D.createTexture(
136 alpha.width,
137 alpha.height,
138 Context3DTextureFormat.BGRA_PACKED,
139 false
140 );
141 textureRGBA4444.uploadFromBitmapData(alpha);
142
143 curTexture = textureRGB888;
144
145 modeDisplay = new TextField();
146 modeDisplay.autoSize = TextFieldAutoSize.LEFT;
147 modeDisplay.defaultTextFormat = new TextFormat("_sans", 36);
148 modeDisplay.text = "RGB888";
149 addChild(modeDisplay);
150
151 addEventListener(Event.ENTER_FRAME, onEnterFrame);
152 }
153
154 private function makeButtons(...labels): Number
155 {
156 var curX:Number = PAD;
157 var curY:Number = stage.stageHeight - PAD;
158 for each (var label:String in labels)
159 {
160 var tf:TextField = new TextField();
161 tf.mouseEnabled = false;
162 tf.selectable = false;
163 tf.defaultTextFormat = new TextFormat("_sans");
164 tf.autoSize = TextFieldAutoSize.LEFT;
165 tf.text = label;
166 tf.name = "lbl";
167
168 var button:Sprite = new Sprite();
169 button.buttonMode = true;
170 button.graphics.beginFill(0xF5F5F5);
171 button.graphics.drawRect(0, 0, tf.width+PAD, tf.height+PAD);
172 button.graphics.endFill();
173 button.graphics.lineStyle(1);
174 button.graphics.drawRect(0, 0, tf.width+PAD, tf.height+PAD);
175 button.addChild(tf);
176 button.addEventListener(MouseEvent.CLICK, onButton);
177 if (curX + button.width > stage.stageWidth - PAD)
178 {
179 curX = PAD;
180 curY -= button.height + PAD;
181 }
182 button.x = curX;
183 button.y = curY - button.height;
184 addChild(button);
185
186 curX += button.width + PAD;
187 }
188
189 return curY - button.height;
190 }
191
192 private function onButton(ev:MouseEvent): void
193 {
194 var mode:String = ev.target.getChildByName("lbl").text;
195 switch (mode)
196 {
197 case "RGB888":
198 curTexture = textureRGB888;
199 modeDisplay.text = "RGB888";
200 break;
201 case "RGB565":
202 curTexture = textureRGB565;
203 modeDisplay.text = "RGB565";
204 break;
205 case "RGBA8888":
206 curTexture = textureRGBA8888;
207 modeDisplay.text = "RGBA8888";
208 break;
209 case "RGBA4444":
210 curTexture = textureRGBA4444;
211 modeDisplay.text = "RGBA4444";
212 break;
213 }
214 }
215
216 private function onEnterFrame(ev:Event): void
217 {
218 context3D.clear(0.5, 0.5, 0.5);
219 context3D.setProgram(program);
220 context3D.setBlendFactors(
221 Context3DBlendFactor.SOURCE_ALPHA,
222 Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA
223 );
224
225 // Draw selected texture
226 context3D.setTextureAt(0, curTexture);
227 context3D.setVertexBufferAt(0, posUV, 0, Context3DVertexBufferFormat.FLOAT_3);
228 context3D.setVertexBufferAt(1, posUV, 3, Context3DVertexBufferFormat.FLOAT_2);
229 context3D.drawTriangles(tris);
230
231 context3D.present();
232 }
233 }
234 }
结果会根据你先则的纹理图片而又稍微的不同。土地纹理使用16位的与24位的相比没多大区别,但是内存却能节省不少。Flash 标志则看起来要糟糕点。即使是阴影模式,图片的网格还是看起来很糟糕, 这可能不是一个降低内存的好例子,但是你还是降低了50%的内存消耗。
原文链接:如果将纹理的内存使用减半