sphere.h

来自「Ray tracing on PS3, using the accelerati」· C头文件 代码 · 共 150 行

H
150
字号
/* Copyright (c) 2007 Massachusetts Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *//** * sphere.h - blue-steel Sphere class * @author Brian Sweatt *  * Contains methods for intersecting a RayPacket with a Sphere and getting a Sphere's bounding box on the SPU * As well as methods for translating and setting the center position of a Sphere on the PPU */#ifndef _SPHERE_H_ #define _SPHERE_H_#include <libvector.h>#include "raypacket.h"#include "hitpacket.h"#include "common.h"extern "C" {#ifdef __SPU__#include <spu_intrinsics.h>#endif#include <simdmath.h>#include <dot_product3_v.h>#include <normalize3_v.h>}class Sphere {private:  vector float m_x, m_y, m_z, m_r; //first 3 are origin, last is radius  uint32_t m_materialID, pad1, pad2, pad3;public:  Sphere(const vector float &sphere, uint32_t materialID);  ~Sphere() { };#ifdef __SPU__  //void intersectPacket(const RayPacket r, HitPacket &h, float tmin);  /**   * Algebraic intersection routine for a ray with a sphere   * @param r The RayPacket to test for intersection with this sphere   * @param h The HitPacket that will hold a record of this hit   * @param tmin The minimum time that will be considered a valid hit (the near clipping plane for the rays)   */  inline void intersectPacket(const RayPacket &r, HitPacket &h, float tmin) {     // Fast algebraic intersection routine for a ray with a sphere...    // Slightly hard to follow due to some hand-tuning for instruction pipelining    // and variable reusing....    vector float two_v = spu_splats(2.0f);    vector float zero_v = spu_splats(0.0f);    vector float r0x = spu_sub(r.x0, m_x);    vector float r0y = spu_sub(r.y0, m_y);    vector float r0z = spu_sub(r.z0, m_z);    vector float radius_squared = spu_mul(m_r, m_r);    // Partially compute b... since we can save operations by fusing the rest of the     // computation with the calculation of t1 and t2    vector float a = _dot_product3_v(r.dx, r.dy, r.dz, r.dx, r.dy, r.dz);    vector float b = _dot_product3_v(r.dx, r.dy, r.dz, r0x, r0y, r0z);    vector float c = _dot_product3_v(r0x, r0y, r0z, r0x, r0y, r0z);    // We don't really need a anymore... just 2*a    a = spu_mul(two_v,a);    b = spu_mul(two_v, b);    c = spu_sub(c, radius_squared);    // 4*a*c = 2*a....    vector float four_a_c = spu_mul(two_v, a);    // Now we don't even need 2*a... just it's reciprocal    a = spu_re(a);    four_a_c = spu_mul(four_a_c, c);    vector float tmin_v = spu_splats(tmin);    vector float neg_one_v = spu_splats(-1.0f);    vector float d = spu_msub(b, b, four_a_c);    vector unsigned int isvalid = spu_cmpgt(d, zero_v);    d = sqrtf4(d);    // Compute the t1 and t2 values = (b+d) and (d-b)....    vector float t1 = spu_add(b, d);    vector float t2 = spu_sub(d, b);    // ... times -1 = (-b-d)    t1 = spu_mul(t1, neg_one_v);        // ... times 1/2a and 1/2a = (-b-d)/2a and (-b+d)/2a, respectively    t2 = spu_mul(t2, a);    t1 = spu_mul(t1, a);    vector float max_v = spu_splats(MAX_FLOAT);    vector unsigned int t2gt = spu_cmpgt(t2, tmin_v);    vector unsigned int t1gt = spu_cmpgt(t1, tmin_v);    t2 = spu_sel(max_v, t2, t2gt);    t1 = spu_sel(max_v, t1, t1gt);    t2gt = spu_cmpgt(t2, t1);    // Select the smaller of the time values and store in t2    t2 = spu_sel(t2, t1, t2gt);    t2 = spu_sel(max_v, t2, isvalid);    // We can precompute the normal based on the t value, regardless of whether or not    // it will be chosen, since we'll spu_sel it out later    // To save space, we'll just reuse the r0x, r0y, r0z to store the intersected point    // Calculated by r0 = r.dir*t2 + r.origin    r0x = spu_madd(r.dx, t2, r.x0);    r0y = spu_madd(r.dy, t2, r.y0);    r0z = spu_madd(r.dz, t2, r.z0);    isvalid = spu_cmpgt(t2, zero_v);    // Compare the smaller time to the time stored in the hit packet...    // This will be used to select the intersect time, as well as the normal...    t2gt = spu_cmpgt(t2, h.t);    t2gt = spu_and(t2gt, isvalid);    // Compute normal = intersection point - center point    r0x = spu_sub(r0x, m_x);    r0y = spu_sub(r0y, m_y);    r0z = spu_sub(r0z, m_z);    // if it's greater, select the hitPacket time, if not, select t2    h.t = spu_sel(t2, h.t, t2gt);            // Normalize the computed normal    _normalize3_v(&r0x, &r0y, &r0z, r0x, r0y, r0z);            h.nx = spu_sel(r0x, h.nx, t2gt);    h.ny = spu_sel(r0y, h.ny, t2gt);    h.nz = spu_sel(r0z, h.nz, t2gt);    h.materialID = spu_sel(spu_splats(m_materialID), h.materialID, t2gt);        return;  }    vector float getBoundingBoxMin();   vector float getBoundingBoxMax(); #endif  void setPosition(vector float pos);  void translate(vector float dir);};#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?