Ogre 相关老代码-- 第一部分
2010-11-08 22:38
363 查看
// CattonShading.cg
void vs_main(
in float4 pos : POSITION,
in float4 norm : NORMAL,
in float2 uv : TEXCOORD0,
uniform float4x4 worldMat,
uniform float4x4 viewProjMat,
uniform float4 eyePos,
out float4 oPos : POSITION,
out float4 oColor : COLOR0,
out float2 oUv : TEXCOORD0
)
{
float4 wPos = mul(worldMat, pos);
oPos = mul(viewProjMat, wPos);
oUv = uv;
norm = mul( worldMat, norm );
float4 dir = eyePos - wPos;
dir = normalize(dir);
float d = dot(norm, dir);
if (d > 0.66) d = 0.66;
else if (d > 0.33) d = 0.33;
else d = 0;
d += 0.2;
oColor = float4(d, d, d, 1);
}
void ps_main(
in float2 uv : TEXCOORD0,
in float4 color : COLOR0,
uniform sampler2D tex : TEXUNIT0,
out float4 oColor : COLOR0
)
{
oColor = tex2D( tex, uv ) * color;
}
//######################################################################
// CattonShading.material
vertex_program CatoonShading_vs cg
{
source CatoonShading.cg
profiles vs_3_0
entry_point vs_main
default_params
{
param_named_auto worldMat world_matrix
param_named_auto viewProjMat viewproj_matrix
param_named_auto eyePos camera_position
}
}
fragment_program CatoonShading_ps cg
{
source CatoonShading.cg
profiles ps_3_0
entry_point ps_main
default_params
{
}
}
material Ogre/Earring_Catoon
{
technique
{
pass
{
ambient 0.7 0.7 0
diffuse 0.7 0.7 0
vertex_program_ref CatoonShading_vs{}
fragment_program_ref CatoonShading_ps{}
texture_unit
{
texture spheremap.png
colour_op_ex add src_texture src_current
colour_op_multipass_fallback one one
env_map spherical
}
}
}
}
material Ogre/Skin_Catoon
{
technique
{
pass
{
ambient 0.3 0.8 0.3
vertex_program_ref CatoonShading_vs{}
fragment_program_ref CatoonShading_ps{}
texture_unit
{
texture GreenSkin.jpg
tex_address_mode mirror
}
}
}
}
material Ogre/Tusks_Catoon
{
technique
{
pass
{
ambient 0.7 0.7 0.6
vertex_program_ref CatoonShading_vs{}
fragment_program_ref CatoonShading_ps{}
texture_unit
{
texture tusk.jpg
scale 0.2 0.2
}
}
}
}
material Ogre/Eyes_Catoon
{
technique
{
pass
{
ambient 1 0.4 0.4
diffuse 1 0.7 0
emissive 0.3 0.1 0
}
}
}
//##################################################################
//ssao.material
///////////////////////////////////////////////////////////////////////////////
vertex_program Mix_AmbientOcclusion_vs cg
{
source 1_Mix_AmbientOcclusion.cg
profiles vs_2_x vp40 arbvp1
entry_point Mix_AmbientOcclusion_vs
default_params
{
param_named_auto wvpMat worldviewproj_matrix
}
}
fragment_program Mix_AmbientOcclusion_ps cg
{
source 1_Mix_AmbientOcclusion.cg
profiles ps_2_x fp40 arbfp1
entry_point Mix_AmbientOcclusion_ps
default_params
{
param_named_auto TexSize texture_size 0
}
}
///////////////////////////////////////////////////////////////////////////////
material Mix_AmbientOcclusion
{
technique
{
pass
{
//scene_blend add
ambient 0 0 0
diffuse 0 0 0
specular 0 0 0 0
emissive 0 0 0
vertex_program_ref Mix_AmbientOcclusion_vs
{
}
fragment_program_ref Mix_AmbientOcclusion_ps
{
}
texture_unit
{
texture RttTex_DfShNormal
filtering none
tex_address_mode clamp
}
texture_unit
{
texture RttTex_DfShPosition
filtering none
tex_address_mode clamp
}
texture_unit
{
texture randomnormals.png
}
}
}
}
//###############################################################
// 1_Mix_AmbientOcclusion.cg
/////////////////////////////////////////////////////////////////////////////
// Expand a range-compressed vector
float3 expand(float3 v)
{
return (v - 0.5) * 2;
}
// compress a normalized vector
float3 compress(float3 v)
{
return (v * 0.5) + 0.5 ;
}
////////////////////////////////////////////////////////////////////////////
// connector structures
struct VIn {
float4 p : POSITION;
float2 uv : TEXCOORD0;
};
struct VOut {
float4 p : POSITION;
float2 uv : TEXCOORD0;
};
/////////////////////////////////////////////////////////////////////////////
// vertex program
VOut Mix_AmbientOcclusion_vs(
VIn IN,
uniform float4x4 wvpMat
)
{
VOut OUT;
OUT.p = mul(wvpMat, IN.p);
OUT.uv.xy = IN.uv;
return OUT;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SSAO based on http://www.gamedev.net/reference/programming/features/simpleSSAO/ by José María Méndez, MIT license
float3 getPosition(sampler2D g_buffer_pos, in float2 uv)
{
return tex2D(g_buffer_pos,uv).xyz;
}
float3 getNormal(sampler2D g_buffer_norm, in float2 uv)
{
return=tex2D(g_buffer_norm, uv).xyz ;
}
float doAmbientOcclusion(sampler2D g_buffer_pos, float2 tcoord,in float2 uv, in float3 p, in float3 cnorm)
{
float g_intensity=128;
float g_scale=1.0;
float g_bias=0.0;
float3 diff = getPosition(g_buffer_pos, tcoord + uv) - p;
const float3 v = normalize(diff);
const float d = length(diff)*g_scale;
return max(0.0,dot(cnorm,v)-g_bias)*(1.0/(1.0+d))*g_intensity;
}
void Mix_AmbientOcclusion_ps( VOut IN,
uniform float4 TexSize,
out float4 colour : COLOR,
uniform sampler2D Tex_Norm : TEXUNIT0,
uniform sampler2D Tex_Pos : TEXUNIT1,
uniform sampler2D Tex_Rand : TEXUNIT2
)
{
const float2 vec[4] = {
float2(1,0),
float2(-1,0),
float2(0,1),
float2(0,-1)
};
float4 Pos= tex2D(Tex_Pos, IN.uv);
float3 p = Pos.xyz;
float3 n = getNormal(Tex_Norm, IN.uv);
float2 rand = normalize(tex2D(Tex_Rand, TexSize * IN.uv / 64.0).xy * 2.0f - 1.0f) ;
float ao = 0.0f;
float g_sample_rad=32.0 ;
float rad = g_sample_rad/p.z;
int iterations = 4;
for (int j = 0; j < iterations; ++j)
{
float2 coord1 = reflect(vec[j],rand)*rad;
float2 coord2 = float2(coord1.x*0.707 - coord1.y*0.707, coord1.x*0.707 + coord1.y*0.707);
ao += doAmbientOcclusion(Tex_Pos, IN.uv,coord1*0.25, p, n);
ao += doAmbientOcclusion(Tex_Pos, IN.uv,coord2*0.5, p, n);
ao += doAmbientOcclusion(Tex_Pos, IN.uv,coord1*0.75, p, n);
ao += doAmbientOcclusion(Tex_Pos, IN.uv,coord2, p, n);
}
ao/=(float)iterations*4.0;
ao=1-ao ;
//Do stuff here with your occlusion value “ao”: modulate ambient lighting, write it to a buffer for later //use, etc.
colour=float4(ao,ao,ao, 1) ;
}
//#######################################################################
// WARNING: modified by Jacob 'jacmoe' Moen
// Ported to Ogre3D
/* * * * * * * * * * * * * Author's note * * * * * * * * * * * */
* _ _ _ _ _ _ _ _ _ _ _ _ *
* |_| |_| |_| |_| |_|_ _|_| |_| |_| _|_|_|_|_| *
* |_|_ _ _|_| |_| |_| |_|_|_|_|_| |_| |_| |_|_ _ _ *
* |_|_|_|_|_| |_| |_| |_| |_| |_| |_| |_| |_|_|_|_ *
* |_| |_| |_|_ _ _|_| |_| |_| |_|_ _ _|_| _ _ _ _|_| *
* |_| |_| |_|_|_| |_| |_| |_|_|_| |_|_|_|_| *
* *
* http://www.humus.name *
* *
* This file is a part of the work done by Humus. You are free to *
* use the code in any way you like, modified, unmodified or copied *
* into your own work. However, I expect you to respect these points: *
* - If you use this file and its contents unmodified, or use a major *
* part of this file, please credit the author and leave this note. *
* - For use in anything commercial, please request my approval. *
* - Share your work and ideas too as much as you can. *
* *
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef _BSP_H_
#define _BSP_H_
#include "Ogre.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>
#include <stddef.h>
#if _MSC_VER >= 1400
// To make MSVC 2005 happy
#pragma warning (disable: 4996)
# define assume(x) __assume(x)
# define no_alias __declspec(noalias)
#else
# define assume(x)
# define no_alias
#endif
// Define some sized types
typedef unsigned char uint8;
typedef signed char int8;
typedef unsigned short uint16;
typedef signed short int16;
typedef unsigned int uint32;
typedef signed int int32;
#ifdef _WIN32
typedef signed __int64 int64;
typedef unsigned __int64 uint64;
#else
typedef signed long long int64;
typedef unsigned long long uint64;
#endif
typedef unsigned char ubyte;
typedef unsigned short ushort;
typedef unsigned int uint;
template <class TYPE>
class Array {
public:
Array(){
count = capacity = 0;
list = NULL;
}
Array(const unsigned int iCapasity){
count = 0;
capacity = iCapasity;
list = (TYPE *) malloc(capacity * sizeof(TYPE));
}
~Array(){
free(list);
}
TYPE *getArray() const { return list; }
TYPE *abandonArray(){
TYPE *rList = list;
list = NULL;
return rList;
}
TYPE &operator [] (const unsigned int index) const { return list[index]; }
unsigned int getCount() const { return count; }
void setCount(const unsigned int newCount){
capacity = count = newCount;
list = (TYPE *) realloc(list, capacity * sizeof(TYPE));
}
unsigned int add(const TYPE object){
if (count >= capacity){
if (capacity) capacity += capacity; else capacity = 8;
list = (TYPE *) realloc(list, capacity * sizeof(TYPE));
}
list[count] = object;
return count++;
}
void fastRemove(const unsigned int index){
if (index < count){
count--;
list[index] = list[count];
}
}
void orderedRemove(const unsigned int index){
if (index < count){
count--;
memmove(list + index, list + index + 1, (count - index) * sizeof(TYPE));
}
}
void clear(){
count = 0;
}
void reset(){
free(list);
list = NULL;
count = capacity = 0;
}
private:
int partition(int (*compare)(const TYPE &elem0, const TYPE &elem1), int p, int r){
TYPE tmp, pivot = list[p];
int left = p;
for (int i = p + 1; i <= r; i++){
if (compare(list[i], pivot) < 0){
left++;
tmp = list[i];
list[i] = list[left];
list[left] = tmp;
}
}
tmp = list[p];
list[p] = list[left];
list[left] = tmp;
return left;
}
void quickSort(int (*compare)(const TYPE &elem0, const TYPE &elem1), int p, int r){
if (p < r){
int q = partition(compare, p, r);
quickSort(compare, p, q - 1);
quickSort(compare, q + 1, r);
}
}
public:
void sort(int (*compare)(const TYPE &elem0, const TYPE &elem1)){
quickSort(compare, 0, count - 1);
}
protected:
unsigned int capacity;
unsigned int count;
TYPE *list;
};
struct BTri {
void split(BTri *dest, int &nPos, int &nNeg, const Ogre::Vector4 &plane, const float epsilon) const;
void finalize();
bool intersects(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1) const;
bool isAbove(const Ogre::Vector3 &pos) const;
float getDistance(const Ogre::Vector3 &pos) const;
Ogre::Vector4 plane;
Ogre::Vector4 edgePlanes[3];
Ogre::Vector3 v[3];
/*
Ogre::Vector3 edgeNormals[3];
float edgeOffsets[3];
Ogre::Vector3 normal;
float offset;
*/
void *data;
};
struct BNode {
~BNode();
bool intersects(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector3 &dir, Ogre::Vector3 *point, const BTri **triangle) const;
BTri *intersectsCached(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector3 &dir) const;
bool pushSphere(Ogre::Vector3 &pos, const float radius) const;
void getDistance(const Ogre::Vector3 &pos, float &minDist) const;
void build(Array <BTri> &tris, const int splitCost, const int balCost, const float epsilon);
//void build(Array <BTri> &tris);
void read(FILE *file);
void write(FILE *file) const;
BNode *back;
BNode *front;
BTri tri;
};
class BSP {
public:
BSP(){
top = NULL;
cache = NULL;
}
~BSP(){
delete top;
}
void addTriangle(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector3 &v2, void *data = NULL);
void build(const int splitCost = 3, const int balCost = 1, const float epsilon = 0.001f);
bool intersects(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, Ogre::Vector3 *point = NULL, const BTri **triangle = NULL) const;
bool intersectsCached(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1);
bool pushSphere(Ogre::Vector3 &pos, const float radius) const;
float getDistance(const Ogre::Vector3 &pos) const;
bool isInOpenSpace(const Ogre::Vector3 &pos) const;
bool loadFile(const char *fileName);
bool saveFile(const char *fileName) const;
protected:
Array <BTri> tris;
BNode *top;
BTri *cache;
};
#endif // _BSP_H_
//###########################################################################
// WARNING: modified by Jacob 'jacmoe' Moen
// Ported to Ogre3D
/* * * * * * * * * * * * * Author's note * * * * * * * * * * * */
* _ _ _ _ _ _ _ _ _ _ _ _ *
* |_| |_| |_| |_| |_|_ _|_| |_| |_| _|_|_|_|_| *
* |_|_ _ _|_| |_| |_| |_|_|_|_|_| |_| |_| |_|_ _ _ *
* |_|_|_|_|_| |_| |_| |_| |_| |_| |_| |_| |_|_|_|_ *
* |_| |_| |_|_ _ _|_| |_| |_| |_|_ _ _|_| _ _ _ _|_| *
* |_| |_| |_|_|_| |_| |_| |_|_|_| |_|_|_|_| *
* *
* http://www.humus.name *
* *
* This file is a part of the work done by Humus. You are free to *
* use the code in any way you like, modified, unmodified or copied *
* into your own work. However, I expect you to respect these points: *
* - If you use this file and its contents unmodified, or use a major *
* part of this file, please credit the author and leave this note. *
* - For use in anything commercial, please request my approval. *
* - Share your work and ideas too as much as you can. *
* *
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "BSP.h"
#ifdef _WIN32
#pragma warning(push, 1)
#pragma warning(disable: 4799)
#endif
float planeDistance(const Ogre::Vector3 &normal, const float offset, const Ogre::Vector3 &point){
return point.x * normal.x + point.y * normal.y + point.z * normal.z + offset;
}
float planeDistance(const Ogre::Vector4 &plane, const Ogre::Vector3 &point){
return point.x * plane.x + point.y * plane.y + point.z * plane.z + plane.w;
}
float dot(const Ogre::Vector3 &u, const Ogre::Vector3 &v){
return u.x * v.x + u.y * v.y + u.z * v.z;
}
float dot(const Ogre::Vector4 &u, const Ogre::Vector4 &v){
return u.x * v.x + u.y * v.y + u.z * v.z + u.w * v.w;
}
//# define no_alias
no_alias Ogre::Vector3 planeHit(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector4 &plane){
Ogre::Vector3 dir = v1 - v0;
float d = planeDistance(plane, v0);
Ogre::Vector3 pos = v0 - (d / dot((Ogre::Vector3 &) plane, dir)) * dir;
return pos;
}
void BTri::split(BTri *dest, int &nPos, int &nNeg, const Ogre::Vector4 &plane, const float epsilon) const {
float d[3];
for (int i = 0; i < 3; i++){
d[i] = planeDistance(plane, v[i]);
}
int first = 2;
int second = 0;
while (!(d[second] > epsilon && d[first] <= epsilon)){
first = second;
second++;
}
// Positive triangles
nPos = 0;
Ogre::Vector3 h = planeHit(v[first], v[second], plane);
do {
first = second;
second++;
if (second >= 3) second = 0;
dest->v[0] = h;
dest->v[1] = v[first];
if (d[second] > epsilon){
dest->v[2] = v[second];
} else {
dest->v[2] = h = planeHit(v[first], v[second], plane);
}
dest->data = data;
dest->finalize();
dest++;
nPos++;
} while (d[second] > epsilon);
// Skip zero area triangle
if (fabsf(d[second]) <= epsilon){
first = second;
second++;
if (second >= 3) second = 0;
}
// Negative triangles
nNeg = 0;
do {
first = second;
second++;
if (second >= 3) second = 0;
dest->v[0] = h;
dest->v[1] = v[first];
if (d[second] < -epsilon){
dest->v[2] = v[second];
} else {
dest->v[2] = planeHit(v[first], v[second], plane);
}
dest->data = data;
dest->finalize();
dest++;
nNeg++;
} while (d[second] < -epsilon);
}
Ogre::Vector3 normalize(const Ogre::Vector3 &v){
float invLen = 1.0f / sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
return v * invLen;
}
Ogre::Vector4 normalize(const Ogre::Vector4 &v){
float invLen = 1.0f / sqrtf(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
return v * invLen;
}
Ogre::Vector3 cross(const Ogre::Vector3 &u, const Ogre::Vector3 &v){
return Ogre::Vector3(u.y * v.z - v.y * u.z, u.z * v.x - u.x * v.z, u.x * v.y - u.y * v.x);
}
void BTri::finalize(){
Ogre::Vector3 normal = normalize(cross(v[1] - v[0], v[2] - v[0]));
float offset = -dot(v[0], normal);
Ogre::Vector3 edgeNormals[3];
edgeNormals[0] = cross(normal, v[0] - v[2]);
edgeNormals[1] = cross(normal, v[1] - v[0]);
edgeNormals[2] = cross(normal, v[2] - v[1]);
float edgeOffsets[3];
edgeOffsets[0] = dot(edgeNormals[0], v[0]);
edgeOffsets[1] = dot(edgeNormals[1], v[1]);
edgeOffsets[2] = dot(edgeNormals[2], v[2]);
plane = Ogre::Vector4(normal.x, normal.y, normal.z, offset);
edgePlanes[0] = Ogre::Vector4(edgeNormals[0].x, edgeNormals[0].y, edgeNormals[0].z, -edgeOffsets[0]);
edgePlanes[1] = Ogre::Vector4(edgeNormals[1].x, edgeNormals[1].y, edgeNormals[1].z, -edgeOffsets[1]);
edgePlanes[2] = Ogre::Vector4(edgeNormals[2].x, edgeNormals[2].y, edgeNormals[2].z, -edgeOffsets[2]);
}
no_alias bool BTri::intersects(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1) const {
Ogre::Vector3 dir = v0 - v1;
// float k = (dot(normal, v0) + offset) / dot(normal, dir);
float k = planeDistance(plane, v0) / dot(Ogre::Vector3(plane.x, plane.y, plane.z), dir);
if (k < 0 || k > 1) return false;
Ogre::Vector3 pos = v0 - k * dir;
for (unsigned int i = 0; i < 3; i++){
if (planeDistance(edgePlanes[i], pos) < 0){
// if (dot(edgeNormals[i], pos) < edgeOffsets[i]){
return false;
}
}
return true;
}
no_alias bool BTri::isAbove(const Ogre::Vector3 &pos) const {
/*
return (edgeNormals[0].x * pos.x + edgeNormals[0].y * pos.y + edgeNormals[0].z * pos.z >= edgeOffsets[0] &&
edgeNormals[1].x * pos.x + edgeNormals[1].y * pos.y + edgeNormals[1].z * pos.z >= edgeOffsets[1] &&
edgeNormals[2].x * pos.x + edgeNormals[2].y * pos.y + edgeNormals[2].z * pos.z >= edgeOffsets[2]);
*/
/*
return (edgePlanes[0].x * pos.x + edgePlanes[0].y * pos.y + edgePlanes[0].z * pos.z >= -edgePlanes[0].w &&
edgePlanes[1].x * pos.x + edgePlanes[1].y * pos.y + edgePlanes[1].z * pos.z >= -edgePlanes[1].w &&
edgePlanes[2].x * pos.x + edgePlanes[2].y * pos.y + edgePlanes[2].z * pos.z >= -edgePlanes[2].w);
*/
return (planeDistance(edgePlanes[0], pos) >= 0 && planeDistance(edgePlanes[1], pos) >= 0 && planeDistance(edgePlanes[2], pos) >= 0);
}
no_alias float BTri::getDistance(const Ogre::Vector3 &pos) const {
int k = 2;
for (int i = 0; i < 3; i++){
float d = planeDistance(edgePlanes[i], pos);
if (d < 0){
// Project onto the line between the points
Ogre::Vector3 dir = v[i] - v[k];
float c = dot(dir, pos - v[k]) / dot(dir, dir);
Ogre::Vector3 d;
if (c >= 1){
d = v[i];
} else {
d = v[k];
if (c > 0) d += c * dir;
}
return Ogre::Vector3(pos - d).length();
}
k = i;
}
return fabsf(planeDistance(plane, pos));
}
#ifdef USE_SIMD
bool BTri::isAbove3DNow(v2sf v0XY, v2sf v0Z1) const {
for (int i = 0; i < 3; i++){
v2sf planeXY = ((v2sf *) &edgePlanes[i])[0];
v2sf planeZD = ((v2sf *) &edgePlanes[i])[1];
v2sf dotXY = pfmul(planeXY, v0XY);
v2sf dotZD = pfmul(planeZD, v0Z1);
v2sf dot = pfacc(dotXY, dotZD);
dot = pfacc(dot, dot);
int d = _m_to_int(dot);
if (d < 0) return false;
}
return true;
}
#endif
BNode::~BNode(){
delete back;
delete front;
}
no_alias bool BNode::intersects(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1,
const Ogre::Vector3 &dir, Ogre::Vector3 *point, const BTri **triangle) const {
#if 0
float d0 = planeDistance(tri.plane, v0);
float d1 = planeDistance(tri.plane, v1);
vec3 pos;
if (d0 > 0){
if (d1 <= 0){
pos = v0 - (d0 / dot(tri.plane.xyz(), dir)) * dir;
}
if (front != NULL && front->intersects(v0, (d1 <= 0)? pos : v1, dir, point, triangle)) return true;
if (d1 <= 0){
if (tri.isAbove(pos)){
if (point) *point = pos;
if (triangle) *triangle = &tri;
return true;
}
if (back != NULL && back->intersects(pos, v1, dir, point, triangle)) return true;
}
} else {
if (d1 > 0){
pos = v0 - (d0 / dot(tri.plane.xyz(), dir)) * dir;
}
if (back != NULL && back->intersects(v0, (d1 > 0)? pos : v1, dir, point, triangle)) return true;
if (d1 > 0){
if (tri.isAbove(pos)){
if (point) *point = pos;
if (triangle) *triangle = &tri;
return true;
}
if (front != NULL && front->intersects(pos, v1, dir, point, triangle)) return true;
}
}
#else
float d = planeDistance(tri.plane, v0);
if (d > 0){
if (front != NULL && front->intersects(v0, v1, dir, point, triangle)) return true;
if (planeDistance(tri.plane, v1) < 0){
Ogre::Vector3 pos = v0 - (d / dot(Ogre::Vector3(tri.plane.x,tri.plane.y,tri.plane.z), dir)) * dir;
if (tri.isAbove(pos)){
if (point) *point = pos;
if (triangle) *triangle = &tri;
return true;
}
if (back != NULL && back->intersects(v0, v1, dir, point, triangle)) return true;
}
} else {
if (back != NULL && back->intersects(v0, v1, dir, point, triangle)) return true;
if (planeDistance(tri.plane, v1) > 0){
Ogre::Vector3 pos = v0 - (d / dot(Ogre::Vector3(tri.plane.x,tri.plane.y,tri.plane.z), dir)) * dir;
if (tri.isAbove(pos)){
if (point) *point = pos;
if (triangle) *triangle = &tri;
return true;
}
if (front != NULL && front->intersects(v0, v1, dir, point, triangle)) return true;
}
}
#endif
return false;
}
no_alias BTri *BNode::intersectsCached(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector3 &dir) const {
#if 0
float d0 = planeDistance(tri.plane, v0);
float d1 = planeDistance(tri.plane, v1);
vec3 pos;
if (d0 > 0){
if (d1 <= 0){
pos = v0 - (d0 / dot((vec3 &) tri.plane, dir)) * dir;
}
if (front != NULL){
BTri *tri;
if (d1 <= 0){
tri = front->intersectsCached(v0, pos, dir);
} else {
tri = front->intersectsCached(v0, v1, dir);
}
if (tri) return tri;
}
if (d1 <= 0){
if (tri.isAbove(pos)) return (BTri *) &tri;
if (back != NULL){
BTri *tri = back->intersectsCached(pos, v1, dir);
if (tri) return tri;
}
}
} else {
if (d1 > 0){
pos = v0 - (d0 / dot((vec3 &) tri.plane, dir)) * dir;
}
if (back != NULL){
BTri *tri;
if (d1 > 0){
tri = back->intersectsCached(v0, pos, dir);
} else {
tri = back->intersectsCached(v0, v1, dir);
}
if (tri) return tri;
}
if (d1 > 0){
if (tri.isAbove(pos)) return (BTri *) &tri;
if (front != NULL){
BTri *tri = front->intersectsCached(pos, v1, dir);
if (tri) return tri;
}
}
}
#else
float d = planeDistance(tri.plane, v0);
if (d > 0){
if (front != NULL){
BTri *tri = front->intersectsCached(v0, v1, dir);
if (tri) return tri;
}
if (planeDistance(tri.plane, v1) < 0){
Ogre::Vector3 pos = v0 - (d / dot(Ogre::Vector3(tri.plane.x,tri.plane.y,tri.plane.z), dir)) * dir;
if (tri.isAbove(pos)) return (BTri *) &tri;
if (back != NULL){
BTri *tri = back->intersectsCached(v0, v1, dir);
if (tri) return tri;
}
}
} else {
if (back != NULL){
BTri *tri = back->intersectsCached(v0, v1, dir);
if (tri) return tri;
}
if (planeDistance(tri.plane, v1) > 0){
Ogre::Vector3 pos = v0 - (d / dot(Ogre::Vector3(tri.plane.x,tri.plane.y,tri.plane.z), dir)) * dir;
if (tri.isAbove(pos)) return (BTri *) &tri;
if (front != NULL){
BTri *tri = front->intersectsCached(v0, v1, dir);
if (tri) return tri;
}
}
}
#endif
return NULL;
}
no_alias bool BNode::pushSphere(Ogre::Vector3 &pos, const float radius) const {
float d = planeDistance(tri.plane, pos);
bool pushed = false;
if (fabsf(d) < radius){
if (tri.isAbove(pos)){
// pos += (radius - d) * tri.normal;
pos += (radius - d) * Ogre::Vector3(tri.plane.x,tri.plane.y,tri.plane.z);
pushed = true;
}
}
if (front != NULL && d > -radius) pushed |= front->pushSphere(pos, radius);
if (back != NULL && d < radius) pushed |= back ->pushSphere(pos, radius);
return pushed;
}
no_alias void BNode::getDistance(const Ogre::Vector3 &pos, float &minDist) const {
float d = planeDistance(tri.plane, pos);
float dist = tri.getDistance(pos);
if (dist < minDist){
minDist = dist;
}
if (back && d < minDist){
back->getDistance(pos, minDist);
}
if (front && -d < minDist){
front->getDistance(pos, minDist);
}
}
void BNode::read(FILE *file){
fread(&tri.v, sizeof(tri.v), 1, file);
tri.finalize();
int flags = 0;
fread(&flags, sizeof(int), 1, file);
if (flags & 1){
back = new BNode;
back->read(file);
} else back = NULL;
if (flags & 2){
front = new BNode;
front->read(file);
} else front = NULL;
}
void BNode::write(FILE *file) const {
fwrite(&tri.v, sizeof(tri.v), 1, file);
int flags = 0;
if (back) flags |= 1;
if (front) flags |= 2;
fwrite(&flags, sizeof(int), 1, file);
if (back) back->write(file);
if (front) front->write(file);
}
/*
void BNode::build(Array <BTri> &tris){
uint index = 0;
int minScore = 0x7FFFFFFF;
for (uint i = 0; i < tris.getCount(); i++){
int score = 0;
int diff = 0;
for (uint k = 0; k < tris.getCount(); k++){
uint neg = 0, pos = 0;
for (uint j = 0; j < 3; j++){
// float dist = dot(tris[k].v[j], tris[i].normal) + tris[i].offset;
float dist = planeDistance(tris[i].plane, tris[k].v[j]);
if (dist < 0) neg++; else pos++;
}
if (pos){
if (neg) score += 3; else diff++;
} else diff--;
}
score += abs(diff);
if (score < minScore){
minScore = score;
index = i;
}
}
tri = tris[index];
tris.fastRemove(index);
Array <BTri> backTris;
Array <BTri> frontTris;
for (uint i = 0; i < tris.getCount(); i++){
uint neg = 0, pos = 0;
for (uint j = 0; j < 3; j++){
// float dist = dot(tris[i].v[j], tri.normal) + tri.offset;
float dist = planeDistance(tri.plane, tris[i].v[j]);
if (dist < 0) neg++; else pos++;
}
if (neg) backTris.add(tris[i]);
if (pos) frontTris.add(tris[i]);
}
//tris.clear();
if (backTris.getCount() > 0){
back = new BNode;
back->build(backTris);
} else back = NULL;
if (frontTris.getCount() > 0){
front = new BNode;
front->build(frontTris);
} else front = NULL;
}
*/
void BNode::build(Array <BTri> &tris, const int splitCost, const int balCost, const float epsilon){
uint index = 0;
int minScore = 0x7FFFFFFF;
for (uint i = 0; i < tris.getCount(); i++){
int score = 0;
int diff = 0;
for (uint k = 0; k < tris.getCount(); k++){
uint neg = 0, pos = 0;
for (uint j = 0; j < 3; j++){
float dist = planeDistance(tris[i].plane, tris[k].v[j]);
if (dist < -epsilon) neg++; else
if (dist > epsilon) pos++;
}
if (pos){
if (neg) score += splitCost; else diff++;
} else {
if (neg) diff--; else diff++;
}
}
score += balCost * abs(diff);
if (score < minScore){
minScore = score;
index = i;
}
}
tri = tris[index];
tris.fastRemove(index);
Array <BTri> backTris;
Array <BTri> frontTris;
for (uint i = 0; i < tris.getCount(); i++){
uint neg = 0, pos = 0;
for (uint j = 0; j < 3; j++){
float dist = planeDistance(tri.plane, tris[i].v[j]);
if (dist < -epsilon) neg++; else
if (dist > epsilon) pos++;
}
if (neg){
if (pos){
BTri newTris[3];
int nPos, nNeg;
tris[i].split(newTris, nPos, nNeg, tri.plane, epsilon);
for (int i = 0; i < nPos; i++){
frontTris.add(newTris[i]);
}
for (int i = 0; i < nNeg; i++){
backTris.add(newTris[nPos + i]);
}
} else {
backTris.add(tris[i]);
}
} else {
frontTris.add(tris[i]);
}
}
tris.reset();
if (backTris.getCount() > 0){
back = new BNode;
back->build(backTris, splitCost, balCost, epsilon);
} else back = NULL;
if (frontTris.getCount() > 0){
front = new BNode;
front->build(frontTris, splitCost, balCost, epsilon);
} else front = NULL;
}
void BSP::addTriangle(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector3 &v2, void *data){
BTri tri;
tri.v[0] = v0;
tri.v[1] = v1;
tri.v[2] = v2;
tri.data = data;
tri.finalize();
tris.add(tri);
}
void BSP::build(const int splitCost, const int balCost, const float epsilon){
// int nTris = tris.getCount();
top = new BNode;
// top->build(tris);
top->build(tris, splitCost, balCost, epsilon);
/*
SSENode *mem = new SSENode[nTris * 4];
sseTop = (SSENode *) ((intptr(mem) + 15) & ~intptr(0xF));
sseDest = sseTop + 1;
sseTop->build(top, sseDest);
sseDest = mem;
*/
}
no_alias bool BSP::intersects(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1,
Ogre::Vector3 *point, const BTri **triangle) const {
if (top != NULL) return top->intersects(v0, v1, v1 - v0, point, triangle);
return false;
}
bool BSP::intersectsCached(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1){
if (top != NULL){
if (cache){
if (cache->intersects(v0, v1)) return true;
}
cache = top->intersectsCached(v0, v1, v1 - v0);
return (cache != NULL);
}
return false;
}
bool BSP::pushSphere(Ogre::Vector3 &pos, const float radius) const {
if (top != NULL) return top->pushSphere(pos, radius);
return false;
}
no_alias float BSP::getDistance(const Ogre::Vector3 &pos) const {
float dist = FLT_MAX;
if (top != NULL) top->getDistance(pos, dist);
return dist;
}
no_alias bool BSP::isInOpenSpace(const Ogre::Vector3 &pos) const {
if (top != NULL){
BNode *node = top;
while (true){
float d = planeDistance(node->tri.plane, pos);
if (d > 0){
if (node->front){
node = node->front;
} else return true;
} else {
if (node->back){
node = node->back;
} else return false;
}
}
}
return false;
}
bool BSP::loadFile(const char *fileName){
FILE *file = fopen(fileName, "rb");
if (file == NULL) return false;
delete top;
top = new BNode;
top->read(file);
fclose(file);
return true;
}
bool BSP::saveFile(const char *fileName) const {
if (top == NULL) return false;
FILE *file = fopen(fileName, "wb");
if (file == NULL) return false;
top->write(file);
fclose(file);
return true;
}
#ifdef _WIN32
#pragma warning(pop)
#endif
void vs_main(
in float4 pos : POSITION,
in float4 norm : NORMAL,
in float2 uv : TEXCOORD0,
uniform float4x4 worldMat,
uniform float4x4 viewProjMat,
uniform float4 eyePos,
out float4 oPos : POSITION,
out float4 oColor : COLOR0,
out float2 oUv : TEXCOORD0
)
{
float4 wPos = mul(worldMat, pos);
oPos = mul(viewProjMat, wPos);
oUv = uv;
norm = mul( worldMat, norm );
float4 dir = eyePos - wPos;
dir = normalize(dir);
float d = dot(norm, dir);
if (d > 0.66) d = 0.66;
else if (d > 0.33) d = 0.33;
else d = 0;
d += 0.2;
oColor = float4(d, d, d, 1);
}
void ps_main(
in float2 uv : TEXCOORD0,
in float4 color : COLOR0,
uniform sampler2D tex : TEXUNIT0,
out float4 oColor : COLOR0
)
{
oColor = tex2D( tex, uv ) * color;
}
//######################################################################
// CattonShading.material
vertex_program CatoonShading_vs cg
{
source CatoonShading.cg
profiles vs_3_0
entry_point vs_main
default_params
{
param_named_auto worldMat world_matrix
param_named_auto viewProjMat viewproj_matrix
param_named_auto eyePos camera_position
}
}
fragment_program CatoonShading_ps cg
{
source CatoonShading.cg
profiles ps_3_0
entry_point ps_main
default_params
{
}
}
material Ogre/Earring_Catoon
{
technique
{
pass
{
ambient 0.7 0.7 0
diffuse 0.7 0.7 0
vertex_program_ref CatoonShading_vs{}
fragment_program_ref CatoonShading_ps{}
texture_unit
{
texture spheremap.png
colour_op_ex add src_texture src_current
colour_op_multipass_fallback one one
env_map spherical
}
}
}
}
material Ogre/Skin_Catoon
{
technique
{
pass
{
ambient 0.3 0.8 0.3
vertex_program_ref CatoonShading_vs{}
fragment_program_ref CatoonShading_ps{}
texture_unit
{
texture GreenSkin.jpg
tex_address_mode mirror
}
}
}
}
material Ogre/Tusks_Catoon
{
technique
{
pass
{
ambient 0.7 0.7 0.6
vertex_program_ref CatoonShading_vs{}
fragment_program_ref CatoonShading_ps{}
texture_unit
{
texture tusk.jpg
scale 0.2 0.2
}
}
}
}
material Ogre/Eyes_Catoon
{
technique
{
pass
{
ambient 1 0.4 0.4
diffuse 1 0.7 0
emissive 0.3 0.1 0
}
}
}
//##################################################################
//ssao.material
///////////////////////////////////////////////////////////////////////////////
vertex_program Mix_AmbientOcclusion_vs cg
{
source 1_Mix_AmbientOcclusion.cg
profiles vs_2_x vp40 arbvp1
entry_point Mix_AmbientOcclusion_vs
default_params
{
param_named_auto wvpMat worldviewproj_matrix
}
}
fragment_program Mix_AmbientOcclusion_ps cg
{
source 1_Mix_AmbientOcclusion.cg
profiles ps_2_x fp40 arbfp1
entry_point Mix_AmbientOcclusion_ps
default_params
{
param_named_auto TexSize texture_size 0
}
}
///////////////////////////////////////////////////////////////////////////////
material Mix_AmbientOcclusion
{
technique
{
pass
{
//scene_blend add
ambient 0 0 0
diffuse 0 0 0
specular 0 0 0 0
emissive 0 0 0
vertex_program_ref Mix_AmbientOcclusion_vs
{
}
fragment_program_ref Mix_AmbientOcclusion_ps
{
}
texture_unit
{
texture RttTex_DfShNormal
filtering none
tex_address_mode clamp
}
texture_unit
{
texture RttTex_DfShPosition
filtering none
tex_address_mode clamp
}
texture_unit
{
texture randomnormals.png
}
}
}
}
//###############################################################
// 1_Mix_AmbientOcclusion.cg
/////////////////////////////////////////////////////////////////////////////
// Expand a range-compressed vector
float3 expand(float3 v)
{
return (v - 0.5) * 2;
}
// compress a normalized vector
float3 compress(float3 v)
{
return (v * 0.5) + 0.5 ;
}
////////////////////////////////////////////////////////////////////////////
// connector structures
struct VIn {
float4 p : POSITION;
float2 uv : TEXCOORD0;
};
struct VOut {
float4 p : POSITION;
float2 uv : TEXCOORD0;
};
/////////////////////////////////////////////////////////////////////////////
// vertex program
VOut Mix_AmbientOcclusion_vs(
VIn IN,
uniform float4x4 wvpMat
)
{
VOut OUT;
OUT.p = mul(wvpMat, IN.p);
OUT.uv.xy = IN.uv;
return OUT;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SSAO based on http://www.gamedev.net/reference/programming/features/simpleSSAO/ by José María Méndez, MIT license
float3 getPosition(sampler2D g_buffer_pos, in float2 uv)
{
return tex2D(g_buffer_pos,uv).xyz;
}
float3 getNormal(sampler2D g_buffer_norm, in float2 uv)
{
return=tex2D(g_buffer_norm, uv).xyz ;
}
float doAmbientOcclusion(sampler2D g_buffer_pos, float2 tcoord,in float2 uv, in float3 p, in float3 cnorm)
{
float g_intensity=128;
float g_scale=1.0;
float g_bias=0.0;
float3 diff = getPosition(g_buffer_pos, tcoord + uv) - p;
const float3 v = normalize(diff);
const float d = length(diff)*g_scale;
return max(0.0,dot(cnorm,v)-g_bias)*(1.0/(1.0+d))*g_intensity;
}
void Mix_AmbientOcclusion_ps( VOut IN,
uniform float4 TexSize,
out float4 colour : COLOR,
uniform sampler2D Tex_Norm : TEXUNIT0,
uniform sampler2D Tex_Pos : TEXUNIT1,
uniform sampler2D Tex_Rand : TEXUNIT2
)
{
const float2 vec[4] = {
float2(1,0),
float2(-1,0),
float2(0,1),
float2(0,-1)
};
float4 Pos= tex2D(Tex_Pos, IN.uv);
float3 p = Pos.xyz;
float3 n = getNormal(Tex_Norm, IN.uv);
float2 rand = normalize(tex2D(Tex_Rand, TexSize * IN.uv / 64.0).xy * 2.0f - 1.0f) ;
float ao = 0.0f;
float g_sample_rad=32.0 ;
float rad = g_sample_rad/p.z;
int iterations = 4;
for (int j = 0; j < iterations; ++j)
{
float2 coord1 = reflect(vec[j],rand)*rad;
float2 coord2 = float2(coord1.x*0.707 - coord1.y*0.707, coord1.x*0.707 + coord1.y*0.707);
ao += doAmbientOcclusion(Tex_Pos, IN.uv,coord1*0.25, p, n);
ao += doAmbientOcclusion(Tex_Pos, IN.uv,coord2*0.5, p, n);
ao += doAmbientOcclusion(Tex_Pos, IN.uv,coord1*0.75, p, n);
ao += doAmbientOcclusion(Tex_Pos, IN.uv,coord2, p, n);
}
ao/=(float)iterations*4.0;
ao=1-ao ;
//Do stuff here with your occlusion value “ao”: modulate ambient lighting, write it to a buffer for later //use, etc.
colour=float4(ao,ao,ao, 1) ;
}
//#######################################################################
// WARNING: modified by Jacob 'jacmoe' Moen
// Ported to Ogre3D
/* * * * * * * * * * * * * Author's note * * * * * * * * * * * */
* _ _ _ _ _ _ _ _ _ _ _ _ *
* |_| |_| |_| |_| |_|_ _|_| |_| |_| _|_|_|_|_| *
* |_|_ _ _|_| |_| |_| |_|_|_|_|_| |_| |_| |_|_ _ _ *
* |_|_|_|_|_| |_| |_| |_| |_| |_| |_| |_| |_|_|_|_ *
* |_| |_| |_|_ _ _|_| |_| |_| |_|_ _ _|_| _ _ _ _|_| *
* |_| |_| |_|_|_| |_| |_| |_|_|_| |_|_|_|_| *
* *
* http://www.humus.name *
* *
* This file is a part of the work done by Humus. You are free to *
* use the code in any way you like, modified, unmodified or copied *
* into your own work. However, I expect you to respect these points: *
* - If you use this file and its contents unmodified, or use a major *
* part of this file, please credit the author and leave this note. *
* - For use in anything commercial, please request my approval. *
* - Share your work and ideas too as much as you can. *
* *
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef _BSP_H_
#define _BSP_H_
#include "Ogre.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>
#include <stddef.h>
#if _MSC_VER >= 1400
// To make MSVC 2005 happy
#pragma warning (disable: 4996)
# define assume(x) __assume(x)
# define no_alias __declspec(noalias)
#else
# define assume(x)
# define no_alias
#endif
// Define some sized types
typedef unsigned char uint8;
typedef signed char int8;
typedef unsigned short uint16;
typedef signed short int16;
typedef unsigned int uint32;
typedef signed int int32;
#ifdef _WIN32
typedef signed __int64 int64;
typedef unsigned __int64 uint64;
#else
typedef signed long long int64;
typedef unsigned long long uint64;
#endif
typedef unsigned char ubyte;
typedef unsigned short ushort;
typedef unsigned int uint;
template <class TYPE>
class Array {
public:
Array(){
count = capacity = 0;
list = NULL;
}
Array(const unsigned int iCapasity){
count = 0;
capacity = iCapasity;
list = (TYPE *) malloc(capacity * sizeof(TYPE));
}
~Array(){
free(list);
}
TYPE *getArray() const { return list; }
TYPE *abandonArray(){
TYPE *rList = list;
list = NULL;
return rList;
}
TYPE &operator [] (const unsigned int index) const { return list[index]; }
unsigned int getCount() const { return count; }
void setCount(const unsigned int newCount){
capacity = count = newCount;
list = (TYPE *) realloc(list, capacity * sizeof(TYPE));
}
unsigned int add(const TYPE object){
if (count >= capacity){
if (capacity) capacity += capacity; else capacity = 8;
list = (TYPE *) realloc(list, capacity * sizeof(TYPE));
}
list[count] = object;
return count++;
}
void fastRemove(const unsigned int index){
if (index < count){
count--;
list[index] = list[count];
}
}
void orderedRemove(const unsigned int index){
if (index < count){
count--;
memmove(list + index, list + index + 1, (count - index) * sizeof(TYPE));
}
}
void clear(){
count = 0;
}
void reset(){
free(list);
list = NULL;
count = capacity = 0;
}
private:
int partition(int (*compare)(const TYPE &elem0, const TYPE &elem1), int p, int r){
TYPE tmp, pivot = list[p];
int left = p;
for (int i = p + 1; i <= r; i++){
if (compare(list[i], pivot) < 0){
left++;
tmp = list[i];
list[i] = list[left];
list[left] = tmp;
}
}
tmp = list[p];
list[p] = list[left];
list[left] = tmp;
return left;
}
void quickSort(int (*compare)(const TYPE &elem0, const TYPE &elem1), int p, int r){
if (p < r){
int q = partition(compare, p, r);
quickSort(compare, p, q - 1);
quickSort(compare, q + 1, r);
}
}
public:
void sort(int (*compare)(const TYPE &elem0, const TYPE &elem1)){
quickSort(compare, 0, count - 1);
}
protected:
unsigned int capacity;
unsigned int count;
TYPE *list;
};
struct BTri {
void split(BTri *dest, int &nPos, int &nNeg, const Ogre::Vector4 &plane, const float epsilon) const;
void finalize();
bool intersects(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1) const;
bool isAbove(const Ogre::Vector3 &pos) const;
float getDistance(const Ogre::Vector3 &pos) const;
Ogre::Vector4 plane;
Ogre::Vector4 edgePlanes[3];
Ogre::Vector3 v[3];
/*
Ogre::Vector3 edgeNormals[3];
float edgeOffsets[3];
Ogre::Vector3 normal;
float offset;
*/
void *data;
};
struct BNode {
~BNode();
bool intersects(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector3 &dir, Ogre::Vector3 *point, const BTri **triangle) const;
BTri *intersectsCached(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector3 &dir) const;
bool pushSphere(Ogre::Vector3 &pos, const float radius) const;
void getDistance(const Ogre::Vector3 &pos, float &minDist) const;
void build(Array <BTri> &tris, const int splitCost, const int balCost, const float epsilon);
//void build(Array <BTri> &tris);
void read(FILE *file);
void write(FILE *file) const;
BNode *back;
BNode *front;
BTri tri;
};
class BSP {
public:
BSP(){
top = NULL;
cache = NULL;
}
~BSP(){
delete top;
}
void addTriangle(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector3 &v2, void *data = NULL);
void build(const int splitCost = 3, const int balCost = 1, const float epsilon = 0.001f);
bool intersects(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, Ogre::Vector3 *point = NULL, const BTri **triangle = NULL) const;
bool intersectsCached(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1);
bool pushSphere(Ogre::Vector3 &pos, const float radius) const;
float getDistance(const Ogre::Vector3 &pos) const;
bool isInOpenSpace(const Ogre::Vector3 &pos) const;
bool loadFile(const char *fileName);
bool saveFile(const char *fileName) const;
protected:
Array <BTri> tris;
BNode *top;
BTri *cache;
};
#endif // _BSP_H_
//###########################################################################
// WARNING: modified by Jacob 'jacmoe' Moen
// Ported to Ogre3D
/* * * * * * * * * * * * * Author's note * * * * * * * * * * * */
* _ _ _ _ _ _ _ _ _ _ _ _ *
* |_| |_| |_| |_| |_|_ _|_| |_| |_| _|_|_|_|_| *
* |_|_ _ _|_| |_| |_| |_|_|_|_|_| |_| |_| |_|_ _ _ *
* |_|_|_|_|_| |_| |_| |_| |_| |_| |_| |_| |_|_|_|_ *
* |_| |_| |_|_ _ _|_| |_| |_| |_|_ _ _|_| _ _ _ _|_| *
* |_| |_| |_|_|_| |_| |_| |_|_|_| |_|_|_|_| *
* *
* http://www.humus.name *
* *
* This file is a part of the work done by Humus. You are free to *
* use the code in any way you like, modified, unmodified or copied *
* into your own work. However, I expect you to respect these points: *
* - If you use this file and its contents unmodified, or use a major *
* part of this file, please credit the author and leave this note. *
* - For use in anything commercial, please request my approval. *
* - Share your work and ideas too as much as you can. *
* *
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "BSP.h"
#ifdef _WIN32
#pragma warning(push, 1)
#pragma warning(disable: 4799)
#endif
float planeDistance(const Ogre::Vector3 &normal, const float offset, const Ogre::Vector3 &point){
return point.x * normal.x + point.y * normal.y + point.z * normal.z + offset;
}
float planeDistance(const Ogre::Vector4 &plane, const Ogre::Vector3 &point){
return point.x * plane.x + point.y * plane.y + point.z * plane.z + plane.w;
}
float dot(const Ogre::Vector3 &u, const Ogre::Vector3 &v){
return u.x * v.x + u.y * v.y + u.z * v.z;
}
float dot(const Ogre::Vector4 &u, const Ogre::Vector4 &v){
return u.x * v.x + u.y * v.y + u.z * v.z + u.w * v.w;
}
//# define no_alias
no_alias Ogre::Vector3 planeHit(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector4 &plane){
Ogre::Vector3 dir = v1 - v0;
float d = planeDistance(plane, v0);
Ogre::Vector3 pos = v0 - (d / dot((Ogre::Vector3 &) plane, dir)) * dir;
return pos;
}
void BTri::split(BTri *dest, int &nPos, int &nNeg, const Ogre::Vector4 &plane, const float epsilon) const {
float d[3];
for (int i = 0; i < 3; i++){
d[i] = planeDistance(plane, v[i]);
}
int first = 2;
int second = 0;
while (!(d[second] > epsilon && d[first] <= epsilon)){
first = second;
second++;
}
// Positive triangles
nPos = 0;
Ogre::Vector3 h = planeHit(v[first], v[second], plane);
do {
first = second;
second++;
if (second >= 3) second = 0;
dest->v[0] = h;
dest->v[1] = v[first];
if (d[second] > epsilon){
dest->v[2] = v[second];
} else {
dest->v[2] = h = planeHit(v[first], v[second], plane);
}
dest->data = data;
dest->finalize();
dest++;
nPos++;
} while (d[second] > epsilon);
// Skip zero area triangle
if (fabsf(d[second]) <= epsilon){
first = second;
second++;
if (second >= 3) second = 0;
}
// Negative triangles
nNeg = 0;
do {
first = second;
second++;
if (second >= 3) second = 0;
dest->v[0] = h;
dest->v[1] = v[first];
if (d[second] < -epsilon){
dest->v[2] = v[second];
} else {
dest->v[2] = planeHit(v[first], v[second], plane);
}
dest->data = data;
dest->finalize();
dest++;
nNeg++;
} while (d[second] < -epsilon);
}
Ogre::Vector3 normalize(const Ogre::Vector3 &v){
float invLen = 1.0f / sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
return v * invLen;
}
Ogre::Vector4 normalize(const Ogre::Vector4 &v){
float invLen = 1.0f / sqrtf(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
return v * invLen;
}
Ogre::Vector3 cross(const Ogre::Vector3 &u, const Ogre::Vector3 &v){
return Ogre::Vector3(u.y * v.z - v.y * u.z, u.z * v.x - u.x * v.z, u.x * v.y - u.y * v.x);
}
void BTri::finalize(){
Ogre::Vector3 normal = normalize(cross(v[1] - v[0], v[2] - v[0]));
float offset = -dot(v[0], normal);
Ogre::Vector3 edgeNormals[3];
edgeNormals[0] = cross(normal, v[0] - v[2]);
edgeNormals[1] = cross(normal, v[1] - v[0]);
edgeNormals[2] = cross(normal, v[2] - v[1]);
float edgeOffsets[3];
edgeOffsets[0] = dot(edgeNormals[0], v[0]);
edgeOffsets[1] = dot(edgeNormals[1], v[1]);
edgeOffsets[2] = dot(edgeNormals[2], v[2]);
plane = Ogre::Vector4(normal.x, normal.y, normal.z, offset);
edgePlanes[0] = Ogre::Vector4(edgeNormals[0].x, edgeNormals[0].y, edgeNormals[0].z, -edgeOffsets[0]);
edgePlanes[1] = Ogre::Vector4(edgeNormals[1].x, edgeNormals[1].y, edgeNormals[1].z, -edgeOffsets[1]);
edgePlanes[2] = Ogre::Vector4(edgeNormals[2].x, edgeNormals[2].y, edgeNormals[2].z, -edgeOffsets[2]);
}
no_alias bool BTri::intersects(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1) const {
Ogre::Vector3 dir = v0 - v1;
// float k = (dot(normal, v0) + offset) / dot(normal, dir);
float k = planeDistance(plane, v0) / dot(Ogre::Vector3(plane.x, plane.y, plane.z), dir);
if (k < 0 || k > 1) return false;
Ogre::Vector3 pos = v0 - k * dir;
for (unsigned int i = 0; i < 3; i++){
if (planeDistance(edgePlanes[i], pos) < 0){
// if (dot(edgeNormals[i], pos) < edgeOffsets[i]){
return false;
}
}
return true;
}
no_alias bool BTri::isAbove(const Ogre::Vector3 &pos) const {
/*
return (edgeNormals[0].x * pos.x + edgeNormals[0].y * pos.y + edgeNormals[0].z * pos.z >= edgeOffsets[0] &&
edgeNormals[1].x * pos.x + edgeNormals[1].y * pos.y + edgeNormals[1].z * pos.z >= edgeOffsets[1] &&
edgeNormals[2].x * pos.x + edgeNormals[2].y * pos.y + edgeNormals[2].z * pos.z >= edgeOffsets[2]);
*/
/*
return (edgePlanes[0].x * pos.x + edgePlanes[0].y * pos.y + edgePlanes[0].z * pos.z >= -edgePlanes[0].w &&
edgePlanes[1].x * pos.x + edgePlanes[1].y * pos.y + edgePlanes[1].z * pos.z >= -edgePlanes[1].w &&
edgePlanes[2].x * pos.x + edgePlanes[2].y * pos.y + edgePlanes[2].z * pos.z >= -edgePlanes[2].w);
*/
return (planeDistance(edgePlanes[0], pos) >= 0 && planeDistance(edgePlanes[1], pos) >= 0 && planeDistance(edgePlanes[2], pos) >= 0);
}
no_alias float BTri::getDistance(const Ogre::Vector3 &pos) const {
int k = 2;
for (int i = 0; i < 3; i++){
float d = planeDistance(edgePlanes[i], pos);
if (d < 0){
// Project onto the line between the points
Ogre::Vector3 dir = v[i] - v[k];
float c = dot(dir, pos - v[k]) / dot(dir, dir);
Ogre::Vector3 d;
if (c >= 1){
d = v[i];
} else {
d = v[k];
if (c > 0) d += c * dir;
}
return Ogre::Vector3(pos - d).length();
}
k = i;
}
return fabsf(planeDistance(plane, pos));
}
#ifdef USE_SIMD
bool BTri::isAbove3DNow(v2sf v0XY, v2sf v0Z1) const {
for (int i = 0; i < 3; i++){
v2sf planeXY = ((v2sf *) &edgePlanes[i])[0];
v2sf planeZD = ((v2sf *) &edgePlanes[i])[1];
v2sf dotXY = pfmul(planeXY, v0XY);
v2sf dotZD = pfmul(planeZD, v0Z1);
v2sf dot = pfacc(dotXY, dotZD);
dot = pfacc(dot, dot);
int d = _m_to_int(dot);
if (d < 0) return false;
}
return true;
}
#endif
BNode::~BNode(){
delete back;
delete front;
}
no_alias bool BNode::intersects(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1,
const Ogre::Vector3 &dir, Ogre::Vector3 *point, const BTri **triangle) const {
#if 0
float d0 = planeDistance(tri.plane, v0);
float d1 = planeDistance(tri.plane, v1);
vec3 pos;
if (d0 > 0){
if (d1 <= 0){
pos = v0 - (d0 / dot(tri.plane.xyz(), dir)) * dir;
}
if (front != NULL && front->intersects(v0, (d1 <= 0)? pos : v1, dir, point, triangle)) return true;
if (d1 <= 0){
if (tri.isAbove(pos)){
if (point) *point = pos;
if (triangle) *triangle = &tri;
return true;
}
if (back != NULL && back->intersects(pos, v1, dir, point, triangle)) return true;
}
} else {
if (d1 > 0){
pos = v0 - (d0 / dot(tri.plane.xyz(), dir)) * dir;
}
if (back != NULL && back->intersects(v0, (d1 > 0)? pos : v1, dir, point, triangle)) return true;
if (d1 > 0){
if (tri.isAbove(pos)){
if (point) *point = pos;
if (triangle) *triangle = &tri;
return true;
}
if (front != NULL && front->intersects(pos, v1, dir, point, triangle)) return true;
}
}
#else
float d = planeDistance(tri.plane, v0);
if (d > 0){
if (front != NULL && front->intersects(v0, v1, dir, point, triangle)) return true;
if (planeDistance(tri.plane, v1) < 0){
Ogre::Vector3 pos = v0 - (d / dot(Ogre::Vector3(tri.plane.x,tri.plane.y,tri.plane.z), dir)) * dir;
if (tri.isAbove(pos)){
if (point) *point = pos;
if (triangle) *triangle = &tri;
return true;
}
if (back != NULL && back->intersects(v0, v1, dir, point, triangle)) return true;
}
} else {
if (back != NULL && back->intersects(v0, v1, dir, point, triangle)) return true;
if (planeDistance(tri.plane, v1) > 0){
Ogre::Vector3 pos = v0 - (d / dot(Ogre::Vector3(tri.plane.x,tri.plane.y,tri.plane.z), dir)) * dir;
if (tri.isAbove(pos)){
if (point) *point = pos;
if (triangle) *triangle = &tri;
return true;
}
if (front != NULL && front->intersects(v0, v1, dir, point, triangle)) return true;
}
}
#endif
return false;
}
no_alias BTri *BNode::intersectsCached(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector3 &dir) const {
#if 0
float d0 = planeDistance(tri.plane, v0);
float d1 = planeDistance(tri.plane, v1);
vec3 pos;
if (d0 > 0){
if (d1 <= 0){
pos = v0 - (d0 / dot((vec3 &) tri.plane, dir)) * dir;
}
if (front != NULL){
BTri *tri;
if (d1 <= 0){
tri = front->intersectsCached(v0, pos, dir);
} else {
tri = front->intersectsCached(v0, v1, dir);
}
if (tri) return tri;
}
if (d1 <= 0){
if (tri.isAbove(pos)) return (BTri *) &tri;
if (back != NULL){
BTri *tri = back->intersectsCached(pos, v1, dir);
if (tri) return tri;
}
}
} else {
if (d1 > 0){
pos = v0 - (d0 / dot((vec3 &) tri.plane, dir)) * dir;
}
if (back != NULL){
BTri *tri;
if (d1 > 0){
tri = back->intersectsCached(v0, pos, dir);
} else {
tri = back->intersectsCached(v0, v1, dir);
}
if (tri) return tri;
}
if (d1 > 0){
if (tri.isAbove(pos)) return (BTri *) &tri;
if (front != NULL){
BTri *tri = front->intersectsCached(pos, v1, dir);
if (tri) return tri;
}
}
}
#else
float d = planeDistance(tri.plane, v0);
if (d > 0){
if (front != NULL){
BTri *tri = front->intersectsCached(v0, v1, dir);
if (tri) return tri;
}
if (planeDistance(tri.plane, v1) < 0){
Ogre::Vector3 pos = v0 - (d / dot(Ogre::Vector3(tri.plane.x,tri.plane.y,tri.plane.z), dir)) * dir;
if (tri.isAbove(pos)) return (BTri *) &tri;
if (back != NULL){
BTri *tri = back->intersectsCached(v0, v1, dir);
if (tri) return tri;
}
}
} else {
if (back != NULL){
BTri *tri = back->intersectsCached(v0, v1, dir);
if (tri) return tri;
}
if (planeDistance(tri.plane, v1) > 0){
Ogre::Vector3 pos = v0 - (d / dot(Ogre::Vector3(tri.plane.x,tri.plane.y,tri.plane.z), dir)) * dir;
if (tri.isAbove(pos)) return (BTri *) &tri;
if (front != NULL){
BTri *tri = front->intersectsCached(v0, v1, dir);
if (tri) return tri;
}
}
}
#endif
return NULL;
}
no_alias bool BNode::pushSphere(Ogre::Vector3 &pos, const float radius) const {
float d = planeDistance(tri.plane, pos);
bool pushed = false;
if (fabsf(d) < radius){
if (tri.isAbove(pos)){
// pos += (radius - d) * tri.normal;
pos += (radius - d) * Ogre::Vector3(tri.plane.x,tri.plane.y,tri.plane.z);
pushed = true;
}
}
if (front != NULL && d > -radius) pushed |= front->pushSphere(pos, radius);
if (back != NULL && d < radius) pushed |= back ->pushSphere(pos, radius);
return pushed;
}
no_alias void BNode::getDistance(const Ogre::Vector3 &pos, float &minDist) const {
float d = planeDistance(tri.plane, pos);
float dist = tri.getDistance(pos);
if (dist < minDist){
minDist = dist;
}
if (back && d < minDist){
back->getDistance(pos, minDist);
}
if (front && -d < minDist){
front->getDistance(pos, minDist);
}
}
void BNode::read(FILE *file){
fread(&tri.v, sizeof(tri.v), 1, file);
tri.finalize();
int flags = 0;
fread(&flags, sizeof(int), 1, file);
if (flags & 1){
back = new BNode;
back->read(file);
} else back = NULL;
if (flags & 2){
front = new BNode;
front->read(file);
} else front = NULL;
}
void BNode::write(FILE *file) const {
fwrite(&tri.v, sizeof(tri.v), 1, file);
int flags = 0;
if (back) flags |= 1;
if (front) flags |= 2;
fwrite(&flags, sizeof(int), 1, file);
if (back) back->write(file);
if (front) front->write(file);
}
/*
void BNode::build(Array <BTri> &tris){
uint index = 0;
int minScore = 0x7FFFFFFF;
for (uint i = 0; i < tris.getCount(); i++){
int score = 0;
int diff = 0;
for (uint k = 0; k < tris.getCount(); k++){
uint neg = 0, pos = 0;
for (uint j = 0; j < 3; j++){
// float dist = dot(tris[k].v[j], tris[i].normal) + tris[i].offset;
float dist = planeDistance(tris[i].plane, tris[k].v[j]);
if (dist < 0) neg++; else pos++;
}
if (pos){
if (neg) score += 3; else diff++;
} else diff--;
}
score += abs(diff);
if (score < minScore){
minScore = score;
index = i;
}
}
tri = tris[index];
tris.fastRemove(index);
Array <BTri> backTris;
Array <BTri> frontTris;
for (uint i = 0; i < tris.getCount(); i++){
uint neg = 0, pos = 0;
for (uint j = 0; j < 3; j++){
// float dist = dot(tris[i].v[j], tri.normal) + tri.offset;
float dist = planeDistance(tri.plane, tris[i].v[j]);
if (dist < 0) neg++; else pos++;
}
if (neg) backTris.add(tris[i]);
if (pos) frontTris.add(tris[i]);
}
//tris.clear();
if (backTris.getCount() > 0){
back = new BNode;
back->build(backTris);
} else back = NULL;
if (frontTris.getCount() > 0){
front = new BNode;
front->build(frontTris);
} else front = NULL;
}
*/
void BNode::build(Array <BTri> &tris, const int splitCost, const int balCost, const float epsilon){
uint index = 0;
int minScore = 0x7FFFFFFF;
for (uint i = 0; i < tris.getCount(); i++){
int score = 0;
int diff = 0;
for (uint k = 0; k < tris.getCount(); k++){
uint neg = 0, pos = 0;
for (uint j = 0; j < 3; j++){
float dist = planeDistance(tris[i].plane, tris[k].v[j]);
if (dist < -epsilon) neg++; else
if (dist > epsilon) pos++;
}
if (pos){
if (neg) score += splitCost; else diff++;
} else {
if (neg) diff--; else diff++;
}
}
score += balCost * abs(diff);
if (score < minScore){
minScore = score;
index = i;
}
}
tri = tris[index];
tris.fastRemove(index);
Array <BTri> backTris;
Array <BTri> frontTris;
for (uint i = 0; i < tris.getCount(); i++){
uint neg = 0, pos = 0;
for (uint j = 0; j < 3; j++){
float dist = planeDistance(tri.plane, tris[i].v[j]);
if (dist < -epsilon) neg++; else
if (dist > epsilon) pos++;
}
if (neg){
if (pos){
BTri newTris[3];
int nPos, nNeg;
tris[i].split(newTris, nPos, nNeg, tri.plane, epsilon);
for (int i = 0; i < nPos; i++){
frontTris.add(newTris[i]);
}
for (int i = 0; i < nNeg; i++){
backTris.add(newTris[nPos + i]);
}
} else {
backTris.add(tris[i]);
}
} else {
frontTris.add(tris[i]);
}
}
tris.reset();
if (backTris.getCount() > 0){
back = new BNode;
back->build(backTris, splitCost, balCost, epsilon);
} else back = NULL;
if (frontTris.getCount() > 0){
front = new BNode;
front->build(frontTris, splitCost, balCost, epsilon);
} else front = NULL;
}
void BSP::addTriangle(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1, const Ogre::Vector3 &v2, void *data){
BTri tri;
tri.v[0] = v0;
tri.v[1] = v1;
tri.v[2] = v2;
tri.data = data;
tri.finalize();
tris.add(tri);
}
void BSP::build(const int splitCost, const int balCost, const float epsilon){
// int nTris = tris.getCount();
top = new BNode;
// top->build(tris);
top->build(tris, splitCost, balCost, epsilon);
/*
SSENode *mem = new SSENode[nTris * 4];
sseTop = (SSENode *) ((intptr(mem) + 15) & ~intptr(0xF));
sseDest = sseTop + 1;
sseTop->build(top, sseDest);
sseDest = mem;
*/
}
no_alias bool BSP::intersects(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1,
Ogre::Vector3 *point, const BTri **triangle) const {
if (top != NULL) return top->intersects(v0, v1, v1 - v0, point, triangle);
return false;
}
bool BSP::intersectsCached(const Ogre::Vector3 &v0, const Ogre::Vector3 &v1){
if (top != NULL){
if (cache){
if (cache->intersects(v0, v1)) return true;
}
cache = top->intersectsCached(v0, v1, v1 - v0);
return (cache != NULL);
}
return false;
}
bool BSP::pushSphere(Ogre::Vector3 &pos, const float radius) const {
if (top != NULL) return top->pushSphere(pos, radius);
return false;
}
no_alias float BSP::getDistance(const Ogre::Vector3 &pos) const {
float dist = FLT_MAX;
if (top != NULL) top->getDistance(pos, dist);
return dist;
}
no_alias bool BSP::isInOpenSpace(const Ogre::Vector3 &pos) const {
if (top != NULL){
BNode *node = top;
while (true){
float d = planeDistance(node->tri.plane, pos);
if (d > 0){
if (node->front){
node = node->front;
} else return true;
} else {
if (node->back){
node = node->back;
} else return false;
}
}
}
return false;
}
bool BSP::loadFile(const char *fileName){
FILE *file = fopen(fileName, "rb");
if (file == NULL) return false;
delete top;
top = new BNode;
top->read(file);
fclose(file);
return true;
}
bool BSP::saveFile(const char *fileName) const {
if (top == NULL) return false;
FILE *file = fopen(fileName, "wb");
if (file == NULL) return false;
top->write(file);
fclose(file);
return true;
}
#ifdef _WIN32
#pragma warning(pop)
#endif
相关文章推荐
- Axiom3D:Ogre地形组件代码解析
- 使用tortoisegit进行代码控制及相关设置
- Ogre材质解析代码初步分析(二)
- Android编程之图片相关代码集锦
- iOS_ UITextField相关代码
- Ogre相关的物理引擎
- 编写高质量代码:改善Java的151个建议二:11-14(序列化相关内容)
- Toast只显示一次相关代码
- 量化相关代码学习
- kernel 3.10代码分析--KVM相关--虚拟机创建
- yii2 数据库的相关操作的代码示例
- Android毕设相关PM2.5,空气监测的谁有代码啊
- 代理上网相关代码收藏
- 关于Latent Dirichlet Allocation及Hierarchical LDA模型的必读文章和相关代码
- android 多媒体相关代码
- 代码注入相关知识以及扫雷程序的分析(分析过程之后添加)
- ecstore b2b2c 商城页面伪静态代码 及相关注意事项
- 安庆百佳投票软件代码及验证码识别相关
- GitHub上创建工程及代码提交、更新等相关操作
- mybatise插件反向生成数据库表相关Java代码