1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
| package com.dafishinsea.tutorials.normalmap
{
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.TriangleCulling;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import flash.geom.Utils3D;
import flash.geom.Vector3D;
import flash.text.TextField;
/**
* procedural model of a Pumpkin to demonstrate use of normal map
*/
[SWF(backgroundColor="0x000000", width="800", height="600", frameRate="20")]
public class NormalMap1 extends Sprite
{
private var vertices:Vector.<Number>;
private var projectedVerts:Vector.<Number>;
private var numverts:int;
private var indices:Vector.<int>;
private var uvts:Vector.<Number>;
private var texture:BitmapData;
private var perspective:PerspectiveProjection;
private var projMatrix:Matrix3D;
private var sphereRadius:Number;
private var sphereCenter:Vector3D;
private var rows:int;//number of times the sphere is sliced to form segments
private var cols:int;
private const PI:Number = Math.PI;//half revolution in radians
private const HALFPI:Number = Math.PI/2;//1/4 revolution in radians
private const TWOPI:Number = 2*Math.PI;//full revolution in radians
private var canvas:Sprite;
private var r:Number = 0;
//the number of segments = num slices - 1
//this is the same as lines of longitude
//thus there are twice as many as horizontal slices
public function NormalMap1()
{
init();
createMesh();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
addEventListener(Event.RENDER, render);
//render();
}
private function onEnterFrame(event:Event):void {
r = r + 0.2;
prerender();
stage.invalidate();
}
/**
* initialize common properties
*/
private function init():void
{
perspective = root.transform.perspectiveProjection;
texture = new BitmapData(800,800,false,0xCCCCCC);
sphereRadius = 100;
//sphereCenter = new Vector3D(stage.stageWidth/2, stage.stageHeight/2, 200);
cols = 40;
rows = 20;
numverts = (cols+1)*(rows+1);
vertices = new Vector.<Number>(numverts*3);//x,y,z for each vertex
projectedVerts = new Vector.<Number>(numverts*3);
uvts = new Vector.<Number>(numverts*3);
indices = new Vector.<int>();
//we need to work around the fact that Utils3D.projectVectors disregards the projection center
//of the projectionMatrix it is passed .. it always projects around 0,0
//so we must render things on a canvas centered on stage
canvas = new Sprite();
canvas.x = stage.stageWidth/2;
canvas.y = stage.stageHeight/2;
addChild(canvas);
}
/**
* create the mesh of the Sphere
*/
private function createMesh():void
{
var lon_incr:Number = TWOPI/cols;
var lat_incr = PI/rows;
var lon:Number = 0;//angle of rotation around the y axis, *in radians*
var lat:Number = 0;//angle of rotation around the x axis
var x:Number, y:Number, z:Number;
var vnum:int = 0;
var ind:int = 0;
//a full rotation is PI radians
for(var h:int = 0; h <= rows; ++h)
{
y = sphereRadius*Math.cos(lat);//need to shift angle downwards by 1/4 rev
for(var v:int = 0; v <= cols; ++v)
{
x = sphereRadius*Math.cos(lon)*Math.sin(lat);
z = sphereRadius*Math.sin(lon)*Math.sin(lat);//seen from above, z = y
//add vertex triplet
vertices[vnum] = x;
vertices[vnum+1] = y;
vertices[vnum+2] = z;
vnum+=3;
//add indices
if(h < rows && v < cols){
indices.push(ind, ind+1, ind + cols+1);
indices.push(ind + cols+1, ind+1, ind + cols + 2);
}
ind+=1;
lon += lon_incr;
}
lat += lat_incr;
}
}
/**
* prerender the sphere -- project vertices using rotated matrix
*/
private function prerender():void
{
projMatrix = perspective.toMatrix3D();
projMatrix.prependTranslation(0,0,400);
projMatrix.prependRotation(r, new Vector3D(0,1,0));
Utils3D.projectVectors(projMatrix, vertices, projectedVerts,uvts);
}
/**
* render
*/
private function render(event:Event):void
{
canvas.graphics.clear();
canvas.graphics.beginFill(0xFFFFFF);
canvas.graphics.lineStyle(1,0xcccccc,1);
canvas.graphics.drawTriangles(projectedVerts, indices, null /* uvts */, TriangleCulling.POSITIVE);
canvas.graphics.endFill();
}
}
}
|