Neither adding a SKShapeNode nor adding a SKLabelNode to a SKScene appears to work?
My gut guesses that I have a coordinate problem .. so here's the short code snippet which I have placed in my GameViewController class:
Note: I've added print statements below to debug.
FYI: I believe the values are wrong because they appear to be Frame coordinates, not Scene Coordinates. Frankly, I'm at a loss how to correct this error.
func addScoreLabelToScene(toScene: SKScene) {
if thisSceneName == "GameScene" {
let circleRadius = Double(100),
circleOffset = Double(30),
labelOffset = Double(10),
//
circlePosX = toScene.frame.size.width/2 - circleRadius - circleOffset,
labelPosX = circlePosX - labelOffset,
circlePosY = toScene.frame.size.height/2 + circleRadius + circleOffset,
labelPosY = circlePosY + labelOffset
// frame.size = 818, 1340
print("circlePosX = \(circlePosX)") // 279
print("circlePosY = \(circlePosY)") // 800
print("labelPosX = \(labelPosX)") // 269
print("labelPosY = \(labelPosY)") // 810
let circle = SKShapeNode(circleOfRadius: circleRadius)
circle.position = CGPoint(x: circlePosX, y: circlePosY)
circle.strokeColor = SKColor.red
circle.lineWidth = 2.0
circle.fillColor = SKColor.white
toScene.addChild(circle)
itsScoreLabel = SKLabelNode(fontNamed: "HelveticaNeue-Bold")
itsScoreLabel!.position = CGPoint(x: labelPosX, y: labelPosY)
itsScoreLabel!.text = "\(thisScore)"
itsScoreLabel!.fontSize = 20
itsScoreLabel!.fontColor = SKColor.blue
toScene.addChild(itsScoreLabel!)
}
} // addScoreLabelToScene
WRT to the above guess about a coordinate problem, I have hard-wired values for the PosX and PosY variables, but no success there.
In addition I have commented out both toScene.addChild() calls (one at a time) with no luck.
To complete the problem description, I have code elsewhere that adds several SKSpriteNodes with no problem.
So, what mammoth error am I committing?
As already commented above, I owe kelin above immeasurable thanks for motivating me to check my code again!
The central issue centers on specifying .zPosition = 10 or any very large number so the 2 Objects are not buried under everything.
So ... the NEW code which does it right:
func addScoreLabelToScene(toScene: SKScene) {
if thisSceneName == "GameScene" {
let circleRadius = Double(50), // lots of messing with #s involved
circleOffsetX = Double(25)
#if os(iOS)
let circleOffsetY = Double(105)
#elseif os(tvOS)
let circleOffsetY = Double(25)
#endif
// NR because we've centered the label within the circle.
// Nevertheless, as noted below, we still have to position it
// for horizontal + vertical alignment to take effect.
let labelOffsetX = Double(0),
labelOffsetY = Double(0),
//
circlePosX = toScene.frame.size.width/2 - circleRadius - circleOffsetX,
labelPosX = circlePosX - labelOffsetX,
circlePosY = toScene.frame.size.height/2 - circleRadius - circleOffsetY,
labelPosY = circlePosY - labelOffsetY
// added these print statements to debug:
// frame.size = 818, 1340
print("circlePosX = \(circlePosX)") // 334 = 818/2 - 50 - 25
print("circlePosY = \(circlePosY)") // 515 = 1340/2 - 50 - 105
print("labelPosX = \(labelPosX)") // 334 = 334 - 0
print("labelPosY = \(labelPosY)") // 515 = 515 - 0
let circle = SKShapeNode(circleOfRadius: circleRadius)
circle.zPosition = 10 // otherwise, the Object will be buried at the bottom
circle.position = CGPoint(x: circlePosX, y: circlePosY)
circle.strokeColor = SKColor.red
circle.lineWidth = 6.0
circle.fillColor = SKColor.white
toScene.addChild(circle)
itsScoreLabel = SKLabelNode(fontNamed: "HelveticaNeue-Bold")
itsScoreLabel!.zPosition = 10
// still gotta position it for alignment to take affect
itsScoreLabel!.position = CGPoint(x: labelPosX, y: labelPosY)
itsScoreLabel!.horizontalAlignmentMode = .center
itsScoreLabel!.verticalAlignmentMode = .center
itsScoreLabel!.text = "\(thisScore)"
itsScoreLabel!.fontSize = 30
itsScoreLabel!.fontColor = SKColor.blue
toScene.addChild(itsScoreLabel!)
}
} // addScoreLabelToScene
I have two points in my world, P0 and P1 (xyz,..) which basically represent the start of my line and the end of my line. I also have a plane/side with 4 points, ABCD (xyz,..).
What I want to do is send a "ray" (in this case a line) through the plane and check whether or not it intersects with it. I have used this (How to find intersection point of a line in a plane in 3D space using MATLAB) question as a reference and this function mathlabcentral. I tried the example "isp-zax" gave and that does give me the same values as he does, but as soon as I plop in my own values it is clearly wrong. The answers formula;
>> AB = B-A
AB = 0.8660 0.5000 0
>> AD = D-A
AD = 0 0 1
>> n = cross(AB,AD)/sqrt(dot(cross(AB,AD),cross(AB,AD)))
n = 0.5000 -0.8660 0
>> [I,check]=plane_line_intersect(n,A,P0,P1)
I = 1.0961 44.5116 6.6948
check = 3
--
So the first set of line points (P) work perfectly fine which it should (see image) but if I move the end point of the line (P1) outside of the plane it still says it intersects (see 2nd image). What could cause this?
A = [1312.901701, 2360.12542566832, 74.24415425756794];
B = [1312.901701, 2423.58274087539, 88.31230234462595];
C = [1312.901701, 2371.241313396465, 24.103624956470995];
D = [1312.901701, 2434.698628603535, 38.171773043529];
P0 = [1495.468628, 2261.038086, 161.329498];
P1 = [1153.250854, 2479.341797, -14.787056];
--
This is it in javascript;
const ab = subtract(B, A);
const ad = subtract(D, A);
const n = divide(cross(ab, ad), sqrt(dot(cross(ab, ad), cross(ab, ad))));
const intersects = planeLineIntersect(n, A, P0, P1);
function planeLineIntersect(n, v0, p0, p1) {
const u = subtract(p1, p0);
const w = subtract(p0, v0);
const D = dot(n, u);
const N = -dot(n, w);
let check = 0;
if (abs(D) < 0.0000001) {
if (N === 0) {
check = 2;
return check;
}
check = 0;
return check;
}
const sI = divide(N, D);
const I = add(p0, multiply(sI, u)); // not used
if (sI < 0 || sI > 1) {
check = 3;
} else check = 1;
return check;
}
I have changed my post and posted the whole of my code! Could someone tell me how can I optimize it?
import Base: *, +, -, /, ^
using Images
const Π = convert(Float64, π)
#define vector
mutable struct Vec3
x::Float64
y::Float64
z::Float64
end
function +(u::Vec3, v::Vec3)
Vec3(u.x+v.x, u.y+v.y, u.z+v.z)
end
function -(u::Vec3, v::Vec3)
Vec3(u.x-v.x, u.y-v.y, u.z-v.z)
end
function /(u::Vec3, v::Float64)
Vec3(u.x/v, u.y/v, u.z/v)
end
function *(u, v::Vec3)
if typeof(u) == Float64
Vec3(u*v.x, u*v.y, u*v.z)
elseif typeof(u) == Vec3
Vec3(u.x*v.x, u.y*v.y, u.z*v.z)
end
end
function ^(u::Vec3, v::Float64)
Vec3(u.x^v, u.y^v, u.z^v)
end
function dot(u::Vec3, v::Vec3)
u.x*v.x + u.y*v.y + u.z*v.z
end
function normalize(u::Vec3)
u/sqrt(dot(u,u))
end
function cross(u::Vec3, v::Vec3)
Vec3(u.y*v.z - v.y*u.z, u.z*v.x - v.z*u.x, u.x*v.y - v.x*u.y)
end
function gamma(u::Vec3)
Vec3(u.x^(1/2.2), u.y^(1/2.2), u.z^(1/2.2))
end
function clamp(u::Vec3)
u.x = u.x <= 1 ? u.x : 1
u.y = u.y <= 1 ? u.y : 1
u.z = u.z <= 1 ? u.z : 1
u
end
#define ray
struct Ray
s::Vec3
d::Vec3
end
#define planes
struct xyRect
z; x1; x2; y1; y2::Float64
normal; emittance; reflectance::Vec3
isLight::Bool
end
struct xzRect
y; x1; x2; z1; z2::Float64
normal; emittance; reflectance::Vec3
isLight::Bool
end
struct yzRect
x; y1; y2; z1; z2::Float64
normal; emittance; reflectance::Vec3
isLight::Bool
end
#define sphere
mutable struct Sphere
radius::Float64
center; normal; emittance; reflectance::Vec3
isLight::Bool
end
#define empty object
struct Empty
normal; emittance; reflectance::Vec3
end
#define surfaces
Surfaces = Union{xyRect, xzRect, yzRect, Sphere}
#define intersection function
function intersect(surface::Surfaces, ray::Ray)
if typeof(surface) == xyRect
t = (surface.z - ray.s.z)/ray.d.z
if surface.x1 < ray.s.x + t*ray.d.x < surface.x2 && surface.y1 < ray.s.y + t*ray.d.y < surface.y2 && t > 0
t
else
Inf
end
elseif typeof(surface) == xzRect
t = (surface.y - ray.s.y)/ray.d.y
if surface.x1 < ray.s.x + t*ray.d.x < surface.x2 && surface.z1 < ray.s.z + t*ray.d.z < surface.z2 && t > 0
t
else
Inf
end
elseif typeof(surface) == yzRect
t = (surface.x - ray.s.x)/ray.d.x
if surface.y1 < ray.s.y + t*ray.d.y < surface.y2 && surface.z1 < ray.s.z + t*ray.d.z < surface.z2 && t > 0
t
else
Inf
end
elseif typeof(surface) == Sphere
a = dot(ray.d, ray.d)
b = 2dot(ray.d, ray.s - surface.center)
c = dot(ray.s - surface.center, ray.s - surface.center) - surface.radius*surface.radius
Δ = b*b - 4*a*c
if Δ > 0
Δ = sqrt(Δ)
t1 = 0.5(-b-Δ)/a
t2 = 0.5(-b+Δ)/a
if t1 > 0
surface.normal = normalize(ray.s + t1*ray.d - surface.center)
t1
elseif t2 > 0
surface.normal = normalize(ray.s + t2*ray.d - surface.center)
t2
else
Inf
end
else
Inf
end
end
end
#define nearest function
function nearest(surfaces::Array{Surfaces, 1}, ray::Ray, tMin::Float64)
hitSurface = Empty(Vec3(0,0,0), Vec3(0,0,0), Vec3(0,0,0))
for surface in surfaces
t = intersect(surface, ray)
if t < tMin
tMin = t
hitSurface = surface
end
end
tMin, hitSurface
end
#cosine weighted sampling of hemisphere
function hemiRand(n::Vec3)
ξ1 = rand()
ξ2 = rand()
x = cos(2π*ξ2)*sqrt(ξ1)
y = sin(2π*ξ2)*sqrt(ξ1)
z = sqrt(1-ξ1)
r = normalize(Vec3(2rand()-1, 2rand()-1, 2rand()-1))
b = cross(n,r)
t = cross(n,b)
Vec3(x*t.x + y*b.x + z*n.x, x*t.y + y*b.y + z*n.y, x*t.z + y*b.z + z*n.z)
end
#trace the path
function trace(surfaces::Array{Surfaces, 1}, ray::Ray, depth::Int64, maxDepth::Int64)
if depth >= maxDepth
return Vec3(0,0,0)
end
t, material = nearest(surfaces, ray, Inf)
if typeof(material) == Empty
return Vec3(0,0,0)
end
if material.isLight == true
return material.emittance
end
ρ = material.reflectance
BRDF = ρ/Π
n = material.normal
R = hemiRand(n)
In = trace(surfaces, Ray(ray.s + t*ray.d, R), depth+1, maxDepth)
return Π*BRDF*In
end
#define camera
struct Camera
eye; v_up; N::Vec3
fov; aspect; distance::Float64
end
#render function
function render(surfaces::Array{Surfaces,1},camera::Camera,xRes::Int64,yRes::Int64,numSamples::Int64,maxDepth::Int64)
n = normalize(camera.N)
e = camera.eye
c = e - camera.distance*n
θ = camera.fov*(π/180)
H = 2*camera.distance*tan(θ/2)
W = H*camera.aspect
u = normalize(cross(camera.v_up,n))
v = cross(n,u)
img = zeros(3, xRes, yRes)
pixHeight = H/yRes
pixWidth = W/xRes
L = c - 0.5*W*u - 0.5*H*v
for i=1:xRes
for j=1:yRes
cl = Vec3(0,0,0)
for s=1:numSamples
pt = L + (i-rand())*pixWidth*u + (yRes-j+rand())*pixHeight*v
cl = cl + trace(surfaces, Ray(e, pt-e), 0, maxDepth)
end
cl = gamma(clamp(cl/convert(Float64, numSamples)))
img[:,j,i] = [cl.x, cl.y, cl.z]
end
end
img
end
#the scene
p1 = xzRect(1.,0.,1.,-1.,0.,Vec3(0,-1,0),Vec3(0,0,0),Vec3(0.75,0.75,0.75),false)
p2 = xzRect(0.,0.,1.,-1.,0.,Vec3(0,1,0),Vec3(0,0,0),Vec3(0.75,0.75,0.75),false)
p3 = xyRect(-1.,0.,1.,0.,1.,Vec3(0,0,1),Vec3(0,0,0),Vec3(0.75,0.75,0.75),false)
p4 = yzRect(0.,0.,1.,-1.,0.,Vec3(1,0,0),Vec3(0,0,0),Vec3(0.75,0.25,0.25),false)
p5 = yzRect(1.,0.,1.,-1.,0.,Vec3(-1,0,0),Vec3(0,0,0),Vec3(0.25,0.25,0.75),false)
p6 = xzRect(0.999,0.35,0.65,-0.65,-0.35,Vec3(0,-1,0),Vec3(18,18,18),Vec3(0,0,0),true)
s1 = Sphere(0.15,Vec3(0.3,0.15,-0.6),Vec3(0,0,0),Vec3(0,0,0),Vec3(0.75,0.75,0.75),false)
surfs = Surfaces[p1,p2,p3,p4,p5,p6,s1]
cam = Camera(Vec3(0.5,0.5,2),Vec3(0,1,0),Vec3(0,0,1),28.07,1,2)
#time image = render(surfs, cam, 400, 400, 1, 4);
colorview(RGB, image)
I need to know why my code is bad and slow. I am a beginner programmer and I don't have enough experience. My path tracer scene contains 7 objects, its maximum depth is 4, and it takes more than 2 seconds to generate an image of size 400*400. I think It shouldn't be that slow because my cpu is core i7 4770.
Sorry for changing my post.
To start with,
struct yzRect
x; y1; y2; z1; z2::Float64
normal; emittance; reflectance::Vec3
isLight::Bool
end
ends up only applying the type to the last variable for each line:
julia> fieldtypes(yzRect)
(Any, Any, Any, Any, Float64, Any, Any, Vec3, Bool)
so Julia will basically not know about any types in your structs which slows things down.
Also, your Vec3 should really be immutable and you then just create new instances of it when you want to "modify" the Vector.
There might be many more issues but those are two standing out.
Reading through https://docs.julialang.org/en/v1/manual/performance-tips/index.html and applying the guidelines in there is strongly recommended when analyzing performance.