bool Player::RayCastApprox(spades::Vector3 start, spades::Vector3 dir){ Vector3 diff = position - start; // |P-A| * cos(theta) float c = Vector3::Dot(diff, dir); // |P-A|^2 float sq = diff.GetPoweredLength(); // |P-A| * sin(theta) float dist = sqrtf(sq - c * c); return dist < 8.f; }
void GLSoftLitSpriteRenderer::Render() { SPADES_MARK_FUNCTION(); if(sprites.empty()) return; // light every sprite const std::vector<GLDynamicLight>& lights = renderer->lights; for(size_t i = 0; i < sprites.size(); i++){ Sprite& spr = sprites[i]; if(spr.color.w < .0001f) { // maybe emissive sprite... spr.emission = spr.color.GetXYZ(); spr.color = MakeVector4(0.f, 0.f, 0.f, 0.f); }else{ spr.emission = MakeVector3(0.f, 0.f, 0.f); } spr.dlR = MakeVector4(0, 0, 0, 0); spr.dlG = MakeVector4(0, 0, 0, 0); spr.dlB = MakeVector4(0, 0, 0, 0); } for(size_t j = 0; j < lights.size(); j++) { const GLDynamicLight& l = lights[j]; const client::DynamicLightParam& dl = l.GetParam(); float spotTan = dl.type == client::DynamicLightTypeSpotlight ? tanf(dl.spotAngle * .5f) : 0.; for(size_t i = 0; i < sprites.size(); i++){ Sprite& spr = sprites[i]; Vector3 v = dl.origin - spr.center; float effectiveRadius = spr.radius + dl.radius; if(v.GetChebyshevLength() > effectiveRadius) continue; float powdist = v.GetPoweredLength(); if(powdist > effectiveRadius * effectiveRadius) continue; float att = 1.f - powdist / (effectiveRadius * effectiveRadius); float unif; float directionalFactor = 1.f; unif = 1.f - powdist / (spr.radius * spr.radius); unif = std::max(.2f, unif); if(dl.type == client::DynamicLightTypeSpotlight) { float forward = Vector3::Dot(v, dl.spotAxis[2]); if(forward > spr.radius) { continue; }else if(forward >= -spr.radius){ att *= .5f - (forward / spr.radius) * .5f; directionalFactor = 1.f; }else{ float cx = Vector3::Dot(spr.center - dl.origin, dl.spotAxis[0]); float cy = Vector3::Dot(spr.center - dl.origin, dl.spotAxis[1]); float sq = sqrtf(cx * cx + cy * cy); float sprTan = spr.radius / (-spr.radius - forward); float eff = sprTan + spotTan; sq /= -forward; if(sq > eff){ continue; } if(sq > eff - spotTan){ att *= (eff - sq) / spotTan; } } } Vector4 final; if(unif < .9999f) { Vector3 directional = v; directional *= att * directionalFactor * (1.f - unif) / sqrtf(powdist); final.x = directional.x; final.y = directional.y; final.z = directional.z;
bool OBB3::RayCast(spades::Vector3 start, spades::Vector3 dir, spades::Vector3 *hitPos) { Vector3 normX = {m.m[0], m.m[1], m.m[2]}; Vector3 normY = {m.m[4], m.m[5], m.m[6]}; Vector3 normZ = {m.m[8], m.m[9], m.m[10]}; // subtract offset Vector3 origin = {m.m[12], m.m[13], m.m[14]}; start -= origin; Vector3 end = start + dir; float dotX = Vector3::Dot(dir, normX); float dotY = Vector3::Dot(dir, normY); float dotZ = Vector3::Dot(dir, normZ); // inside? if(*this && start){ *hitPos = start; return true; } // x-plane hit test if(dotX != 0.f){ float startp = Vector3::Dot(start, normX); float endp = Vector3::Dot(end, normX); float boxp = Vector3::Dot(normX, normX); float hit; // 0=start, 1=end if(startp < endp){ hit = startp / (startp - endp); }else{ hit = (boxp - startp) / (endp - startp); } if(hit >= 0.f){ *hitPos = start + dir * hit; float yd = Vector3::Dot(*hitPos, normY); float zd = Vector3::Dot(*hitPos, normZ); if(yd >= 0 && zd >= 0 && yd <= normY.GetPoweredLength() && zd <= normZ.GetPoweredLength()) { // hit x-plane *hitPos += origin; return true; } } } // y-plane hit test if(dotY != 0.f){ float startp = Vector3::Dot(start, normY); float endp = Vector3::Dot(end, normY); float boxp = Vector3::Dot(normY, normY); float hit; // 0=start, 1=end if(startp < endp){ hit = startp / (startp - endp); }else{ hit = (boxp - startp) / (endp - startp); } if(hit >= 0.f){ *hitPos = start + dir * hit; float xd = Vector3::Dot(*hitPos, normX); float zd = Vector3::Dot(*hitPos, normZ); if(xd >= 0 && zd >= 0 && xd <= normX.GetPoweredLength() && zd <= normZ.GetPoweredLength()) { // hit y-plane *hitPos += origin; return true; } } } // z-plane hit test if(dotZ != 0.f){ float startp = Vector3::Dot(start, normZ); float endp = Vector3::Dot(end, normZ); float boxp = Vector3::Dot(normZ, normZ); float hit; // 0=start, 1=end if(startp < endp){ hit = startp / (startp - endp); }else{ hit = (boxp - startp) / (endp - startp); } if(hit >= 0.f){ *hitPos = start + dir * hit; float xd = Vector3::Dot(*hitPos, normX); float yd = Vector3::Dot(*hitPos, normY); if(xd >= 0 && yd >= 0 && xd <= normX.GetPoweredLength() && yd <= normY.GetPoweredLength()) { // hit z-plane *hitPos += origin; return true; } } } return false; }
void SWRenderer::ApplyDynamicLight(const DynamicLight &light) { int fw = this->fb->GetWidth(); int fh = this->fb->GetHeight(); float fovX = tanf(sceneDef.fovX * 0.5f); float fovY = tanf(sceneDef.fovY * 0.5f); float dvx = -fovX * 2.f / static_cast<float>(fw); float dvy = -fovY * 2.f / static_cast<float>(fh); int minX = light.minX; int minY = light.minY; int maxX = light.maxX; int maxY = light.maxY; int lightHeight = maxY - minY; SPAssert(minX >= 0); SPAssert(minY >= 0); SPAssert(maxX <= fw); SPAssert(maxY <= fh); Vector3 lightCenter; Vector3 diff = light.param.origin - sceneDef.viewOrigin; lightCenter.x = Vector3::Dot(diff, sceneDef.viewAxis[0]); lightCenter.y = Vector3::Dot(diff, sceneDef.viewAxis[1]); lightCenter.z = Vector3::Dot(diff, sceneDef.viewAxis[2]); int lightR = ToFixedFactor8(light.param.color.x); int lightG = ToFixedFactor8(light.param.color.y); int lightB = ToFixedFactor8(light.param.color.z); float invRadius2 = 1.f / (light.param.radius * light.param.radius); InvokeParallel2([=](unsigned int threadId, unsigned int numThreads) { int startY = lightHeight * threadId / numThreads; int endY = lightHeight * (threadId + 1) / numThreads; startY += minY; endY += minY; auto *fb = this->fb->GetPixels(); float *db = depthBuffer.data(); fb += startY * fw + minX; db += startY * fw + minX; float vy = fovY + dvy * startY; float vx = fovX + dvx * minX; int lightWidth = maxX - minX; for(int y = startY; y < endY; y++) { float vx2 = vx; auto *fb2 = fb; auto *db2 = db; for(int x = lightWidth; x > 0; x--) { Vector3 pos; pos.z = *db2; pos.x = vx2 * pos.z; pos.y = vy * pos.z; pos -= lightCenter; float dist = pos.GetPoweredLength(); dist *= invRadius2; if(dist < 1.f) { float strength = 1.f - dist; strength *= strength; strength *= 256.f; int factor = static_cast<int>(strength); int actualLightR = lightR * factor; int actualLightG = lightG * factor; int actualLightB = lightB * factor; auto srcColor = *fb2; auto srcColorR = (srcColor >> 16) & 0xff; auto srcColorG = (srcColor >> 8) & 0xff; auto srcColorB = srcColor & 0xff; actualLightR *= srcColorR; actualLightG *= srcColorG; actualLightB *= srcColorB; auto destColorR = actualLightR >> 16; auto destColorG = actualLightG >> 16; auto destColorB = actualLightB >> 16; destColorR = std::min<uint32_t>(destColorR+srcColorR, 255); destColorG = std::min<uint32_t>(destColorG+srcColorG, 255); destColorB = std::min<uint32_t>(destColorB+srcColorB, 255); uint32_t destColor = destColorB | (destColorG<<8) | (destColorR<<16); *fb2 = destColor; } vx2 += dvx; fb2++; db2++; } vy += dvy; fb += fw; db += fw; } });