A Flash Developer Resource Site

Results 1 to 3 of 3

Thread: I almost have shadows working in a 3d engine in flash, need help on a little problem

  1. #1
    Junior Member
    Join Date
    Apr 2007
    Posts
    7

    I almost have shadows working in a 3d engine in flash, need help on a little problem

    Hi

    I am using a modified version of the 3d system given in the book "actionscript animation"

    it works well except that the shadows do not render properly, I am completely stumped as to what to do.

    as you will be able to see from the code (no movieclips required) the shadows only seem to join 2 of their points, thus not filling themselves.

    any help would be greatly appreciated

    thanks

    Code:
    var points:Array = new Array();
    var triangles:Array = new Array();
    var shadowPoints:Array = new Array();
    var shadowTriangles:Array = new Array();
    
    var fl:Number = 500;
    var vpX:Number = Stage.width / 2;
    var vpY:Number = Stage.height / 2;
    var zOffset:Number = 500;
    var bottom:Number = 300;
    var light:Object = new Object();
    var basePoints:Number;
    
    var angle:Number = 0;
    var centerZ:Number = 0;
    var centerX:Number = 0;
    var radius:Number = 500;
    var speed:Number = 0.1;
    
    init();
    function init() {
    	light.x = 100;
    	light.y = -900;
    	light.z = 100;
    	light.brightness = 100;
    	
    	points[0] = {x:   0, y: 100, z:   0};
    	points[1] = {x: 100, y: 250, z:-100};
    	points[2] = {x:-100, y: 250, z:-100};
    	points[3] = {x:-100, y: 250, z: 100};
    	points[4] = {x: 100, y: 250, z: 100};	
    	
    	triangles[0] =  {a:0, b:1,  c:2,  col:0xffcc00};
    	triangles[1] =  {a:0, b:2,  c:3,  col:0xffcc00};
    	triangles[2] =  {a:0, b:3,  c:4,  col:0xffcc00};
    	triangles[3] =	{a:0, b:4,  c:1,  col:0xffcc00};
    	triangles[4] =	{a:1, b:3,  c:2,  col:0xffcc00};
    	triangles[5] =	{a:1, b:4,  c:3,  col:0xffcc00};
    	
    	for (var j:Number=0;j<triangles.length;j++)
    	{
    		shadowTriangles[j] = {a:triangles[j].a, b:triangles[j].b, c:triangles[j].b, col:0x000000, isShadow:true};
    	}
    }
    
    function onEnterFrame():Void {
    	var numPoints:Number = points.length;
    	makeShadows()
    	for (var i:Number=0;i<numPoints;i++) {
    		var point:MovieClip = points[i];
    		var scale:Number = fl / (fl + point.z + zOffset);
    		point.xPos = vpX + point.x * scale;
    		point.yPos = vpY + point.y * scale;
    	}
    	
    	light.z = centerZ + Math.cos(angle) * radius;
    	light.x = centerX + Math.sin(angle) * radius;
    	angle += speed;
    	clear();
    	triangles.sort(triSort);	
    	for(var i:Number=0;i<shadowTriangles.length;i++)
    	{
    		renderShadows(shadowTriangles[i]);
    	}
    	for(var i:Number =0;i<triangles.length;i++)
    	{
    		renderTriangle(triangles[i]);
    	}
    }
    
    function makeShadows()
    {
    	for (var i:Number=0;i<points.length;i++) 
    	{
    		var point:MovieClip = points[i];
    		var sunDifferenceX = point.x - light.x;
    		var sunDifferenceY = point.y - light.y;
    		var sunDifferenceZ = point.z - light.z;
    		var sunBearing:Number = Math.atan2(sunDifferenceZ, sunDifferenceX);
    		var sunElevation:Number = Math.atan2(sunDifferenceY, Math.sqrt(sunDifferenceX*sunDifferenceX + sunDifferenceZ*sunDifferenceZ));
    		
    		var radius:Number = Math.tan(sunElevation)* (bottom - point.y);
    		var bearing:Number = sunBearing;
    		var Xpos:Number = point.x + Math.cos(bearing) * radius;
    		var Zpos:Number = point.z + Math.sin(bearing) * radius;
    		shadowPoints[i] = {x:Xpos , y:bottom ,z:Zpos};
    		var scale:Number = fl / (fl + shadowPoints[i].z + zOffset);
    		shadowPoints[i].xPos = vpX + shadowPoints[i].x * scale;
    		shadowPoints[i].yPos = vpY + shadowPoints[i].y * scale;
    	}
    }
    
    function renderShadows(tri:Object):Void
    {
    	var pointA:Object = shadowPoints[tri.a];
    	var pointB:Object = shadowPoints[tri.b];
    	var pointC:Object = shadowPoints[tri.c];
    	lineStyle(1);
    	beginFill(0x000000,100);
    	moveTo(pointA.xPos, pointA.yPos);
    	lineTo(pointB.xPos, pointB.yPos);
    	lineTo(pointC.xPos, pointC.yPos);
    	lineTo(pointA.xPos, pointA.yPos);
    	endFill();
    }
    
    function renderTriangle(tri:Object):Void
    {
    	var pointA:Object = points[tri.a];
    	var pointB:Object = points[tri.b];
    	var pointC:Object = points[tri.c];
    	
    	if(isBackFace(pointA, pointB, pointC))
    	{
    		return;
    	}
    
    	var col:Number = getTriangleColor(tri);
    	lineStyle(0,0,0)
    	beginFill(col, 100);
    	moveTo(pointA.xPos, pointA.yPos);
    	lineTo(pointB.xPos, pointB.yPos);
    	lineTo(pointC.xPos, pointC.yPos);
    	lineTo(pointA.xPos, pointA.yPos);
    	endFill();
    }
    
    function isBackFace(pointA:Object, pointB:Object, pointC:Object):Boolean
    {
    	var cax:Number = pointC.xPos - pointA.xPos;
    	var cay:Number = pointC.yPos - pointA.yPos;
    	
    	var bcx:Number = pointB.xPos - pointC.xPos;
    	var bcy:Number = pointB.yPos - pointC.yPos;
    	
    	return cax * bcy > cay * bcx;
    }
    
    function triSort(triA:Object, triB:Object):Number
    {
    	var zA:Number = Math.min(points[triA.a].z, points[triA.b].z);
    	zA = Math.min(zA, points[triA.c].z);
    	
    	var zB:Number = Math.min(points[triB.a].z, points[triB.b].z);
    	zB = Math.min(zB, points[triB.c].z);
    	
    	if(zA < zB)
    	{
    		return 1;
    	}
    	else
    	{
    		return -1;
    	}
    }
    
    function getTriangleColor(tri:Object):Number
    {
    	var pointA:Object = points[tri.a];
    	var pointB:Object = points[tri.b];
    	var pointC:Object = points[tri.c];
    	
    	var lightFactor:Number = getLightFactor(pointA, pointB, pointC);
    	
    	var red:Number = tri.col >> 16;
    	var green:Number = tri.col >> 8 & 0xff;
    	var blue:Number = tri.col & 0xff;
    	
    	red *= lightFactor;
    	green *= lightFactor;
    	blue *= lightFactor;
    	
    	return red << 16 | green << 8 | blue;
    }
    
    function getLightFactor(ptA:Object, ptB:Object, ptC:Object):Number
    {
    	var ab:Object = new Object();
    	ab.x = ptA.x - ptB.x;
    	ab.y = ptA.y - ptB.y;
    	ab.z = ptA.z - ptB.z;
    	
    	var bc:Object = new Object();
    	bc.x = ptB.x - ptC.x;
    	bc.y = ptB.y - ptC.y;
    	bc.z = ptB.z - ptC.z;
    	
    	var norm:Object = new Object();
    	norm.x =   (ab.y * bc.z) - (ab.z * bc.y);
    	norm.y = -((ab.x * bc.z) - (ab.z * bc.x));
    	norm.z =   (ab.x * bc.y) - (ab.y * bc.x);
    	
    	var dotProd:Number = norm.x * light.x + 
    	                norm.y * light.y + 
    					norm.z * light.z;
    	
    	var normMag:Number = Math.sqrt(norm.x * norm.x +
    								norm.y * norm.y +
    								norm.z * norm.z);
    	
    	var lightMag:Number = Math.sqrt(light.x * light.x +
    									light.y * light.y +
    									light.z * light.z);
    	
    	return (Math.acos(dotProd / (normMag * lightMag)) / Math.PI) * light.brightness / 100;
    }

  2. #2
    All 1s and 0s dmonkey's Avatar
    Join Date
    Nov 2005
    Location
    Leeds, UK
    Posts
    606
    Hi,

    Just a coding error (see italics)

    code:

    for (var j:Number=0;j<triangles.length;j++)
    {
    shadowTriangles[j] = {a:triangles[j].a, b:triangles[j].b, c:triangles[j].c, col:0x000000, isShadow:true};
    }



    Hope this helps.
    "If I have seen further, it is by standing on the shoulders of giants." - Sir Isaac Newton

  3. #3
    Junior Member
    Join Date
    Apr 2007
    Posts
    7
    thanks for that, but I have found a better way to do this, the shadowTriangles are identical to the triangles, they just refer to different points.

    I just used the regular triangles, eliminating the need for the shadowtrianlges.

    Code:
    var points:Array = new Array();
    var triangles:Array = new Array();
    var shadowPoints:Array = new Array();
    var shadowTriangles:Array = new Array();
    
    var fl:Number = 500;
    var vpX:Number = Stage.width / 2;
    var vpY:Number = Stage.height / 2;
    var zOffset:Number = 50;
    var xOffset:Number = 0;
    var bottom:Number = 250;
    var light:Object = new Object();
    var basePoints:Number;
    
    var angle:Number = 0.5;
    var centerZ:Number = 0;
    var centerX:Number = 0;
    var radius:Number = 10000;
    var speed:Number = 0.01;
    
    init();
    function init() {
    	light.x = -100;
    	light.y = -400;
    	light.z = -100;
    	light.brightness = 100;
    	
    	var numFaces:Number = 150;
    	var radius:Number = 100;
    	var length:Number = 200
    	
    	var index:Number = 0;
    	for(var i:Number = 0;i<numFaces;i++)
    	{
    		var angle:Number = Math.PI * 2 / numFaces * i;
    		var x:Number = Math.cos(angle) * radius;
    		var y:Number = Math.sin(angle) * radius;
    		points[index] = {x:x, y:y, z:length/2 - length};
    		points[index + 1] = {x:x, y:y, z:length/2};
    		index += 2;
    	}
    	points[points.length+1] =  {x:0, y:0, z:length/2 - length};
    	points[points.length+1] =  {x:0, y:0, z:length/2};
    
    	index = 0;
    	pointsNo = points.length
    	for(var i:Number = 0;i<numFaces-1;i++)
    	{
    		triangles[index] = {a:index, b:index + 1,  c:index + 3, col:0x6666cc};
    		triangles[index+1] = {a:index, b:index + 3, c:index + 2, col:0x6666cc};
    		//triangles[index+2] = {a:pointsNo, b:index, c:index + 1, col:0x6666cc};
    		//triangles[index+3] = {a:pointsNo - 1, b:index + 3, c:index + 2, col:0x6666cc};
    		index += 2;
    	}
    	triangles[index] = {a:index, b:index + 1, c:1, col:0x6666cc};
    	triangles[index+1] = {a:index, b:1, c:0, col:0x6666cc};
    	
    	/*
    	index = 0;
    	pointsNo = points.length
    	for(var i:Number = 0;i<numFaces-2;i++)
    	{
    		triNo = triangles.length
    		triangles[triNo+1] = {a:pointsNo, b:index, c:index + 1, col:0x6666cc};
    		//triangles[index+3] = {a:pointsNo - 1, b:index + 3, c:index + 2, col:0x6666cc};
    		index += 1;
    	}
    	*/
    	
    	
    	/*
    	points[0] = {x:   0, y: 100, z:   0};
    	points[1] = {x: 100, y: 250, z:-100};
    	points[2] = {x:-100, y: 250, z:-100};
    	points[3] = {x:-100, y: 250, z: 100};
    	points[4] = {x: 100, y: 250, z: 100};	
    	
    	triangles[0] =  {a:0, b:1,  c:2,  col:0xffcc00};
    	triangles[1] =  {a:0, b:2,  c:3,  col:0xffcc00};
    	triangles[2] =  {a:0, b:3,  c:4,  col:0xffcc00};
    	triangles[3] =	{a:0, b:4,  c:1,  col:0xffcc00};
    	triangles[4] =	{a:1, b:3,  c:2,  col:0xffcc00};
    	triangles[5] =	{a:1, b:4,  c:3,  col:0xffcc00};
    	
    	
    	points[5] = {x:   200, y: 100, z:   0};
    	points[6] = {x: 300, y: 250, z:-100};
    	points[7] = {x:100, y: 250, z:-100};
    	points[8] = {x:100, y: 250, z: 100};
    	points[9] = {x: 300, y: 250, z: 100};	
    	
    	triangles[6] =  {a:5, b:6,  c:7,  col:0xffcc00};
    	triangles[7] =  {a:5, b:7,  c:8,  col:0xffcc00};
    	triangles[8] =  {a:5, b:8,  c:9,  col:0xffcc00};
    	triangles[9] =	{a:5, b:9,  c:6,  col:0xffcc00};
    	triangles[10] =	{a:6, b:8,  c:7,  col:0xffcc00};
    	triangles[11] =	{a:6, b:9,  c:8,  col:0xffcc00};
    	*/
    }
    
    function onEnterFrame():Void {
    	if(Key.isDown(Key.LEFT))
    	{
    		xOffset -= 10;
    	}
    	else if(Key.isDown(Key.RIGHT))
    	{
    		xOffset += 10;
    	}
    	if(Key.isDown(Key.UP))
    	{
    		zOffset += 10;
    	}
    	else if(Key.isDown(Key.DOWN))
    	{
    		zOffset -= 10;
    	}
    	makeShadows()
    	var numPoints:Number = points.length;
    	for (var i:Number=0;i<numPoints;i++) {
    		var point:MovieClip = points[i];
    		
    		var angleY:Number = (_xmouse - vpX) * .0003;
    		var cosY:Number = Math.cos(angleY);
    		var sinY:Number = Math.sin(angleY);
    		
    		var angleX:Number = (_ymouse - vpY) * .0003;
    		var cosX:Number = Math.cos(angleX);
    		var sinX:Number = Math.sin(angleX);
    		
    		var x1:Number = point.x * cosY - point.z * sinY;
    		var z1:Number = point.z * cosY + point.x * sinY;
    		
    		var y1:Number = point.y * cosX - z1 * sinX;
    		var z2:Number = z1 * cosX + point.y * sinX;
    		
    		point.x = x1;
    		point.y = y1;
    		point.z = z2;
    		
    		var scale:Number = fl / (fl + point.z + zOffset);
    		point.xPos = vpX + (point.x + xOffset) * scale;
    		point.yPos = vpY + point.y * scale;
    	}
    	
    	light.z = centerZ + Math.cos(angle) * radius;
    	light.x = centerX + Math.sin(angle) * radius;
    	//angle += speed;
    	clear();
    	triangles.sort(triSort);
    	for(var i:Number =0;i<triangles.length;i++)
    	{
    		renderTriangle(triangles[i],true);
    	}
    	for(var i:Number =0;i<triangles.length;i++)
    	{
    		renderTriangle(triangles[i],false);
    	}
    	
    }
    
    function makeShadows()
    {
    	for (var i:Number=0;i<points.length;i++) 
    	{
    		var point:MovieClip = points[i];
    		var sunDifferenceX = point.x - light.x;
    		var sunDifferenceY = point.y - light.y;
    		var sunDifferenceZ = point.z - light.z;
    		var sunBearing:Number = Math.atan2(sunDifferenceZ, sunDifferenceX);
    		var sunElevation:Number = Math.atan2(sunDifferenceY, Math.sqrt(sunDifferenceX*sunDifferenceX + sunDifferenceZ*sunDifferenceZ));
    		
    		var radius:Number = Math.tan(sunElevation)* (bottom - point.y);
    		var bearing:Number = sunBearing;
    		var Xpos:Number = point.x + Math.cos(bearing) * radius;
    		var Zpos:Number = point.z + Math.sin(bearing) * radius;
    		shadowPoints[i] = {x:Xpos , y:bottom ,z:Zpos};
    		var scale:Number = fl / (fl + shadowPoints[i].z + zOffset);
    		shadowPoints[i].xPos = vpX + (shadowPoints[i].x + xOffset) * scale;
    		shadowPoints[i].yPos = vpY + shadowPoints[i].y * scale;
    	}
    }
    
    function renderTriangle(tri:Object,isShadow:Boolean):Void
    {
    	if (isShadow)
    	{
    	var pointA:Object = shadowPoints[tri.a];
    	var pointB:Object = shadowPoints[tri.b];
    	var pointC:Object = shadowPoints[tri.c];
    	col = 0xCCCCCC
    	lineStyle(0,0,0)
    	beginFill(col, 100);
    	moveTo(pointA.xPos, pointA.yPos);
    	lineTo(pointB.xPos, pointB.yPos);
    	lineTo(pointC.xPos, pointC.yPos);
    	lineTo(pointA.xPos, pointA.yPos);
    	endFill();
    	}
    	
    		var pointA:Object = points[tri.a];
    		var pointB:Object = points[tri.b];
    		var pointC:Object = points[tri.c];
    	var col:Number = getTriangleColor(tri);
    	if(isBackFace(pointA, pointB, pointC))
    	{
    		//return;
    	}
    	lineStyle(0,0,0)
    	beginFill(col, 100);
    	moveTo(pointA.xPos, pointA.yPos);
    	lineTo(pointB.xPos, pointB.yPos);
    	lineTo(pointC.xPos, pointC.yPos);
    	lineTo(pointA.xPos, pointA.yPos);
    	endFill();
    }
    
    function isBackFace(pointA:Object, pointB:Object, pointC:Object):Boolean
    {
    	var cax:Number = pointC.xPos - pointA.xPos;
    	var cay:Number = pointC.yPos - pointA.yPos;
    	
    	var bcx:Number = pointB.xPos - pointC.xPos;
    	var bcy:Number = pointB.yPos - pointC.yPos;
    	
    	return cax * bcy > cay * bcx;
    }
    
    function triSort(triA:Object, triB:Object):Number
    {
    	var zA:Number = Math.min(points[triA.a].z, points[triA.b].z);
    	zA = Math.min(zA, points[triA.c].z);
    	
    	var zB:Number = Math.min(points[triB.a].z, points[triB.b].z);
    	zB = Math.min(zB, points[triB.c].z);
    	
    	if(zA < zB)
    	{
    		return 1;
    	}
    	else
    	{
    		return -1;
    	}
    }
    
    function getTriangleColor(tri:Object):Number
    {
    	var pointA:Object = points[tri.a];
    	var pointB:Object = points[tri.b];
    	var pointC:Object = points[tri.c];
    	
    	var lightFactor:Number = getLightFactor(pointA, pointB, pointC);
    	
    	var red:Number = tri.col >> 16;
    	var green:Number = tri.col >> 8 & 0xff;
    	var blue:Number = tri.col & 0xff;
    	
    	red *= lightFactor;
    	green *= lightFactor;
    	blue *= lightFactor;
    	
    	return red << 16 | green << 8 | blue;
    }
    
    function getLightFactor(ptA:Object, ptB:Object, ptC:Object):Number
    {
    	var ab:Object = new Object();
    	ab.x = ptA.x - ptB.x;
    	ab.y = ptA.y - ptB.y;
    	ab.z = ptA.z - ptB.z;
    	
    	var bc:Object = new Object();
    	bc.x = ptB.x - ptC.x;
    	bc.y = ptB.y - ptC.y;
    	bc.z = ptB.z - ptC.z;
    	
    	var norm:Object = new Object();
    	norm.x =   (ab.y * bc.z) - (ab.z * bc.y);
    	norm.y = -((ab.x * bc.z) - (ab.z * bc.x));
    	norm.z =   (ab.x * bc.y) - (ab.y * bc.x);
    	
    	var dotProd:Number = norm.x * light.x + 
    	                norm.y * light.y + 
    					norm.z * light.z;
    	
    	var normMag:Number = Math.sqrt(norm.x * norm.x +
    								norm.y * norm.y +
    								norm.z * norm.z);
    	
    	var lightMag:Number = Math.sqrt(light.x * light.x +
    									light.y * light.y +
    									light.z * light.z);
    	
    	return (Math.acos(dotProd / (normMag * lightMag)) / Math.PI) * light.brightness / 100;
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center