FillCircleMaterial
forked from forked from: MeshUtility (diff: 1621)
A simple shader example for Alternativa3d to help draw solid 3d circles. The material fills surface with solid color in light-independent manner within a circle radius.
ActionScript3 source code
/**
* Copyright Glidias ( http://wonderfl.net/user/Glidias )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/21s7
*/
package {
import alternativa.engine3d.alternativa3d;
import alternativa.engine3d.materials.TextureMaterial;
import alternativa.engine3d.materials.VertexLightTextureMaterial;
import alternativa.engine3d.materials.StandardMaterial;
import alternativa.engine3d.objects.WireFrame;
import alternativa.engine3d.objects.Mesh
import alternativa.engine3d.primitives.GeoSphere;
import alternativa.engine3d.primitives.Plane;
import alternativa.engine3d.resources.BitmapTextureResource;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.net.URLRequest;
import flash.system.LoaderContext;
use namespace alternativa3d;
public class FillCircleMaterialTest extends Sprite {
private var scene:Template
private const RADIAN:Number = Math.PI / 180;
public function FillCircleMaterialTest():void {
// preload crap before init
init();
}
private function init():void {
scene = new Template();
scene.addEventListener(Template.VIEW_CREATE, initialize);
addChild(scene);
}
private function initialize(event:Event):void {
scene.removeEventListener(Template.VIEW_CREATE, initialize);
var material:FillCircleMaterial = new FillCircleMaterial(0xFF0000, .4);
var plane:Plane = new Plane(200, 200, 1, 1, true, false, material, material);
scene.controlObject.addChild(plane)
scene.initialize();
}
}
}
import alternativa.engine3d.alternativa3d;
import alternativa.engine3d.primitives.GeoSphere;
import alternativa.engine3d.controllers.SimpleObjectController;
import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Resource;
import alternativa.engine3d.core.View;
import alternativa.engine3d.core.VertexAttributes;
import alternativa.engine3d.core.Transform3D;
import alternativa.engine3d.objects.Mesh;
import alternativa.engine3d.objects.Surface;
import alternativa.engine3d.objects.Joint;
import alternativa.engine3d.lights.AmbientLight;
import alternativa.engine3d.lights.DirectionalLight;
import alternativa.engine3d.resources.Geometry;
import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.utils.Dictionary;
import flash.geom.Vector3D;
import flash.utils.Dictionary;
import flash.geom.*;
class Template extends Sprite {
public static const VIEW_CREATE:String = 'view_create'
private var stage3D:Stage3D
private var camera:Camera3D
public var scene:Object3D
public var cameraController:SimpleObjectController;
public var objectController:SimpleObjectController;
public var controlObject:Object3D;
protected var directionalLight:DirectionalLight;
protected var ambientLight:AmbientLight;
public function Template() {
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.HIGH;
//Stage3Dを用意
stage3D = stage.stage3Ds[0];
//Context3Dの生成、呼び出し、初期化
stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate);
stage3D.requestContext3D();
}
private function onContextCreate(e:Event):void {
stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreate);
//View3D(表示エリア)の作成
var view:View = new View(stage.stageWidth, stage.stageHeight);
view.antiAlias = 4
addChild(view);
//Scene(コンテナ)の作成
scene = new Object3D();
//Camera(カメラ)の作成
camera = new Camera3D(1, 100000);
camera.view = view;
scene.addChild(camera)
camera.diagram
addChild(camera.diagram)
//Cameraをコントロールする場合は、CameraControlerの作成
cameraController = new SimpleObjectController(stage, camera, 100);
cameraController.mouseSensitivity = 0;
cameraController.unbindAll();
//Cameraの位置調整
cameraController.setObjectPosXYZ(0, -300, 0);
cameraController.lookAtXYZ(0, 0, 0);
//Lightを追加
ambientLight = new AmbientLight(0xFFFFFF);
ambientLight.intensity = 0.5;
// scene.addChild(ambientLight);
//Lightを追加
directionalLight = new DirectionalLight(0xFFFFFF);
//手前右上から中央へ向けた指向性light
directionalLight.x = 0;
directionalLight.y = -100;
directionalLight.z = -100;
directionalLight.lookAt(0, 0, 0);
scene.addChild(directionalLight);
//directionalLight.visible = false;
//コントロールオブジェクトの作成
controlObject = new Object3D()
scene.addChild(controlObject);
dispatchEvent(new Event(VIEW_CREATE));
}
public function initialize():void {
for each (var resource:Resource in scene.getResources(true)) {
trace(resource)
resource.upload(stage3D.context3D);
}
//オブジェクト用のコントローラー(マウス操作)
objectController = new SimpleObjectController(stage, controlObject, 100);
objectController.mouseSensitivity = 0.2;
//レンダリング
camera.render(stage3D);
addEventListener(Event.ENTER_FRAME, onRenderTick);
}
public function onRenderTick(e:Event):void {
objectController.update()
camera.render(stage3D);
}
}
/**
* Primitive
*/
class Primitive extends Mesh {
protected const RADIAN:Number = Math.PI / 180;
public var inSide:Surface = null;
public var outSide:Surface = null;
protected var indices:Vector.<uint> = new Vector.<uint>();
protected var positions:Vector.<Number> = new Vector.<Number>();
protected var texcoords:Vector.<Number> = new Vector.<Number>();
//表用と裏用のpositionsとtexcoordsとindicesとを追加
protected var positionsInSide:Vector.<Number> = new Vector.<Number>();
protected var positionsOutSide:Vector.<Number> = new Vector.<Number>();
protected var texcoordsInSide:Vector.<Number> = new Vector.<Number>();
protected var texcoordsOutSide:Vector.<Number> = new Vector.<Number>();
protected var indicesInSide:Vector.<uint> = new Vector.<uint>();
protected var indicesOutSide:Vector.<uint> = new Vector.<uint>();
public function Primitive() {
geometry = new Geometry();
var pos:int = VertexAttributes.POSITION
var tex:int = VertexAttributes.TEXCOORDS[0]
geometry.addVertexStream([pos,pos,pos,tex,tex]);
}
protected function setGeometry():void {
positions = positionsOutSide.concat(positionsInSide);
texcoords = texcoordsOutSide.concat(texcoordsInSide);
indices = indicesOutSide.concat();
var indexStart:int = positionsOutSide.length / 3;
var count:uint = indicesInSide.length;
for (var i:uint = 0; i < count; i++) {
indices.push(indicesInSide[i] + indexStart);
}
geometry.numVertices = positions.length / 3;
geometry.setAttributeValues(VertexAttributes.POSITION, positions);
geometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], texcoords);
geometry.indices = indices;
if (indicesInSide.length) {
inSide = this.addSurface(null, indicesOutSide.length, indicesInSide.length / 3);
}
if (indicesOutSide.length) {
outSide = this.addSurface(null, 0, indicesOutSide.length / 3);
}
MeshUtility.createNormal(this);
}
}
class RoundMesh extends Primitive {
public function RoundMesh(lineList:Vector.<Point>, radialSegments:uint = 3,lastSegments:uint = 0,star:Number = 0, twoSide:Boolean = false, reverse:Boolean = false) {
super();
var rInterval:Number = 360 / radialSegments;
var heightSegments:uint = lineList.length - 1;
var height:Number = lineList[heightSegments].y - lineList[0].y;
var radian:Number
var segmentCount:int = (lastSegments > 0) ? lastSegments : radialSegments;
for (var i:int = 0; i < segmentCount; i++) {
for (var j:int = 0; j < heightSegments; j++) {
var vertices:Vector.<Vector3D> = new Vector.<Vector3D>(4);
var uvs:Vector.<Point> = new Vector.<Point>(4);
//時計周りで四角を作成していく
var tempRadiusA:Number = (i % 2 == 1 && star > 0) ? lineList[j].x * star : lineList[j].x
var tempRadiusB:Number = (i % 2 == 1 && star > 0) ? lineList[j+1].x * star : lineList[j+1].x
radian = (rInterval * i - 90) * RADIAN;
vertices[0] = new Vector3D(Math.cos(radian) * tempRadiusA, Math.sin(radian) * tempRadiusA, lineList[j].y-(height/2));
vertices[3] = new Vector3D(Math.cos(radian) * tempRadiusB, Math.sin(radian) * tempRadiusB, lineList[j+1].y-(height/2));
radian = (rInterval * (i + 1) - 90) * RADIAN;
vertices[1] = new Vector3D(Math.cos(radian) * tempRadiusA, Math.sin(radian) * tempRadiusA, lineList[j].y-(height/2));
vertices[2] = new Vector3D(Math.cos(radian) * tempRadiusB, Math.sin(radian) * tempRadiusB, lineList[j+1].y-(height/2));
uvs[0] = new Point(1 / radialSegments * -i, 1 / heightSegments * j);
uvs[3] = new Point(1 / radialSegments * -i, 1 / heightSegments * (j+1));
uvs[1] = new Point(1 / radialSegments * -(i+1), 1 / heightSegments * j);
uvs[2] = new Point(1 / radialSegments * -(i+1), 1 / heightSegments * (j+1));
//Cylinderに巻きつける場合、裏表が逆になるので注意(UVも逆)
if (reverse == false || twoSide == true) {
MeshUtility.createSquare(vertices, uvs, indicesOutSide, positionsOutSide, texcoordsOutSide, true)
}
if (reverse == true || twoSide == true) {
MeshUtility.createSquare(vertices, uvs, indicesInSide, positionsInSide, texcoordsInSide, false)
}
}
}
setGeometry();
}
}
class Cylinder extends Primitive {
public function Cylinder(topRadius:Number = 0, bottomRadius:Number = 50, height:Number = 100, radialSegments:uint = 3, heightSegments:uint = 1, lastSegments:uint = 0,star:Number = 0, twoSide:Boolean = false, reverse:Boolean = false) {
var rInterval:Number = 360 / radialSegments;
var hInterval:Number = height / heightSegments;
var radian:Number
var segmentCount:int = (lastSegments > 0) ? lastSegments : radialSegments;
for (var i:int = 0; i < segmentCount; i++) {
for (var j:int = 0; j < heightSegments; j++) {
var vertices:Vector.<Vector3D> = new Vector.<Vector3D>(4);
var uvs:Vector.<Point> = new Vector.<Point>(4);
var px:Number=0;
var py:Number = 0;
var tmpR:Number = 0;
var starRatio:Number = 0;
radian = (rInterval * i - 90) * RADIAN;
starRatio = (i % 2 == 1 && star > 0) ? star : 1;
px = Math.cos(radian)
py = Math.sin(radian)
tmpR = getRadius(topRadius, bottomRadius, height, hInterval * j, starRatio);
vertices[0] = new Vector3D(px * tmpR, py * tmpR, hInterval * j - (height / 2));
tmpR = getRadius(topRadius, bottomRadius, height, hInterval * (j + 1), starRatio);
vertices[3] = new Vector3D(px * tmpR, py * tmpR, hInterval * (j + 1) - (height / 2));
radian = (rInterval * (i + 1) - 90) * RADIAN;
starRatio = (i % 2 == 0 && star > 0) ? star : 1;
px = Math.cos(radian);
py = Math.sin(radian);
tmpR = getRadius(topRadius, bottomRadius, height, hInterval * j, starRatio);
vertices[1] = new Vector3D(px * tmpR, py * tmpR, hInterval * j - (height / 2));
tmpR = getRadius(topRadius, bottomRadius, height, hInterval * (j + 1), starRatio);
vertices[2] = new Vector3D(px * tmpR, py * tmpR, hInterval * (j + 1) - (height / 2));
var u:Number = 1 / radialSegments;
var v:Number = 1 / heightSegments;
uvs[0] = new Point(u * -i, v * j);
uvs[3] = new Point(u * -i, v * (j + 1));
uvs[1] = new Point(u * -(i + 1), v * j);
uvs[2] = new Point(u * -(i + 1), v * (j + 1));
//Cylinderに巻きつける場合、裏表が逆になるので注意(UVも逆)
if (reverse == false || twoSide == true) {
MeshUtility.createSquare(vertices, uvs, indicesOutSide, positionsOutSide, texcoordsOutSide, true)
}
if (reverse == true || twoSide == true) {
MeshUtility.createSquare(vertices, uvs, indicesInSide, positionsInSide, texcoordsInSide, false)
}
}
}
setGeometry()
}
/**
* 半径を高さの比率から割り出す
* @return
*/
private function getRadius(topRadius:Number, bottomRadius:Number, height:Number, length:Number, starRatio:Number):Number {
var result:Number
var difference:Number
var ratio:Number
if (topRadius > bottomRadius) {
difference = topRadius - bottomRadius;
ratio = (length) ? (height - length) / height : 1
result = (bottomRadius + (difference * ratio));
} else {
difference = bottomRadius - topRadius;
ratio = (length) ? length / height : 0
result = (topRadius + (difference * ratio));
}
result *= starRatio
return result;
}
}
/**
* 頂点に隣接する面法線を収集するクラス
*/
class ExtraVertex {
public var vertex:Vector3D;
public var normals:Dictionary;
public var indices:Vector.<uint>;
public function ExtraVertex(x:Number, y:Number, z:Number) {
vertex = new Vector3D(x, y, z);
normals = new Dictionary();
indices = new Vector.<uint>();
}
}
/**
* MeshUtility
*/
use namespace alternativa3d;
class MeshUtility {
public function MeshUtility() {
}
/**
* 3つの頂点座標から、Faceを作成し、indices、positionsに各値を登録する
*/
public static function createTriangle(vertices:Vector.<Vector3D>, uvs:Vector.<Point>,
indices:Vector.<uint>, positions:Vector.<Number>,
texcoords:Vector.<Number>, reverse:Boolean = false):void {
if (reverse == false) {
//三角形用の頂点を登録
positions.push(vertices[0].x, vertices[0].y, vertices[0].z,
vertices[2].x, vertices[2].y, vertices[2].z,
vertices[1].x, vertices[1].y, vertices[1].z);
//三角形用のUVを登録
texcoords.push(uvs[0].x, uvs[0].y,uvs[2].x, uvs[2].y,uvs[1].x, uvs[1].y);
} else {
//三角形用の頂点を登録
positions.push(vertices[0].x, vertices[0].y, vertices[0].z,
vertices[1].x, vertices[1].y, vertices[1].z,
vertices[2].x, vertices[2].y, vertices[2].z);
//三角形用のUVを登録
texcoords.push(uvs[0].x, uvs[0].y,uvs[1].x, uvs[1].y,uvs[2].x, uvs[2].y);
}
//Face用indexを登録
var startIndex:uint = indices.length
indices.push(startIndex + 0, startIndex + 1, startIndex + 2);
}
/**
* 4つの頂点座標から、四角形(2つのFace)を作成し、indices、positions、uvsに各値を登録する
*/
public static function createSquare(vertices:Vector.<Vector3D>, uvs:Vector.<Point>,
indices:Vector.<uint>, positions:Vector.<Number>,
texcoords:Vector.<Number>, reverse:Boolean = false):void {
if (reverse == false) {
positions.push( vertices[0].x, vertices[0].y, vertices[0].z,
vertices[3].x, vertices[3].y, vertices[3].z,
vertices[1].x, vertices[1].y, vertices[1].z);
positions.push( vertices[1].x, vertices[1].y, vertices[1].z,
vertices[3].x, vertices[3].y, vertices[3].z,
vertices[2].x, vertices[2].y, vertices[2].z);
//三角形用のUVを登録
texcoords.push(uvs[0].x, uvs[0].y,uvs[3].x, uvs[3].y,uvs[1].x, uvs[1].y);
texcoords.push(uvs[1].x, uvs[1].y,uvs[3].x, uvs[3].y,uvs[2].x, uvs[2].y);
} else {
positions.push( vertices[0].x, vertices[0].y, vertices[0].z,
vertices[1].x, vertices[1].y, vertices[1].z,
vertices[3].x, vertices[3].y, vertices[3].z);
positions.push( vertices[1].x, vertices[1].y, vertices[1].z,
vertices[2].x, vertices[2].y, vertices[2].z,
vertices[3].x, vertices[3].y, vertices[3].z);
//三角形用のUVを登録
texcoords.push(uvs[0].x, uvs[0].y,uvs[1].x, uvs[1].y,uvs[3].x, uvs[3].y);
texcoords.push(uvs[1].x, uvs[1].y, uvs[2].x, uvs[2].y, uvs[3].x, uvs[3].y);
}
//Face用indexを登録
var startIndex:uint = indices.length
indices.push(startIndex + 0, startIndex + 1, startIndex + 2);
indices.push(startIndex + 3, startIndex + 4, startIndex + 5);
}
/**
* 指定Meshの法線を作成します
* @param mesh
*/
public static function createNormal(mesh:Mesh):void {
//法線の有無のチェック
if (mesh.geometry.hasAttribute(VertexAttributes.NORMAL) == false) {
var nml:int = VertexAttributes.NORMAL;
mesh.geometry.addVertexStream([nml,nml,nml]);
}
var indices:Vector.<uint> = mesh.geometry.indices;
var positions:Vector.<Number> = mesh.geometry.getAttributeValues(VertexAttributes.POSITION);
var vartices:Vector.<Vector3D> = new Vector.<Vector3D>(positions.length / 3);
var vNormals:Vector.<Vector3D> = new Vector.<Vector3D>(positions.length / 3);
var i:int;
var count:uint = positions.length / 3;
for (i = 0; i < count; i++) {
vartices[i] = new Vector3D(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]);
}
//面法線を求め、頂点法線に代入する
count = indices.length;
for (i = 0; i < count; i += 3) {
var normal:Vector3D = calcNormal(vartices[indices[i]], vartices[indices[i + 1]], vartices[indices[i + 2]]);
vNormals[indices[i]] = normal;
vNormals[indices[i + 1]] = normal;
vNormals[indices[i + 2]] = normal;
}
var normals:Vector.<Number> = new Vector.<Number>();
count = vNormals.length;
for (i = 0; i < count; i++) {
if (vNormals[i]) {
normals.push(vNormals[i].x, vNormals[i].y, vNormals[i].z);
}
}
mesh.geometry.setAttributeValues(VertexAttributes.NORMAL, normals);
}
/**
* 面法線の計算
* 三つの頂点座標からなる三角ポリゴンの法線を計算し返します
*/
public static function calcNormal(a:Vector3D, b:Vector3D, c:Vector3D):Vector3D {
var v1:Vector3D = b.subtract(a);
var v2:Vector3D = c.subtract(a);
var v3:Vector3D = v1.crossProduct(v2);
//var v3:Vector3D = cross(v1,v2);
v3.normalize();
return (v3);
}
/**
* 指定Meshの法線をSmoothShadingにします
* @param mesh
*/
public static function smoothShading(mesh:Mesh,separateSurface:Boolean=false,threshold:Number=0.000001):void {
var indices:Vector.<uint> = mesh.geometry.indices;
var positions:Vector.<Number> = mesh.geometry.getAttributeValues(VertexAttributes.POSITION);
var normals:Vector.<Number> = mesh.geometry.getAttributeValues(VertexAttributes.NORMAL);
var vartices:Vector.<Vector3D> = new Vector.<Vector3D>(positions.length / 3);
var vNormals:Vector.<Vector3D> = new Vector.<Vector3D>(normals.length / 3);
var vertexDictionary:Dictionary = new Dictionary()
var exVertex:ExtraVertex;
//サーフェースごとに判断する
for (var s:uint = 0; s < mesh.numSurfaces; s++ ) {
var side:String = (separateSurface) ? s.toString() : '';
for (var n:uint = 0; n < mesh.getSurface(s).numTriangles * 3; n++) {
var i:uint = indices[n+mesh.getSurface(s).indexBegin];
vartices[i] = new Vector3D(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]);
//誤差を丸める
vartices[i].x = int(vartices[i].x / threshold) * threshold;
vartices[i].y = int(vartices[i].y / threshold) * threshold;
vartices[i].z = int(vartices[i].z / threshold) * threshold;
vNormals[i] = new Vector3D(normals[i * 3], normals[i * 3 + 1], normals[i * 3 + 2]);
//誤差を丸める
vNormals[i].x = int(vNormals[i].x / threshold) * threshold;
vNormals[i].y = int(vNormals[i].y / threshold) * threshold;
vNormals[i].z = int(vNormals[i].z / threshold) * threshold;
//同じ頂点を集める
//ただし、表裏がある場合があるので法線の方向もチェックする
if (vertexDictionary[vartices[i].toString()+'_'+side]) {
exVertex = vertexDictionary[vartices[i].toString()+'_'+side]
if (exVertex.normals[vNormals[i].toString()+'_'+side] == null) {
exVertex.normals[vNormals[i].toString()+'_'+side] = vNormals[i];
}
exVertex.indices.push(i);
} else {
exVertex = new ExtraVertex(vNormals[i].x, vNormals[i].y, vNormals[i].z);
exVertex.normals[vNormals[i].toString()+'_'+side] = vNormals[i];
exVertex.indices.push(i)
vertexDictionary[vartices[i].toString()+'_'+side] = exVertex
}
}
}
//Normalの平均化
var count:uint = 0;
for each (exVertex in vertexDictionary) {
var normalX:Number = 0;
var normalY:Number = 0;
var normalZ:Number = 0;
count = 0
for each (var normal:Vector3D in exVertex.normals) {
normalX += normal.x;
normalY += normal.y;
normalZ += normal.z;
count++
}
normal = new Vector3D(normalX / count, normalY / count, normalZ / count);
normal.normalize();
count = exVertex.indices.length;
for (i = 0; i < count; i++) {
vNormals[exVertex.indices[i]] = normal;
}
}
count = vNormals.length;
normals = new Vector.<Number>();
for (i = 0; i < count; i++) {
normals.push(vNormals[i].x, vNormals[i].y, vNormals[i].z);
}
mesh.geometry.setAttributeValues(VertexAttributes.NORMAL, normals);
}
/**
* 指定MeshのUVをVertexのxyから仮に作成する
* @param mesh
*/
public static function createUv(mesh:Mesh):void {
if (mesh.geometry.hasAttribute(VertexAttributes.TEXCOORDS[0]) == false) {
var tex:int = VertexAttributes.TEXCOORDS[0];
mesh.geometry.addVertexStream([tex,tex]);
}
mesh.calculateBoundBox()
var width:Number = mesh.boundBox.maxX - mesh.boundBox.minX
var length:Number = mesh.boundBox.maxZ - mesh.boundBox.minZ
var positions:Vector.<Number> = mesh.geometry.getAttributeValues(VertexAttributes.POSITION);
var texcoords:Vector.<Number> = new Vector.<Number>;
var i:int;
for (i = 0; i < positions.length; i += 3) {
texcoords.push((positions[i] - mesh.boundBox.minX) / width, (positions[i + 2] - mesh.boundBox.minZ) / length);
}
mesh.geometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], texcoords);
}
/**
* 指定MeshのTangentを作成する
* @param mesh
*/
static public function createTangent(mesh:Mesh):void {
//接線有無のチェック
var positions:Vector.<Number> = mesh.geometry.getAttributeValues(VertexAttributes.POSITION);
var texcoords:Vector.<Number> = mesh.geometry.getAttributeValues(VertexAttributes.TEXCOORDS[0]);
var normals:Vector.<Number> = mesh.geometry.getAttributeValues(VertexAttributes.NORMAL);
var indices:Vector.<uint> = mesh.geometry.indices;
var vertices:Vector.<Vector3D> = new Vector.<Vector3D>;
var uvs:Vector.<Point> = new Vector.<Point>;
var vNormals:Vector.<Vector3D> = new Vector.<Vector3D>;
var i:int;
for (i = 0; i < positions.length; i += 3) {
vertices.push(new Vector3D(positions[i], positions[i + 1], positions[i + 2]));
}
for (i = 0; i < texcoords.length; i += 2) {
uvs.push(new Point(texcoords[i], texcoords[i + 1]));
}
for (i = 0; i < normals.length; i += 3) {
vNormals.push(new Vector3D(normals[i], normals[i + 1], normals[i + 2]));
}
var tangents:Vector.<Number> = calcTangent(mesh.geometry.indices, vertices, uvs, vNormals);
var geometry:Geometry = new Geometry();
//if (mesh.geometry.hasAttribute(VertexAttributes.TANGENT4) == false) {
var tan:int = VertexAttributes.TANGENT4;
var pos:int = VertexAttributes.POSITION;
var nor:int = VertexAttributes.NORMAL;
var tex:int = VertexAttributes.TEXCOORDS[0];
var attribute:Array = [
pos, pos, pos,
nor, nor, nor,
tan, tan, tan, tan,
tex, tex
]
geometry.addVertexStream(attribute)
//}
geometry.numVertices = mesh.geometry.numVertices
geometry.indices = mesh.geometry.indices;
geometry.setAttributeValues(VertexAttributes.POSITION, positions);
geometry.setAttributeValues(VertexAttributes.NORMAL, normals);
geometry.setAttributeValues(VertexAttributes.TANGENT4, tangents);
geometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], texcoords);
mesh.geometry = geometry;
}
/**
* 複数のMeshを結合し、1つのMeshにします
* @param meshs
* @return
*/
public static function bindMeshs(meshs:Vector.<Mesh>):Mesh {
var count:uint = meshs.length;
var indices:Vector.<uint> = new Vector.<uint>();
var positions:Vector.<Number> = new Vector.<Number>();
var texcoords:Vector.<Number> = new Vector.<Number>();
var nextIndex:uint = 0;
var nextPosition:uint = 0;
var mesh:Mesh = meshs[i];
var i:int
var j:int
for (i = 0; i < count; i++) {
mesh = meshs[i];
var tempPositions:Vector.<Number> = mesh.geometry.getAttributeValues(VertexAttributes.POSITION);
mesh.matrix.transformVectors(tempPositions, tempPositions);
positions = positions.concat(tempPositions);
texcoords = texcoords.concat(mesh.geometry.getAttributeValues(VertexAttributes.TEXCOORDS[0]));
var tempIndices:Vector.<uint> = mesh.geometry.indices;
var indexCount:uint = tempIndices.length
for (j = 0; j < indexCount; j++) {
tempIndices[j] += nextIndex;
}
indices = indices.concat(tempIndices);
nextIndex += tempPositions.length/3
}
var geometry:Geometry = new Geometry();
var attributes:Array = [];
attributes[0] = VertexAttributes.POSITION;
attributes[1] = VertexAttributes.POSITION;
attributes[2] = VertexAttributes.POSITION;
attributes[3] = VertexAttributes.TEXCOORDS[0];
attributes[4] = VertexAttributes.TEXCOORDS[0];
geometry.addVertexStream(attributes);
geometry.numVertices = positions.length/3;
geometry.setAttributeValues(VertexAttributes.POSITION, positions);
geometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], texcoords);
geometry.indices = indices;
var result:Mesh = new Mesh()
result.geometry = geometry;
//サーフェースのコピー
var indexBegin:uint = 0
for (i = 0; i < count; i++) {
mesh = meshs[i];
for (j = 0; j < mesh.numSurfaces; j++) {
var surface:Surface = mesh.getSurface(j);
result.addSurface(surface.material, surface.indexBegin+indexBegin, surface.numTriangles)
}
indexBegin = surface.indexBegin+indexBegin + surface.numTriangles * 3;
}
//normal再計算
createNormal(result);
return result;
}
/**
* Cylinder、Cone、Dome、RoundMesh等を合成した、MeshのSurfaceを合成します
* UVのV値のみ更新されます
*
* 頂点情報の高さ(Z座標)で判断します
*
*/
public static function repairRoundSurface(mesh:Mesh):Mesh {
var positions:Vector.<Number> = mesh.geometry.getAttributeValues(VertexAttributes.POSITION);
var texcoords:Vector.<Number> = mesh.geometry.getAttributeValues(VertexAttributes.TEXCOORDS[0]);
var count:int = positions.length / 3
//全体の高さを割り出す
var minY:Number=0
var maxY:Number=0
for (var i:int = 0; i < count; i++) {
if (minY > positions[i * 3 + 2])
minY = positions[i * 3 + 2];
if (maxY < positions[i * 3 + 2])
maxY = positions[i * 3 + 2];
}
var height:Number = maxY - minY;
for (i = 0; i < count; i++) {
texcoords[i * 2 + 1] = (positions[i * 3 + 2] - minY) / height;
}
mesh.geometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], texcoords);
var result:Mesh = new Mesh();
result.geometry = mesh.geometry
result.addSurface(null, 0, positions.length / 9);
return result;
}
/**
* サーフェースのコピー
* @param origin
* @param mesh
*/
public static function copySurface(origin:Mesh, mesh:Mesh):void {
for (var i:uint = 0; i < origin.numSurfaces; i++) {
var surface:Surface = origin.getSurface(i);
mesh.addSurface(surface.material, surface.indexBegin, surface.numTriangles)
}
}
/**
* TANGENT4を再計算
* @param indices
* @param vertex
* @param uvs
* @param normals
* @return
*/
static public function calcTangent(indices:Vector.<uint>, vertices:Vector.<Vector3D>, uvs:Vector.<Point>, normals:Vector.<Vector3D>):Vector.<Number> {
var tangent:Vector.<Number> = new Vector.<Number>;
var numTriangle:int = indices.length / 3;
var numVertex:int = vertices.length;
var tan1:Vector.<Vector3D> = new Vector.<Vector3D>;
var tan2:Vector.<Vector3D> = new Vector.<Vector3D>;
var i:int;
for (i = 0; i < vertices.length; i++) {
tan1.push(new Vector3D());
tan2.push(new Vector3D());
}
var max:int = indices.length;
for (i = 0; i < max; i += 3) {
var i1:Number = indices[i];
var i2:Number = indices[i + 1];
var i3:Number = indices[i + 2];
var v1:Vector3D = vertices[i1];
var v2:Vector3D = vertices[i2];
var v3:Vector3D = vertices[i3];
var w1:Point = uvs[i1];
var w2:Point = uvs[i2];
var w3:Point = uvs[i3];
var x1:Number = v2.x - v1.x;
var x2:Number = v3.x - v1.x;
var y1:Number = v2.y - v1.y;
var y2:Number = v3.y - v1.y;
var z1:Number = v2.z - v1.z;
var z2:Number = v3.z - v1.z;
var s1:Number = w2.x - w1.x;
var s2:Number = w3.x - w1.x;
var t1:Number = w2.y - w1.y;
var t2:Number = w3.y - w1.y;
var r:Number = 1 / (s1 * t2 - s2 * t1);
var sdir:Vector3D = new Vector3D((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
var tdir:Vector3D = new Vector3D((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
tan1[i1].incrementBy(sdir);
tan1[i2].incrementBy(sdir);
tan1[i3].incrementBy(sdir);
tan2[i1].incrementBy(tdir);
tan2[i2].incrementBy(tdir);
tan2[i3].incrementBy(tdir);
}
for (i = 0; i < numVertex; i++) {
var n:Vector3D = normals[i];
var t:Vector3D = tan1[i];
var tgt:Vector3D = t.subtract(getScaled(n, dot(n, t)));
tgt.normalize();
var w:Number = dot(cross(n, t), tan2[i]) < 0 ? -1 : 1;
tangent.push(tgt.x, tgt.y, tgt.z, w);
}
return tangent;
}
/**
* 2つのベクトルの内積を返します。
* (内積:2つのベクトルがどれだけ平行に近いかを示す数値)
* ・ 1 に近いほど同じ向きで平行
* ・ 0 に近いほど直角
* ・-1 に近いほど逆向きで平行
*/
static public function dot(a:Vector3D, b:Vector3D):Number {
return (a.x * b.x) + (a.y * b.y) + (a.z * b.z);
}
/**
* 2つのベクトルの外積を返します。
* (外積:2つのベクトルで作られる面に垂直なベクトル(=法線)。)
*/
static public function cross(a:Vector3D, b:Vector3D):Vector3D {
return new Vector3D((a.y * b.z) - (a.z * b.y), (a.z * b.x) - (a.x * b.z), (a.x * b.y) - (a.y * b.x));
}
/**
* スケーリングした新しいベクトルを取得
* @param v
* @param scale
* @return
*/
static public function getScaled(v:Vector3D, scale:Number):Vector3D {
var sv:Vector3D = v.clone();
sv.scaleBy(scale);
return sv;
}
/**
* Jointの位置を初期化
* @param joints
*/
public static function JointBindPose(joints:Vector.<Joint>):void {
var count:uint = joints.length;
for (var i:uint = 0; i < count; i++)
{
var joint:Joint = joints[i]
var jointMatrix:Matrix3D = joint.concatenatedMatrix.clone();
jointMatrix.transpose();
var jointBindingTransform:Transform3D = new Transform3D();
jointBindingTransform.initFromVector(jointMatrix.rawData);
jointBindingTransform.invert();
var matrixVector:Vector.<Number> = new Vector.<Number>();
matrixVector.push(jointBindingTransform.a);
matrixVector.push(jointBindingTransform.b);
matrixVector.push(jointBindingTransform.c);
matrixVector.push(jointBindingTransform.d);
matrixVector.push(jointBindingTransform.e);
matrixVector.push(jointBindingTransform.f);
matrixVector.push(jointBindingTransform.g);
matrixVector.push(jointBindingTransform.h);
matrixVector.push(jointBindingTransform.i);
matrixVector.push(jointBindingTransform.j);
matrixVector.push(jointBindingTransform.k);
matrixVector.push(jointBindingTransform.l);
joint.setBindPoseMatrix(matrixVector);
}
}
}
import alternativa.engine3d.materials.ShaderProgram;
import alternativa.engine3d.materials.compiler.Linker;
import flash.display3D.Context3D;
class TileIndexMaterialProgram extends ShaderProgram {
public var aPosition:int = -1;
public var aUV:int = -1;
public var aUV1:int = -1;
public var aNormal:int = -1;
public var aTangent:int = -1;
public var cProjMatrix:int = -1;
public var cCameraPosition:int = -1;
public var cAmbientColor:int = -1;
public var cSurface:int = -1;
public var cThresholdAlpha:int = -1;
public var sDiffuse:int = -1;
public var sOpacity:int = -1;
public var sBump:int = -1;
public var sGlossiness:int = -1;
public var sSpecular:int = -1;
public var sLightMap:int = -1;
public var cPosition:Vector.<int>;
public var cRadius:Vector.<int>;
public var cAxis:Vector.<int>;
public var cColor:Vector.<int>;
public var cTilePaddSize:int = -1;
public var cTileFrac:int = -1;
public var sTileIndices:int = -1;
public function TileIndexMaterialProgram(vertex:Linker, fragment:Linker, numLigths:int) {
super(vertex, fragment);
cPosition = new Vector.<int>(numLigths);
cRadius = new Vector.<int>(numLigths);
cAxis = new Vector.<int>(numLigths);
cColor = new Vector.<int>(numLigths);
}
override public function upload(context3D:Context3D):void {
super.upload(context3D);
aPosition = vertexShader.findVariable("aPosition");
aUV = vertexShader.findVariable("aUV");
aUV1 = vertexShader.findVariable("aUV1");
aNormal = vertexShader.findVariable("aNormal");
aTangent = vertexShader.findVariable("aTangent");
cProjMatrix = vertexShader.findVariable("cProjMatrix");
cCameraPosition = vertexShader.findVariable("cCameraPosition");
cAmbientColor = fragmentShader.findVariable("cAmbientColor");
cSurface = fragmentShader.findVariable("cSurface");
cThresholdAlpha = fragmentShader.findVariable("cThresholdAlpha");
sDiffuse = fragmentShader.findVariable("sDiffuse");
sOpacity = fragmentShader.findVariable("sOpacity");
sBump = fragmentShader.findVariable("sBump");
sGlossiness = fragmentShader.findVariable("sGlossiness");
sSpecular = fragmentShader.findVariable("sSpecular");
sLightMap = fragmentShader.findVariable("sLightMap");
sTileIndices = fragmentShader.findVariable("sTileIndices");
cTilePaddSize = fragmentShader.findVariable("cTilePaddSize"); // u padding, v padding on atlas. u and v tile sizes + padding on atlas.
cTileFrac = fragmentShader.findVariable("cTileFrac"); // u and v recriprocal fractionals for tile index map, u and v tile sizes on atlas
var count:int = cPosition.length;
for (var i:int = 0; i < count; i++) {
cPosition[i] = fragmentShader.findVariable("c" + i + "Position");
cRadius[i] = fragmentShader.findVariable("c" + i + "Radius");
cAxis[i] = fragmentShader.findVariable("c" + i + "Axis");
cColor[i] = fragmentShader.findVariable("c" + i + "Color");
}
}
}
/**
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
* If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.
* You may add additional accurate notices of copyright ownership.
*
* It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/
* */
import alternativa.engine3d.materials.ShaderProgram;
import alternativa.engine3d.materials.compiler.Linker;
import flash.display3D.Context3D;
class FillCircleMaterialProgram extends ShaderProgram {
public var aPosition:int = -1;
public var cProjMatrix:int = -1;
public var cColor:int = -1;
public var cHalf:int = -1;
public var aUV:int = -1;
public function FillCircleMaterialProgram(vertex:Linker, fragment:Linker) {
super(vertex, fragment);
}
override public function upload(context3D:Context3D):void {
super.upload(context3D);
aPosition = vertexShader.findVariable("aPosition");
aUV = vertexShader.findVariable("aUV");
cProjMatrix = vertexShader.findVariable("cProjMatrix");
cColor = fragmentShader.findVariable("cColor");
cHalf = fragmentShader.findVariable("cHalf");
}
}
import alternativa.engine3d.alternativa3d;
import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.core.DrawUnit;
import alternativa.engine3d.core.Light3D;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Renderer;
import alternativa.engine3d.core.VertexAttributes;
import alternativa.engine3d.materials.compiler.Linker;
import alternativa.engine3d.materials.compiler.Procedure;
import alternativa.engine3d.materials.compiler.VariableType;
import alternativa.engine3d.materials.Material;
import alternativa.engine3d.materials.TextureMaterial;
import alternativa.engine3d.objects.Surface;
import alternativa.engine3d.resources.Geometry;
import flash.display3D.Context3D;
import flash.display3D.Context3DBlendFactor;
import flash.display3D.Context3DProgramType;
import flash.display3D.VertexBuffer3D;
import flash.utils.Dictionary;
use namespace alternativa3d;
/**
* The material fills surface with solid color in light-independent manner within a circle radius.
* @see alternativa.engine3d.objects.Skin#divide()
*/
class FillCircleMaterial extends Material {
private static var caches:Dictionary = new Dictionary(true);
private var cachedContext3D:Context3D;
private var programsCache:Dictionary;
static alternativa3d const _passUVProcedure:Procedure = new Procedure(["#v0=vUV", "#a0=aUV", "mov v0, a0"], "passUVProcedure");
private static const outColorProcedure:Procedure = new Procedure([
"#v0=vUV",
"#c0=cColor", // -- CIRCLE MASKING
"#c1=cHalf", // 0.5
"sub ft0, v0, c1", // subtract uv coordinates from center point to get difference vector
"dp3 ft0, ft0 ft0", // get dot product of difference vector (just dump scalar value in x register)
"sqt ft0.x, ft0.x", // get square root of self-applied dot product to find actual magnitude distance
"sub ft0.x, c1.x, ft0.x", // scalar value = 0.5 - actual magnitude distance
"kil ft0.x", // if value less than 0, do not draw anything!
"mov o0, c0"
],
"outColorProcedure");
/**
* Transparency
*/
public var alpha:Number = 1;
private var red:Number;
private var green:Number;
private var blue:Number;
/**
* Color.
*/
public function get color():uint {
return (red*0xFF << 16) + (green*0xFF << 8) + blue*0xFF;
}
/**
* @private
*/
public function set color(value:uint):void {
red = ((value >> 16) & 0xFF)/0xFF;
green = ((value >> 8) & 0xFF)/0xFF;
blue = (value & 0xff)/0xFF;
}
/**
* Creates a new FillCircleMaterial instance.
* @param color Color .
* @param alpha Transparency.
*/
public function FillCircleMaterial(color:uint = 0x7F7F7F, alpha:Number = 1) {
this.color = color;
this.alpha = alpha;
}
private function setupProgram(object:Object3D):FillCircleMaterialProgram {
var vertexLinker:Linker = new Linker(Context3DProgramType.VERTEX);
var positionVar:String = "aPosition";
vertexLinker.declareVariable(positionVar, VariableType.ATTRIBUTE);
if (object.transformProcedure != null) {
positionVar = appendPositionTransformProcedure(object.transformProcedure, vertexLinker);
}
vertexLinker.addProcedure(_projectProcedure);
vertexLinker.setInputParams(_projectProcedure, positionVar);
vertexLinker.addProcedure(_passUVProcedure);
var fragmentLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
fragmentLinker.addProcedure(outColorProcedure);
fragmentLinker.varyings = vertexLinker.varyings;
return new FillCircleMaterialProgram(vertexLinker, fragmentLinker);
}
/**
* @private
*/
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
var object:Object3D = surface.object;
// Strams
var positionBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
var uvBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.TEXCOORDS[0]);
// Check validity
if (positionBuffer == null || uvBuffer == null) return;
// Program
// Renew program cache for this context
if (camera.context3D != cachedContext3D) {
cachedContext3D = camera.context3D;
programsCache = caches[cachedContext3D];
if (programsCache == null) {
programsCache = new Dictionary();
caches[cachedContext3D] = programsCache;
}
}
var program:FillCircleMaterialProgram = programsCache[object.transformProcedure];
if (program == null) {
program = setupProgram(object);
program.upload(camera.context3D);
programsCache[object.transformProcedure] = program;
}
// Drawcall
var drawUnit:DrawUnit = camera.renderer.createDrawUnit(object, program.program, geometry._indexBuffer, surface.indexBegin, surface.numTriangles, program);
// Streams
drawUnit.setVertexBufferAt(program.aPosition, positionBuffer, geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]);
drawUnit.setVertexBufferAt(program.aUV, uvBuffer, geometry._attributesOffsets[VertexAttributes.TEXCOORDS[0]], VertexAttributes.FORMATS[VertexAttributes.TEXCOORDS[0]]);
// Constants
object.setTransformConstants(drawUnit, surface, program.vertexShader, camera);
drawUnit.setProjectionConstants(camera, program.cProjMatrix, object.localToCameraTransform);
drawUnit.setFragmentConstantsFromNumbers(program.cColor, red, green, blue, alpha);
if (program.cHalf >=0) drawUnit.setFragmentConstantsFromNumbers(program.cHalf, 0.5, 0.5, 0, 1);
// Send to render
if (alpha < 1) {
drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
drawUnit.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT);
} else {
camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE);
}
}
/**
* @inheritDoc
*/
override public function clone():Material {
var res:FillCircleMaterial = new FillCircleMaterial(color, alpha);
res.clonePropertiesFrom(this);
return res;
}
}