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 + -
显示快捷键?