Stage3DでPerlinノイズ
新しいAPI,Stage3DでPerlinノイズを作ってみました。
ハードウェアレンダリングに対応している人は、ソフトウェアレンダリングを選ぶこともできます。
フレームレートとCPU使用率にGPUとソフトウェアエミュレートの違いが出ていると思います。
7/20
コードの解説を書いてみました。
http://9ballsyndrome.blog.fc2.com/blog-entry-27.html
/**
* Copyright 9balls ( http://wonderfl.net/user/9balls )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/pgiJ
*/
package {
import com.adobe.utils.AGALMiniAssembler;
import com.bit101.components.PushButton;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.textures.Texture;
import flash.display3D.VertexBuffer3D;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.utils.ByteArray;
import net.hires.debug.Stats;
/**
* ...
* @author
*/
public class Main extends Sprite {
private const RAD_T:Number = Math.PI / 180 / 10;
//
private var hardButton:PushButton;
private var softButton:PushButton;
//
private var stage3D:Stage3D;
private var context3D:Context3D;
//
private var program:Program3D;
private var indexBuffer:IndexBuffer3D;
//
private var textures:Vector.<Texture>;
private var dxy:Vector.<Number>;
private var rgb:Vector.<Number>;
private var count:uint = 800;
public function Main():void {
Wonderfl.disable_capture();
addChild(new Stats());
stage.frameRate = 60;
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
//
stage3D = stage.stage3Ds[0];
stage3D.x = 0;
stage3D.y = 0;
stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate);
stage3D.requestContext3D(Context3DRenderMode.AUTO);
}
private function onContextCreate(e:Event):void {
stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreate);
context3D = stage3D.context3D;
if (context3D.driverInfo.match("Software")){
init();
} else {
hardButton = new PushButton(this, stage.stageWidth / 2 - 50 - 100, stage.stageHeight / 2 - 20, "Hardware", onHard);
softButton = new PushButton(this, stage.stageWidth / 2 - 50 + 100, stage.stageHeight / 2 - 20, "Software", onSoft);
}
}
private function onHard(e:MouseEvent):void {
removeChild(hardButton);
removeChild(softButton);
init();
}
private function onSoft(e:MouseEvent):void {
removeChild(hardButton);
removeChild(softButton);
context3D.dispose();
context3D = null;
stage3D.addEventListener(Event.CONTEXT3D_CREATE, onSoftContextCreate);
stage3D.requestContext3D(Context3DRenderMode.SOFTWARE);
}
private function onSoftContextCreate(e:Event):void {
stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onSoftContextCreate);
context3D = stage3D.context3D;
init();
}
private function init():void {
//context3D.enableErrorChecking = true;
context3D.configureBackBuffer(466, 466, 0, false);
//text
var tf:TextField = new TextField();
tf.wordWrap = true;
tf.width = 400;
tf.text = context3D.driverInfo;
tf.y = 440;
addChild(tf);
//create
createShaders();
setConstant();
setBuffer();
textures = new Vector.<Texture>(6);
for (var i:int = 0; i < 6; i++){
textures[i] = createRandomTexture(256 >> i)
}
//set
context3D.setProgram(program);
context3D.setTextureAt(0, textures[0]);
context3D.setTextureAt(1, textures[1]);
context3D.setTextureAt(2, textures[2]);
context3D.setTextureAt(3, textures[3]);
context3D.setTextureAt(4, textures[4]);
context3D.setTextureAt(5, textures[5]);
context3D.setRenderToBackBuffer();
//run
addEventListener(Event.ENTER_FRAME, onEnter);
}
private function onEnter(e:Event):void {
context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 2, rgb, 1);
context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 3, dxy, 1);
dxy[0] += 0.004;
dxy[1] += 0.0008;
var sin:Number = Math.sin(count * RAD_T);
rgb[0] = 2 - sin;
rgb[2] = 2 + sin;
count++;
//
context3D.clear(0, 0, 0, 1);
context3D.drawTriangles(indexBuffer);
context3D.present();
}
//
private function createRandomTexture(size:uint):Texture {
var bd:BitmapData = new BitmapData(size, size, false);
bd.noise(Math.random() * 0xFFFFFFFF >> 0, 0, 255, 7, true);
var texture:Texture = context3D.createTexture(size, size, Context3DTextureFormat.BGRA, false);
texture.uploadFromBitmapData(bd);
return texture;
}
private function createShaders():void {
//create shaders
var agalAssembler:AGALMiniAssembler = new AGALMiniAssembler();
//
//vertex
var vertexShader:ByteArray = agalAssembler.assemble(Context3DProgramType.VERTEX, "mov op, va0 \n" + "mov v0, va1\n");
//
//fragment
var code:String = "";
//load and blend texture
code += "mov ft0 v0\n";
code += "add ft0.xy, ft0.xy fc3.xy\n";
code += "tex ft1, ft0, fs0<2d,repeat,linear>\n";
code += "mul ft1, ft1, fc1.y\n";
code += "tex ft2, ft0, fs1<2d,repeat,linear>\n";
code += "mul ft2, ft2, fc1.x\n";
code += "add ft1, ft1, ft2\n";
code += "tex ft2, ft0, fs2<2d,repeat,linear>\n";
code += "mul ft2, ft2, fc0.w\n";
code += "add ft1, ft1, ft2\n";
code += "add ft0.xy, ft0.xy fc3.xy\n";
code += "tex ft2, ft0, fs3<2d,repeat,linear>\n";
code += "mul ft2, ft2, fc0.z\n";
code += "add ft1, ft1, ft2\n";
code += "tex ft2, ft0, fs4<2d,repeat,linear>\n";
code += "mul ft2, ft2, fc0.y\n";
code += "add ft1, ft1, ft2\n";
code += "tex ft2, ft0, fs5<2d,repeat,linear>\n";
code += "mul ft2, ft2, fc0.x\n";
code += "add ft1, ft1, ft2\n";
code += "mov ft0, ft1\n";
//set color
code += "mul ft0, ft0, fc2\n";
code += "mov oc, ft0\n";
var fragmentShader:ByteArray = agalAssembler.assemble(Context3DProgramType.FRAGMENT, code);
//
//set shaders to program
program = context3D.createProgram();
program.upload(vertexShader, fragmentShader);
}
private function setConstant():void {
//ft
var blend:Vector.<Number> = new Vector.<Number>(6);
var max:Number = 0.6;
for (var i:int = 0; i < 6; i++){
blend[i] = max;
max /= 2;
}
context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.<Number>([blend[0], blend[1], blend[2], blend[3]]), 1);
context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 1, Vector.<Number>([blend[4], blend[5], 0, 0]), 1);
rgb = Vector.<Number>([1, 1, 1, 0]);
dxy = Vector.<Number>([0, 0, 0, 0]);
}
private function setBuffer():void {
//vertex buffer
var vertexBuffer:VertexBuffer3D = context3D.createVertexBuffer(4, 4);
context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
context3D.setVertexBufferAt(1, vertexBuffer, 2, Context3DVertexBufferFormat.FLOAT_2);
vertexBuffer.uploadFromVector(Vector.<Number>([-1, -1, 0, 1, -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0]), 0, 4);
//index buffer
indexBuffer = context3D.createIndexBuffer(6);
indexBuffer.uploadFromVector(Vector.<uint>([0, 1, 2, 1, 2, 3]), 0, 6);
}
}
}