So I need the camera to orbit my data multiple times. I thought this should be quite easy but I could not figure it out. Double clicking the camera sequence in the Animation View allowed me to add another path but it added a default path which was different to the orbit. Manually (and painfully) copying the path parameters over did not work either? Any ideas on how to do this?
I know this is quite some time later, but I was stuck on this same need. I ended up tracing to see how a follow path camera cue worked in python code, and then I stacked a few of those lines in a for loop making sure I updated the KeyTime of the frame. This gave me an animation that orbited the focal point set for as many orbits as I did loops.
https://discourse.paraview.org/t/issues-with-multiple-orbit-laps-in-single-animation/11371
from paraview.simple import *
anim = GetAnimationScene()
renderView1 = GetActiveViewOrCreate("RenderView")
cameraAnimationCue1 = CameraAnimationCue()
#cameraAnimationCue1 = GetCameraTrack(view=rv)
cameraAnimationCue1.Mode = 'Path-based'
cameraAnimationCue1.AnimatedProxy = renderView1
# create a new key frame
n = 3
for i in range(n):
keyFrameN = CameraKeyFrame()
keyFrameN.Position = [-6.6921304299024635, 0.0, 0.0]
keyFrameN.FocalPoint = [1e-20, 0.0, 0.0]
keyFrameN.ViewUp = [0.0, 0.0, 1.0]
keyFrameN.ParallelScale = 1.7320508075688772
keyFrameN.PositionPathPoints = [0.0, -5.0, 0.0, 2.938926261462365, -4.045084971874736, 0.0, 4.755282581475766, -1.545084971874737, 0.0, 4.755282581475766, 1.5450849718747361, 0.0, 2.938926261462365, 4.045084971874735, 0.0, 1.3322676295501878e-15, 4.9999999999999964, 0.0, -2.9389262614623624, 4.045084971874735, 0.0, -4.755282581475763, 1.5450849718747368, 0.0, -4.755282581475763, -1.5450849718747341, 0.0, -2.9389262614623632, -4.045084971874731, 0.0]
keyFrameN.FocalPathPoints = [0.0, 0.0, 0.0]
keyFrameN.ClosedPositionPath = 1
keyFrameN.KeyTime = i/n
cameraAnimationCue1.KeyFrames.append(keyFrameN)
# ending scale
keyFrame9333 = CameraKeyFrame()
keyFrame9333.KeyTime = 1.0
keyFrame9333.Position = [-6.6921304299024635, 0.0, 0.0]
keyFrame9333.FocalPoint = [1e-20, 0.0, 0.0]
keyFrame9333.ViewUp = [0.0, 0.0, 1.0]
keyFrame9333.ParallelScale = 1.7320508075688772
# initialize the animation track
cameraAnimationCue1.KeyFrames.append( keyFrame9333)
anim.Cues.append(cameraAnimationCue1)
Related
This little method that I wrote, changes spotlight1's position to the unexpected value.
If I understand well, setPosition method should set spotlight's translation relative to the tv's position
TV's translation: [0.0, 0.0, -5.0]
setPosition to [0.0, 5.0, 0.5] relative to Tv's translation.
So:
[0.0 + 0, 0.0 + 5, -5.0 + 0.5] = [0.0, 5.0, -4.5]
But what I get is:
[0.0, 0.9999994, -4.9]
Am I missing some important information here?
func loadLights() {
arView.scene.addAnchor(lightAnchor)
lightAnchor.addChild(spotlight1)
print(tv?.position) // 0.0, 0.0, -5.0
spotlight1.setPosition([0, 5, 0.5], relativeTo: tv)
if let tv = tv {
spotlight1.look(at: tv.position,
from: spotlight1.position,
relativeTo: nil)
}
print(spotlight1.position) // 0.0, 0.99999994, -4.99
}
Reference Coordinate Frame
As paradoxical as it may sound, RealityKit did everything right. You need to take into account the frame of reference (frame of your tv model). As far as I understand, you reduced the scale of the tv model by five times. Am I right? However, reference's transform matters.
In other words, you've scaled down the local coordinate frame (a.k.a. local coordinate system) of the TV model, you're trying to position spotLight1 relative to.
About relativeTo parameter
Read this post and this post to explore possible issues.
i have some codes which i need to reimplement with Cairo::RefPtrCairo::Context...It is a bit confusing since i could not find good example which uses pattern while we have Cairo::RefPtrCairo::Context instead of cairo_t..
Cairo::RefPtr<Cairo::Surface> surface =
Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, width, height);
Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface);
cairo_pattern_t *cp = cairo_pattern_create_radial(x_off, y_off, 0, x_off, y_off, cent_point_radius);
cairo_pattern_add_color_stop_rgba(cp, 0.0, 0.7, 0.7, 0.7, 0.8);
cairo_pattern_add_color_stop_rgba(cp, 1.0, 0.1, 0.1, 0.1, 0.8);
cairo_set_source(cr, cp);
How i can change "cp" to something which is recognizable for cr->set_resource().....cr used to be a cairo_t,but then i had to change it to Cairo::RefPtrCairo::Context
best regards
Since you've already decided to do it the C++ way, why not go all the way in?
// Create image surface.
Cairo::RefPtr <Cairo::Surface> refSurface =
Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32,
nWidth,
nHeight);
// Create Cairo context for the image surface.
Cairo::RefPtr <Cairo::Context> refContext =
Cairo::Context::create(refSurface);
// Create a radial gradient (pattern)
Cairo::RefPtr <Cairo::RadialGradient> refPattern =
Cairo::RadialGradient::create(x_off,
y_off,
0,
x_off,
y_off,
cent_point_radius);
// Add color stops to the pattern
refPattern->add_color_stop_rgba(0.0,
0.7,
0.7,
0.7,
0.8);
refPattern->add_color_stop_rgba(1.0,
0.1,
0.1,
0.1,
0.8);
// Set the pattern as the source for the context.
refContext->set_source(refPattern);
// Add a closed path and fill...
If I run the following vertex shader in Metal/Swift I get a nice rectangle on the screen:
vertex Vertex vertexShader(uint k [[ vertex_id ]],
device float2* position [[buffer(1)]]){
Vertex output;
float2 pos = position[k];
output.position = float4(pos,0,1);
return output;
};
//position [0.0, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.5]
//indexList [0, 1, 2, 2, 1, 3]
Now if I run the following I get a blank screen:
vertex Vertex vertexShader(uint k [[ vertex_id ]],
device float3* position [[buffer(1)]]){
Vertex output;
float3 pos = position[k];
output.position = float4(pos,1);
return output;
};
//position [0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.0]
//indexList [0, 1, 2, 2, 1, 3]
It seems to me these should produce identical results. What am I missing?
How exactly are you filling the buffer associated with index 1 in your app code?
I suspect you're just supplying an array of floats. Well, float3 is not packed. Its layout is not the same as 3 floats. There's padding. Its size is actually the same as float4 or 4 floats.
Probably, the simplest fix is to declare position as a pointer to packed_float3.
I'm trying to pass a GLKVector4 to a shader that should receive it as a vec4. I'm using a fragment shader modifier:
material.shaderModifiers = [ SCNShaderModifierEntryPoint.fragment: shaderModifier ]
where shaderModifier is:
// color changes
uniform float colorModifier;
uniform vec4 colorOffset;
vec4 color = _output.color;
color = color + colorOffset;
color = color + vec4(0.0, colorModifier, 0.0, 0.0);
_output.color = color;
(I'm simply adding a color offset) I've tried:
material.setValue(GLKVector4(v: (250.0, 0.0, 0.0, 0.0)), "colorOffset")
which doesn't work (no offset is added and the shader uses the default value that is (0, 0, 0, 0)). Same happens if I replace GLKVector4 by SCNVector4
Following this I've also tried:
let points: [float2] = [float2(250.0), float2(0.0), float2(0.0), float2(0.0)]
material.setValue(NSData(bytes: points, length: points.count * sizeof(float2)), "colorOffset")
However, I can pass a float value to the uniform colorModifier easily by doing:
material.setValue(250.0, forKey: "colorModifier")
and that will increase the green channel as excepted
So you have to use NSValue, that has a convenience initialization for SCNVector4, so:
let v = SCNVector4(x: 250.0, y: 0.0, z: 0.0, w: 0.0)
material.setValue(NSValue(scnVector4: v), "colorOffset")
It'd be too good if SceneKit could handle it's own types directly...
I should see 2 yellow triangles, but I see nothing.
class Terrain {
private class func createGeometry () -> SCNGeometry {
let sources = [
SCNGeometrySource(vertices:[
SCNVector3(x: -1.0, y: -1.0, z: 0.0),
SCNVector3(x: -1.0, y: 1.0, z: 0.0),
SCNVector3(x: 1.0, y: 1.0, z: 0.0),
SCNVector3(x: 1.0, y: -1.0, z: 0.0)], count:4),
SCNGeometrySource(normals:[
SCNVector3(x: 0.0, y: 0.0, z: -1.0),
SCNVector3(x: 0.0, y: 0.0, z: -1.0),
SCNVector3(x: 0.0, y: 0.0, z: -1.0),
SCNVector3(x: 0.0, y: 0.0, z: -1.0)], count:4)
]
let elements = [
SCNGeometryElement(indices: [0, 2, 3, 0, 1, 2], primitiveType: .Triangles)
]
let geo = SCNGeometry(sources:sources, elements:elements)
let mat = SCNMaterial()
mat.diffuse.contents = UIColor.yellowColor()
mat.doubleSided = true
geo.materials = [mat]
return geo
}
class func createNode () -> SCNNode {
let node = SCNNode(geometry: createGeometry())
node.name = "Terrain"
node.position = SCNVector3()
return node
}
}
I use it as follows:
let terrain = Terrain.createNode()
sceneView.scene?.rootNode.addChildNode(terrain)
let camera = SCNCamera()
camera.zFar = 10000
self.camera = SCNNode()
self.camera.camera = camera
self.camera.position = SCNVector3(x: -20, y: 15, z: 30)
let constraint = SCNLookAtConstraint(target: terrain)
constraint.gimbalLockEnabled = true
self.camera.constraints = [constraint]
sceneView.scene?.rootNode.addChildNode(self.camera)
I get other nodes with non-custom geometry which I see. What's wrong?
Hal Mueller is quite correct in that the indices involved must be a specified type, but it should be noted that this functionality has changed significantly in recent versions of the Swift language. Notably, SCNGeometryElement(indices:, primitiveType:) now functions perfectly well in Swift 4 and I would advise against using CInt which did not work for me. Instead use one of the standard integer types that conforms to the FixedWidthInteger protocol, i.e. Int32. If you know there's a maximum number of vertices involved in your mesh, use the smallest bit size you can that will encompass all of them.
Example:
let vertices = [
SCNVector3(x: 5, y: 4, z: 0),
SCNVector3(x: -5 , y: 4, z: 0),
SCNVector3(x: -5, y: -5, z: 0),
SCNVector3(x: 5, y: -5, z: 0)
]
let allPrimitives: [Int32] = [0, 1, 2, 0, 2, 3]
let vertexSource = SCNGeometrySource(vertices: vertices)
let element = SCNGeometryElement(indices: allPrimitives, primitiveType: .triangles)
let geometry = SCNGeometry(sources: [vertexSource], elements: [element])
SCNNode(geometry: geometry)
What's Happening Here?
First we create an array of vertices describing points in three-dimensional space. The allPrimitives array describes how those vertices link up. Each element is an index from the vertices array. Since we're using triangles, these should be considered in groups of three, one for each corner. For simplicity's sake I've done a simple flat square here. We then create a geometry source with the semantic type of vertices using the original array of all vertices, and a geometry element using the allPrimitives array, also informing it that they are triangles so it knows to group them in threes. These can then be used to create the SCNGeometry object with which we initialise our SCNNode.
An easy way to think about it is that the vertex source exists only to list all the vertices in the object. The geometry element exists only to describe how those vertices are linked up. It's the SCNGeometry that combines these two objects together to create the final physical representation.
Note: see Ash's answer, which is a much better approach for modern Swift than this one.
Your index array has the wrong size element. It's being inferred as [Int]. You need [CInt].
I broke out your elements setup into:
let indices = [0, 2, 3, 0, 1, 2] // [Int]
print(sizeof(Int)) // 8
print(sizeof(CInt)) // 4
let elements = [
SCNGeometryElement(indices: indices, primitiveType: .Triangles)
]
To get the indices to be packed like the expected C array, declare the type explicitly:
let indices: [CInt] = [0, 2, 3, 0, 1, 2]
Custom SceneKit Geometry in Swift on iOS not working but equivalent Objective C code does goes into more detail, but it's written against Swift 1, so you'll have to do some translation.
SCNGeometryElement(indices:, primitiveType:) doesn't appear to be documented anywhere, although it does appear in the headers.