Спасибо за советы, но изменение zNear до 0.1 и zFar до 2000 ни к каким улучшениям не привело. По-прежнему этот проклятый срез присутствует и все остальные проблемные эффекты остались. Какие есть еще предложения. Приведу весь код:
1. PointCloudRender.as

Код AS3:
package
{
import com.adobe.utils.AGALMiniAssembler;
import com.adobe.utils.PerspectiveMatrix3D;
import flash.display.BlendMode;
import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.TriangleCulling;
import flash.display3D.Context3D;
import flash.display3D.Context3DCompareMode;
import flash.display3D.Context3DProfile;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DTriangleFace;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.Program3D;
import flash.display3D.VertexBuffer3D;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.MouseEvent;
import flash.filters.DropShadowFilter;
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import flash.geom.Point;
import flash.geom.Vector3D;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.utils.ByteArray;
import flash.utils.getTimer;
[SWF(width=800, height=600, frameRate=30)]
public class PointCloudRender extends Sprite
{
public function PointCloudRender()
{
if(stage)
loadData()
else
addEventListener(Event.ADDED_TO_STAGE,loadData);
}
private function loadData(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, loadData);
var urlrequest:URLRequest=new URLRequest("data.pcd");
var urlloader:URLLoader=new URLLoader();
urlloader.addEventListener(IOErrorEvent.IO_ERROR,onIOError);
urlloader.addEventListener(Event.COMPLETE,onComplete);
urlloader.dataFormat= URLLoaderDataFormat.BINARY;
urlloader.load(urlrequest);
function onIOError(e:IOErrorEvent):void
{
urlloader.removeEventListener(IOErrorEvent.IO_ERROR,onIOError);
urlloader.removeEventListener(Event.COMPLETE,onComplete);
}
function onComplete(e:Event):void
{
urlloader.removeEventListener(IOErrorEvent.IO_ERROR,onIOError);
urlloader.removeEventListener(Event.COMPLETE,onComplete);
pointCloud=urlloader.data;
callContext3D();
}
}
private var context3D:Context3D;
private function callContext3D(e:Event=null):void
{
stage.addEventListener(MouseEvent.MOUSE_WHEEL,onMWheel);
stage.addEventListener(MouseEvent.MOUSE_DOWN,onMDown);
stage.addEventListener(MouseEvent.MOUSE_UP,onMUp);
removeEventListener(Event.ADDED_TO_STAGE,callContext3D);
if(!stage)
{
log("callContext3D stage == null");
return;
}
if(!stage.stage3Ds)
{
log("callContext3D stage3Ds == null");
return;
}
if(stage.stage3Ds.length == 0)
{
log("callContext3D stage3Ds length == 0");
return;
}
var stage3D:Stage3D = stage.stage3Ds[0];
if(!stage3D)
{
log("callContext3D stage3D == null");
return;
}
stage3D.removeEventListener(Event.CONTEXT3D_CREATE,initContext3D);
stage3D.addEventListener(Event.CONTEXT3D_CREATE,initContext3D);
stage3D.requestContext3D(Context3DRenderMode.AUTO);
log("callContext3D OK");
}
private var vertexShader:AGALMiniAssembler = new AGALMiniAssembler();
private var fragmentShader:AGALMiniAssembler = new AGALMiniAssembler();
private function initContext3D(e:Event):void
{
context3D = (e.target as Stage3D).context3D;
//Режим ошибок.
context3D.enableErrorChecking = true;
//Кюлинг
context3D.setCulling(Context3DTriangleFace.NONE);
//Не знаю для чего это, но взял от сюда - https://gist.github.com/noonat/847106
//context3D.setDepthTest(true,Context3DCompareMode.LESS_EQUAL);
//Ширина и высота frameBuffer-а
var backBufferWidth:uint = stage.stageHeight;
var backBufferHeight:uint = stage.stageHeight;
//AntiAliasing
var antiAlias:uint = 0//0,2,4,8,16
log("backBuffer",backBufferWidth,backBufferHeight);
//Конфигурируем размеры.
context3D.configureBackBuffer(backBufferWidth,backBufferHeight,antiAlias,true,true);
//Наши шейдеры.
const VERTEX_SHADER:String =
//"mov op, va0 \n" +
"m44 op, va0, vc0 \n" +
"mov v0, va1";
const FRAGMENT_SHADER:String =
"mov oc, v0";
//Наши скомпилированные шейдеры.
vertexShader.assemble(Context3DProgramType.VERTEX,VERTEX_SHADER);
fragmentShader.assemble(Context3DProgramType.FRAGMENT,FRAGMENT_SHADER);
//Программа
var program:Program3D = context3D.createProgram();
program.upload(vertexShader.agalcode,fragmentShader.agalcode);
context3D.setProgram(program);
// Создаем спрайты
// var sprite3D:Sprite3D = new Sprite3D(context3D,Vector.<Number>([
// //xyz rgb
// -0.3, 0.3, 0.0, 1.0, 0.0, 0.0,
//
// 0.3, 0.3, 0.0, 0.0, 0.0, 0.0,
// 0.0,-0.3, 0.0, 1.0, 1.0, 0.0
// ]),Vector.<uint>([0,1,2]));
// sprite3Ds.push(sprite3D);
sprite3Ds = new Vector.<Sprite3D>();
//Переводим данные кинекта в треугольники.
initPointCloud(320,240,1,true);
amountOfSprites = sprite3Ds.length;
contextChanged = true;
//Начинаем рендерить
removeEventListener(Event.ENTER_FRAME,render);
addEventListener(Event.ENTER_FRAME,render);
log("initContext3D OK");
}
private var perspective:PerspectiveMatrix3D;
private var modelMatrix:Matrix3D;
private var perspectiveMatrix:Matrix3D;
private var modelPerspectiveMatrix:Matrix3D;
private var amountOfSprites:uint=0;
private var sprite3Ds:Vector.<Sprite3D> = new Vector.<Sprite3D>();
private var contextChanged:Boolean=false;
private var matrix3D:Matrix3D;
public function render(e:Event):void
{
if(!contextChanged)return;
context3D.clear(0,0,0);
if(!matrix3D)
{
matrix3D = new Matrix3D();
}
else
{
matrix3D.identity();
}
matrix3D.appendRotation(rY, Vector3D.Y_AXIS);
matrix3D.appendRotation(rX, Vector3D.X_AXIS);
matrix3D.appendRotation(rZ, Vector3D.Z_AXIS);
matrix3D.appendScale(scale,scale,scale);
matrix3D.appendTranslation(offsetX, offsetY, offsetZ);
if(!perspective)
{
perspective = new PerspectiveMatrix3D();
var aspect:Number = 3/3;
var zNear:Number = 0.1;
var zFar:Number = 2000;
var fov:Number = this.fov*Math.PI/180;
perspective.perspectiveFieldOfViewLH(fov, aspect, zNear, zFar);
}
matrix3D.append(perspective);
for(var i:uint=0;i<amountOfSprites;i++)
{
//Геометрия
context3D.setVertexBufferAt(0,sprite3Ds[i].vertexBuffer3D,0,Context3DVertexBufferFormat.FLOAT_3);
context3D.setVertexBufferAt(1,sprite3Ds[i].vertexBuffer3D,3,Context3DVertexBufferFormat.FLOAT_3);
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX,0,matrix3D);
//Отрисовка
context3D.drawTriangles(sprite3Ds[i].indexBuffer3D,0,sprite3Ds[i].numTriangles);
}
//Окончательный вывод изображения.
context3D.present();
contextChanged = false;
log("render OK");
}
private var rY:Number=0;
private var rX:Number=0;
private var rZ:Number=0;
private var offsetX:Number=0;
private var offsetY:Number=0;
private var offsetZ:Number= 2;
private var scale:Number= 1;
private var fov:Number=45;
public var press:Boolean=false;
public var ctrl:Boolean=false;
public var shift:Boolean=false;
public var lastMouse:Point;
public function onMDown(e:MouseEvent):void
{
lastMouse=new Point(stage.mouseX,stage.mouseY);
updateInput();
removeEventListener(Event.ENTER_FRAME,updateInput);
addEventListener(Event.ENTER_FRAME,updateInput);
ctrl=e.ctrlKey;
shift = e.shiftKey;
}
public function onMUp(e:MouseEvent):void
{
removeEventListener(Event.ENTER_FRAME,updateInput);
ctrl = false;
shift = false;
}
public function onMWheel(e:MouseEvent):void
{
contextChanged = true;
if(e.ctrlKey)
{
fov -= e.delta;
perspective = null;
log2("fov =",fov.toFixed(2));
}
else
{
rZ -= e.delta;
log2("rotationZ =",rZ.toFixed(2));
}
}
private var sZ:Number = 1;
private function updateInput(e:Event=null):void {
var currentMouse:Point=new Point(stage.mouseX,stage.mouseY);
if(ctrl && shift)
{
scale += (currentMouse.x-lastMouse.x)*0.01;
log2("scale =",scale);
}
else if(ctrl)
{
offsetZ += (currentMouse.x-lastMouse.x);
log2("offsetZ =",offsetZ);
}
else if(shift)
{
offsetX += (currentMouse.x-lastMouse.x)*0.01;
offsetY -= (currentMouse.y-lastMouse.y)*0.01;
log2("offsetX =",offsetX.toFixed(2),"offsetY =",offsetY.toFixed(2));
}
else
{
rY-= (currentMouse.x-lastMouse.x);
rX-= (currentMouse.y-lastMouse.y);
log2("rotationY =",rY.toFixed(2),"rotationX =",rX.toFixed(2));
}
lastMouse=currentMouse;
contextChanged = true;
}
private var pointCloud:ByteArray;
public function initPointCloud(width:int=320,height:int=240,density:int=1,includeRGB:Boolean=false):void
{
var vertices:Vector.<Number> = new Vector.<Number>();
var indexes:Vector.<uint> = initIndexes2(width);
var i:uint=0;
var j:uint=0;
var offset:Number = 0.5;
var centerX:Number = width*0.5;
var centerY:Number = height*0.5;
pointCloud.position=0;
if(!includeRGB)
{
while(pointCloud.bytesAvailable>0)
{
var x:Number = Number(pointCloud.readUnsignedByte());
x += pointCloud.readUnsignedByte() << 8;
var y:Number = Number(pointCloud.readUnsignedByte());
y += pointCloud.readUnsignedByte() << 8;
var z:Number = Number(pointCloud.readUnsignedByte());
z += pointCloud.readUnsignedByte() << 8;
vertices.push(x);
vertices.push(y);
vertices.push(z*0.01);
i++;
}
}
else
{
while(pointCloud.bytesAvailable>0)
{
//1 байт 0-255
x = Number(pointCloud.readUnsignedByte());
//2 байт 255 - 25535
x += pointCloud.readUnsignedByte() << 8;
//3 байт
y = Number(pointCloud.readUnsignedByte());
//4 байт
y += pointCloud.readUnsignedByte() << 8;
//5 байт
z = Number(pointCloud.readUnsignedByte());
//6 байт
z += pointCloud.readUnsignedByte() << 8;
//7 байт - RED 1
var r:Number = Number(pointCloud.readUnsignedByte());
//8 байт - RED 2
pointCloud.readUnsignedByte();
//9 байт - GREEN 1
var g:Number = Number(pointCloud.readUnsignedByte());
//10 байт - GREEN 2
pointCloud.readUnsignedByte();
//11 байт - BLUE 1
var b:Number = Number(pointCloud.readUnsignedByte());
//12 байт - BLUE 2
pointCloud.readUnsignedByte();
x-=centerX;
y-=centerY;
//z*= 0;
r/=255;
g/=255;
b/=255;
//Первая вершина треугольника
vertices.push(x-offset);
vertices.push(y-offset);
vertices.push(z);
vertices.push(r);
vertices.push(g);
vertices.push(b);
//Вторая вершина треугольника
vertices.push(x+offset);
vertices.push(y-offset);
vertices.push(z);
vertices.push(r);
vertices.push(g);
vertices.push(b);
//Третья вершина треугольника
vertices.push(x+offset);
vertices.push(y+offset);
vertices.push(z);
vertices.push(r);
vertices.push(g);
vertices.push(b);
//Четвертая вершина треугольника
vertices.push(x-offset);
vertices.push(y+offset);
vertices.push(z);
vertices.push(r);
vertices.push(g);
vertices.push(b);
i++;
if(i>=width)
{
var sprite3D:Sprite3D = new Sprite3D(context3D,vertices,indexes);
sprite3Ds.push(sprite3D);
vertices = new Vector.<Number>();
i = 0;
j++;
}
}
}
log("initPointCloud OK");
function initIndexes2(triangles:int=320):Vector.<uint>
{
var vi:Vector.<uint> = new Vector.<uint>();
var indexAmount:uint = triangles*4;
for(var i:uint=0;i<indexAmount;i+=4)
{
vi.push(i);
vi.push(i+1);
vi.push(i+2);
vi.push(i);
vi.push(i+2);
vi.push(i+3);
}
vi.fixed=true;
return vi;
}
}
private var tf:TextField;
public var log:Function=drawText;
public function clearLog():void
{
if(tf)tf.text="";
}
private var previewText:String;
private var previewCount:int=1;
private var previewLength:int=0;
public function drawText(...args):void
{
if(!tf)
{
tf=new TextField();
tf.textColor=0x0000ff;
tf.type=TextFieldType.INPUT;
tf.addEventListener(Event.CHANGE,posTf);
tf.multiline=true;
tf.autoSize="right";
var tfr:TextFormat = new TextFormat();
tfr.align ="right";
tf.defaultTextFormat=tfr;
tf.setTextFormat(tf.defaultTextFormat);
tf.filters=[new DropShadowFilter(0,0,0xffffff,1,5,5,3)];
}
if(stage)stage.addChild(tf);
var text:String="";
for(var i:uint=0;i<args.length;i++)text+=(i==0?"":" ")+String(args[i]);
if(previewText==text)
{
previewCount++;
if(previewCount==2)
{
var extendedText:String="[ "+previewCount+" ] "+text;
tf.text=tf.text.substring(0,tf.text.length-text.length)+extendedText;
previewLength=extendedText.length;
}
else
{
extendedText="[ "+previewCount+" ] "+text;
tf.text=tf.text.substring(0,tf.text.length-previewLength)+extendedText;
previewLength=extendedText.length;
}
}
else
{
previewCount=1;
previewLength=0;
tf.appendText((tf.text==""?"":"\n")+text);
}
previewText=text;
posTf();
function posTf(e:Event=null):void
{
tf.x=stage?stage.stageWidth-tf.width-10:10;
tf.y=stage?stage.stageHeight-tf.height:300-tf.height;
}
}
public var log2:Function = drawText2;
private var tf2:TextField;
private var previewText2:String;
private var previewCount2:int=1;
private var previewLength2:int=0;
public function drawText2(...args):void
{
if(!tf2)
{
tf2=new TextField();
tf2.textColor=0x00ffff;
tf2.type=TextFieldType.INPUT;
tf2.addEventListener(Event.CHANGE,posTf);
tf2.multiline=true;
tf2.autoSize="right";
var tfr:TextFormat = new TextFormat();
tfr.align ="right";
tf2.defaultTextFormat=tfr;
tf2.setTextFormat(tf2.defaultTextFormat);
// tf2.filters=[new DropShadowFilter(0,0,0xffffff,1,5,5,3)];
}
tf2.text="";
if(stage)stage.addChild(tf2);
var text:String="";
for(var i:uint=0;i<args.length;i++)text+=(i==0?"":" ")+String(args[i]);
if(previewText==text)
{
previewCount++;
if(previewCount==2)
{
var extendedText:String="[ "+previewCount2+" ] "+text;
tf2.text=tf2.text.substring(0,tf2.text.length-text.length)+extendedText;
previewLength2=extendedText.length;
}
else
{
extendedText="[ "+previewCount2+" ] "+text;
tf2.text=tf2.text.substring(0,tf2.text.length-previewLength2)+extendedText;
previewLength2=extendedText.length;
}
}
else
{
previewCount2=1;
previewLength2=0;
tf2.appendText((tf2.text==""?"":"\n")+text);
}
previewText2=text;
posTf();
function posTf(e:Event=null):void
{
tf2.x=10;
tf2.y=stage?stage.stageHeight-tf2.height:300-tf2.height;
}
}
}
}
2. Sprite3D.as