mirror of
https://github.com/MapMakersAndProgrammers/Alternativa3D.git
synced 2025-10-26 01:49:07 -07:00
Added shadow from omni light source. Added useShadow and excludeLight() method in Object3D. Fixed normals and tangents of skins from collada. Now can be used unlimited light sources with StandardMaterial.
This commit is contained in:
57
pom.xml
Normal file
57
pom.xml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>platform.clients.fp11.libraries</groupId>
|
||||||
|
<artifactId>Alternativa3D</artifactId>
|
||||||
|
<packaging>swc</packaging>
|
||||||
|
<version>8.30.0-SNAPSHOT</version>
|
||||||
|
<parent>
|
||||||
|
<groupId>platform.clients.fp11.tools.maven</groupId>
|
||||||
|
<artifactId>BasePom</artifactId>
|
||||||
|
<version>2.58.0</version>
|
||||||
|
</parent>
|
||||||
|
<scm>
|
||||||
|
<connection>
|
||||||
|
scm:git:https://github.com/AlternativaPlatform/Alternativa3D/master/
|
||||||
|
</connection>
|
||||||
|
</scm>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>platform.client.formats</groupId>
|
||||||
|
<artifactId>A3DModelsBase</artifactId>
|
||||||
|
<version>2.5.2</version>
|
||||||
|
<type>swc</type>
|
||||||
|
<scope>external</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>platform.clients.fp10.libraries</groupId>
|
||||||
|
<artifactId>AlternativaProtocol</artifactId>
|
||||||
|
<version>2.53.0</version>
|
||||||
|
<type>swc</type>
|
||||||
|
<scope>external</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>platform.client.formats</groupId>
|
||||||
|
<artifactId>A3DModelsBase</artifactId>
|
||||||
|
<type>swc</type>
|
||||||
|
<scope>external</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>platform.clients.fp10</groupId>
|
||||||
|
<artifactId>OSGiBase</artifactId>
|
||||||
|
<type>swc</type>
|
||||||
|
<scope>external</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>platform.clients.fp10.libraries</groupId>
|
||||||
|
<artifactId>AlternativaProtocol</artifactId>
|
||||||
|
<type>swc</type>
|
||||||
|
<scope>external</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -17,6 +17,6 @@ package alternativa {
|
|||||||
/**
|
/**
|
||||||
* Library version in the format: generation.feature-version.fix-version.
|
* Library version in the format: generation.feature-version.fix-version.
|
||||||
*/
|
*/
|
||||||
public static const version:String = "8.27.0";
|
public static const version:String = "8.29.0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ public class Camera3D extends Object3D {
|
|||||||
if (transformChanged) composeTransforms();
|
if (transformChanged) composeTransforms();
|
||||||
localToGlobalTransform.copy(transform);
|
localToGlobalTransform.copy(transform);
|
||||||
globalToLocalTransform.copy(inverseTransform);
|
globalToLocalTransform.copy(inverseTransform);
|
||||||
|
// Searching for upper hierarchy point
|
||||||
var root:Object3D = this;
|
var root:Object3D = this;
|
||||||
while (root.parent != null) {
|
while (root.parent != null) {
|
||||||
root = root.parent;
|
root = root.parent;
|
||||||
@@ -227,6 +228,8 @@ public class Camera3D extends Object3D {
|
|||||||
localToGlobalTransform.append(root.transform);
|
localToGlobalTransform.append(root.transform);
|
||||||
globalToLocalTransform.prepend(root.inverseTransform);
|
globalToLocalTransform.prepend(root.inverseTransform);
|
||||||
}
|
}
|
||||||
|
var excludedLightLength:int = root.excludedLights.length;
|
||||||
|
|
||||||
// Calculating the rays of mouse events
|
// Calculating the rays of mouse events
|
||||||
view.calculateRays(this);
|
view.calculateRays(this);
|
||||||
for (i = origins.length; i < view.raysLength; i++) {
|
for (i = origins.length; i < view.raysLength; i++) {
|
||||||
@@ -283,7 +286,7 @@ public class Camera3D extends Object3D {
|
|||||||
occluder = occluders[i];
|
occluder = occluders[i];
|
||||||
if (occluder.enabled) {
|
if (occluder.enabled) {
|
||||||
// Debug
|
// Debug
|
||||||
occluder.collectDraws(this, null, 0);
|
occluder.collectDraws(this, null, 0, false);
|
||||||
if (debug && occluder.boundBox != null && (checkInDebug(occluder) & Debug.BOUNDS)) Debug.drawBoundBox(this, occluder.boundBox, occluder.localToCameraTransform);
|
if (debug && occluder.boundBox != null && (checkInDebug(occluder) & Debug.BOUNDS)) Debug.drawBoundBox(this, occluder.boundBox, occluder.localToCameraTransform);
|
||||||
occluders[j] = occluder;
|
occluders[j] = occluder;
|
||||||
j++;
|
j++;
|
||||||
@@ -300,12 +303,11 @@ public class Camera3D extends Object3D {
|
|||||||
light.green = ((light.color >> 8) & 0xFF) * light.intensity / 255;
|
light.green = ((light.color >> 8) & 0xFF) * light.intensity / 255;
|
||||||
light.blue = (light.color & 0xFF) * light.intensity / 255;
|
light.blue = (light.color & 0xFF) * light.intensity / 255;
|
||||||
// Debug
|
// Debug
|
||||||
light.collectDraws(this, null, 0);
|
light.collectDraws(this, null, 0, false);
|
||||||
if (debug && light.boundBox != null && (checkInDebug(light) & Debug.BOUNDS)) Debug.drawBoundBox(this, light.boundBox, light.localToCameraTransform);
|
if (debug && light.boundBox != null && (checkInDebug(light) & Debug.BOUNDS)) Debug.drawBoundBox(this, light.boundBox, light.localToCameraTransform);
|
||||||
|
|
||||||
// Shadows preparing
|
// Shadows preparing
|
||||||
if (light.shadow != null) {
|
if (light.shadow != null) {
|
||||||
light.shadow._light = light;
|
|
||||||
light.shadow.process(this);
|
light.shadow.process(this);
|
||||||
}
|
}
|
||||||
lights[j] = light;
|
lights[j] = light;
|
||||||
@@ -327,10 +329,15 @@ public class Camera3D extends Object3D {
|
|||||||
// Check if object needs in lightning
|
// Check if object needs in lightning
|
||||||
if (lightsLength > 0 && root.useLights) {
|
if (lightsLength > 0 && root.useLights) {
|
||||||
// Pass the lights to children and calculate appropriate transformations
|
// Pass the lights to children and calculate appropriate transformations
|
||||||
|
var childLightsLength:int = 0;
|
||||||
if (root.boundBox != null) {
|
if (root.boundBox != null) {
|
||||||
var childLightsLength:int = 0;
|
|
||||||
for (i = 0; i < lightsLength; i++) {
|
for (i = 0; i < lightsLength; i++) {
|
||||||
light = lights[i];
|
light = lights[i];
|
||||||
|
// Checking light source for existing in excludedLights
|
||||||
|
j = 0;
|
||||||
|
while (j<excludedLightLength && excludedLights[j]!=light) j++;
|
||||||
|
if (j<excludedLightLength) continue;
|
||||||
|
|
||||||
light.lightToObjectTransform.combine(root.cameraToLocalTransform, light.localToCameraTransform);
|
light.lightToObjectTransform.combine(root.cameraToLocalTransform, light.localToCameraTransform);
|
||||||
// Detect influence
|
// Detect influence
|
||||||
if (light.boundBox == null || light.checkBound(root)) {
|
if (light.boundBox == null || light.checkBound(root)) {
|
||||||
@@ -338,23 +345,30 @@ public class Camera3D extends Object3D {
|
|||||||
childLightsLength++;
|
childLightsLength++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root.collectDraws(this, childLights, childLightsLength);
|
|
||||||
} else {
|
} else {
|
||||||
// Calculate transformation from light space to object space
|
// Calculate transformation from light space to object space
|
||||||
for (i = 0; i < lightsLength; i++) {
|
for (i = 0; i < lightsLength; i++) {
|
||||||
light = lights[i];
|
light = lights[i];
|
||||||
|
// Checking light source for existing in excludedLights
|
||||||
|
j = 0;
|
||||||
|
while (j<excludedLightLength && excludedLights[j]!=light) j++;
|
||||||
|
if (j<excludedLightLength) continue;
|
||||||
|
|
||||||
light.lightToObjectTransform.combine(root.cameraToLocalTransform, light.localToCameraTransform);
|
light.lightToObjectTransform.combine(root.cameraToLocalTransform, light.localToCameraTransform);
|
||||||
|
|
||||||
|
childLights[childLightsLength] = light;
|
||||||
|
childLightsLength++;
|
||||||
}
|
}
|
||||||
root.collectDraws(this, lights, lightsLength);
|
|
||||||
}
|
}
|
||||||
|
root.collectDraws(this, childLights, childLightsLength, root.useShadow);
|
||||||
} else {
|
} else {
|
||||||
root.collectDraws(this, null, 0);
|
root.collectDraws(this, null, 0, root.useShadow);
|
||||||
}
|
}
|
||||||
// Debug the boundbox
|
// Debug the boundbox
|
||||||
if (debug && root.boundBox != null && (checkInDebug(root) & Debug.BOUNDS)) Debug.drawBoundBox(this, root.boundBox, root.localToCameraTransform);
|
if (debug && root.boundBox != null && (checkInDebug(root) & Debug.BOUNDS)) Debug.drawBoundBox(this, root.boundBox, root.localToCameraTransform);
|
||||||
}
|
}
|
||||||
// Gather the draws for children
|
// Gather the draws for children
|
||||||
root.collectChildrenDraws(this, lights, lightsLength);
|
root.collectChildrenDraws(this, lights, lightsLength, root.useShadow);
|
||||||
}
|
}
|
||||||
cpuTimeSum += getTimer() - cpuTimer;
|
cpuTimeSum += getTimer() - cpuTimer;
|
||||||
cpuTimeCount++;
|
cpuTimeCount++;
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ package alternativa.engine3d.core {
|
|||||||
|
|
||||||
boundWire.transform.compose((boundBox.minX + boundBox.maxX)*0.5, (boundBox.minY + boundBox.maxY)*0.5, (boundBox.minZ + boundBox.maxZ)*0.5, 0, 0, 0, boundBox.maxX - boundBox.minX, boundBox.maxY - boundBox.minY, boundBox.maxZ - boundBox.minZ);
|
boundWire.transform.compose((boundBox.minX + boundBox.maxX)*0.5, (boundBox.minY + boundBox.maxY)*0.5, (boundBox.minZ + boundBox.maxZ)*0.5, 0, 0, 0, boundBox.maxX - boundBox.minX, boundBox.maxY - boundBox.minY, boundBox.maxZ - boundBox.minZ);
|
||||||
boundWire.localToCameraTransform.combine(transform, boundWire.transform);
|
boundWire.localToCameraTransform.combine(transform, boundWire.transform);
|
||||||
boundWire.collectDraws(camera, null, 0);
|
boundWire.collectDraws(camera, null, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,10 @@ package alternativa.engine3d.core {
|
|||||||
*/
|
*/
|
||||||
public class Light3D extends Object3D {
|
public class Light3D extends Object3D {
|
||||||
|
|
||||||
public var shadow:Shadow;
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
alternativa3d var _shadow:Shadow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Color of the light.
|
* Color of the light.
|
||||||
@@ -110,5 +113,16 @@ package alternativa.engine3d.core {
|
|||||||
intensity = src.intensity;
|
intensity = src.intensity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get shadow():Shadow {
|
||||||
|
return _shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
public function set shadow(value:Shadow):void {
|
||||||
|
_shadow = value;
|
||||||
|
_shadow._light = this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,6 +135,11 @@ package alternativa.engine3d.core {
|
|||||||
*/
|
*/
|
||||||
public var useShadow:Boolean = true;
|
public var useShadow:Boolean = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
alternativa3d var excludedLights:Vector.<Light3D> = new Vector.<Light3D>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@@ -282,6 +287,16 @@ package alternativa.engine3d.core {
|
|||||||
*/
|
*/
|
||||||
alternativa3d var globalToLocalTransform:Transform3D = new Transform3D();
|
alternativa3d var globalToLocalTransform:Transform3D = new Transform3D();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
alternativa3d var localToLightTransform:Transform3D = new Transform3D();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
alternativa3d var lightToLocalTransform:Transform3D = new Transform3D();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@@ -1272,6 +1287,7 @@ package alternativa.engine3d.core {
|
|||||||
*/
|
*/
|
||||||
alternativa3d function calculateChildrenVisibility(camera:Camera3D):void {
|
alternativa3d function calculateChildrenVisibility(camera:Camera3D):void {
|
||||||
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||||
|
// Checking visibility flag
|
||||||
if (child.visible) {
|
if (child.visible) {
|
||||||
// Compose matrix and inverse matrix
|
// Compose matrix and inverse matrix
|
||||||
if (child.transformChanged) child.composeTransforms();
|
if (child.transformChanged) child.composeTransforms();
|
||||||
@@ -1297,16 +1313,19 @@ package alternativa.engine3d.core {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
alternativa3d function collectChildrenDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
alternativa3d function collectChildrenDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
var i:int;
|
var i:int;
|
||||||
var light:Light3D;
|
var light:Light3D;
|
||||||
|
var excludedLightLength:int = excludedLights.length;
|
||||||
|
|
||||||
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||||
|
// Checking visibility flag
|
||||||
if (child.visible) {
|
if (child.visible) {
|
||||||
// Check getting in frustum and occluding
|
// Check getting in frustum and occluding
|
||||||
if (child.culling >= 0 && (child.boundBox == null || camera.occludersLength == 0 || !child.boundBox.checkOcclusion(camera.occluders, camera.occludersLength, child.localToCameraTransform))) {
|
if (child.culling >= 0 && (child.boundBox == null || camera.occludersLength == 0 || !child.boundBox.checkOcclusion(camera.occluders, camera.occludersLength, child.localToCameraTransform))) {
|
||||||
@@ -1320,10 +1339,16 @@ package alternativa.engine3d.core {
|
|||||||
// Check if object needs in lightning
|
// Check if object needs in lightning
|
||||||
if (lightsLength > 0 && child.useLights) {
|
if (lightsLength > 0 && child.useLights) {
|
||||||
// Pass the lights to children and calculate appropriate transformations
|
// Pass the lights to children and calculate appropriate transformations
|
||||||
|
var childLightsLength:int = 0;
|
||||||
|
var j:int;
|
||||||
if (child.boundBox != null) {
|
if (child.boundBox != null) {
|
||||||
var childLightsLength:int = 0;
|
|
||||||
for (i = 0; i < lightsLength; i++) {
|
for (i = 0; i < lightsLength; i++) {
|
||||||
light = lights[i];
|
light = lights[i];
|
||||||
|
// Checking object for existing in excludedLights
|
||||||
|
j = 0;
|
||||||
|
while (j<excludedLightLength && excludedLights[j]!=light) j++;
|
||||||
|
if (j<excludedLightLength) continue;
|
||||||
|
|
||||||
light.lightToObjectTransform.combine(child.cameraToLocalTransform, light.localToCameraTransform);
|
light.lightToObjectTransform.combine(child.cameraToLocalTransform, light.localToCameraTransform);
|
||||||
// Detect influence
|
// Detect influence
|
||||||
if (light.boundBox == null || light.checkBound(child)) {
|
if (light.boundBox == null || light.checkBound(child)) {
|
||||||
@@ -1331,23 +1356,28 @@ package alternativa.engine3d.core {
|
|||||||
childLightsLength++;
|
childLightsLength++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
child.collectDraws(camera, camera.childLights, childLightsLength);
|
|
||||||
} else {
|
} else {
|
||||||
// Calculate transformation from light space to object space
|
// Calculate transformation from light space to object space
|
||||||
for (i = 0; i < lightsLength; i++) {
|
for (i = 0; i < lightsLength; i++) {
|
||||||
light = lights[i];
|
light = lights[i];
|
||||||
|
// Проверка источника света на отсутствие в excludedLights
|
||||||
|
j = 0;
|
||||||
|
while (j<excludedLightLength && excludedLights[j]!=light) j++;
|
||||||
|
if (j<excludedLightLength) continue;
|
||||||
light.lightToObjectTransform.combine(child.cameraToLocalTransform, light.localToCameraTransform);
|
light.lightToObjectTransform.combine(child.cameraToLocalTransform, light.localToCameraTransform);
|
||||||
|
camera.childLights[childLightsLength] = light;
|
||||||
|
childLightsLength++;
|
||||||
}
|
}
|
||||||
child.collectDraws(camera, lights, lightsLength);
|
|
||||||
}
|
}
|
||||||
|
child.collectDraws(camera, camera.childLights, childLightsLength, useShadow&&child.useShadow);
|
||||||
} else {
|
} else {
|
||||||
child.collectDraws(camera, null, 0);
|
child.collectDraws(camera, null, 0, useShadow&&child.useShadow);
|
||||||
}
|
}
|
||||||
// Debug the boundbox
|
// Debug the boundbox
|
||||||
if (camera.debug && child.boundBox != null && (camera.checkInDebug(child) & Debug.BOUNDS)) Debug.drawBoundBox(camera, child.boundBox, child.localToCameraTransform);
|
if (camera.debug && child.boundBox != null && (camera.checkInDebug(child) & Debug.BOUNDS)) Debug.drawBoundBox(camera, child.boundBox, child.localToCameraTransform);
|
||||||
}
|
}
|
||||||
// Gather the draws for children
|
// Gather the draws for children
|
||||||
if (child.childrenList != null) child.collectChildrenDraws(camera, lights, lightsLength);
|
if (child.childrenList != null) child.collectChildrenDraws(camera, lights, lightsLength, useShadow && child.useShadow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1394,7 +1424,21 @@ package alternativa.engine3d.core {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a copy of this <code>Object3D</code>.
|
* Toggle off light source from litting this object
|
||||||
|
*/
|
||||||
|
public function excludeLight(light:Light3D):void{
|
||||||
|
excludedLights.push(light);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets list of lights excluded from litting this object
|
||||||
|
*/
|
||||||
|
public function resetLights():void{
|
||||||
|
excludedLights.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of object
|
||||||
* @return A copy of this <code>Object3D</code>.
|
* @return A copy of this <code>Object3D</code>.
|
||||||
*/
|
*/
|
||||||
public function clone():Object3D {
|
public function clone():Object3D {
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ package alternativa.engine3d.core {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
// Debug
|
// Debug
|
||||||
if (camera.debug) {
|
if (camera.debug) {
|
||||||
if (camera.checkInDebug(this) & Debug.CONTENT) {
|
if (camera.checkInDebug(this) & Debug.CONTENT) {
|
||||||
@@ -145,7 +145,7 @@ package alternativa.engine3d.core {
|
|||||||
debugWire.geometry.upload(camera.context3D);
|
debugWire.geometry.upload(camera.context3D);
|
||||||
}
|
}
|
||||||
debugWire.localToCameraTransform.copy(localToCameraTransform);
|
debugWire.localToCameraTransform.copy(localToCameraTransform);
|
||||||
debugWire.collectDraws(camera, null, 0);
|
debugWire.collectDraws(camera, null, 0, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -567,9 +567,9 @@ package alternativa.engine3d.core {
|
|||||||
island[i] = newFace;
|
island[i] = newFace;
|
||||||
island[j] = null;
|
island[j] = null;
|
||||||
face = newFace;
|
face = newFace;
|
||||||
|
// TODO: comment to ENG
|
||||||
// Если, то собираться будет парами, иначе к одной прицепляется максимально (это чуть быстрее)
|
// Если, то собираться будет парами, иначе к одной прицепляется максимально (это чуть быстрее)
|
||||||
//if (pairWeld) break;
|
//if (pairWeld) break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ package alternativa.engine3d.core {
|
|||||||
|
|
||||||
public static const OPAQUE:int = 20;
|
public static const OPAQUE:int = 20;
|
||||||
|
|
||||||
|
public static const OPAQUE_OVERHEAD:int = 25;
|
||||||
|
|
||||||
public static const DECALS:int = 30;
|
public static const DECALS:int = 30;
|
||||||
|
|
||||||
public static const TRANSPARENT_SORT:int = 40;
|
public static const TRANSPARENT_SORT:int = 40;
|
||||||
@@ -62,6 +64,9 @@ package alternativa.engine3d.core {
|
|||||||
case OPAQUE:
|
case OPAQUE:
|
||||||
_context3D.setDepthTest(true, Context3DCompareMode.LESS);
|
_context3D.setDepthTest(true, Context3DCompareMode.LESS);
|
||||||
break;
|
break;
|
||||||
|
case OPAQUE_OVERHEAD:
|
||||||
|
_context3D.setDepthTest(false, Context3DCompareMode.EQUAL);
|
||||||
|
break;
|
||||||
case DECALS:
|
case DECALS:
|
||||||
_context3D.setDepthTest(false, Context3DCompareMode.LESS_EQUAL);
|
_context3D.setDepthTest(false, Context3DCompareMode.LESS_EQUAL);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
* You may add additional accurate notices of copyright ownership.
|
* 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/
|
* It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/
|
||||||
* */
|
*
|
||||||
|
*/
|
||||||
package alternativa.engine3d.effects {
|
package alternativa.engine3d.effects {
|
||||||
|
|
||||||
import alternativa.engine3d.alternativa3d;
|
import alternativa.engine3d.alternativa3d;
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ package alternativa.engine3d.effects {
|
|||||||
return pause ? (stopTime - subtractiveTime) : (getTimer()*0.001 - subtractiveTime);
|
return pause ? (stopTime - subtractiveTime) : (getTimer()*0.001 - subtractiveTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
// Create geometry and program
|
// Create geometry and program
|
||||||
if (vertexBuffer == null) createAndUpload(camera.context3D);
|
if (vertexBuffer == null) createAndUpload(camera.context3D);
|
||||||
// Average size
|
// Average size
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ package alternativa.engine3d.lights {
|
|||||||
import alternativa.engine3d.core.Light3D;
|
import alternativa.engine3d.core.Light3D;
|
||||||
import alternativa.engine3d.core.Object3D;
|
import alternativa.engine3d.core.Object3D;
|
||||||
import alternativa.engine3d.core.Transform3D;
|
import alternativa.engine3d.core.Transform3D;
|
||||||
|
import alternativa.engine3d.shadows.OmniLightShadow;
|
||||||
|
import alternativa.engine3d.shadows.Shadow;
|
||||||
|
|
||||||
use namespace alternativa3d;
|
use namespace alternativa3d;
|
||||||
|
|
||||||
@@ -200,5 +202,14 @@ package alternativa.engine3d.lights {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
override public function set shadow(value:Shadow):void {
|
||||||
|
_shadow = value;
|
||||||
|
_shadow._light = this;
|
||||||
|
var omniShadow:OmniLightShadow = value as OmniLightShadow;
|
||||||
|
if (omniShadow!=null) omniShadow.setBoundSize(this.attenuationEnd*1.5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -436,7 +436,6 @@ package alternativa.engine3d.loaders {
|
|||||||
|
|
||||||
for each(a3DDirLight in a3d.directionalLights) {
|
for each(a3DDirLight in a3d.directionalLights) {
|
||||||
var resDirLight:DirectionalLight = new DirectionalLight(a3DDirLight.color);
|
var resDirLight:DirectionalLight = new DirectionalLight(a3DDirLight.color);
|
||||||
resDirLight.intensity = resDirLight.intensity;
|
|
||||||
resDirLight.visible = a3DDirLight.visible;
|
resDirLight.visible = a3DDirLight.visible;
|
||||||
resDirLight.name = a3DDirLight.name;
|
resDirLight.name = a3DDirLight.name;
|
||||||
parents[resDirLight] = a3DDirLight.parentId;
|
parents[resDirLight] = a3DDirLight.parentId;
|
||||||
|
|||||||
@@ -44,7 +44,9 @@ package alternativa.engine3d.loaders {
|
|||||||
private static const CHUNK_FACESMATERIAL:int = 0x4130;
|
private static const CHUNK_FACESMATERIAL:int = 0x4130;
|
||||||
private static const CHUNK_FACESSMOOTHGROUPS:int = 0x4150;
|
private static const CHUNK_FACESSMOOTHGROUPS:int = 0x4150;
|
||||||
private static const CHUNK_MAPPINGCOORDS:int = 0x4140;
|
private static const CHUNK_MAPPINGCOORDS:int = 0x4140;
|
||||||
|
//private static const CHUNK_OBJECTCOLOR:int = 0x4165;
|
||||||
private static const CHUNK_TRANSFORMATION:int = 0x4160;
|
private static const CHUNK_TRANSFORMATION:int = 0x4160;
|
||||||
|
//private static const CHUNK_MESHANIMATION:int = 0xB002;
|
||||||
private static const CHUNK_MATERIAL:int = 0xAFFF;
|
private static const CHUNK_MATERIAL:int = 0xAFFF;
|
||||||
|
|
||||||
private var data:ByteArray;
|
private var data:ByteArray;
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ package alternativa.engine3d.loaders {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, objectRenderPriority:int = -1):void {
|
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
|
||||||
var colorO:Object = colors[renderChannel];
|
var colorO:Object = colors[renderChannel];
|
||||||
var map:ExternalTextureResource;
|
var map:ExternalTextureResource;
|
||||||
if (colorO != null) {
|
if (colorO != null) {
|
||||||
@@ -90,14 +90,14 @@ package alternativa.engine3d.loaders {
|
|||||||
} else {
|
} else {
|
||||||
fillMaterial.color = int(colorO);
|
fillMaterial.color = int(colorO);
|
||||||
}
|
}
|
||||||
fillMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, objectRenderPriority);
|
fillMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, false, objectRenderPriority);
|
||||||
} else if ((map = textures[renderChannel]) != null) {
|
} else if ((map = textures[renderChannel]) != null) {
|
||||||
if(textureMaterial == null) {
|
if(textureMaterial == null) {
|
||||||
textureMaterial = new TextureMaterial(map);
|
textureMaterial = new TextureMaterial(map);
|
||||||
} else {
|
} else {
|
||||||
textureMaterial.diffuseMap = map;
|
textureMaterial.diffuseMap = map;
|
||||||
}
|
}
|
||||||
textureMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, objectRenderPriority);
|
textureMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, false, objectRenderPriority);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -138,6 +138,10 @@ package alternativa.engine3d.loaders.collada {
|
|||||||
private function transformVertices(geometry:Geometry):void {
|
private function transformVertices(geometry:Geometry):void {
|
||||||
var data:ByteArray = geometry._vertexStreams[0].data;
|
var data:ByteArray = geometry._vertexStreams[0].data;
|
||||||
var numMappings:int = geometry._vertexStreams[0].attributes.length;
|
var numMappings:int = geometry._vertexStreams[0].attributes.length;
|
||||||
|
|
||||||
|
var normalOffset:uint = geometry.getAttributeOffset(VertexAttributes.NORMAL);
|
||||||
|
var tangentOffset:uint = geometry.getAttributeOffset(VertexAttributes.TANGENT4);
|
||||||
|
|
||||||
for (var i:int = 0; i < geometry._numVertices; i++) {
|
for (var i:int = 0; i < geometry._numVertices; i++) {
|
||||||
data.position = 4*numMappings*i;
|
data.position = 4*numMappings*i;
|
||||||
var x:Number = data.readFloat();
|
var x:Number = data.readFloat();
|
||||||
@@ -147,6 +151,26 @@ package alternativa.engine3d.loaders.collada {
|
|||||||
data.writeFloat(x*bindShapeMatrix[0] + y*bindShapeMatrix[1] + z*bindShapeMatrix[2] + bindShapeMatrix[3]);
|
data.writeFloat(x*bindShapeMatrix[0] + y*bindShapeMatrix[1] + z*bindShapeMatrix[2] + bindShapeMatrix[3]);
|
||||||
data.writeFloat(x*bindShapeMatrix[4] + y*bindShapeMatrix[5] + z*bindShapeMatrix[6] + bindShapeMatrix[7]);
|
data.writeFloat(x*bindShapeMatrix[4] + y*bindShapeMatrix[5] + z*bindShapeMatrix[6] + bindShapeMatrix[7]);
|
||||||
data.writeFloat(x*bindShapeMatrix[8] + y*bindShapeMatrix[9] + z*bindShapeMatrix[10] + bindShapeMatrix[11]);
|
data.writeFloat(x*bindShapeMatrix[8] + y*bindShapeMatrix[9] + z*bindShapeMatrix[10] + bindShapeMatrix[11]);
|
||||||
|
|
||||||
|
data.position = 4*(numMappings*i + normalOffset);
|
||||||
|
var normalX:Number = data.readFloat();
|
||||||
|
var normalY:Number = data.readFloat();
|
||||||
|
var normalZ:Number = data.readFloat();
|
||||||
|
data.position -= 12;
|
||||||
|
|
||||||
|
data.writeFloat(normalX*bindShapeMatrix[0] + normalY*bindShapeMatrix[1] + normalZ*bindShapeMatrix[2]);
|
||||||
|
data.writeFloat(normalX*bindShapeMatrix[4] + normalY*bindShapeMatrix[5] + normalZ*bindShapeMatrix[6]);
|
||||||
|
data.writeFloat(normalX*bindShapeMatrix[8] + normalY*bindShapeMatrix[9] + normalZ*bindShapeMatrix[10]);
|
||||||
|
|
||||||
|
data.position = 4*(numMappings*i + tangentOffset);
|
||||||
|
var tangentX:Number = data.readFloat();
|
||||||
|
var tangentY:Number = data.readFloat();
|
||||||
|
var tangentZ:Number = data.readFloat();
|
||||||
|
data.position -= 12;
|
||||||
|
data.writeFloat(tangentX*bindShapeMatrix[0] + tangentY*bindShapeMatrix[1] + tangentZ*bindShapeMatrix[2]);
|
||||||
|
data.writeFloat(tangentX*bindShapeMatrix[4] + tangentY*bindShapeMatrix[5] + tangentZ*bindShapeMatrix[6]);
|
||||||
|
data.writeFloat(tangentX*bindShapeMatrix[8] + tangentY*bindShapeMatrix[9] + tangentZ*bindShapeMatrix[10]);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +423,6 @@ package alternativa.engine3d.loaders.collada {
|
|||||||
* Auxiliary joints will be added to the end of the vector, if it's necessary.
|
* Auxiliary joints will be added to the end of the vector, if it's necessary.
|
||||||
* @param parentNode Node of parent joint
|
* @param parentNode Node of parent joint
|
||||||
* @param nodes Dictionary. Key is a node of joint. And value is an index of joint in animatedJoints vector
|
* @param nodes Dictionary. Key is a node of joint. And value is an index of joint in animatedJoints vector
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
private function addJointChildren(parent:Joint, animatedJoints:Vector.<DaeObject>, parentNode:DaeNode, nodes:Dictionary):void {
|
private function addJointChildren(parent:Joint, animatedJoints:Vector.<DaeObject>, parentNode:DaeNode, nodes:Dictionary):void {
|
||||||
var object:DaeObject;
|
var object:DaeObject;
|
||||||
@@ -462,7 +485,6 @@ package alternativa.engine3d.loaders.collada {
|
|||||||
* Returns <code>true</code> if joint hasn't parent joint.
|
* Returns <code>true</code> if joint hasn't parent joint.
|
||||||
* @param node Joint node
|
* @param node Joint node
|
||||||
* @param nodes Dictionary. It items are the nodes keys.
|
* @param nodes Dictionary. It items are the nodes keys.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
private function isRootJointNode(node:DaeNode, nodes:Dictionary):Boolean {
|
private function isRootJointNode(node:DaeNode, nodes:Dictionary):Boolean {
|
||||||
for (var parent:DaeNode = node.parent; parent != null; parent = parent.parent) {
|
for (var parent:DaeNode = node.parent; parent != null; parent = parent.parent) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ package alternativa.engine3d.loaders.collada {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Source of vertex coordinates data. Stores coordinates in <code>numbers</code> array.
|
* Source of vertex coordinates data. Stores coordinates in <code>numbers</code> array.
|
||||||
*<code>stride</code> property of source is not less than three.
|
* <code>stride</code> property of source is not less than three.
|
||||||
* Call <code>parse()</code> before using.
|
* Call <code>parse()</code> before using.
|
||||||
*/
|
*/
|
||||||
public var positions:DaeSource;
|
public var positions:DaeSource;
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ package alternativa.engine3d.materials {
|
|||||||
crsInSpace,
|
crsInSpace,
|
||||||
"mul t1.xyz, t1.xyz, i0.w",
|
"mul t1.xyz, t1.xyz, i0.w",
|
||||||
// Transpose normal matrix
|
// Transpose normal matrix
|
||||||
|
// TODO: can be optimized like in StandardMaterial
|
||||||
"mov v0.x, i0.x",
|
"mov v0.x, i0.x",
|
||||||
"mov v0.y, t1.x",
|
"mov v0.y, t1.x",
|
||||||
"mov v0.z, i1.x",
|
"mov v0.z, i1.x",
|
||||||
@@ -807,7 +808,7 @@ package alternativa.engine3d.materials {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, objectRenderPriority:int = -1):void {
|
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
|
||||||
if (diffuseMap == null || diffuseMap._texture == null) return;
|
if (diffuseMap == null || diffuseMap._texture == null) return;
|
||||||
if (_environmentMap == null || _environmentMap._texture == null || !(_environmentMap._texture is CubeTexture)) return;
|
if (_environmentMap == null || _environmentMap._texture == null || !(_environmentMap._texture is CubeTexture)) return;
|
||||||
if (opacityMap != null && opacityMap._texture == null) return;
|
if (opacityMap != null && opacityMap._texture == null) return;
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ package alternativa.engine3d.materials {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, objectRenderPriority:int = -1):void {
|
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;
|
var object:Object3D = surface.object;
|
||||||
// Strams
|
// Strams
|
||||||
var positionBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
|
var positionBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ package alternativa.engine3d.materials {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, objectRenderPriority:int = -1):void {
|
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
|
||||||
if (diffuseMap == null || lightMap == null || diffuseMap._texture == null || lightMap._texture == null) return;
|
if (diffuseMap == null || lightMap == null || diffuseMap._texture == null || lightMap._texture == null) return;
|
||||||
if (opacityMap != null && opacityMap._texture == null) return;
|
if (opacityMap != null && opacityMap._texture == null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ package alternativa.engine3d.materials {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, objectRenderPriority:int = -1):void {
|
alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ package alternativa.engine3d.materials {
|
|||||||
private static var caches:Dictionary = new Dictionary(true);
|
private static var caches:Dictionary = new Dictionary(true);
|
||||||
private var cachedContext3D:Context3D;
|
private var cachedContext3D:Context3D;
|
||||||
private var programsCache:Dictionary;
|
private var programsCache:Dictionary;
|
||||||
|
private var groups:Vector.<Vector.<Light3D>> = new Vector.<Vector.<Light3D>>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -133,19 +134,16 @@ package alternativa.engine3d.materials {
|
|||||||
// Calculate binormal
|
// Calculate binormal
|
||||||
crsInSpace,
|
crsInSpace,
|
||||||
"mul t1.xyz, t1.xyz, i0.w",
|
"mul t1.xyz, t1.xyz, i0.w",
|
||||||
// Transpose normal matrix
|
// Транспонируем матрицу нормалей
|
||||||
|
"mov v0.xyzw, i1.xyxw",
|
||||||
"mov v0.x, i0.x",
|
"mov v0.x, i0.x",
|
||||||
"mov v0.y, t1.x",
|
"mov v0.y, t1.x",
|
||||||
"mov v0.z, i1.x",
|
"mov v1.xyzw, i1.xyyw",
|
||||||
"mov v0.w, i1.w",
|
|
||||||
"mov v1.x, i0.y",
|
"mov v1.x, i0.y",
|
||||||
"mov v1.y, t1.y",
|
"mov v1.y, t1.y",
|
||||||
"mov v1.z, i1.y",
|
"mov v2.xyzw, i1.xyzw",
|
||||||
"mov v1.w, i1.w",
|
|
||||||
"mov v2.x, i0.z",
|
"mov v2.x, i0.z",
|
||||||
"mov v2.y, t1.z",
|
"mov v2.y, t1.z"
|
||||||
"mov v2.z, i1.z",
|
|
||||||
"mov v2.w, i1.w"
|
|
||||||
], "passTBNProcedure");
|
], "passTBNProcedure");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,10 +425,9 @@ package alternativa.engine3d.materials {
|
|||||||
"sat t0.x, t0.x",
|
"sat t0.x, t0.x",
|
||||||
];
|
];
|
||||||
if (useShadow) {
|
if (useShadow) {
|
||||||
source.push("mul t0.x, t0.x, i2.x");
|
source.push("mul t0.xw, t0.xw, i2.x");
|
||||||
source.push("mul t0.xyz, c1.xyz, t0.xxx");
|
source.push("mul t0.xyz, c1.xyz, t0.xxx");
|
||||||
source.push("add o0.xyz, t0.xyz, i3.xyz");
|
source.push("add o0.xyz, t0.xyz, i3.xyz");
|
||||||
source.push("mul t0.w, i2.x, t0.w");
|
|
||||||
source.push("mul o1.xyz, c1.xyz, t0.www");
|
source.push("mul o1.xyz, c1.xyz, t0.www");
|
||||||
} else {
|
} else {
|
||||||
// Apply calculated values
|
// Apply calculated values
|
||||||
@@ -442,16 +439,89 @@ package alternativa.engine3d.materials {
|
|||||||
procedure.compileFromArray(source);
|
procedure.compileFromArray(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function formOmniProcedure(procedure:Procedure, light:Light3D, useShadow:Boolean):void {
|
||||||
|
// fragmentLinker.setInputParams(omniMulShadowProcedure, "tNormal", "tViewVector", "tTotalLight", "cAmbientColor");
|
||||||
|
var source:Array = [
|
||||||
|
"#c0=c" + light.lightID + "Position",
|
||||||
|
"#c1=c" + light.lightID + "Color",
|
||||||
|
"#c2=c" + light.lightID + "Radius",
|
||||||
|
"#v0=vPosition"
|
||||||
|
];
|
||||||
|
if (useShadow) {
|
||||||
|
// Считаем вектор из точки к свету
|
||||||
|
source.push("sub t0, c0, v0"); // L = lightPos - PointPos
|
||||||
|
source.push("dp3 t0.w, t0.xyz, t0.xyz"); // lenSqr
|
||||||
|
source.push("nrm t0.xyz, t0.xyz"); // L = normalize(L)
|
||||||
|
// Считаем half-way вектор
|
||||||
|
source.push("add t1.xyz, i1.xyz, t0.xyz");
|
||||||
|
source.push("nrm t1.xyz, t1.xyz");
|
||||||
|
// Считаем блик
|
||||||
|
source.push("dp3 t1.w, t1.xyz, i0.xyz");
|
||||||
|
source.push("pow t1.w, t1.w, o1.w");
|
||||||
|
// Считаем расстояние до источника света
|
||||||
|
source.push("sqt t1.x, t0.w"); // len = sqt(lensqr)
|
||||||
|
// Считаем свет
|
||||||
|
source.push("dp3 t0.w, t0.xyz, i0.xyz"); // dot = dot(normal, L)
|
||||||
|
// Считаем затухание
|
||||||
|
source.push("sub t0.x, t1.x, c2.z"); // len = len - atenuationBegin
|
||||||
|
source.push("div t0.y, t0.x, c2.y"); // att = len/radius
|
||||||
|
source.push("sub t0.x, c2.x, t0.y"); // att = 1 - len/radius
|
||||||
|
source.push("sat t0.xw, t0.xw"); // t = max(t, 0)
|
||||||
|
|
||||||
|
// i3 - ambient
|
||||||
|
// i2 - shadow-test
|
||||||
|
|
||||||
|
source.push("mul t0.xw, t0.xw, i2.xw");
|
||||||
|
source.push("mul t0.xyz, c1.xyz, t0.xxx"); // t = color*t
|
||||||
|
source.push("mul t1.xyz, t0.xyz, t1.w");
|
||||||
|
source.push("add o1.xyz, o1.xyz, t1.xyz");
|
||||||
|
source.push("mul t0.xyz, t0.xyz, t0.www");
|
||||||
|
source.push("add o0.xyz, t0.xyz, i3.xyz");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Считаем вектор из точки к свету
|
||||||
|
source.push("sub t0, c0, v0"); // L = lightPos - PointPos
|
||||||
|
source.push("dp3 t0.w, t0.xyz, t0.xyz"); // lenSqr
|
||||||
|
source.push("nrm t0.xyz, t0.xyz"); // L = normalize(L)
|
||||||
|
// Считаем half-way вектор
|
||||||
|
source.push("add t1.xyz, i1.xyz, t0.xyz");
|
||||||
|
source.push("mov t1.w, c0.w");
|
||||||
|
source.push("nrm t1.xyz, t1.xyz");
|
||||||
|
// Считаем блик
|
||||||
|
source.push("dp3 t1.w, t1.xyz, i0.xyz");
|
||||||
|
source.push("pow t1.w, t1.w, o1.w"); //!!!
|
||||||
|
// Считаем расстояние до источника света
|
||||||
|
source.push("sqt t1.x, t0.w"); // len = sqt(lensqr)
|
||||||
|
// Считаем свет
|
||||||
|
source.push("dp3 t0.w, t0.xyz, i0.xyz"); // dot = dot(normal, L)
|
||||||
|
// Считаем затухание
|
||||||
|
source.push("sub t0.x, t1.x, c2.z"); // len = len - atenuationBegin
|
||||||
|
source.push("div t0.y, t0.x, c2.y"); // att = len/radius
|
||||||
|
source.push("sub t0.x, c2.x, t0.y"); // att = 1 - len/radius
|
||||||
|
source.push("sat t0.xw, t0.xw"); // t = max(t, 0)
|
||||||
|
|
||||||
|
// Перемножаем цвет источника с затуханием
|
||||||
|
source.push("mul t0.xyz, c1.xyz, t0.xxx"); // t = color*t
|
||||||
|
source.push("mul t1.xyz, t0.xyz, t1.w");
|
||||||
|
source.push("add o1.xyz, o1.xyz, t1.xyz");
|
||||||
|
source.push("mul t0.xyz, t0.xyz, t0.www");
|
||||||
|
source.push("add o0.xyz, o0.xyz, t0.xyz");
|
||||||
|
}
|
||||||
|
|
||||||
|
procedure.compileFromArray(source);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param object
|
* @param object
|
||||||
* @param materialKey
|
* @param materialKey
|
||||||
* @param opacityMap
|
* @param opacityMap
|
||||||
* @param alphaTest 0:disabled 1:alpha-test 2:contours
|
* @param alphaTest 0:disabled 1:alpha-test 2:contours
|
||||||
* @param lights
|
* @param lightsGroup
|
||||||
* @param directionalLight
|
* @param directionalLight
|
||||||
* @param lightsLength
|
* @param lightsLength
|
||||||
*/
|
*/
|
||||||
private function getProgram(object:Object3D, programs:Dictionary, camera:Camera3D, materialKey:String, opacityMap:TextureResource, alphaTest:int, lights:Vector.<Light3D>, lightsLength:int, shadowedLight:Light3D):ShaderProgram {
|
private function getProgram(object:Object3D, programs:Dictionary, camera:Camera3D, materialKey:String, opacityMap:TextureResource, alphaTest:int, lightsGroup:Vector.<Light3D>, lightsLength:int, isFirstGroup:Boolean, shadowedLight:Light3D):ShaderProgram {
|
||||||
var key:String = materialKey + (opacityMap != null ? "O" : "o") + alphaTest.toString();
|
var key:String = materialKey + (opacityMap != null ? "O" : "o") + alphaTest.toString();
|
||||||
var program:ShaderProgram = programs[key];
|
var program:ShaderProgram = programs[key];
|
||||||
if (program == null) {
|
if (program == null) {
|
||||||
@@ -459,13 +529,34 @@ package alternativa.engine3d.materials {
|
|||||||
var fragmentLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
|
var fragmentLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
|
||||||
var i:int;
|
var i:int;
|
||||||
|
|
||||||
|
// Merge program using lightsGroup
|
||||||
|
// add property useShadow
|
||||||
|
|
||||||
fragmentLinker.declareVariable("tTotalLight");
|
fragmentLinker.declareVariable("tTotalLight");
|
||||||
fragmentLinker.declareVariable("tTotalHighLight");
|
fragmentLinker.declareVariable("tTotalHighLight");
|
||||||
fragmentLinker.declareVariable("tNormal");
|
fragmentLinker.declareVariable("tNormal");
|
||||||
fragmentLinker.declareVariable("cAmbientColor", VariableType.CONSTANT);
|
|
||||||
fragmentLinker.addProcedure(_ambientLightProcedure);
|
if (isFirstGroup){
|
||||||
fragmentLinker.setInputParams(_ambientLightProcedure, "cAmbientColor");
|
fragmentLinker.declareVariable("cAmbientColor", VariableType.CONSTANT);
|
||||||
fragmentLinker.setOutputParams(_ambientLightProcedure, "tTotalLight", "tTotalHighLight");
|
fragmentLinker.addProcedure(_ambientLightProcedure);
|
||||||
|
fragmentLinker.setInputParams(_ambientLightProcedure, "cAmbientColor");
|
||||||
|
fragmentLinker.setOutputParams(_ambientLightProcedure, "tTotalLight", "tTotalHighLight");
|
||||||
|
|
||||||
|
if (lightMap != null) {
|
||||||
|
vertexLinker.addProcedure(_passLightMapUVProcedure);
|
||||||
|
fragmentLinker.addProcedure(_addLightMapProcedure);
|
||||||
|
fragmentLinker.setInputParams(_addLightMapProcedure, "tTotalLight");
|
||||||
|
fragmentLinker.setOutputParams(_addLightMapProcedure, "tTotalLight");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// сбросить tTotalLight tTotalHighLight
|
||||||
|
fragmentLinker.declareVariable("cAmbientColor", VariableType.CONSTANT);
|
||||||
|
fragmentLinker.addProcedure(_ambientLightProcedure);
|
||||||
|
fragmentLinker.setInputParams(_ambientLightProcedure, "cAmbientColor");
|
||||||
|
fragmentLinker.setOutputParams(_ambientLightProcedure, "tTotalLight", "tTotalHighLight");
|
||||||
|
}
|
||||||
|
|
||||||
var positionVar:String = "aPosition";
|
var positionVar:String = "aPosition";
|
||||||
var normalVar:String = "aNormal";
|
var normalVar:String = "aNormal";
|
||||||
var tangentVar:String = "aTangent";
|
var tangentVar:String = "aTangent";
|
||||||
@@ -488,7 +579,8 @@ package alternativa.engine3d.materials {
|
|||||||
fragmentLinker.addProcedure(_setGlossinessFromConstantProcedure);
|
fragmentLinker.addProcedure(_setGlossinessFromConstantProcedure);
|
||||||
fragmentLinker.setOutputParams(_setGlossinessFromConstantProcedure, "tTotalHighLight");
|
fragmentLinker.setOutputParams(_setGlossinessFromConstantProcedure, "tTotalHighLight");
|
||||||
}
|
}
|
||||||
if (lightsLength > 0) {
|
|
||||||
|
if (lightsLength > 0 || shadowedLight) {
|
||||||
var procedure:Procedure;
|
var procedure:Procedure;
|
||||||
if (object.deltaTransformProcedure != null) {
|
if (object.deltaTransformProcedure != null) {
|
||||||
vertexLinker.declareVariable("tTransformedNormal");
|
vertexLinker.declareVariable("tTransformedNormal");
|
||||||
@@ -519,25 +611,44 @@ package alternativa.engine3d.materials {
|
|||||||
fragmentLinker.addProcedure(_getNormalAndViewObjectProcedure);
|
fragmentLinker.addProcedure(_getNormalAndViewObjectProcedure);
|
||||||
fragmentLinker.setOutputParams(_getNormalAndViewObjectProcedure, "tNormal", "tViewVector");
|
fragmentLinker.setOutputParams(_getNormalAndViewObjectProcedure, "tNormal", "tViewVector");
|
||||||
}
|
}
|
||||||
if (shadowedLight != null && shadowedLight is DirectionalLight) {
|
if (shadowedLight != null) {
|
||||||
vertexLinker.addProcedure(shadowedLight.shadow.vertexShadowProcedure, positionVar);
|
var shadowProc:Procedure;
|
||||||
var shadowProc:Procedure = shadowedLight.shadow.fragmentShadowProcedure;
|
if (shadowedLight is DirectionalLight){
|
||||||
fragmentLinker.addProcedure(shadowProc);
|
vertexLinker.addProcedure(shadowedLight.shadow.vertexShadowProcedure, positionVar);
|
||||||
fragmentLinker.setOutputParams(shadowProc, "tTotalLight");
|
shadowProc = shadowedLight.shadow.fragmentShadowProcedure;
|
||||||
|
fragmentLinker.addProcedure(shadowProc);
|
||||||
|
fragmentLinker.setOutputParams(shadowProc, "tTotalLight");
|
||||||
|
|
||||||
var dirMulShadowProcedure:Procedure = _lightFragmentProcedures[shadowedLight.shadow];
|
var dirMulShadowProcedure:Procedure = _lightFragmentProcedures[shadowedLight.shadow];
|
||||||
if (dirMulShadowProcedure == null) {
|
if (dirMulShadowProcedure == null) {
|
||||||
dirMulShadowProcedure = new Procedure();
|
dirMulShadowProcedure = new Procedure();
|
||||||
formDirectionalProcedure(dirMulShadowProcedure, shadowedLight, true);
|
formDirectionalProcedure(dirMulShadowProcedure, shadowedLight, true);
|
||||||
|
}
|
||||||
|
fragmentLinker.addProcedure(dirMulShadowProcedure);
|
||||||
|
fragmentLinker.setInputParams(dirMulShadowProcedure, "tNormal", "tViewVector", "tTotalLight", "cAmbientColor");
|
||||||
|
fragmentLinker.setOutputParams(dirMulShadowProcedure, "tTotalLight", "tTotalHighLight");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shadowedLight is OmniLight){
|
||||||
|
vertexLinker.addProcedure(shadowedLight.shadow.vertexShadowProcedure, positionVar);
|
||||||
|
shadowProc = shadowedLight.shadow.fragmentShadowProcedure;
|
||||||
|
fragmentLinker.addProcedure(shadowProc);
|
||||||
|
fragmentLinker.setOutputParams(shadowProc, "tTotalLight");
|
||||||
|
|
||||||
|
var omniMulShadowProcedure:Procedure = _lightFragmentProcedures[shadowedLight.shadow];
|
||||||
|
if (omniMulShadowProcedure == null) {
|
||||||
|
omniMulShadowProcedure= new Procedure();
|
||||||
|
formOmniProcedure(omniMulShadowProcedure, shadowedLight, true);
|
||||||
|
}
|
||||||
|
fragmentLinker.addProcedure(omniMulShadowProcedure);
|
||||||
|
fragmentLinker.setInputParams(omniMulShadowProcedure, "tNormal", "tViewVector", "tTotalLight", "cAmbientColor");
|
||||||
|
fragmentLinker.setOutputParams(omniMulShadowProcedure, "tTotalLight", "tTotalHighLight");
|
||||||
}
|
}
|
||||||
fragmentLinker.addProcedure(dirMulShadowProcedure);
|
|
||||||
fragmentLinker.setInputParams(dirMulShadowProcedure, "tNormal", "tViewVector", "tTotalLight", "cAmbientColor");
|
|
||||||
fragmentLinker.setOutputParams(dirMulShadowProcedure, "tTotalLight", "tTotalHighLight");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < lightsLength; i++) {
|
for (i = 0; i < lightsLength; i++) {
|
||||||
var light:Light3D = lights[i];
|
var light:Light3D = lightsGroup[i];
|
||||||
if (light == shadowedLight) continue;
|
if (light == shadowedLight && (shadowedLight is DirectionalLight || shadowedLight is OmniLight)) continue;
|
||||||
var lightFragmentProcedure:Procedure = _lightFragmentProcedures[light];
|
var lightFragmentProcedure:Procedure = _lightFragmentProcedures[light];
|
||||||
if (lightFragmentProcedure == null) {
|
if (lightFragmentProcedure == null) {
|
||||||
lightFragmentProcedure = new Procedure();
|
lightFragmentProcedure = new Procedure();
|
||||||
@@ -546,38 +657,7 @@ package alternativa.engine3d.materials {
|
|||||||
formDirectionalProcedure(lightFragmentProcedure, light, false);
|
formDirectionalProcedure(lightFragmentProcedure, light, false);
|
||||||
lightFragmentProcedure.name += "Directional";
|
lightFragmentProcedure.name += "Directional";
|
||||||
} else if (light is OmniLight) {
|
} else if (light is OmniLight) {
|
||||||
lightFragmentProcedure.compileFromArray([
|
formOmniProcedure(lightFragmentProcedure, light, false);
|
||||||
"#c0=c" + light.lightID + "Position",
|
|
||||||
"#c1=c" + light.lightID + "Color",
|
|
||||||
"#c2=c" + light.lightID + "Radius",
|
|
||||||
"#v0=vPosition",
|
|
||||||
// Calculate vector from the point to light
|
|
||||||
"sub t0, c0, v0", // L = lightPos - PointPos
|
|
||||||
"dp3 t0.w, t0.xyz, t0.xyz", // lenSqr
|
|
||||||
"nrm t0.xyz, t0.xyz", // L = normalize(L)
|
|
||||||
// Calculate half-way vector
|
|
||||||
"add t1.xyz, i1.xyz, t0.xyz",
|
|
||||||
"mov t1.w, c0.w",
|
|
||||||
"nrm t1.xyz, t1.xyz",
|
|
||||||
// Calculate a flare
|
|
||||||
"dp3 t1.w, t1.xyz, i0.xyz",
|
|
||||||
"pow t1.w, t1.w, o1.w",
|
|
||||||
// Calculate distance to the light source
|
|
||||||
"sqt t1.x, t0.w", // len = sqt(lensqr)
|
|
||||||
// Calculate light
|
|
||||||
"dp3 t0.w, t0.xyz, i0.xyz", // dot = dot(normal, L)
|
|
||||||
// Calculate decay
|
|
||||||
"sub t0.x, t1.x, c2.z", // len = len - atenuationBegin
|
|
||||||
"div t0.y, t0.x, c2.y", // att = len/radius
|
|
||||||
"sub t0.x, c2.x, t0.y", // att = 1 - len/radius
|
|
||||||
"sat t0.xw, t0.xw", // t = max(t, 0)
|
|
||||||
// Multiply light color with the decay value
|
|
||||||
"mul t0.xyz, c1.xyz, t0.xxx", // t = color*t
|
|
||||||
"mul t1.xyz, t0.xyz, t1.w",
|
|
||||||
"add o1.xyz, o1.xyz, t1.xyz",
|
|
||||||
"mul t0.xyz, t0.xyz, t0.www",
|
|
||||||
"add o0.xyz, o0.xyz, t0.xyz"
|
|
||||||
]);
|
|
||||||
lightFragmentProcedure.name += "Omni";
|
lightFragmentProcedure.name += "Omni";
|
||||||
} else if (light is SpotLight) {
|
} else if (light is SpotLight) {
|
||||||
lightFragmentProcedure.compileFromArray([
|
lightFragmentProcedure.compileFromArray([
|
||||||
@@ -628,13 +708,7 @@ package alternativa.engine3d.materials {
|
|||||||
fragmentLinker.setOutputParams(_applySpecularProcedure, "tTotalHighLight");
|
fragmentLinker.setOutputParams(_applySpecularProcedure, "tTotalHighLight");
|
||||||
outputProcedure = _applySpecularProcedure;
|
outputProcedure = _applySpecularProcedure;
|
||||||
}
|
}
|
||||||
if (lightMap != null) {
|
|
||||||
vertexLinker.addProcedure(_passLightMapUVProcedure);
|
|
||||||
fragmentLinker.addProcedure(_addLightMapProcedure);
|
|
||||||
fragmentLinker.setInputParams(_addLightMapProcedure, "tTotalLight");
|
|
||||||
fragmentLinker.setOutputParams(_addLightMapProcedure, "tTotalLight");
|
|
||||||
}
|
|
||||||
|
|
||||||
fragmentLinker.declareVariable("tColor");
|
fragmentLinker.declareVariable("tColor");
|
||||||
outputProcedure = opacityMap != null ? getDiffuseOpacityProcedure : getDiffuseProcedure;
|
outputProcedure = opacityMap != null ? getDiffuseOpacityProcedure : getDiffuseProcedure;
|
||||||
fragmentLinker.addProcedure(outputProcedure);
|
fragmentLinker.addProcedure(outputProcedure);
|
||||||
@@ -648,37 +722,37 @@ package alternativa.engine3d.materials {
|
|||||||
|
|
||||||
fragmentLinker.addProcedure(_mulLightingProcedure, "tColor", "tTotalLight", "tTotalHighLight");
|
fragmentLinker.addProcedure(_mulLightingProcedure, "tColor", "tTotalLight", "tTotalHighLight");
|
||||||
|
|
||||||
|
|
||||||
if (fogMode == SIMPLE || fogMode == ADVANCED) {
|
// if (fogMode == SIMPLE || fogMode == ADVANCED) {
|
||||||
fragmentLinker.setOutputParams(_mulLightingProcedure, "tColor");
|
// fragmentLinker.setOutputParams(_mulLightingProcedure, "tColor");
|
||||||
}
|
// }
|
||||||
if (fogMode == SIMPLE) {
|
// if (fogMode == SIMPLE) {
|
||||||
vertexLinker.addProcedure(passSimpleFogConstProcedure);
|
// vertexLinker.addProcedure(passSimpleFogConstProcedure);
|
||||||
vertexLinker.setInputParams(passSimpleFogConstProcedure, positionVar);
|
// vertexLinker.setInputParams(passSimpleFogConstProcedure, positionVar);
|
||||||
fragmentLinker.addProcedure(outputWithSimpleFogProcedure);
|
// fragmentLinker.addProcedure(outputWithSimpleFogProcedure);
|
||||||
fragmentLinker.setInputParams(outputWithSimpleFogProcedure, "tColor");
|
// fragmentLinker.setInputParams(outputWithSimpleFogProcedure, "tColor");
|
||||||
outputProcedure = outputWithSimpleFogProcedure;
|
// outputProcedure = outputWithSimpleFogProcedure;
|
||||||
} else if (fogMode == ADVANCED) {
|
// } else if (fogMode == ADVANCED) {
|
||||||
vertexLinker.declareVariable("tProjected");
|
// vertexLinker.declareVariable("tProjected");
|
||||||
vertexLinker.setOutputParams(_projectProcedure, "tProjected");
|
// vertexLinker.setOutputParams(_projectProcedure, "tProjected");
|
||||||
vertexLinker.addProcedure(postPassAdvancedFogConstProcedure);
|
// vertexLinker.addProcedure(postPassAdvancedFogConstProcedure);
|
||||||
vertexLinker.setInputParams(postPassAdvancedFogConstProcedure, positionVar, "tProjected");
|
// vertexLinker.setInputParams(postPassAdvancedFogConstProcedure, positionVar, "tProjected");
|
||||||
fragmentLinker.addProcedure(outputWithAdvancedFogProcedure);
|
// fragmentLinker.addProcedure(outputWithAdvancedFogProcedure);
|
||||||
fragmentLinker.setInputParams(outputWithAdvancedFogProcedure, "tColor");
|
// fragmentLinker.setInputParams(outputWithAdvancedFogProcedure, "tColor");
|
||||||
outputProcedure = outputWithAdvancedFogProcedure;
|
// outputProcedure = outputWithAdvancedFogProcedure;
|
||||||
}
|
// }
|
||||||
|
|
||||||
fragmentLinker.varyings = vertexLinker.varyings;
|
fragmentLinker.varyings = vertexLinker.varyings;
|
||||||
program = new ShaderProgram(vertexLinker, fragmentLinker);
|
program = new ShaderProgram(vertexLinker, fragmentLinker);
|
||||||
|
|
||||||
|
|
||||||
program.upload(camera.context3D);
|
program.upload(camera.context3D);
|
||||||
programs[key] = program;
|
programs[key] = program;
|
||||||
}
|
}
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getDrawUnit(program:ShaderProgram, camera:Camera3D, surface:Surface, geometry:Geometry, opacityMap:TextureResource, lights:Vector.<Light3D>, lightsLength:int, shadowedLight:Light3D):DrawUnit {
|
// TODO: return not neccessary more
|
||||||
|
private function getDrawUnit(program:ShaderProgram, camera:Camera3D, surface:Surface, geometry:Geometry, opacityMap:TextureResource, lights:Vector.<Light3D>, lightsLength:int, isFirstGroup:Boolean, shadowedLight:Light3D, opaqueOption:Boolean, transparentOption:Boolean, objectRenderPriority:int):DrawUnit {
|
||||||
// Buffers
|
// Buffers
|
||||||
var positionBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
|
var positionBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
|
||||||
var uvBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.TEXCOORDS[0]);
|
var uvBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.TEXCOORDS[0]);
|
||||||
@@ -701,7 +775,7 @@ package alternativa.engine3d.materials {
|
|||||||
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cSurface"), 0, glossiness, specularPower, 1);
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cSurface"), 0, glossiness, specularPower, 1);
|
||||||
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cThresholdAlpha"), alphaThreshold, 0, 0, alpha);
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cThresholdAlpha"), alphaThreshold, 0, 0, alpha);
|
||||||
|
|
||||||
if (lightsLength > 0) {
|
if (lightsLength > 0 || shadowedLight) {
|
||||||
if (_normalMapSpace == NormalMapSpace.TANGENT_RIGHT_HANDED || _normalMapSpace == NormalMapSpace.TANGENT_LEFT_HANDED) {
|
if (_normalMapSpace == NormalMapSpace.TANGENT_RIGHT_HANDED || _normalMapSpace == NormalMapSpace.TANGENT_LEFT_HANDED) {
|
||||||
drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aNormal"), normalsBuffer, geometry._attributesOffsets[VertexAttributes.NORMAL], VertexAttributes.FORMATS[VertexAttributes.NORMAL]);
|
drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aNormal"), normalsBuffer, geometry._attributesOffsets[VertexAttributes.NORMAL], VertexAttributes.FORMATS[VertexAttributes.NORMAL]);
|
||||||
drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aTangent"), tangentsBuffer, geometry._attributesOffsets[VertexAttributes.TANGENT4], VertexAttributes.FORMATS[VertexAttributes.TANGENT4]);
|
drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aTangent"), tangentsBuffer, geometry._attributesOffsets[VertexAttributes.TANGENT4], VertexAttributes.FORMATS[VertexAttributes.TANGENT4]);
|
||||||
@@ -750,6 +824,40 @@ package alternativa.engine3d.materials {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shadowedLight){
|
||||||
|
var light:Light3D = shadowedLight;
|
||||||
|
if (light is DirectionalLight) {
|
||||||
|
transform = light.lightToObjectTransform;
|
||||||
|
var len:Number = Math.sqrt(transform.c*transform.c + transform.g*transform.g + transform.k*transform.k);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Direction"), -transform.c/len, -transform.g/len, -transform.k/len, 1);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Color"), light.red, light.green, light.blue);
|
||||||
|
} else if (light is OmniLight) {
|
||||||
|
var omni:OmniLight = light as OmniLight;
|
||||||
|
transform = light.lightToObjectTransform;
|
||||||
|
rScale = Math.sqrt(transform.a*transform.a + transform.e*transform.e + transform.i*transform.i);
|
||||||
|
rScale += Math.sqrt(transform.b*transform.b + transform.f*transform.f + transform.j*transform.j);
|
||||||
|
rScale += Math.sqrt(transform.c*transform.c + transform.g*transform.g + transform.k*transform.k);
|
||||||
|
rScale /= 3;
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Position"), transform.d, transform.h, transform.l);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Radius"), 1, omni.attenuationEnd*rScale - omni.attenuationBegin*rScale, omni.attenuationBegin*rScale);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Color"), light.red, light.green, light.blue);
|
||||||
|
} else if (light is SpotLight) {
|
||||||
|
var spot:SpotLight = light as SpotLight;
|
||||||
|
transform = light.lightToObjectTransform;
|
||||||
|
rScale = Math.sqrt(transform.a*transform.a + transform.e*transform.e + transform.i*transform.i);
|
||||||
|
rScale += Math.sqrt(transform.b*transform.b + transform.f*transform.f + transform.j*transform.j);
|
||||||
|
rScale += len = Math.sqrt(transform.c*transform.c + transform.g*transform.g + transform.k*transform.k);
|
||||||
|
rScale /= 3;
|
||||||
|
var falloff:Number = Math.cos(spot.falloff*0.5);
|
||||||
|
var hotspot:Number = Math.cos(spot.hotspot*0.5);
|
||||||
|
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Position"), transform.d, transform.h, transform.l);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Axis"), -transform.c/len, -transform.g/len, -transform.k/len);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Radius"), spot.attenuationEnd*rScale - spot.attenuationBegin*rScale, spot.attenuationBegin*rScale, hotspot == falloff ? 0.000001 : hotspot - falloff, falloff);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Color"), light.red, light.green, light.blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Textures
|
// Textures
|
||||||
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sDiffuse"), diffuseMap._texture);
|
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sDiffuse"), diffuseMap._texture);
|
||||||
if (opacityMap != null) {
|
if (opacityMap != null) {
|
||||||
@@ -762,69 +870,104 @@ package alternativa.engine3d.materials {
|
|||||||
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sSpecular"), specularMap._texture);
|
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sSpecular"), specularMap._texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lightMap != null) {
|
|
||||||
drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aUV1"),
|
if (isFirstGroup){
|
||||||
geometry.getVertexBuffer(VertexAttributes.TEXCOORDS[lightMapChannel]),
|
if (lightMap != null) {
|
||||||
geometry._attributesOffsets[VertexAttributes.TEXCOORDS[lightMapChannel]],
|
drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aUV1"),
|
||||||
Context3DVertexBufferFormat.FLOAT_2);
|
geometry.getVertexBuffer(VertexAttributes.TEXCOORDS[lightMapChannel]),
|
||||||
|
geometry._attributesOffsets[VertexAttributes.TEXCOORDS[lightMapChannel]],
|
||||||
|
Context3DVertexBufferFormat.FLOAT_2);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cAmbientColor"), 0,0,0, 1);
|
||||||
|
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sLightMap"), lightMap._texture);
|
||||||
|
} else {
|
||||||
|
drawUnit.setFragmentConstantsFromVector(program.fragmentShader.getVariableIndex("cAmbientColor"), camera.ambient, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cAmbientColor"), 0,0,0, 1);
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cAmbientColor"), 0,0,0, 1);
|
||||||
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sLightMap"), lightMap._texture);
|
|
||||||
} else {
|
|
||||||
drawUnit.setFragmentConstantsFromVector(program.fragmentShader.getVariableIndex("cAmbientColor"), camera.ambient, 1);
|
|
||||||
}
|
}
|
||||||
setPassUVProcedureConstants(drawUnit, program.vertexShader);
|
setPassUVProcedureConstants(drawUnit, program.vertexShader);
|
||||||
|
|
||||||
if (shadowedLight != null && shadowedLight is DirectionalLight) {
|
if (shadowedLight != null && ((shadowedLight is DirectionalLight)||(shadowedLight is OmniLight))) {
|
||||||
shadowedLight.shadow.setup(drawUnit, program.vertexShader, program.fragmentShader, surface);
|
shadowedLight.shadow.setup(drawUnit, program.vertexShader, program.fragmentShader, surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fogMode == SIMPLE || fogMode == ADVANCED) {
|
|
||||||
var lm:Transform3D = object.localToCameraTransform;
|
|
||||||
var dist:Number = fogFar - fogNear;
|
|
||||||
drawUnit.setVertexConstantsFromNumbers(program.vertexShader.getVariableIndex("cFogSpace"), lm.i/dist, lm.j/dist, lm.k/dist, (lm.l - fogNear)/dist);
|
|
||||||
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cFogRange"), fogMaxDensity, 1, 0, 1 - fogMaxDensity);
|
|
||||||
}
|
|
||||||
if (fogMode == SIMPLE) {
|
|
||||||
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cFogColor"), fogColorR, fogColorG, fogColorB);
|
|
||||||
}
|
|
||||||
if (fogMode == ADVANCED) {
|
|
||||||
if (fogTexture == null) {
|
|
||||||
var bmd:BitmapData = new BitmapData(32, 1, false, 0xFF0000);
|
|
||||||
for (i = 0; i < 32; i++) {
|
|
||||||
bmd.setPixel(i, 0, ((i/32)*255) << 16);
|
|
||||||
}
|
|
||||||
fogTexture = new BitmapTextureResource(bmd);
|
|
||||||
fogTexture.upload(camera.context3D);
|
|
||||||
}
|
|
||||||
var cLocal:Transform3D = camera.localToGlobalTransform;
|
|
||||||
var halfW:Number = camera.view.width/2;
|
|
||||||
var leftX:Number = -halfW*cLocal.a + camera.focalLength*cLocal.c;
|
|
||||||
var leftY:Number = -halfW*cLocal.e + camera.focalLength*cLocal.g;
|
|
||||||
var rightX:Number = halfW*cLocal.a + camera.focalLength*cLocal.c;
|
|
||||||
var rightY:Number = halfW*cLocal.e + camera.focalLength*cLocal.g;
|
|
||||||
// Finding UV
|
|
||||||
var angle:Number = (Math.atan2(leftY, leftX) - Math.PI/2);
|
|
||||||
if (angle < 0) angle += Math.PI*2;
|
|
||||||
var dx:Number = rightX - leftX;
|
|
||||||
var dy:Number = rightY - leftY;
|
|
||||||
var lens:Number = Math.sqrt(dx*dx + dy*dy);
|
|
||||||
leftX /= lens;
|
|
||||||
leftY /= lens;
|
|
||||||
rightX /= lens;
|
|
||||||
rightY /= lens;
|
|
||||||
var uScale:Number = Math.acos(leftX*rightX + leftY*rightY)/Math.PI/2;
|
|
||||||
var uRight:Number = angle/Math.PI/2;
|
|
||||||
|
|
||||||
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cFogConsts"), 0.5*uScale, 0.5 - uRight, 0);
|
// Inititalizing render properties
|
||||||
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sFogTexture"), fogTexture._texture);
|
if (opaqueOption)
|
||||||
|
// Use z-buffer within DrawCall, draws without blending
|
||||||
|
if (isFirstGroup){
|
||||||
|
drawUnit.blendSource = Context3DBlendFactor.ONE;
|
||||||
|
drawUnit.blendDestination = Context3DBlendFactor.ZERO;
|
||||||
|
camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
drawUnit.blendSource = Context3DBlendFactor.ONE;
|
||||||
|
drawUnit.blendDestination = Context3DBlendFactor.ONE;
|
||||||
|
camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE_OVERHEAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transparentOption){
|
||||||
|
// Do not use z-buffer, draws with blending
|
||||||
|
if (isFirstGroup){
|
||||||
|
drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
|
||||||
|
drawUnit.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
|
||||||
|
drawUnit.blendDestination = Context3DBlendFactor.ONE;
|
||||||
|
}
|
||||||
|
camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// if (fogMode == SIMPLE || fogMode == ADVANCED) {
|
||||||
|
// var lm:Transform3D = object.localToCameraTransform;
|
||||||
|
// var dist:Number = fogFar - fogNear;
|
||||||
|
// drawUnit.setVertexConstantsFromNumbers(program.vertexShader.getVariableIndex("cFogSpace"), lm.i/dist, lm.j/dist, lm.k/dist, (lm.l - fogNear)/dist);
|
||||||
|
// drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cFogRange"), fogMaxDensity, 1, 0, 1 - fogMaxDensity);
|
||||||
|
// }
|
||||||
|
// if (fogMode == SIMPLE) {
|
||||||
|
// drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cFogColor"), fogColorR, fogColorG, fogColorB);
|
||||||
|
// }
|
||||||
|
// if (fogMode == ADVANCED) {
|
||||||
|
// if (fogTexture == null) {
|
||||||
|
// var bmd:BitmapData = new BitmapData(32, 1, false, 0xFF0000);
|
||||||
|
// for (i = 0; i < 32; i++) {
|
||||||
|
// bmd.setPixel(i, 0, ((i/32)*255) << 16);
|
||||||
|
// }
|
||||||
|
// fogTexture = new BitmapTextureResource(bmd);
|
||||||
|
// fogTexture.upload(camera.context3D);
|
||||||
|
// }
|
||||||
|
// var cLocal:Transform3D = camera.localToGlobalTransform;
|
||||||
|
// var halfW:Number = camera.view.width/2;
|
||||||
|
// var leftX:Number = -halfW*cLocal.a + camera.focalLength*cLocal.c;
|
||||||
|
// var leftY:Number = -halfW*cLocal.e + camera.focalLength*cLocal.g;
|
||||||
|
// var rightX:Number = halfW*cLocal.a + camera.focalLength*cLocal.c;
|
||||||
|
// var rightY:Number = halfW*cLocal.e + camera.focalLength*cLocal.g;
|
||||||
|
// // Finding UV
|
||||||
|
// var angle:Number = (Math.atan2(leftY, leftX) - Math.PI/2);
|
||||||
|
// if (angle < 0) angle += Math.PI*2;
|
||||||
|
// var dx:Number = rightX - leftX;
|
||||||
|
// var dy:Number = rightY - leftY;
|
||||||
|
// var lens:Number = Math.sqrt(dx*dx + dy*dy);
|
||||||
|
// leftX /= lens;
|
||||||
|
// leftY /= lens;
|
||||||
|
// rightX /= lens;
|
||||||
|
// rightY /= lens;
|
||||||
|
// var uScale:Number = Math.acos(leftX*rightX + leftY*rightY)/Math.PI/2;
|
||||||
|
// var uRight:Number = angle/Math.PI/2;
|
||||||
|
//
|
||||||
|
// drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cFogConsts"), 0.5*uScale, 0.5 - uRight, 0);
|
||||||
|
// drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sFogTexture"), fogTexture._texture);
|
||||||
|
// }
|
||||||
return drawUnit;
|
return drawUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, objectRenderPriority:int = -1):void {
|
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
|
||||||
if (diffuseMap == null || normalMap == null || diffuseMap._texture == null || normalMap._texture == null) return;
|
if (diffuseMap == null || normalMap == null || diffuseMap._texture == null || normalMap._texture == null) return;
|
||||||
// Check if textures uploaded in to the context.
|
// Check if textures uploaded in to the context.
|
||||||
if (opacityMap != null && opacityMap._texture == null || glossinessMap != null && glossinessMap._texture == null || specularMap != null && specularMap._texture == null || lightMap != null && lightMap._texture == null) return;
|
if (opacityMap != null && opacityMap._texture == null || glossinessMap != null && glossinessMap._texture == null || specularMap != null && specularMap._texture == null || lightMap != null && lightMap._texture == null) return;
|
||||||
@@ -839,26 +982,12 @@ package alternativa.engine3d.materials {
|
|||||||
|
|
||||||
if (positionBuffer == null || uvBuffer == null) return;
|
if (positionBuffer == null || uvBuffer == null) return;
|
||||||
|
|
||||||
|
var i:int;
|
||||||
|
|
||||||
if (lightsLength > 0 && (_normalMapSpace == NormalMapSpace.TANGENT_RIGHT_HANDED || _normalMapSpace == NormalMapSpace.TANGENT_LEFT_HANDED)) {
|
if (lightsLength > 0 && (_normalMapSpace == NormalMapSpace.TANGENT_RIGHT_HANDED || _normalMapSpace == NormalMapSpace.TANGENT_LEFT_HANDED)) {
|
||||||
if (normalsBuffer == null || tangentsBuffer == null) return;
|
if (normalsBuffer == null || tangentsBuffer == null) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make shared part of the key.
|
|
||||||
var materialKey:String = (fogMode.toString()) +
|
|
||||||
((lightMap != null) ? "L" : "l") +
|
|
||||||
(_normalMapSpace.toString()) +
|
|
||||||
((glossinessMap != null) ? "G" : "g") +
|
|
||||||
((specularMap != null) ? "S" : "s");
|
|
||||||
var shadowedLight:Light3D;
|
|
||||||
for (var i:int = 0; i < lightsLength; i++) {
|
|
||||||
var light:Light3D = lights[i];
|
|
||||||
if (light.shadow != null && shadowedLight == null) {
|
|
||||||
shadowedLight = light;
|
|
||||||
materialKey += light.shadow.type;
|
|
||||||
}
|
|
||||||
materialKey += light.lightID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh programs for this context.
|
// Refresh programs for this context.
|
||||||
if (camera.context3D != cachedContext3D) {
|
if (camera.context3D != cachedContext3D) {
|
||||||
cachedContext3D = camera.context3D;
|
cachedContext3D = camera.context3D;
|
||||||
@@ -875,40 +1004,170 @@ package alternativa.engine3d.materials {
|
|||||||
programsCache[object.transformProcedure] = optionsPrograms;
|
programsCache[object.transformProcedure] = optionsPrograms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Form groups
|
||||||
|
var groupsCount:int = groups.length = 0;
|
||||||
|
var firstGroup:Vector.<Light3D> = new Vector.<Light3D>();
|
||||||
|
var shadowGroup:Vector.<Light3D> = new Vector.<Light3D>();
|
||||||
|
var firstGroupLength:int = 0;
|
||||||
|
for (i = 0; i < lightsLength; i++) {
|
||||||
|
var light:Light3D = lights[i];
|
||||||
|
if (light.shadow!=null && useShadow){
|
||||||
|
shadowGroup.push(light);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (firstGroupLength==6){
|
||||||
|
groups[groupsCount++] = firstGroup;
|
||||||
|
firstGroup = new Vector.<Light3D>();
|
||||||
|
firstGroupLength = 0;
|
||||||
|
}
|
||||||
|
firstGroup[firstGroupLength++] = light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (firstGroupLength!=0){
|
||||||
|
groups[groupsCount++] = firstGroup;
|
||||||
|
}
|
||||||
|
var shadowGroupLength:int = shadowGroup.length;
|
||||||
|
|
||||||
|
// Iterate groups
|
||||||
|
var materialKey:String;
|
||||||
var program:ShaderProgram;
|
var program:ShaderProgram;
|
||||||
var drawUnit:DrawUnit;
|
var drawUnit:DrawUnit;
|
||||||
// Opaque pass
|
|
||||||
if (opaquePass && alphaThreshold <= alpha) {
|
if (groupsCount==0 && shadowGroupLength==0){
|
||||||
if (alphaThreshold > 0) {
|
// There is only Ambient light on the scene
|
||||||
// Alpha test
|
// Form key
|
||||||
|
materialKey = (lightMap != null) ? "L" : "l"+
|
||||||
|
((glossinessMap != null) ? "G" : "g") +
|
||||||
|
((specularMap != null) ? "S" : "s");
|
||||||
|
|
||||||
|
if (opaquePass && alphaThreshold <= alpha) {
|
||||||
|
if (alphaThreshold > 0) {
|
||||||
|
// Alpha test
|
||||||
|
// use opacityMap if it is presented
|
||||||
|
program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 1, null, 0, true, null);
|
||||||
|
drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, null, 0, true, null, true, false, objectRenderPriority);
|
||||||
|
} else {
|
||||||
|
// do not use opacityMap at all
|
||||||
|
program = getProgram(object, optionsPrograms, camera, materialKey, null, 0, null, 0, true, null);
|
||||||
|
drawUnit = getDrawUnit(program, camera, surface, geometry, null, null, 0, true, null, true, false, objectRenderPriority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Transparent pass
|
||||||
|
if (transparentPass && alphaThreshold > 0 && alpha > 0) {
|
||||||
// use opacityMap if it is presented
|
// use opacityMap if it is presented
|
||||||
program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 1, lights, lightsLength, shadowedLight);
|
if (alphaThreshold <= alpha && !opaquePass) {
|
||||||
drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, lights, lightsLength, shadowedLight);
|
// Alpha threshold
|
||||||
} else {
|
program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 2, null, 0, true, null);
|
||||||
// do not use opacityMap at all
|
drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, null, 0, true, null, false, true, objectRenderPriority);
|
||||||
program = getProgram(object, optionsPrograms, camera, materialKey, null, 0, lights, lightsLength, shadowedLight);
|
} else {
|
||||||
drawUnit = getDrawUnit(program, camera, surface, geometry, null, lights, lightsLength, shadowedLight);
|
// There is no Alpha threshold or check z-buffer by previous pass
|
||||||
|
program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 0, null, 0, true, null);
|
||||||
|
drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, null, 0, true, null, false, true, objectRenderPriority);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Use z-buffer within DrawCall, draws without blending
|
|
||||||
camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE);
|
|
||||||
}
|
}
|
||||||
// Transparent pass
|
else{
|
||||||
if (transparentPass && alphaThreshold > 0 && alpha > 0) {
|
var lightLengthInGroup:int;
|
||||||
// use opacityMap if it is presented
|
var isFirstGroup:Boolean = true;
|
||||||
if (alphaThreshold <= alpha && !opaquePass) {
|
for (i = 0; i < groupsCount; i++) {
|
||||||
// Alpha threshold
|
var lightGroup:Vector.<Light3D> = groups[i];
|
||||||
program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 2, lights, lightsLength, shadowedLight);
|
lightLengthInGroup = lightGroup.length;
|
||||||
drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, lights, lightsLength, shadowedLight);
|
|
||||||
} else {
|
// Group of lights without shadow
|
||||||
// There is no Alpha threshold or check z-buffer by previous pass
|
// Form key
|
||||||
program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 0, lights, lightsLength, shadowedLight);
|
materialKey = (isFirstGroup)?((lightMap != null) ? "L" : "l"):"";
|
||||||
drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, lights, lightsLength, shadowedLight);
|
materialKey +=
|
||||||
|
(_normalMapSpace.toString()) +
|
||||||
|
((glossinessMap != null) ? "G" : "g") +
|
||||||
|
((specularMap != null) ? "S" : "s");
|
||||||
|
for (var j:int = 0; j < lightLengthInGroup; j++) {
|
||||||
|
var light:Light3D = lightGroup[j];
|
||||||
|
materialKey += light.lightID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create program and drawUnit for group
|
||||||
|
// Opaque pass
|
||||||
|
if (opaquePass && alphaThreshold <= alpha) {
|
||||||
|
if (alphaThreshold > 0) {
|
||||||
|
// Alpha test
|
||||||
|
// use opacityMap if it is presented
|
||||||
|
program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 1, lightGroup, lightLengthInGroup, isFirstGroup, null);
|
||||||
|
drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, lightGroup, lightLengthInGroup, isFirstGroup, null, true, false, objectRenderPriority);
|
||||||
|
} else {
|
||||||
|
// do not use opacityMap at all
|
||||||
|
program = getProgram(object, optionsPrograms, camera, materialKey, null, 0, lightGroup, lightLengthInGroup, isFirstGroup, null);
|
||||||
|
drawUnit = getDrawUnit(program, camera, surface, geometry, null, lightGroup, lightLengthInGroup, isFirstGroup, null, true, false, objectRenderPriority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Transparent pass
|
||||||
|
if (transparentPass && alphaThreshold > 0 && alpha > 0) {
|
||||||
|
// use opacityMap if it is presented
|
||||||
|
if (alphaThreshold <= alpha && !opaquePass) {
|
||||||
|
// Alpha threshold
|
||||||
|
program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 2, lightGroup, lightLengthInGroup, isFirstGroup, null);
|
||||||
|
drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, lightGroup, lightLengthInGroup, isFirstGroup, null, false, true, objectRenderPriority);
|
||||||
|
} else {
|
||||||
|
// There is no Alpha threshold or check z-buffer by previous pass
|
||||||
|
program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 0, lightGroup, lightLengthInGroup, isFirstGroup, null);
|
||||||
|
drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, lightGroup, lightLengthInGroup, isFirstGroup, null, false, true, objectRenderPriority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isFirstGroup = false;
|
||||||
|
lightGroup.length = 0;
|
||||||
}
|
}
|
||||||
// Do not use z-buffer, draws with blending
|
|
||||||
drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
|
if (shadowGroupLength>0){
|
||||||
drawUnit.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
|
// Group of ligths with shadow
|
||||||
camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT);
|
// For each light we will create new drawUnit
|
||||||
|
for (var j:int = 0; j < shadowGroupLength; j++) {
|
||||||
|
|
||||||
|
var light:Light3D = shadowGroup[j];
|
||||||
|
// Form key
|
||||||
|
materialKey = (isFirstGroup)?((lightMap != null) ? "L" : "l"):"";
|
||||||
|
materialKey +=
|
||||||
|
(_normalMapSpace.toString()) +
|
||||||
|
((glossinessMap != null) ? "G" : "g") +
|
||||||
|
((specularMap != null) ? "S" : "s");
|
||||||
|
materialKey += light.shadow.type;
|
||||||
|
materialKey += light.lightID;
|
||||||
|
|
||||||
|
// Для группы создаем программу и дроуюнит
|
||||||
|
// Opaque pass
|
||||||
|
if (opaquePass && alphaThreshold <= alpha) {
|
||||||
|
if (alphaThreshold > 0) {
|
||||||
|
// Alpha test
|
||||||
|
// use opacityMap if it is presented
|
||||||
|
program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 1, null, 0, isFirstGroup, light);
|
||||||
|
drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, null, 0, isFirstGroup, light, true, false, objectRenderPriority);
|
||||||
|
} else {
|
||||||
|
// do not use opacityMap at all
|
||||||
|
program = getProgram(object, optionsPrograms, camera, materialKey, null, 0, null, 0, isFirstGroup, light);
|
||||||
|
drawUnit = getDrawUnit(program, camera, surface, geometry, null, null, 0, isFirstGroup, light, true, false, objectRenderPriority);
|
||||||
|
}
|
||||||
|
trace(program.vertexShader.describeLinkageInfo());
|
||||||
|
trace(program.fragmentShader.describeLinkageInfo());
|
||||||
|
|
||||||
|
}
|
||||||
|
// Transparent pass
|
||||||
|
if (transparentPass && alphaThreshold > 0 && alpha > 0) {
|
||||||
|
// use opacityMap if it is presented
|
||||||
|
if (alphaThreshold <= alpha && !opaquePass) {
|
||||||
|
// Alpha threshold
|
||||||
|
program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 2, null, 0, isFirstGroup, light);
|
||||||
|
drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, null, 0, isFirstGroup, light, false, true, objectRenderPriority);
|
||||||
|
} else {
|
||||||
|
// There is no Alpha threshold or check z-buffer by previous pass
|
||||||
|
program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 0, null, 0, isFirstGroup, light);
|
||||||
|
drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, null, 0, isFirstGroup, light, false, true, objectRenderPriority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isFirstGroup = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shadowGroup.length = 0;
|
||||||
}
|
}
|
||||||
|
groups.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ package alternativa.engine3d.materials {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, objectRenderPriority:int = -1):void {
|
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;
|
var object:Object3D = surface.object;
|
||||||
|
|
||||||
// Buffers
|
// Buffers
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ package alternativa.engine3d.materials {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, objectRenderPriority:int = -1):void {
|
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
|
||||||
if (diffuseMap == null || diffuseMap._texture == null || opacityMap != null && opacityMap._texture == null) return;
|
if (diffuseMap == null || diffuseMap._texture == null || opacityMap != null && opacityMap._texture == null) return;
|
||||||
|
|
||||||
var object:Object3D = surface.object;
|
var object:Object3D = surface.object;
|
||||||
|
|||||||
@@ -151,9 +151,9 @@ package alternativa.engine3d.objects {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
var geometry:Geometry = getGeometry(camera.context3D);
|
var geometry:Geometry = getGeometry(camera.context3D);
|
||||||
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength);
|
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, -1);
|
||||||
// Mouse events
|
// Mouse events
|
||||||
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
|
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,10 +71,10 @@ package alternativa.engine3d.objects {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
for (var i:int = 0; i < _surfacesLength; i++) {
|
for (var i:int = 0; i < _surfacesLength; i++) {
|
||||||
var surface:Surface = _surfaces[i];
|
var surface:Surface = _surfaces[i];
|
||||||
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, Renderer.DECALS);
|
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, Renderer.DECALS);
|
||||||
// Mouse events
|
// Mouse events
|
||||||
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
|
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,11 +172,11 @@ package alternativa.engine3d.objects {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
var distance:Number = Math.sqrt(localToCameraTransform.d*localToCameraTransform.d + localToCameraTransform.h*localToCameraTransform.h + localToCameraTransform.l*localToCameraTransform.l);
|
var distance:Number = Math.sqrt(localToCameraTransform.d*localToCameraTransform.d + localToCameraTransform.h*localToCameraTransform.h + localToCameraTransform.l*localToCameraTransform.l);
|
||||||
for (var level:Object3D = levelList; level != null; level = level.next) {
|
for (var level:Object3D = levelList; level != null; level = level.next) {
|
||||||
if (distance <= level.distance) {
|
if (distance <= level.distance) {
|
||||||
collectChildDraws(level, this, camera, lights, lightsLength);
|
collectChildDraws(level, this, camera, lights, lightsLength, useShadow);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,7 +185,7 @@ package alternativa.engine3d.objects {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
alternativa3d function collectChildDraws(child:Object3D, parent:Object3D, camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
alternativa3d function collectChildDraws(child:Object3D, parent:Object3D, camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
// Composing direct and reverse matrices
|
// Composing direct and reverse matrices
|
||||||
if (child.transformChanged) child.composeTransforms();
|
if (child.transformChanged) child.composeTransforms();
|
||||||
// Calculation of transfer matrix from camera to local space.
|
// Calculation of transfer matrix from camera to local space.
|
||||||
@@ -198,17 +198,25 @@ package alternativa.engine3d.objects {
|
|||||||
// If object needs on light sources.
|
// If object needs on light sources.
|
||||||
if (lightsLength > 0 && child.useLights) {
|
if (lightsLength > 0 && child.useLights) {
|
||||||
// Calculation of transfer matrices from sources to object.
|
// Calculation of transfer matrices from sources to object.
|
||||||
|
var excludedLightLength:int = excludedLights.length;
|
||||||
|
var childLightsLength:int = 0;
|
||||||
for (var i:int = 0; i < lightsLength; i++) {
|
for (var i:int = 0; i < lightsLength; i++) {
|
||||||
var light:Light3D = lights[i];
|
var light:Light3D = lights[i];
|
||||||
|
var j:int = 0;
|
||||||
|
while (j<excludedLightLength && excludedLights[j]!=light) j++;
|
||||||
|
if (j<excludedLightLength) continue;
|
||||||
|
|
||||||
light.lightToObjectTransform.combine(child.cameraToLocalTransform, light.localToCameraTransform);
|
light.lightToObjectTransform.combine(child.cameraToLocalTransform, light.localToCameraTransform);
|
||||||
|
camera.childLights[childLightsLength] = light;
|
||||||
|
childLightsLength++;
|
||||||
}
|
}
|
||||||
child.collectDraws(camera, lights, lightsLength);
|
child.collectDraws(camera, camera.childLights, childLightsLength, useShadow);
|
||||||
} else {
|
} else {
|
||||||
child.collectDraws(camera, null, 0);
|
child.collectDraws(camera, null, 0, useShadow);
|
||||||
}
|
}
|
||||||
// Hierarchical call
|
// Hierarchical call
|
||||||
for (var c:Object3D = child.childrenList; c != null; c = c.next) {
|
for (var c:Object3D = child.childrenList; c != null; c = c.next) {
|
||||||
collectChildDraws(c, child, camera, lights, lightsLength);
|
collectChildDraws(c, child, camera, lights, lightsLength, useShadow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -149,10 +149,10 @@ package alternativa.engine3d.objects {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
for (var i:int = 0; i < _surfacesLength; i++) {
|
for (var i:int = 0; i < _surfacesLength; i++) {
|
||||||
var surface:Surface = _surfaces[i];
|
var surface:Surface = _surfaces[i];
|
||||||
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength);
|
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, -1);
|
||||||
// Mouse events
|
// Mouse events
|
||||||
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
|
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,14 +73,14 @@ package alternativa.engine3d.objects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
if (geometry == null) return;
|
if (geometry == null) return;
|
||||||
// Calculation of joints matrices.
|
// Calculation of joints matrices.
|
||||||
for (var i:int = 0; i < _surfacesLength; i++) {
|
for (var i:int = 0; i < _surfacesLength; i++) {
|
||||||
var surface:Surface = _surfaces[i];
|
var surface:Surface = _surfaces[i];
|
||||||
transformProcedure = surfaceTransformProcedures[i];
|
transformProcedure = surfaceTransformProcedures[i];
|
||||||
deltaTransformProcedure = surfaceDeltaTransformProcedures[i];
|
deltaTransformProcedure = surfaceDeltaTransformProcedures[i];
|
||||||
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength);
|
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow);
|
||||||
// Mouse events
|
// Mouse events
|
||||||
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
|
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -565,7 +565,7 @@ package alternativa.engine3d.objects {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
if (geometry == null) return;
|
if (geometry == null) return;
|
||||||
// Calculate joints matrices
|
// Calculate joints matrices
|
||||||
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||||
@@ -582,7 +582,7 @@ package alternativa.engine3d.objects {
|
|||||||
var surface:Surface = _surfaces[i];
|
var surface:Surface = _surfaces[i];
|
||||||
transformProcedure = surfaceTransformProcedures[i];
|
transformProcedure = surfaceTransformProcedures[i];
|
||||||
deltaTransformProcedure = surfaceDeltaTransformProcedures[i];
|
deltaTransformProcedure = surfaceDeltaTransformProcedures[i];
|
||||||
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength);
|
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow);
|
||||||
|
|
||||||
/*var destination:DrawUnit = surface.getDrawUnit(camera, geometry, lights, lightsLength);
|
/*var destination:DrawUnit = surface.getDrawUnit(camera, geometry, lights, lightsLength);
|
||||||
if (destination == null) continue;
|
if (destination == null) continue;
|
||||||
|
|||||||
@@ -196,10 +196,10 @@ package alternativa.engine3d.objects {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
for (var i:int = 0; i < _surfacesLength; i++) {
|
for (var i:int = 0; i < _surfacesLength; i++) {
|
||||||
var surface:Surface = _surfaces[i];
|
var surface:Surface = _surfaces[i];
|
||||||
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, Renderer.SKY);
|
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, Renderer.SKY);
|
||||||
//Mouse events
|
//Mouse events
|
||||||
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
|
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,9 +182,9 @@ package alternativa.engine3d.objects {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
override alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
var geometry:Geometry = getGeometry(camera.context3D);
|
var geometry:Geometry = getGeometry(camera.context3D);
|
||||||
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, alwaysOnTop ? Renderer.NEXT_LAYER : -1);
|
if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, alwaysOnTop ? Renderer.NEXT_LAYER : -1);
|
||||||
// Mouse events.
|
// Mouse events.
|
||||||
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
|
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ package alternativa.engine3d.objects {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
alternativa3d override function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int):void {
|
alternativa3d override function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
||||||
if (camera.context3D != cachedContext3D) {
|
if (camera.context3D != cachedContext3D) {
|
||||||
cachedContext3D = camera.context3D;
|
cachedContext3D = camera.context3D;
|
||||||
shaderProgram = cachedPrograms[cachedContext3D];
|
shaderProgram = cachedPrograms[cachedContext3D];
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
*
|
*
|
||||||
* It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/
|
* It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/
|
||||||
* */
|
* */
|
||||||
|
|
||||||
package alternativa.engine3d.shadows {
|
package alternativa.engine3d.shadows {
|
||||||
|
|
||||||
import alternativa.engine3d.alternativa3d;
|
import alternativa.engine3d.alternativa3d;
|
||||||
@@ -60,8 +59,6 @@ package alternativa.engine3d.shadows {
|
|||||||
/**
|
/**
|
||||||
* Debug mode.
|
* Debug mode.
|
||||||
*/
|
*/
|
||||||
public var debug:Boolean = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Degree of correcting offset of shadow map space. It need for getting rid of self-shadowing artifacts.
|
* Degree of correcting offset of shadow map space. It need for getting rid of self-shadowing artifacts.
|
||||||
*/
|
*/
|
||||||
@@ -164,6 +161,7 @@ package alternativa.engine3d.shadows {
|
|||||||
* Enable/disable automatic calculation of shadow zone parameters on specified bound-box at shadowBoundBox property.
|
* Enable/disable automatic calculation of shadow zone parameters on specified bound-box at shadowBoundBox property.
|
||||||
*/
|
*/
|
||||||
public var calculateParametersByVolume:Boolean = false;
|
public var calculateParametersByVolume:Boolean = false;
|
||||||
|
|
||||||
public var volume:BoundBox = null;
|
public var volume:BoundBox = null;
|
||||||
|
|
||||||
// TODO: implement special shader for display of shadowmap in debug (black-and-white).
|
// TODO: implement special shader for display of shadowmap in debug (black-and-white).
|
||||||
@@ -217,7 +215,7 @@ package alternativa.engine3d.shadows {
|
|||||||
this._mapSize = mapSize;
|
this._mapSize = mapSize;
|
||||||
|
|
||||||
this._pcfOffset = pcfOffset;
|
this._pcfOffset = pcfOffset;
|
||||||
this.type = _pcfOffset > 0 ? "S" : "s";
|
this.type = _pcfOffset > 0 ? "DS" : "ds";
|
||||||
|
|
||||||
vertexShadowProcedure = getVShader();
|
vertexShadowProcedure = getVShader();
|
||||||
fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader();
|
fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader();
|
||||||
@@ -381,12 +379,12 @@ package alternativa.engine3d.shadows {
|
|||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
var debugSurface:Surface = debugPlane._surfaces[0];
|
var debugSurface:Surface = debugPlane._surfaces[0];
|
||||||
debugSurface.material.collectDraws(camera, debugSurface, debugPlane.geometry, emptyLightVector, 0, -1);
|
debugSurface.material.collectDraws(camera, debugSurface, debugPlane.geometry, emptyLightVector, 0, false, -1);
|
||||||
|
|
||||||
// Form transformation matrix for debugPlane
|
// Form transformation matrix for debugPlane
|
||||||
debugPlane.transform.compose((frustumMinX + frustumMaxX) / 2, (frustumMinY + frustumMaxY) / 2, frustumMaxZ, 0, 0, 0, (frustumMaxX - frustumMinX), (frustumMaxY - frustumMinY), 1);
|
debugPlane.transform.compose((frustumMinX + frustumMaxX) / 2, (frustumMinY + frustumMaxY) / 2, frustumMaxZ, 0, 0, 0, (frustumMaxX - frustumMinX), (frustumMaxY - frustumMinY), 1);
|
||||||
debugPlane.localToCameraTransform.combine(_light.localToCameraTransform, debugPlane.transform);
|
debugPlane.localToCameraTransform.combine(_light.localToCameraTransform, debugPlane.transform);
|
||||||
debugSurface.material.collectDraws(camera, debugSurface, debugPlane.geometry, emptyLightVector, 0, -1);
|
debugSurface.material.collectDraws(camera, debugSurface, debugPlane.geometry, emptyLightVector, 0, false, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
tempBounds.minX = frustumMinX;
|
tempBounds.minX = frustumMinX;
|
||||||
@@ -567,7 +565,6 @@ package alternativa.engine3d.shadows {
|
|||||||
fLinker.addProcedure(Procedure.compileFromArray([
|
fLinker.addProcedure(Procedure.compileFromArray([
|
||||||
"#v0=vDistance",
|
"#v0=vDistance",
|
||||||
"#c0=cConstants",
|
"#c0=cConstants",
|
||||||
"mov t0.xy, v0.zz",
|
|
||||||
"frc t0.y, v0.z",
|
"frc t0.y, v0.z",
|
||||||
"sub t0.x, v0.z, t0.y",
|
"sub t0.x, v0.z, t0.y",
|
||||||
"mul t0.x, t0.x, c0.x",
|
"mul t0.x, t0.x, c0.x",
|
||||||
@@ -711,6 +708,28 @@ package alternativa.engine3d.shadows {
|
|||||||
|
|
||||||
//------------- ShadowMap Shader ----------
|
//------------- ShadowMap Shader ----------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
alternativa3d override function setup(drawUnit:DrawUnit, vertexLinker:Linker, fragmentLinker:Linker, surface:Surface):void {
|
||||||
|
// Устанавливаем матрицу перевода в шедоумапу
|
||||||
|
objectToShadowMapTransform.combine(cameraToShadowMapUVProjection, surface.object.localToCameraTransform);
|
||||||
|
|
||||||
|
drawUnit.setVertexConstantsFromTransform(vertexLinker.getVariableIndex("cUVProjection"), objectToShadowMapTransform);
|
||||||
|
// Устанавливаем шедоумапу
|
||||||
|
drawUnit.setTextureAt(fragmentLinker.getVariableIndex("sShadowMap"), shadowMap);
|
||||||
|
// TODO: сделать множитель более корректный. Возможно 65536 (разрешающая способность глубины буфера).
|
||||||
|
// Устанавливаем коеффициенты
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -255*10000, -10000, biasMultiplier*255*10000, 1/16);
|
||||||
|
if (_pcfOffset > 0) {
|
||||||
|
var offset1:Number = _pcfOffset/_mapSize;
|
||||||
|
var offset2:Number = offset1/3;
|
||||||
|
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -offset1, -offset2, offset2, offset1);
|
||||||
|
}
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDist"), 0.9999, 10000, 1);
|
||||||
|
}
|
||||||
|
|
||||||
private static function getVShader():Procedure {
|
private static function getVShader():Procedure {
|
||||||
var shader:Procedure = Procedure.compileFromArray([
|
var shader:Procedure = Procedure.compileFromArray([
|
||||||
"#v0=vSample",
|
"#v0=vSample",
|
||||||
@@ -737,6 +756,7 @@ package alternativa.engine3d.shadows {
|
|||||||
// Clipping by distance.
|
// Clipping by distance.
|
||||||
shaderArr[line++] = "sub t0.y, c1.x, t0.z"; // maxDist - z
|
shaderArr[line++] = "sub t0.y, c1.x, t0.z"; // maxDist - z
|
||||||
shaderArr[line++] = "mul t0.y, t0.y, c1.y"; // mul 10000
|
shaderArr[line++] = "mul t0.y, t0.y, c1.y"; // mul 10000
|
||||||
|
|
||||||
shaderArr[line++] = "sat t0.xy, t0.xy";
|
shaderArr[line++] = "sat t0.xy, t0.xy";
|
||||||
shaderArr[line++] = "mul t0.x, t0.x, t0.y";
|
shaderArr[line++] = "mul t0.x, t0.x, t0.y";
|
||||||
shaderArr[line++] = "sub o0, c1.z, t0.x";
|
shaderArr[line++] = "sub o0, c1.z, t0.x";
|
||||||
@@ -790,28 +810,6 @@ package alternativa.engine3d.shadows {
|
|||||||
return Procedure.compileFromArray(shaderArr, "DirectionalShadowMapFragment");
|
return Procedure.compileFromArray(shaderArr, "DirectionalShadowMapFragment");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
alternativa3d override function setup(drawUnit:DrawUnit, vertexLinker:Linker, fragmentLinker:Linker, surface:Surface):void {
|
|
||||||
// Set transfer matrix to shadowmap.
|
|
||||||
objectToShadowMapTransform.combine(cameraToShadowMapUVProjection, surface.object.localToCameraTransform);
|
|
||||||
|
|
||||||
drawUnit.setVertexConstantsFromTransform(vertexLinker.getVariableIndex("cUVProjection"), objectToShadowMapTransform);
|
|
||||||
// Set shadowmap.
|
|
||||||
drawUnit.setTextureAt(fragmentLinker.getVariableIndex("sShadowMap"), shadowMap);
|
|
||||||
// TODO: set multiplier more correct. It is possible that 65536 (resolution of the buffer depth).
|
|
||||||
// Set coefficients.
|
|
||||||
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -255*10000, -10000, biasMultiplier*255*10000, 1/16);
|
|
||||||
if (_pcfOffset > 0) {
|
|
||||||
var offset1:Number = _pcfOffset/_mapSize;
|
|
||||||
var offset2:Number = offset1/3;
|
|
||||||
|
|
||||||
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -offset1, -offset2, offset2, offset1);
|
|
||||||
}
|
|
||||||
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDist"), 0.9999, 10000, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds given object to list of objects, that cast shadow.
|
* Adds given object to list of objects, that cast shadow.
|
||||||
* @param object Added object.
|
* @param object Added object.
|
||||||
|
|||||||
903
src/alternativa/engine3d/shadows/OmniLightShadow.as
Normal file
903
src/alternativa/engine3d/shadows/OmniLightShadow.as
Normal file
@@ -0,0 +1,903 @@
|
|||||||
|
/**
|
||||||
|
* 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/
|
||||||
|
*/
|
||||||
|
package alternativa.engine3d.shadows {
|
||||||
|
|
||||||
|
import alternativa.engine3d.alternativa3d;
|
||||||
|
import alternativa.engine3d.core.Camera3D;
|
||||||
|
import alternativa.engine3d.core.DrawUnit;
|
||||||
|
import alternativa.engine3d.core.Object3D;
|
||||||
|
import alternativa.engine3d.core.Renderer;
|
||||||
|
import alternativa.engine3d.core.Transform3D;
|
||||||
|
import alternativa.engine3d.core.VertexAttributes;
|
||||||
|
import alternativa.engine3d.core.View;
|
||||||
|
import alternativa.engine3d.materials.Material;
|
||||||
|
import alternativa.engine3d.materials.ShaderProgram;
|
||||||
|
import alternativa.engine3d.materials.TextureMaterial;
|
||||||
|
import alternativa.engine3d.materials.compiler.Linker;
|
||||||
|
import alternativa.engine3d.materials.compiler.Procedure;
|
||||||
|
import alternativa.engine3d.materials.compiler.VariableType;
|
||||||
|
import alternativa.engine3d.objects.Joint;
|
||||||
|
import alternativa.engine3d.objects.Mesh;
|
||||||
|
import alternativa.engine3d.objects.Skin;
|
||||||
|
import alternativa.engine3d.objects.Surface;
|
||||||
|
import alternativa.engine3d.primitives.GeoSphere;
|
||||||
|
import alternativa.engine3d.resources.Geometry;
|
||||||
|
import alternativa.engine3d.resources.TextureResource;
|
||||||
|
|
||||||
|
import flash.display3D.Context3D;
|
||||||
|
import flash.display3D.Context3DProgramType;
|
||||||
|
import flash.display3D.Context3DTextureFormat;
|
||||||
|
import flash.display3D.Context3DTriangleFace;
|
||||||
|
import flash.display3D.VertexBuffer3D;
|
||||||
|
import flash.display3D.textures.CubeTexture;
|
||||||
|
import flash.utils.Dictionary;
|
||||||
|
|
||||||
|
use namespace alternativa3d;
|
||||||
|
|
||||||
|
public class OmniLightShadow extends Shadow{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Степень корректирующего смещения пространства карты теней для избавления от артефактов самозатенения.
|
||||||
|
*/
|
||||||
|
public var biasMultiplier:Number = 0.99;
|
||||||
|
|
||||||
|
private var renderer:Renderer = new Renderer();
|
||||||
|
|
||||||
|
private var boundSize:Number = 1;
|
||||||
|
private var _mapSize:Number;
|
||||||
|
private var _pcfOffset:Number;
|
||||||
|
|
||||||
|
private var cubeShadowMap:CubeTexture;
|
||||||
|
private var cameras:Vector.<Camera3D> = new Vector.<Camera3D>();
|
||||||
|
|
||||||
|
private var debugObject:Mesh;
|
||||||
|
private var debugMaterial:ShadowDebugMaterial;
|
||||||
|
|
||||||
|
private var _casters:Vector.<Object3D> = new Vector.<Object3D>();
|
||||||
|
|
||||||
|
private var cachedContext:Context3D;
|
||||||
|
private var programs:Dictionary = new Dictionary();
|
||||||
|
|
||||||
|
private var actualCasters:Vector.<Object3D> = new Vector.<Object3D>();
|
||||||
|
private var actualCastersCount:int;
|
||||||
|
|
||||||
|
private var edgeCameraToCasterTransform:Transform3D = new Transform3D();
|
||||||
|
private var casterToEdgedCameraTransform:Transform3D = new Transform3D();
|
||||||
|
private var objectToLightTransform:Transform3D = new Transform3D();
|
||||||
|
|
||||||
|
private var prevActualCasterCountForEdge:Vector.<int> = new Vector.<int>(6);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Создает экземпляр OmniLightShadow.
|
||||||
|
* @param mapSize Размер карты теней. Должен быть степенью 2.
|
||||||
|
* @param pcfOffset Смягчение границ тени.
|
||||||
|
*/
|
||||||
|
public function OmniLightShadow(mapSize:int = 128, pcfOffset:Number = 0) {
|
||||||
|
|
||||||
|
this.mapSize = mapSize;
|
||||||
|
this.pcfOffset = pcfOffset;
|
||||||
|
vertexShadowProcedure = getVShader();
|
||||||
|
type = _pcfOffset > 0 ? "OS" : "os";
|
||||||
|
fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader();
|
||||||
|
|
||||||
|
debugMaterial = new ShadowDebugMaterial();
|
||||||
|
debugMaterial.alpha = 1.0;
|
||||||
|
|
||||||
|
for (var i:int = 0; i < 6; i++) {
|
||||||
|
// создаем камеры
|
||||||
|
var cam:Camera3D = new Camera3D(1, boundSize);
|
||||||
|
cam.fov = 1.910633237;
|
||||||
|
cam.view = new View(boundSize, boundSize);
|
||||||
|
cam.renderer = renderer;
|
||||||
|
cameras[i] = cam;
|
||||||
|
|
||||||
|
prevActualCasterCountForEdge[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left
|
||||||
|
cameras[1].rotationY = -Math.PI/2;
|
||||||
|
cameras[1].scaleY = -1;
|
||||||
|
cameras[1].composeTransforms();
|
||||||
|
// Right
|
||||||
|
cameras[0].rotationY = Math.PI/2;
|
||||||
|
cameras[0].scaleY = -1;
|
||||||
|
cameras[0].composeTransforms();
|
||||||
|
// Back
|
||||||
|
cameras[3].rotationX = -Math.PI/2;
|
||||||
|
cameras[3].rotationZ = Math.PI;
|
||||||
|
cameras[3].scaleX = -1;
|
||||||
|
cameras[3].composeTransforms();
|
||||||
|
// Front
|
||||||
|
cameras[2].rotationX = -Math.PI/2;
|
||||||
|
cameras[2].scaleY = -1;
|
||||||
|
cameras[2].composeTransforms();
|
||||||
|
// Bottom
|
||||||
|
cameras[5].rotationX = Math.PI;
|
||||||
|
cameras[5].scaleX = -1;
|
||||||
|
cameras[5].composeTransforms();
|
||||||
|
// Top
|
||||||
|
cameras[4].rotationX = 0;
|
||||||
|
cameras[4].scaleY = -1;
|
||||||
|
cameras[4].composeTransforms();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
alternativa3d function setBoundSize(value:Number):void{
|
||||||
|
this.boundSize = value;
|
||||||
|
for (var i:int = 0; i < 6; i++) {
|
||||||
|
var cam:Camera3D = cameras[i];
|
||||||
|
cam.view.width = cam.view.height = int (value);
|
||||||
|
cam.farClipping = value;
|
||||||
|
cam.calculateProjection(value,value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createDebugCube(material:Material, context:Context3D):Mesh{
|
||||||
|
var mesh:Mesh = new Mesh();
|
||||||
|
// TODO: определиться куб или сфера
|
||||||
|
// var geometry:Geometry = new Geometry(8);
|
||||||
|
// mesh.geometry = geometry;
|
||||||
|
//
|
||||||
|
// var attributes:Array = new Array();
|
||||||
|
// attributes[0] = VertexAttributes.POSITION;
|
||||||
|
// attributes[1] = VertexAttributes.POSITION;
|
||||||
|
// attributes[2] = VertexAttributes.POSITION;
|
||||||
|
// geometry.addVertexStream(attributes);
|
||||||
|
//
|
||||||
|
// geometry.setAttributeValues(VertexAttributes.POSITION, Vector.<Number>([-0.5, -0.5, -0.5,
|
||||||
|
// 0.5, -0.5, -0.5,
|
||||||
|
// 0.5, 0.5, -0.5,
|
||||||
|
// -0.5, 0.5, -0.5,
|
||||||
|
// -0.5, -0.5, 0.5,
|
||||||
|
// 0.5, -0.5, 0.5,
|
||||||
|
// 0.5, 0.5, 0.5,
|
||||||
|
// -0.5, 0.5, 0.5]));
|
||||||
|
//
|
||||||
|
// geometry.indices = Vector.<uint>([ 0, 1, 2, 3, 0, 2, 2, 1, 0, 3, 2, 0,
|
||||||
|
// 2, 6, 1, 1, 6, 2, 1, 6, 5, 5, 6, 1,
|
||||||
|
// 6, 4, 5, 5, 4, 6, 6, 4, 7, 7, 4, 6,
|
||||||
|
// 0, 7, 4, 4, 7, 0, 0, 7, 3, 3, 7, 0,
|
||||||
|
// 3, 6, 2, 2, 6, 3, 3, 7, 6, 6, 7, 3,
|
||||||
|
// 0, 5, 1, 1, 5, 0, 0, 4, 5, 5, 4, 0]);
|
||||||
|
//
|
||||||
|
// mesh.addSurface(material, 0, 24);
|
||||||
|
var sphere:GeoSphere = new GeoSphere(1, 4, false);
|
||||||
|
var geometry:Geometry = sphere.geometry;
|
||||||
|
mesh.geometry = geometry;
|
||||||
|
mesh.addSurface(material, 0, geometry.numTriangles);
|
||||||
|
|
||||||
|
geometry.upload(context);
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Вычисление шедоумапы
|
||||||
|
override alternativa3d function process(camera:Camera3D):void {
|
||||||
|
var i:int;
|
||||||
|
var j:int;
|
||||||
|
var caster:Object3D;
|
||||||
|
var context:Context3D = camera.context3D;
|
||||||
|
var castersCount:int = _casters.length;
|
||||||
|
// Отсечение кастеров, тени которых не видны
|
||||||
|
|
||||||
|
// Обработка смены контекста
|
||||||
|
if (context != cachedContext) {
|
||||||
|
programs = new Dictionary();
|
||||||
|
cubeShadowMap = null;
|
||||||
|
cachedContext = context;
|
||||||
|
for (i = 0; i < cameras.length; i++) {
|
||||||
|
cameras[i].context3D = cachedContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cubeShadowMap == null) {
|
||||||
|
cubeShadowMap = context.createCubeTexture(_mapSize, Context3DTextureFormat.BGRA, true);
|
||||||
|
debugMaterial.cubeMap = cubeShadowMap;
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
context.setRenderToTexture(cubeShadowMap, true, 0, i);
|
||||||
|
context.clear(1, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// предрасчитаем некоторые матрицы трансформации
|
||||||
|
for (j = 0; j < castersCount; j++) {
|
||||||
|
caster = _casters[j];
|
||||||
|
|
||||||
|
if (caster.transformChanged) caster.composeTransforms();
|
||||||
|
caster.lightToLocalTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform);
|
||||||
|
caster.localToLightTransform.combine(_light.cameraToLocalTransform, caster.localToCameraTransform);
|
||||||
|
|
||||||
|
var skin:Skin = caster as Skin;
|
||||||
|
if (skin != null) {
|
||||||
|
// Расчет матриц джоинтов
|
||||||
|
for (var child:Object3D = skin.childrenList; child != null; child = child.next) {
|
||||||
|
if (child.transformChanged) child.composeTransforms();
|
||||||
|
// Записываем в localToGlobalTransform матрицу перевода в скин
|
||||||
|
child.localToGlobalTransform.copy(child.transform);
|
||||||
|
if (child is Joint) {
|
||||||
|
Joint(child).calculateTransform();
|
||||||
|
}
|
||||||
|
skin.calculateJointsTransforms(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (caster.childrenList)
|
||||||
|
calculateChildrenTransforms(caster);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Пробегаемся по 6-и камерам
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
// камера соответствующая грани куба
|
||||||
|
var edgeCamera:Camera3D = cameras[i];
|
||||||
|
|
||||||
|
// проверяем, есть ли видимые кастеры попадающие на грань куба
|
||||||
|
actualCastersCount = 0;
|
||||||
|
for (j = 0; j < castersCount; j++) {
|
||||||
|
caster = _casters[j];
|
||||||
|
|
||||||
|
var visible:Boolean = caster.visible;
|
||||||
|
var parent:Object3D = caster._parent;
|
||||||
|
while (visible && parent != null) {
|
||||||
|
visible = parent.visible;
|
||||||
|
parent = parent._parent;
|
||||||
|
}
|
||||||
|
if (visible) {
|
||||||
|
// Проверка куллинга
|
||||||
|
// формируем actualCasters
|
||||||
|
calculateVisibility(caster, edgeCamera);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actualCastersCount>0){
|
||||||
|
// Настройка параметров рендеринга:
|
||||||
|
renderer.camera = edgeCamera;
|
||||||
|
context.setRenderToTexture(cubeShadowMap, true, 0, i);
|
||||||
|
context.clear(1, 0, 0, 0.0);
|
||||||
|
|
||||||
|
// Пробегаемся по кастерам
|
||||||
|
for (j = 0; j <actualCastersCount; j++) {
|
||||||
|
caster = actualCasters[j];
|
||||||
|
// собираем матрицу перевода из кастера в пространство edgeCamera
|
||||||
|
casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform);
|
||||||
|
// Собираем драуколлы для кастера и его дочерних объектов
|
||||||
|
collectDraws(context, caster, edgeCamera);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Отрисовка дроуколов
|
||||||
|
renderer.render(context);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// Если относительно одной из камер ничего не менялось, не вызываем отрисовочный вызов
|
||||||
|
if (prevActualCasterCountForEdge[i]!=0){
|
||||||
|
context.setRenderToTexture(cubeShadowMap, false, 0, i);
|
||||||
|
context.clear(1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevActualCasterCountForEdge[i] = actualCastersCount;
|
||||||
|
}
|
||||||
|
context.setRenderToBackBuffer();
|
||||||
|
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
if (actualCastersCount > 0) {
|
||||||
|
// Создаем дебаговый объект, если он не создан
|
||||||
|
if (debugObject == null) {
|
||||||
|
debugObject = createDebugCube(debugMaterial, camera.context3D);
|
||||||
|
debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = boundSize/12;
|
||||||
|
debugObject.composeTransforms();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Формируем матрицу трансформации для debugObject
|
||||||
|
debugObject.localToCameraTransform.combine(_light.localToCameraTransform, debugObject.transform);
|
||||||
|
|
||||||
|
// Отрисовываем
|
||||||
|
var debugSurface:Surface = debugObject._surfaces[0];
|
||||||
|
debugMaterial.collectDraws(camera, debugSurface, debugObject.geometry, null, 0, false, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// предрасчитывает матрицы для всех детей
|
||||||
|
// localToLightTransform, lightToLocalTransform, transform, и calculateTransform для Joint
|
||||||
|
private function calculateChildrenTransforms(root:Object3D):void{
|
||||||
|
var childrenList:Object3D = root.childrenList;
|
||||||
|
|
||||||
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||||
|
|
||||||
|
// расчет матриц трансформаций для объектов
|
||||||
|
if (child.transformChanged) child.composeTransforms();
|
||||||
|
child.localToLightTransform.combine(root.localToLightTransform, child.transform);
|
||||||
|
child.lightToLocalTransform.combine(child.inverseTransform, root.lightToLocalTransform);
|
||||||
|
|
||||||
|
// расчет матриц трансформаций для скинов
|
||||||
|
var skin:Skin = child as Skin;
|
||||||
|
if (skin != null) {
|
||||||
|
// Расчет матриц джоинтов
|
||||||
|
for (var skinChild:Object3D = skin.childrenList; skinChild != null; skinChild = skinChild.next) {
|
||||||
|
if (skinChild.transformChanged) skinChild.composeTransforms();
|
||||||
|
// Записываем в localToGlobalTransform матрицу перевода в скин
|
||||||
|
skinChild.localToGlobalTransform.copy(skinChild.transform);
|
||||||
|
if (skinChild is Joint) {
|
||||||
|
Joint(skinChild).calculateTransform();
|
||||||
|
}
|
||||||
|
skin.calculateJointsTransforms(skinChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (child.childrenList)
|
||||||
|
calculateChildrenTransforms(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// собирает список actualCasters для одной из 6-и камер
|
||||||
|
private function calculateVisibility(root:Object3D, camera:Camera3D):void{
|
||||||
|
var casterCulling:int;
|
||||||
|
|
||||||
|
if (root.visible) {
|
||||||
|
var skin:Skin = root as Skin;
|
||||||
|
|
||||||
|
// Вычисляем результат кулинга для объекта
|
||||||
|
if (root.boundBox != null) {
|
||||||
|
edgeCameraToCasterTransform.combine(root.lightToLocalTransform, camera.transform);
|
||||||
|
camera.calculateFrustum(edgeCameraToCasterTransform);
|
||||||
|
casterCulling = root.boundBox.checkFrustumCulling(camera.frustum, 63);
|
||||||
|
} else {
|
||||||
|
casterCulling = 63;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если Кулинг кастера дает положительный результат, тогда
|
||||||
|
if (casterCulling){
|
||||||
|
if (skin){
|
||||||
|
actualCasters[actualCastersCount++] = root;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
var childrenList:Object3D = root.childrenList;
|
||||||
|
// Если есть дочерние объекты,
|
||||||
|
if(childrenList!=null){
|
||||||
|
// Проверяем их на кулинг
|
||||||
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||||
|
calculateVisibility(child, camera);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Если дочерних объектов нет
|
||||||
|
else{
|
||||||
|
// добавляем кастер в список актуальных кастеров
|
||||||
|
actualCasters[actualCastersCount++] = root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{
|
||||||
|
|
||||||
|
// если объект является мешем, собираем для него дроуколы
|
||||||
|
var mesh:Mesh = caster as Mesh;
|
||||||
|
if (mesh != null && mesh.geometry != null) {
|
||||||
|
var program:ShaderProgram;
|
||||||
|
var programListByTransformProcedure:Vector.<ShaderProgram>;
|
||||||
|
var skin:Skin = mesh as Skin;
|
||||||
|
|
||||||
|
// пробегаемся по сурфейсам
|
||||||
|
for (var i:int = 0; i < mesh._surfacesLength; i++) {
|
||||||
|
var surface:Surface = mesh._surfaces[i];
|
||||||
|
if (surface.material == null) continue;
|
||||||
|
|
||||||
|
var material:Material = surface.material;
|
||||||
|
var geometry:Geometry = mesh.geometry;
|
||||||
|
var alphaTest:Boolean;
|
||||||
|
var useDiffuseAlpha:Boolean;
|
||||||
|
var alphaThreshold:Number;
|
||||||
|
var materialAlpha:Number;
|
||||||
|
var diffuse:TextureResource;
|
||||||
|
var opacity:TextureResource;
|
||||||
|
var uvBuffer:VertexBuffer3D;
|
||||||
|
|
||||||
|
// ловим параметры прозрачности
|
||||||
|
if (material is TextureMaterial) {
|
||||||
|
alphaThreshold = TextureMaterial(material).alphaThreshold;
|
||||||
|
materialAlpha = TextureMaterial(material).alpha;
|
||||||
|
diffuse = TextureMaterial(material).diffuseMap;
|
||||||
|
opacity = TextureMaterial(material).opacityMap;
|
||||||
|
alphaTest = alphaThreshold > 0;
|
||||||
|
useDiffuseAlpha = TextureMaterial(material).opacityMap == null;
|
||||||
|
uvBuffer = geometry.getVertexBuffer(VertexAttributes.TEXCOORDS[0]);
|
||||||
|
if (uvBuffer == null) continue;
|
||||||
|
} else {
|
||||||
|
alphaTest = false;
|
||||||
|
useDiffuseAlpha = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var positionBuffer:VertexBuffer3D = mesh.geometry.getVertexBuffer(VertexAttributes.POSITION);
|
||||||
|
if (positionBuffer == null) continue;
|
||||||
|
|
||||||
|
// поднимаем и кэшируем programListByTransformProcedure
|
||||||
|
if (skin != null) {
|
||||||
|
caster.transformProcedure = skin.surfaceTransformProcedures[i];
|
||||||
|
}
|
||||||
|
programListByTransformProcedure = programs[caster.transformProcedure];
|
||||||
|
if (programListByTransformProcedure == null) {
|
||||||
|
programListByTransformProcedure = new Vector.<ShaderProgram>(3, true);
|
||||||
|
programs[caster.transformProcedure] = programListByTransformProcedure;
|
||||||
|
}
|
||||||
|
|
||||||
|
// собираем программу и Формируем дроуюнит
|
||||||
|
program = getProgram(caster.transformProcedure, programListByTransformProcedure, context, alphaTest, useDiffuseAlpha);
|
||||||
|
var drawUnit:DrawUnit = renderer.createDrawUnit(caster, program.program, mesh.geometry._indexBuffer, surface.indexBegin, surface.numTriangles, program);
|
||||||
|
drawUnit.culling = Context3DTriangleFace.BACK;
|
||||||
|
|
||||||
|
// Установка стрима
|
||||||
|
drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aPosition"), positionBuffer, mesh.geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]);
|
||||||
|
|
||||||
|
if (alphaTest) {
|
||||||
|
drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aUV"), uvBuffer, geometry._attributesOffsets[VertexAttributes.TEXCOORDS[0]], VertexAttributes.FORMATS[VertexAttributes.TEXCOORDS[0]]);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cThresholdAlpha"), alphaThreshold, 0, 0, materialAlpha);
|
||||||
|
if (useDiffuseAlpha) {
|
||||||
|
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sTexture"), diffuse._texture);
|
||||||
|
} else {
|
||||||
|
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sTexture"), opacity._texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Установка констант
|
||||||
|
caster.setTransformConstants(drawUnit, surface, program.vertexShader, null);
|
||||||
|
drawUnit.setProjectionConstants(edgeCamera, program.vertexShader.getVariableIndex("cProjMatrix"), casterToEdgedCameraTransform);
|
||||||
|
drawUnit.setVertexConstantsFromTransform(program.vertexShader.getVariableIndex("cCasterToOmni"), caster.localToLightTransform);
|
||||||
|
|
||||||
|
drawUnit.setVertexConstantsFromNumbers(program.vertexShader.getVariableIndex("cScale"), 255/boundSize, 0, 0, 1);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cConstants"), 1 / 255, 0, 0, 1);
|
||||||
|
|
||||||
|
renderer.addDrawUnit(drawUnit, Renderer.OPAQUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var child:Object3D;
|
||||||
|
for (child = caster.childrenList; child != null; child = child.next) {
|
||||||
|
if (!(child as Joint) && child.visible) collectDraws(context, child, edgeCamera);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* Процедура для передачи UV координат во фрагментный шейдер
|
||||||
|
*/
|
||||||
|
static private const passUVProcedure:Procedure = new Procedure(["#v0=vUV", "#a0=aUV", "mov v0, a0"], "passUVProcedure");
|
||||||
|
|
||||||
|
// diffuse alpha test
|
||||||
|
private static const diffuseAlphaTestProcedure:Procedure = new Procedure([
|
||||||
|
"#v0=vUV",
|
||||||
|
"#s0=sTexture",
|
||||||
|
"#c0=cThresholdAlpha",
|
||||||
|
"tex t0, v0, s0 <2d, linear,repeat, miplinear>",
|
||||||
|
"mul t0.w, t0.w, c0.w",
|
||||||
|
"sub t0.w, t0.w, c0.x",
|
||||||
|
"kil t0.w"
|
||||||
|
], "diffuseAlphaTestProcedure");
|
||||||
|
|
||||||
|
// opacity alpha test
|
||||||
|
private static const opacityAlphaTestProcedure:Procedure = new Procedure([
|
||||||
|
"#v0=vUV",
|
||||||
|
"#s0=sTexture",
|
||||||
|
"#c0=cThresholdAlpha",
|
||||||
|
"tex t0, v0, s0 <2d, linear,repeat, miplinear>",
|
||||||
|
"mul t0.w, t0.x, c0.w",
|
||||||
|
"sub t0.w, t0.w, c0.x",
|
||||||
|
"kil t0.w"
|
||||||
|
], "opacityAlphaTestProcedure");
|
||||||
|
|
||||||
|
|
||||||
|
private function getProgram(transformProcedure:Procedure, programListByTransformProcedure:Vector.<ShaderProgram>, context:Context3D, alphaTest:Boolean, useDiffuseAlpha:Boolean):ShaderProgram {
|
||||||
|
var key:int = (alphaTest ? (useDiffuseAlpha ? 1 : 2) : 0);
|
||||||
|
var program:ShaderProgram = programListByTransformProcedure[key];
|
||||||
|
|
||||||
|
if (program == null) {
|
||||||
|
var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
|
||||||
|
var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
|
||||||
|
|
||||||
|
var positionVar:String = "aPosition";
|
||||||
|
vLinker.declareVariable(positionVar, VariableType.ATTRIBUTE);
|
||||||
|
|
||||||
|
if (alphaTest) {
|
||||||
|
vLinker.addProcedure(passUVProcedure);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transformProcedure != null) {
|
||||||
|
var newPosVar:String = "tTransformedPosition";
|
||||||
|
vLinker.declareVariable(newPosVar);
|
||||||
|
vLinker.addProcedure(transformProcedure, positionVar);
|
||||||
|
vLinker.setOutputParams(transformProcedure, newPosVar);
|
||||||
|
positionVar = newPosVar;
|
||||||
|
}
|
||||||
|
|
||||||
|
var proc:Procedure = Procedure.compileFromArray([
|
||||||
|
"#c1=cScale",
|
||||||
|
"#v0=vDistance",
|
||||||
|
|
||||||
|
"m34 t0.xyz, i0, c2",
|
||||||
|
"dp3 t0.x, t0.xyz, t0.xyz",
|
||||||
|
"sqt t0.x, t0.x", // x: [0, boundSize]
|
||||||
|
"mul t0.x, t0.x, c1.x", // x: [0, 255]
|
||||||
|
"mov t0.w, c1.w",
|
||||||
|
"mov v0, t0",
|
||||||
|
|
||||||
|
"m44 o0, i0, c0"
|
||||||
|
]);
|
||||||
|
proc.assignVariableName(VariableType.CONSTANT, 0, "cProjMatrix", 4);
|
||||||
|
proc.assignVariableName(VariableType.CONSTANT, 2, "cCasterToOmni", 3);
|
||||||
|
|
||||||
|
vLinker.addProcedure(proc, positionVar);
|
||||||
|
|
||||||
|
if (alphaTest) {
|
||||||
|
if (useDiffuseAlpha) {
|
||||||
|
fLinker.addProcedure(diffuseAlphaTestProcedure);
|
||||||
|
} else {
|
||||||
|
fLinker.addProcedure(opacityAlphaTestProcedure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fLinker.addProcedure(Procedure.compileFromArray([
|
||||||
|
"#v0=vDistance", // x: [0, 255]
|
||||||
|
"#c0=cConstants", // 1/255, 0, 0, 1
|
||||||
|
"frc t0.y, v0.x",
|
||||||
|
"sub t0.x, v0.x, t0.y",
|
||||||
|
"mul t0.x, t0.x, c0.x",
|
||||||
|
"mov t0.zw, c0.zw",
|
||||||
|
|
||||||
|
"mov o0, t0"
|
||||||
|
]));
|
||||||
|
program = new ShaderProgram(vLinker, fLinker);
|
||||||
|
fLinker.varyings = vLinker.varyings;
|
||||||
|
programListByTransformProcedure[key] = program;
|
||||||
|
program.upload(context);
|
||||||
|
|
||||||
|
}
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//------------- ShadowMap Shader ----------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
alternativa3d override function setup(drawUnit:DrawUnit, vertexLinker:Linker, fragmentLinker:Linker, surface:Surface):void {
|
||||||
|
// Устанавливаем матрицу перевода в шедоумапу
|
||||||
|
objectToLightTransform.combine(_light.cameraToLocalTransform, surface.object.localToCameraTransform);
|
||||||
|
drawUnit.setVertexConstantsFromTransform(vertexLinker.getVariableIndex("cObjectToLightTransform"), objectToLightTransform);
|
||||||
|
|
||||||
|
// Устанавливаем шедоумапу
|
||||||
|
drawUnit.setTextureAt(fragmentLinker.getVariableIndex("sCubeMap"), cubeShadowMap);
|
||||||
|
|
||||||
|
// Устанавливаем коеффициенты
|
||||||
|
// TODO: сделать множитель более корректный. Возможно 65536 (разрешающая способность глубины буфера).
|
||||||
|
if (_pcfOffset > 0) {
|
||||||
|
|
||||||
|
var offset:Number = _pcfOffset*0.0175; //1 градус
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -3/2, 1/16, 0, 0);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -1, 1, 0, offset/boundSize);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDecode"), -10000, -10000/255, biasMultiplier*10000/boundSize, 10);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -10000, -10000/255, biasMultiplier*10000/boundSize, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getVShader():Procedure {
|
||||||
|
var shader:Procedure = Procedure.compileFromArray([
|
||||||
|
"#v0=vSample",
|
||||||
|
|
||||||
|
"m34 t0.xyz, i0, c0",
|
||||||
|
"dp3 t0.w, t0.xyz, t0.xyz",
|
||||||
|
"sqt t0.w, t0.w", // w: [0, boundSize]
|
||||||
|
// "div t0.xyz, t0.xyz, t0.w", // norm
|
||||||
|
|
||||||
|
"mov v0, t0"
|
||||||
|
], "OmniShadowMapVertex");
|
||||||
|
shader.assignVariableName(VariableType.CONSTANT, 0, "cObjectToLightTransform", 3);
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getFShader():Procedure {
|
||||||
|
var shaderArr:Array = [
|
||||||
|
"#v0=vSample",
|
||||||
|
"#c0=cConstants",
|
||||||
|
"#s0=sCubeMap"
|
||||||
|
];
|
||||||
|
var line:int = 3;
|
||||||
|
// Расстояние
|
||||||
|
shaderArr[line++] = "mov t0.z, v0.w"; // w: [0, boundSize]
|
||||||
|
shaderArr[line++] = "tex t0.xy, v0, s0 <cube, linear>";
|
||||||
|
shaderArr[line++] = "dp3 t0.x, t0.xyz, c0.xyz"; // декодируем, находим разницу между расстояниями и умножаем ее на большое число
|
||||||
|
|
||||||
|
// рассчитываем значение тени
|
||||||
|
shaderArr[line++] = "sat t0, t0.x";
|
||||||
|
shaderArr[line++] = "sub o0, c0.w, t0.x";
|
||||||
|
|
||||||
|
return Procedure.compileFromArray(shaderArr, "OmniShadowMapFragment");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getFShaderPCF():Procedure {
|
||||||
|
var shaderArr:Array = [
|
||||||
|
"#v0=vSample",
|
||||||
|
"#c0=cDecode",
|
||||||
|
"#c1=cConstants",
|
||||||
|
"#c2=cPCFOffsets",
|
||||||
|
"#s0=sCubeMap"
|
||||||
|
];
|
||||||
|
var line:int = 5;
|
||||||
|
var i:int;
|
||||||
|
var j:int;
|
||||||
|
|
||||||
|
// допустимо использование временных переменных t0 t1 t2 t3
|
||||||
|
// v0 - sample
|
||||||
|
// v0.w - length(sample) [0, boundSize]
|
||||||
|
|
||||||
|
// ищем 2-а перпендикулярных вектора
|
||||||
|
// (-y, x, 0)
|
||||||
|
shaderArr[line++] = "mov t1.xyzw, v0.yxzw";
|
||||||
|
shaderArr[line++] = "mul t1.xyzw, t1.xyzw, c1.xyzz";
|
||||||
|
|
||||||
|
shaderArr[line++] = "crs t0.xyz, v0.xyz, t1.xyz";
|
||||||
|
|
||||||
|
// нормируем их
|
||||||
|
shaderArr[line++] = "nrm t0.xyz, t0.xyz";
|
||||||
|
shaderArr[line++] = "nrm t1.xyz, t1.xyz";
|
||||||
|
|
||||||
|
// задаем оффсеты
|
||||||
|
shaderArr[line++] = "mul t0.w, c1.w, v0.w"; // с1.w = offset/boundSize
|
||||||
|
shaderArr[line++] = "mul t0.xyz, t0.xyz, t0.w";
|
||||||
|
shaderArr[line++] = "mul t1.xyz, t1.xyz, t0.w";
|
||||||
|
// --------- {13 opcode}
|
||||||
|
|
||||||
|
// t0, t1 - перпендикуляры ↑→
|
||||||
|
// t2 - текущий вектор
|
||||||
|
|
||||||
|
// в v0.w, t3.z расстояние до объекта
|
||||||
|
// t3.xy - результат из текстуры
|
||||||
|
// t3.w - сумма sat-ов
|
||||||
|
|
||||||
|
// первая точка
|
||||||
|
shaderArr[line++] = "add t2.xyz, t0.xyz, t1.xyz";
|
||||||
|
shaderArr[line++] = "mul t2.xyz, t2.xyz, c2.xxx";
|
||||||
|
shaderArr[line++] = "add t2.xyz, t2.xyz, v0.xyz";
|
||||||
|
|
||||||
|
// получаем длинну из шадоумапы [0, 1]
|
||||||
|
shaderArr[line++] = "mov t3.z, v0.w";
|
||||||
|
|
||||||
|
shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, linear>";
|
||||||
|
shaderArr[line++] = "dp3 o0." +componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
|
||||||
|
|
||||||
|
//-----
|
||||||
|
|
||||||
|
for (j = 1; j<4; j++){
|
||||||
|
shaderArr[line++] = "add t2.xyz, t2.xyz, t1.xyz";
|
||||||
|
|
||||||
|
shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, linear>";
|
||||||
|
shaderArr[line++] = "dp3 o0." +componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderArr[line++] = "sat o0, o0";
|
||||||
|
shaderArr[line++] = "dp4 t3.w, o0, c2.y";
|
||||||
|
|
||||||
|
//-----
|
||||||
|
|
||||||
|
for (i = 0; i<3; i++){
|
||||||
|
shaderArr[line++] = "add t2.xyz, t2.xyz, t0.xyz";
|
||||||
|
|
||||||
|
shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, linear>";
|
||||||
|
shaderArr[line++] = "dp3 o0." +componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
|
||||||
|
|
||||||
|
for (j = 1; j<4; j++){
|
||||||
|
shaderArr[line++] = (i%2 == 1)?("add t2.xyz, t2.xyz, t1.xyz"):("sub t2.xyz, t2.xyz, t1.xyz");
|
||||||
|
|
||||||
|
shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, linear>";
|
||||||
|
shaderArr[line++] = "dp3 o0." +componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
|
||||||
|
}
|
||||||
|
shaderArr[line++] = "sat o0, o0";
|
||||||
|
shaderArr[line++] = "dp4 o0.x, o0, c2.y";
|
||||||
|
shaderArr[line++] = "add t3.w, t3.w, o0.x";
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderArr[line++] = "sub o0, c1.y, t3.w";
|
||||||
|
|
||||||
|
//--------- {73 opcode}
|
||||||
|
return Procedure.compileFromArray(shaderArr, "OmniShadowMapFragment");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static const componentByIndex:Array = ["x", "y", "z", "w"];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет <code>object</code> в список объектов, отбрасывающих тень.
|
||||||
|
* @param object Добавляемый объект.
|
||||||
|
*/
|
||||||
|
public function addCaster(object:Object3D):void {
|
||||||
|
if (_casters.indexOf(object) < 0) {
|
||||||
|
_casters.push(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Очищает список объектов, отбрасывающих тень.
|
||||||
|
*/
|
||||||
|
public function clearCasters():void {
|
||||||
|
_casters.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Качество тени. Задает разрешение shadowmap. Может принимать значения от <code>2</code> до <code>11</code>.
|
||||||
|
*/
|
||||||
|
public function get mapSize():int {
|
||||||
|
return _mapSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
public function set mapSize(value:int):void {
|
||||||
|
if (value != _mapSize) {
|
||||||
|
this._mapSize = value;
|
||||||
|
if (value < 2) {
|
||||||
|
throw new ArgumentError("Map size cannot be less than 2.");
|
||||||
|
} else if (value > 2048) {
|
||||||
|
throw new ArgumentError("Map size exceeds maximum value 2048.");
|
||||||
|
}
|
||||||
|
if ((Math.log(value)/Math.LN2 % 1) != 0) {
|
||||||
|
throw new ArgumentError("Map size must be power of two.");
|
||||||
|
}
|
||||||
|
if (cubeShadowMap != null) {
|
||||||
|
cubeShadowMap.dispose();
|
||||||
|
}
|
||||||
|
cubeShadowMap = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Смещение Percentage Closer Filtering. Этот способ фильтрации используется для смягчения границ тени.
|
||||||
|
*/
|
||||||
|
public function get pcfOffset():Number {
|
||||||
|
return _pcfOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
public function set pcfOffset(value:Number):void {
|
||||||
|
_pcfOffset = value;
|
||||||
|
type = _pcfOffset > 0 ? "OS" : "os";
|
||||||
|
fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.Material;
|
||||||
|
import alternativa.engine3d.materials.ShaderProgram;
|
||||||
|
import alternativa.engine3d.materials.compiler.Linker;
|
||||||
|
import alternativa.engine3d.materials.compiler.Procedure;
|
||||||
|
import alternativa.engine3d.materials.compiler.VariableType;
|
||||||
|
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.Program3D;
|
||||||
|
|
||||||
|
import flash.display3D.VertexBuffer3D;
|
||||||
|
import flash.display3D.textures.CubeTexture;
|
||||||
|
import flash.utils.Dictionary;
|
||||||
|
|
||||||
|
class ShadowDebugMaterial extends Material {
|
||||||
|
|
||||||
|
use namespace alternativa3d;
|
||||||
|
/**
|
||||||
|
* Прозрачность.
|
||||||
|
* Является дополнительным множителем к прозрачности текстуры.
|
||||||
|
* Значение по умолчанию <code>1</code>.
|
||||||
|
*/
|
||||||
|
alternativa3d var alpha:Number = 1;
|
||||||
|
|
||||||
|
private var cachedContext3D:Context3D;
|
||||||
|
private static var caches:Dictionary = new Dictionary(true);
|
||||||
|
private var program:ShaderProgram;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Текстура.
|
||||||
|
*/
|
||||||
|
alternativa3d var cubeMap:CubeTexture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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;
|
||||||
|
// Стримы
|
||||||
|
var positionBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
|
||||||
|
// Проверка на валидность
|
||||||
|
if (positionBuffer == null) return;
|
||||||
|
|
||||||
|
// Обновляем кеш программы для данного контекста
|
||||||
|
if (camera.context3D != cachedContext3D) {
|
||||||
|
cachedContext3D = camera.context3D;
|
||||||
|
program = caches[cachedContext3D];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program == null) {
|
||||||
|
program = setupProgram(object);
|
||||||
|
program.upload(camera.context3D);
|
||||||
|
caches[cachedContext3D] = program;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Создание отрисовочного вызова
|
||||||
|
var drawUnit:DrawUnit = camera.renderer.createDrawUnit(object, program.program, geometry._indexBuffer, surface.indexBegin, surface.numTriangles, program);
|
||||||
|
// Установка стримов
|
||||||
|
drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aPosition"), positionBuffer, geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]);
|
||||||
|
// Установка констант
|
||||||
|
drawUnit.setProjectionConstants(camera, program.vertexShader.getVariableIndex("cProjMatrix"), object.localToCameraTransform);
|
||||||
|
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cDecode"), 1, 1/255, 0, alpha);
|
||||||
|
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sCubeMap"), cubeMap);
|
||||||
|
|
||||||
|
// Отправка на отрисовку
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setupProgram(object:Object3D):ShaderProgram {
|
||||||
|
var vertexLinker:Linker = new Linker(Context3DProgramType.VERTEX);
|
||||||
|
var positionVar:String = "aPosition";
|
||||||
|
vertexLinker.declareVariable(positionVar, VariableType.ATTRIBUTE);
|
||||||
|
|
||||||
|
var proc:Procedure = Procedure.compileFromArray([
|
||||||
|
"#v0=vCubeMapCoord",
|
||||||
|
"mov v0, i0",
|
||||||
|
"m44 o0, i0, c0"
|
||||||
|
]);
|
||||||
|
proc.assignVariableName(VariableType.CONSTANT, 0, "cProjMatrix", 4);
|
||||||
|
vertexLinker.addProcedure(proc, positionVar);
|
||||||
|
|
||||||
|
var fragmentLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
|
||||||
|
var colorProc:Procedure = Procedure.compileFromArray([
|
||||||
|
"#v0=vCubeMapCoord",
|
||||||
|
"#s0=sCubeMap",
|
||||||
|
"#c0=cDecode",
|
||||||
|
|
||||||
|
"tex t0.xy, v0, s0 <cube, linear>",
|
||||||
|
"dp3 t0.xyz, t0.xy, c0.xy",
|
||||||
|
"mov t0.w, c0.w",
|
||||||
|
"mov o0, t0"
|
||||||
|
]);
|
||||||
|
fragmentLinker.addProcedure(colorProc, "vCubeMapCoord");
|
||||||
|
fragmentLinker.varyings = vertexLinker.varyings;
|
||||||
|
return new ShaderProgram(vertexLinker, fragmentLinker);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -23,6 +23,11 @@ package alternativa.engine3d.shadows {
|
|||||||
*/
|
*/
|
||||||
public class Shadow {
|
public class Shadow {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug mode.
|
||||||
|
*/
|
||||||
|
public var debug:Boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* Key for processing in materials.
|
* Key for processing in materials.
|
||||||
|
|||||||
Reference in New Issue
Block a user